💾 Archived View for gmi.noulin.net › sheepy › main.md captured on 2024-08-25 at 10:14:13.

View Raw

More Information

-=-=-=-=-=-=-

# libsheepy overview


# Overview

The libsheepy API is available in 2 includes: libsheepy.h and libsheepyObject.h

- __libsheepy.h__ for simple system functions and functions handling C basic type: int, char* (string), char** and void**
- __libsheepyObject.h__ for the classes, this h file includes __libsheepy.h__

There are examples for both __libsheepy.h__ and __libsheepyObject.h__ in the  [example folder](https://spartatek.se/r/libsheepy/files.html).

# libsheepy.h

There are 4 function categories:

- system: expandHome, getCwd, chDir, fileExists, fileChmod, fileSize, walkDir, mkdirParents, rmAll, copy, random*, readLine, execOut
- file: readText, readStream, writeText, writeStream, appendText
- string: \*S
- list: list*S and list\*

For string and list, there are these sub function categories:
- *S: create new buffers
- i*S: in place, modify/use existing buffers. The input buffers must be allocated with malloc/calloc.
- b*, bL*: buffer functions. In these functions, the destination buffer is allocated by the caller. In the bL* functions, the destination size is the size of the buffer (strlen+1).
- ic*: Ignore case functions: ic*
- *UTF8: UTF-8 functions. Rune is defined as single UTF-8 code point.

libsheepy.h also has:
- loops: range*, forEach*, linked list forEach (lForEach)
- arrays: staticArray, indexer, ring, dArray, slab

It is advised to use the C11 generics from libsheepyObject.h instead of the libsheepy.h functions directly because there are many functions.

For detailed usage of each function, see [libsheepyTest.c](https://spartatek.se/r/libsheepy/file/src/libsheepyTest.c.html)

# libsheepyObject.h

libsheepyObject.h is an API for handling data in objects like JSON. The functions are similar to the ones in libsheepy.h and are object oriented. The library is compatible with both C99 and C11. The use of generics (only C11) greatly simplify the API.

The classes are:
 __baset__: base class, all other classes inherit baset (libsheepyObject.h)
- __smallArrayt__: array able to hold multiple objects of different types (libsheepyCSmallArray.h), the array elements are s objects, see next section for information about s objects.
- __smallBoolt__: bool (libsheepyCSmallBool.h)
- __smallBytest__: array of bytes (libsheepyCSmallBytes.h)
- __smallContainert__: store a buffer, some class and object functions are user defined and need to initiliazed (libsheepyCSmallContainer.h)
- __smallDictt__: key-value dictionary. Keys are strings and values are s objects, see next section for information about s objects (libsheepyCSmallDict.h)
- __smallDoublet__: double (libsheepyCSmallDouble.h)
- __smallIntt__: int (libsheepyCSmallInt.h)
- __smallJsont__: json object with parse, stringify, serial methods (libsheepyCSmallJson.h)
- __smallStringt__: string (libsheepyCSmallString.h)
- __undefinedt__: undefined, null (libsheepyCUndefined.h)

The file and system functions accepting objects in parameters are declared in libsheepyObject.h.

The method implementation is dynamic, all objects have an array of functions (obj->f->), the functions can be provided at runtime.

The object model is available at [the objects git repo](https://noulin.net/objects/file/README.md.html) and the template for new classes is in libsheepyCClassTemplate.h, libsheepyCClassTemplateInternal.h and libsheepyCClassTemplate.c.

For functions returning a status value, the value for errors is 0, false, NULL or specified otherwise in the function description.
In general, errors are detected with __"if (!func)"__.

## Generics

The C11 generics are the main interface to libsheepy. Generics simplify greatly libsheepy development since only
a few functions are needed and there are many functions in libsheepy (thousands).

The generics are defined in libsheepyObject.h and their names end with G: freeG, setG.

They accept any small object, char, char*, int64_t, uint64_t, double...

All small object methods have a generic in libsheepyObject.h, my advice is to __use the generics all the time__.

There are also the defines for C99 ending in __O__.

The main generics are:

- initiateG, allocG, freeG, terminateG, isOTypeG, getOTypeG, toStringG, duplicateG, smashG, finishG, dupG, putsG
- pushG, pushNFreeG, setG, setNFreeG, setPG, setNFreePG, getG, getNDupG
- appendG, appendNSmashG, prependG, prependNFreeG
- delG, popG, dequeueG
- readFileG, writeFileG, replaceG, eqG, eqIG, startsWithG, endsWithG, countG, parseIntG, intToG, lenG, upperG, lowerG, trimG, uniqG, sliceG, copyRngG, insertG, findG, hasG, emptyG, isEmptyG, isBlankG, fromArrayG, splitG, joinG, extractG, reverseG, addG, sortG, binarySearchG, compactG

Generics returning a value have a returnType parameter to select the return type.

## Base class

The baset classes listed above are the API classes, the data is stored in s objects inside. When a baset object is created, also in s object is created. The s objects are defined in libsheepySmall.h.

The baset objects are containers for s objects.

baset objects holds the pointer to the data and the methods -> s objects hold the data, defined in libsheepySmall.h


All objects have __free, terminate, toString, duplicate methods and create*, createAllocate*, initiate*, initiateAllocate*, finalize* and alloc*__ functions.

- __create*, createAllocate*__ declare and allocate objects. create* declare local objects that need to be freed but cannot be terminated. createAllocate* declare a pointer and allocate the object, the object has to be terminated (or smashed)
- __initiate*, initiateAllocate*__ allocate already declared objects
- __alloc*__ allocate objects and return them, an initial value is sometime required.

smallBoolt myBool, myBool2;

createAllocateSmallBool(mySBool);

initiateAllocateSmallBool(&myBool);

myBool2 = allocSmallBool(true);


- __finalize*__ is to be called when the class or libsheepyObjects are not used anymore. After a call to finalize*, the class or libsheepyObjects are usable anymore, all libsheepyObjects have to be terminated before calling these functions. __finalizeLibsheepy__ finalizes all libsheepy classes and should be called a the end of the program.

- __toString or toStringG__ convert the data in the object to string
- __duplicate or duplicateG__ make a copy of the object
- __free or freeG__ free the s object inside the object
- __terminate or terminateG__ free the s object and the object
- __finish or finishG__ free the object (container) and keep the s object, instead of freeing the objects with free use the finish function to get maximum performance in future version of libsheepy
- __disposeG__ is available in some classes and frees the s object container and keep the elements inside, see appendNSmashG code below.
- __smashG__ is available in some classes and frees the s object container, keep the elements inside and free the object, see appendNSmashG code below. For some classes (all except smallArray, smallDict and smallJson) smash and finish are equivalent.
- __isOTypeG__ tests the object type
- __getOTypeG__ returns the object type string

The object type strings for isOTypeG or return by getOTypeG are:

- "smallArray"
- "smallBool"
- "smallBytes"
- "smallContainer"
- "smallDict"
- "smallDouble"
- "smallInt"
- "smallJson"
- "smallString"
- "undefined"

## Object Life cycle

Objects have to be created

createSmallBool(myBool);

createAllocateSmallBool(myBoolP);


or declared and initialized

smallBoolt myBool;

initiateSmallBool(myBool);

smallBoolt *myBoolP;

initiateAllocateSmallBool(&myBoolP);


use the free method to free the s object inside the object, use the finish method to free the container and keep the s object inside and when the object is not used anymore terminate the object

freeG(myBool);

finishG(myBool);

terminateG(myBoolP);


## Allocating objects

allocG and initiateG both initialize objects, for some classes allocG take an initial parameter.

smallBoolt myBool;

initiateG(myBool);

smallBoolt *myBoolP;

initiateG(&myBoolP);

// allocG

smallStringt *s = allocG("allocate new string");

smallArrayt *array = allocG(rtSmallArrayt);

smallBoolt *boolv = allocG(TRUE);

void *buffer;

smallContainert *c = allocG(buffer);

smallDictt *dict = allocG(rtSmallDictt);

double dbl = 0;

smallDoublet *dblo = allocG(dbl);

int64_t intv = 0;

smallIntt * into = allocG(intv);

smallJsont *json = allocG(json);


## Adding objects to Arrays, Dictionaries and Json

- push, prepend, set, setP add objects
- pop, dequeue, get retrieve objects

The set functions in smallDict __duplicate the given key string__ in parameter to avoid memory management problems when freeing the smallDict dictionary.

When the sObject pointer is updated by realloc, the sObject
pointer in the smallArray has to be updated with setP.
The operations reallocating the sObjects are:

- smallDict: push, set (only for new keys), trim, merge, append
- smallArray: push, prepend
- smallBytes: push, pushBuffer
- smallJson: push, set (only for new keys)
- smallString: append, prepend, replace, intTo, insert, color, readFile

The object is duplicated for the following types:

char * (unused: cBool, cDouble, cInt, stringt)


## Get object in array or dictionary

The get function in smallArrayt and smallDictt creates a baset object and copies the pointer to the data to it. When the operations on the array or dictionary element are finished, the baset object needs to freed, but the data inside to be kept, so the finish function is used, see __smallObjectsUsage.c__.

// the S object is created and has a pointer to the value for "s" in dict

S = getG(dict, S, "s")

S->f->upper(S);

finishG(S);


Sometimes, the data reallocated and the __setP__ function is used to update the pointer in the array or dictionary, see smallObject.c.

// the st object is created by getAtSmallString and holds a pointer to

// the value at 0

st = anotherStringArray->f->getAtSmallString(anotherStringArray, 0)

st->f->color(st, BLD BGRED);

// setPAtNFreeSmallString updates the pointer at 0 and free the st baset object

anotherStringArray->f->setPAtNFreeSmallString(anotherStringArray, 0, st);


__setNFreePG__ is the generics to update the pointer in an array or a dictionary and free the baset object, see __smallObjectsUsage.c__.

// add Dict2 to dict and free Dict2 object

setNFreeG(dict, "Dict2", Dict2);


__pushNFree__ adds data at the end of the array and frees the baset object.

__setNFreeG__ frees the data already present, sets a pointer to the new data and frees the baset object.

__getNDupG__ duplicates the data and creates a baset object.

__appendNSmashG__ appends arrays, the elements of the second array are push in the first array. The smash function frees the second array (not the elements) and frees the baset object, see __smallObjectsUsage.c__.

// the array a is pushed in gotArray

appendNSmashG(gotArray, a);

// same operation with smashG

appendG(gotArray,a);

smashG(a);

// Dispose example

// append a array and keep the baset object

appendG(gotArray,a);

// dispose frees the array but not the elements and the baset object is kept

disposeG(a);


## Duplicating objects

duplicateG duplicates objects of classes inheriting baset.

dupG duplicates objects of classes inheriting baset like duplicateG and also char* strings and char** lists.

## Equality

eqG compares 2 objects of any type and returns true when they are equal. When the objects have different types, they are converted to allow comparison. If the conversion is impossible then the objects have incompatible types and false is returned.

For example, when a string is compared to an int, the string is converted to an int with the parseIntS function and then compared.

char c = '1';

int32_t i = 1;

if (eqG(c, i)) puts("c and i are equal");


## Insert and Inject

insertG add elements from the object in parameter at given. When self and the parameter have different types, the object in parameter is added at the index.
InjectG always add the object in parameter at the index.

smallArrayt *a;

smallArrayt *a1;

insertG(a, -1, a1);

// a becomes [elements in a, elements from a1];

injectG(a, -1, a1);

// a becomes [elements in a, [a1]]


## Terminal colors

The colors and effects are defined libsheepy.h, the effect codes can be added to static strings directly. For dynamic strings, there is the color method in the smallString class, see smallObject.c.

// coloring a static string

puts(BLD RED "At least 2 arguments are needed" RST);

// coloring string

st->f->color(st, BLD BGRED);


# Loops and range

The simplest loops for libsheepy.h are forEachCharP and forEachS, and for libsheepyObject.h the simplest loops are the iterators.

## Iterators

The smallArray and smallDict classes have iterators, the iterator methods start with the prefix iter.

There is an iter macro to loop on all elements in the object:

createAllocateSmallArray(list);

iter(list, e)

smallStringt *s = (smallStringt*)e // or castS(s,e);

logVarG(s);


The memory is managed by the iterator.

There are also a few macros in libsheepy.h for iterating conveniently on integers:

- range: starts from 0 to maxCount
- rangeFrom
- circular
- rangeStep
- rangeDownStep
- rangeFromStep

## Loop methods

The smallArray and smallDict classes have loop methods:

- forEach
- enumerate

These methods take in parameters:

- function to call on each element
- closure for the user function

## forEach, range
The objects used in the loops have to be valid (not NULL).

In libsheepy.h:

- forEachCharP, forEachS, enumerate loops on char**
- forEachType loops on void** and other element type
- range and rangeFrom are loops increasing an index

// forEach, see demo.c

char **list

listPushS(&list, " libsheepy ");

forEachCharP(list, element)

// to access the element use *element

puts(*element);

range(i, 10)

printf("%d", i);


In libsheepyObject.h:

- forEachSmallArray loops on smallArrayt, the element parameter has to be finished (freed) at the end of each loop
- enumerateSmallArray loops on smallArrayt and increases an index, the element parameter has to be finished (freed) at the end of each loop
- forEachSmallDict loops on the keys of smallDictt, the element parameter has to be finished (freed) at the end of each loop and libsheepyInternalKeys has to be freed at the end of the loop

// forEachSmallArray, see demoStatic.c

createAllocateSmallArray(list);

forEachSmallArray(list, e)

smallStringt *s = (smallStringt*)e // or castS(s,e);

// free loop element for each loop

finishG(e);

// enumerateSmallArray, see demoStatic.c

createAllocateSmallArray(list2);

enumerateSmallArray(list2, e, index)

smallStringt *s = (smallStringt*)e // or castS(s,e);

print '%d - %s', index+1, s->f->get(s)

// free loop element for each loop

finishG(e);

// forEachSmallDict, see json.c example

smallDictt* d;

forEachSmallDict(d, key, value)

smallStringt *s = allocSmallString(key);

char *V = toStringG(value);

free V

terminateG(s);

// free loop element for each loop

finishG(value);

// free libsheepyInternalKeys at the end of the loops

listFreeS(libsheepyInternalKeys);


# The sObjects are not duplicated by push, set, append...

To limit the number of memory allocations, functions (push, set, append, ...) copy pointers and sObjects are shared.

C primitives are duplicated, including strings (char*).

Given this code:

// Example 1

smallStringt *s = allocG("string");

createAllocateSmallArray(a);

pushG(a, s);

smashG(s);

// Example 2 - to duplicate the sObject

smallStringt *s = allocG("string");

// convert s to string (char*)

pushG(a, ssGet(s));

// or use dupG

pushNFreeG(a, dupG(s));

// Example 3 - append array

createAllocateSmallArray(b);

appendNSmashG(b,a);


The sString sObject in s and in a[0] have identical pointers. When a function updates the sObject pointer in s, this sObject pointer has to be updated in a[0] with the setP function.

The terminate function cannot be used to free s since it frees the shared sObject, instead use smashG.

# Reading and writing files

readFileG and writeFileG are the generics for reading and writing files, they work diffently depending on the type given in the first paramenter.

readFileG and writeFileG are suitable for small files since they process the complete file at once.

The data is stored in buffers (void*, char*,...) or arrays (char**, smallArray) where each line is an element.

When the data is stored in a small object, the object has to be allocated before calling readFileG or writeFileG since they call the object method to load/save the file.

// loading file to a string buffer

char *s = readFileG(rtChar, path);

// loading file to smallString object

smallStringt *so = allocG("");

readFileG(so, path);

writeFileG(so, path2);




# Limits

The smallArray and smallDict objects can hold 4 billion(2^32) elements at most.