libsheepy

C lib for handling text files, strings and json like data structure with an object oriented system
git clone https://spartatek.se/git/libsheepy.git
Log | Files | Refs | README | LICENSE

commit bbb9cc6dae1094fe32e4df69b38842b1f12d65e4
parent a971a17d08f3ed3543a2240ffe771704730c4957
Author: Remy Noulin <loader2x@gmail.com>
Date:   Thu, 27 Jan 2022 21:14:29 +0200

add bt (bytes type): a pointer with length

buildAsan.sh              |   5 +-
buildMemcheck.sh          |   5 +-
buildMusl.sh              |   5 +-
buildMuslMemcheck.sh      |   5 +-
buildStaticAnalysis.sh    |   4 +-
clean.sh                  |   2 +-
cleanObjects.sh           |   2 +-
example/README.template   |   2 +-
install.sh                |   3 +-
installOpenIndiana.sh     |   1 +
release/libsheepyBt.c     | 871 ++++++++++++++++++++++++++++++++++++++++++++++
release/libsheepyBt.h     | 830 +++++++++++++++++++++++++++++++++++++++++++
release/libsheepyObject.h |   1 +
src/libsheepyBt.c         | 871 ++++++++++++++++++++++++++++++++++++++++++++++
src/libsheepyBt.h         | 830 +++++++++++++++++++++++++++++++++++++++++++
src/libsheepyObject.h     |   1 +
uninstall.sh              |   2 +-
17 files changed, 3426 insertions(+), 14 deletions(-)

Diffstat:
MbuildAsan.sh | 5+++--
MbuildMemcheck.sh | 5+++--
MbuildMusl.sh | 5+++--
MbuildMuslMemcheck.sh | 5+++--
MbuildStaticAnalysis.sh | 4+++-
Mclean.sh | 2+-
McleanObjects.sh | 2+-
Mexample/README.template | 2+-
Minstall.sh | 3++-
MinstallOpenIndiana.sh | 1+
Arelease/libsheepyBt.c | 871+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Arelease/libsheepyBt.h | 830+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mrelease/libsheepyObject.h | 1+
Asrc/libsheepyBt.c | 871+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libsheepyBt.h | 830+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/libsheepyObject.h | 1+
Muninstall.sh | 2+-
17 files changed, 3426 insertions(+), 14 deletions(-)

diff --git a/buildAsan.sh b/buildAsan.sh @@ -7,6 +7,7 @@ DYNAMIC="-shared -fsanitize=address -lasan" echo "Compiling C files" $CC -c release/libsheepy.c $CC -c release/libsheepySmall.c +$CC -c release/libsheepyBt.c $CC -c src/json/libsheepyObject.c $CC -c src/json/libsheepyCSmallJson.c $CC -c src/json/libsheepyCUndefined.c @@ -28,7 +29,7 @@ $CC -c src/tpool.c wait echo "Building static lib" -$STATIC release/libsheepyAsan.a libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o +$STATIC release/libsheepyAsan.a libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o echo "Building dynamic lib" -$CC $DYNAMIC -o release/libsheepyAsan.so libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o +$CC $DYNAMIC -o release/libsheepyAsan.so libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o diff --git a/buildMemcheck.sh b/buildMemcheck.sh @@ -7,6 +7,7 @@ DYNAMIC="-shared" echo "Compiling C files" $CC -c release/libsheepy.c $CC -c release/libsheepySmall.c +$CC -c release/libsheepyBt.c $CC -c src/json/libsheepyObject.c $CC -c src/json/libsheepyCSmallJson.c $CC -c src/json/libsheepyCUndefined.c @@ -26,7 +27,7 @@ $CC -c src/json/ymlReader.c $CC -c src/tpool.c echo "Building static lib" -$STATIC release/libsheepyMemcheck.a libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o +$STATIC release/libsheepyMemcheck.a libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o echo "Building dynamic lib" -$CC $DYNAMIC -o release/libsheepyMemcheck.so libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o +$CC $DYNAMIC -o release/libsheepyMemcheck.so libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o diff --git a/buildMusl.sh b/buildMusl.sh @@ -5,6 +5,7 @@ DYNAMIC="-shared" echo "Compiling C files" $CC -c release/libsheepy.c $CC -c release/libsheepySmall.c +$CC -c release/libsheepyBt.c $CC -c src/json/libsheepyObject.c $CC -c src/json/libsheepyCSmallJson.c $CC -c src/json/libsheepyCUndefined.c @@ -24,7 +25,7 @@ $CC -c src/json/ymlReader.c $CC -c src/tpool.c echo "Building static lib" -$STATIC release/libsheepy.a libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o +$STATIC release/libsheepy.a libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o echo "Building dynamic lib" -$CC $DYNAMIC -o release/libsheepy.so libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o +$CC $DYNAMIC -o release/libsheepy.so libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o diff --git a/buildMuslMemcheck.sh b/buildMuslMemcheck.sh @@ -7,6 +7,7 @@ DYNAMIC="-shared" echo "Compiling C files" $CC -c release/libsheepy.c $CC -c release/libsheepySmall.c +$CC -c release/libsheepyBt.c $CC -c src/json/libsheepyObject.c $CC -c src/json/libsheepyCSmallJson.c $CC -c src/json/libsheepyCUndefined.c @@ -26,7 +27,7 @@ $CC -c src/json/ymlReader.c $CC -c src/tpool.c echo "Building static lib" -$STATIC release/libsheepyMemcheck.a libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o +$STATIC release/libsheepyMemcheck.a libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o echo "Building dynamic lib" -$CC $DYNAMIC -o release/libsheepyMemcheck.so libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o +$CC $DYNAMIC -o release/libsheepyMemcheck.so libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o diff --git a/buildStaticAnalysis.sh b/buildStaticAnalysis.sh @@ -8,10 +8,12 @@ $CC11 ./release/libsheepyObject.h $CC ./release/libsheepy.h $CC ./release/json/recycleContainers.h $CC ./release/libsheepySmall.h +$CC ./release/libsheepyBt.h echo "Compiling C files" $CC -c release/libsheepy.c $CC -c release/libsheepySmall.c +$CC -c release/libsheepyBt.c $CC -c src/json/libsheepyObject.c $CC -c src/json/libsheepyCSmallJson.c $CC -c src/json/libsheepyCUndefined.c @@ -31,4 +33,4 @@ $CC -c src/json/ymlReader.c $CC -c src/tpool.c echo "Building static lib" -$STATIC release/libsheepy.a libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o +$STATIC release/libsheepy.a libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o diff --git a/clean.sh b/clean.sh @@ -1,2 +1,2 @@ -rm libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o release/libsheepy.a release/libsheepy.so release/libsheepyMemcheck.a release/libsheepyMemcheck.so release/libsheepyAsan.a release/libsheepyAsan.so +rm libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o release/libsheepy.a release/libsheepy.so release/libsheepyMemcheck.a release/libsheepyMemcheck.so release/libsheepyAsan.a release/libsheepyAsan.so rm release/*.gch diff --git a/cleanObjects.sh b/cleanObjects.sh @@ -1,2 +1,2 @@ # clean objects only, keep libsheepy.a and .so, because libsheepyMemcheck is built after libsheepy with recycling -rm libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o +rm libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o diff --git a/example/README.template b/example/README.template @@ -62,7 +62,7 @@ libsheepy is NULL safe and any parameter can be NULL. - the list*S functions assume the list elements are not NULL - the listn*S functions can process lists with NULL elements. When there are NULL elements, the developer has to keep track of the list length. -Check out the [user guide](http://spartatek.se/libsheepyUserGuide/) to learn how to use libsheepy and read the more detailed documentation at [http://spartatek.se/libsheepy/](http://spartatek.se/libsheepy/) +Check out the [user guide](https://spartatek.se/libsheepyUserGuide/) to learn how to use libsheepy and read the more detailed documentation at [https://spartatek.se/libsheepy/](https://spartatek.se/libsheepy/) __Status__: (libsheepy.h and libsheepy.c) - Unit tests: 97% code coverage of the core functionality - 98% branch coverage (mainly malloc failures are not tested) diff --git a/install.sh b/install.sh @@ -1,9 +1,10 @@ cp release/libsheepy.h /usr/local/include/ cp release/libsheepySmall.h /usr/local/include/ +cp release/libsheepyBt.h /usr/local/include/ cp release/libsheepyObject.h /usr/local/include/ cp release/tpool.h /usr/local/include/ cp -R release/json /usr/local/include/ -cp ./release/libsheepySmall.h.gch /usr/local/include/ +cp ./release/libsheepyBt.h.gch /usr/local/include/ cp ./release/json/recycleContainers.h.gch /usr/local/include/json/ cp ./release/libsheepy.h.gch /usr/local/include/ cp ./release/libsheepyObject.h.gch /usr/local/include/ diff --git a/installOpenIndiana.sh b/installOpenIndiana.sh @@ -1,5 +1,6 @@ cp release/libsheepy.h /usr/include/ cp release/libsheepySmall.h /usr/include/ +cp release/libsheepyBt.h /usr/include/ cp release/libsheepyObject.h /usr/include/ cp release/tpool.h /usr/include/ cp -R release/json /usr/include/ diff --git a/release/libsheepyBt.c b/release/libsheepyBt.c @@ -0,0 +1,871 @@ +#include "libsheepyBt.h" + +#ifndef LIBSHEEPY_VERSION +#define libsheepyPrealloc (1024*1024) +#define makeRoom(length, alloc, addlength) funcbegin\ + typeof(alloc) r;\ + typeof(alloc) newlen = (length) + (addlength);\ + if (newlen < (alloc)) {\ + r = alloc;\ + } \ + else {\ + if (newlen < libsheepyPrealloc) {\ + r = newlen * 2;\ + }\ + else {\ + r = newlen + libsheepyPrealloc;\ + }\ + }\ + r;\ + funcend +#endif + +/** + * return a bt object with s as buffer + */ +bt initCharB(char *s) { + ret charB(s); +} + +/** + * return a bt object with s as buffer + * the buffer is not going to be reallocated + */ +bt initCCharB(char *s) { + ret ccharB(s); +} + +/** + * return a bt object with buf as buffer + */ +bt initB(void *buf, u32 len, bool allocated) { + ret voidB(buf, len, allocated); +} + +/** + * return a bt object with a heap allocated buffer of size allocateSize + */ +bt newB(u32 allocateSize) { + bt r = {.len = 0}; + r.b = malloc(allocateSize); + if (!r.b) ret emptybt; + r.alloc = allocateSize; + ret r; +} + +/** + * return a heap allocated bt object with a heap allocated buffer of size allocateSize + */ +bt *allocNewB(u32 allocateSize) { + bt *r = malloc(sizeof(*r)); + *r = newB(allocateSize); + ret r; +} + +// not needed, use charB or ccharB +// /** +// * set buf in the b bt object +// */ +// bt *setB(bt *b, char *buf, bool allocated) { +// if (!b or !buf) ret null; +// b->b = buf; +// b->len = strlen(buf); +// b->alloc = (allocated) ? b->len : 0; +// ret b; +// } + +/** + * return a heap allocated bt object with buf assigned to it + */ +bt *allocCharB(char *buf) { + if (!buf) ret null; + bt *r = malloc(sizeof(*r)); + if (!r) ret null; + *r = charB(buf); + ret r; +} + +/** + * return a heap allocated bt object with buf assigned to it + */ +bt *allocCCharB(char *buf) { + if (!buf) ret null; + bt *r = malloc(sizeof(*r)); + if (!r) ret null; + *r = ccharB(buf); + ret r; +} + +bt *allocBufB(void *buf, u32 len, bool allocated) { + if (!buf) ret null; + bt *r = malloc(sizeof(*r)); + if (!r) ret null; + *r = voidB(buf, len, allocated); + ret r; +} + +/** + * return a heap allocated bt object with b assigned to it + */ +bt *allocB(const bt b) { + bt *r = malloc(sizeof(*r)); + if (!r) ret null; + *r = b; + ret r; +} + +/** + * return a heap allocated bt object with *b assigned to it + */ +bt *allocPB(const bt *b) { + if (!b) ret null; + ret allocB(*b); +} + +/** + * return a bt object with a heap allocated copy of b.b + */ +bt copyB(const bt b) { + bt r = b; + r.b = malloc(b.len); + r.alloc = b.len; + memcpy(r.b, b.b, b.len); + ret r; +} + +bt copyPB(bt *b) { + if (!b) ret emptybt; + ret copyB(*b); +} + +/** + * return a heap allocated bt object with a heap allocated copy of b.b + */ +bt *dupB(const bt b) { + bt *r = malloc(sizeof(*r)); + *r = copyB(b); + ret r; +} + +bt *dupPB(bt *b) { + if (!b) ret null; + ret dupB(*b); +} + +/** + * free heap allocated .b + * nothing if not heap allocated + */ +void freeB(bt b) { + if (b.alloc) { + free(b.b); + } +} + +/** + * free heap allocated .b and assign null to .b + * nothing if not heap allocated + */ +void freenB(bt *b) { + if (b and b->alloc) { + freen(b->b); + b->len = 0; + b->alloc = 0; + } +} + +/** + * free the heap allocated bt object (container only, not .b) + */ +void finishB(bt **b) { + if (b) { + free(*b); + *b = null; + } +} + +/** + * free the heap allocated bt object and free .b + */ +void terminateB(bt **b) { + if (b) { + if (*b and (*b)->alloc) { + free((*b)->b); + } + free(*b); + *b = null; + } +} + +// terminate val when it is out of scope +void cleanUpTerminateB(bt **val) { + terminateB(val); +} + +// free local val when it is out of scope +void cleanUpFreeLocalB(bt *val) { + freeB(*val); +} + +// free val when it is out of scope +void cleanUpFreeB(bt **val) { + freeB(**val); +} + +// finish val when it is out of scope +void cleanUpFinishB(bt **val) { + finishB(val); +} + +/** + * return a bt object with s appended to b + * b doesn't need to have a heap allocated buffer + */ +bt pushB(const bt b, const char *s) { + // duplicate b.b + // copy s to b end + bt r = copyB(b); + bt *p = bPushB(&r, s); + if (p) ret r; + else { + freeB(r); + ret emptybt; + } +} + +// TODO pushManyB + +/** + * update b and append s + * b.b is reallocated + */ +bt *bPushB(bt *b, const char *s) { + if (!b or !b->b or !s) ret null; + + size_t len = strlen(s); + u32 newsize = makeRoom(b->len, b->alloc, len); + // check if there is enough space + if (newsize > b->alloc) { + u8 *tmp = realloc(b->b, newsize); + if (!tmp) ret null; + b->b = tmp; + b->alloc = newsize; + } + // copy s to b end + memcpy(b->b+b->len, s, len); + b->len += len; + ret b; +} + +// TODO bPushManyB + +/** + * return a bt object with s bt object appended to b + * b doesn't need to have a heap allocated buffer + */ +bt pushBB(const bt b, const bt s) { + // duplicate b.b + // copy s to b end + bt r = copyB(b); + bt *p = bPushBB(&r, s); + if (p) ret r; + else { + freeB(r); + ret emptybt; + } + ret r; +} + +// TODO bPushManyBB + +/** + * update b and append s bt object + * b.b is reallocated + */ +bt *bPushBB(bt *b, const bt s) { + + if (!b or !b->b or !s.b) ret null; + if (!s.len) ret b; + + u32 newsize = makeRoom(b->len, b->alloc, s.len); + // check if there is enough space + if (newsize > b->alloc) { + u8 *tmp = realloc(b->b, newsize); + if (!tmp) ret null; + b->b = tmp; + b->alloc = newsize; + } + // copy s to b end + memcpy(b->b+b->len, s.b, s.len); + b->len += s.len; + ret b; +} + +// TODO bPushManyBB + +/** + * return a bt object with *s bt object appended to b + * b doesn't need to have a heap allocated buffer + */ +bt pushBPB(const bt b, const bt *s) { + if (!s) ret emptybt; + // duplicate b.b + // copy s to b end + ret pushBB(b, *s); +} + +// TODO bPushManyBPB + +/** + * update b and append *s bt object + * b.b is reallocated + */ +bt *bPushBPB(bt *b, const bt *s) { + if (!s) ret null; + // copy s to b end + ret bPushBB(b, *s); +} + +// TODO bPushManyBB + +/** + * return a bt object with s appended to *b + * b doesn't need to have a heap allocated buffer + */ +bt pushPB(const bt *b, const char *s) { + if (!b) ret emptybt; + ret pushB(*b, s); +} +// TODO pushManyPB... + +/** + * return a bt object with s bt object appended to *b + * b doesn't need to have a heap allocated buffer + */ +bt pushPBB(const bt *b, const bt s) { + if (!b) ret emptybt; + ret pushBB(*b, s); +} +// TODO pushManyPBB... + +/** + * return a bt object with *s bt object appended to *b + * b doesn't need to have a heap allocated buffer + */ +bt pushPBPB(const bt *b, const bt *s) { + if (!b) ret emptybt; + ret pushBPB(*b, s); +} +// TODO pushManyPBPB... + +/** + * split b in vb static vector + * the vector is not reallocated + */ +vbt *sasplitB(vbt *vb, const bt b, const bt delim) { + if (!vb or !b.b or !delim.b) ret null; + + vb->count = 0; + + if (!delim.len or !b.len) { + // empty delimiter empty string, return string in a list + if (vb->count >= vb->maxCount) ret null; + vectorAppend(vb, b); + ret vb; + } + + u8 *working = b.b; + u8 *nextTokenStart = working; + u32 i = 0; + if (delim.len == 1) { + while (i < b.len) { + u8 *ptr = memchr(working, delim.b[0], b.len-i); + if (!ptr) + break; + if (vb->count >= vb->maxCount) ret null; + nextTokenStart = ptr + 1; + bt tok = {.b = working, .len = ptr-working, .alloc = 0}; + vectorAppend(vb, tok); + i += tok.len + delim.len; + working = b.b + i; + } + } + else { + while (i < b.len) { + u8 *ptr = memmem(working, b.len-i, delim.b, delim.len); + if (!ptr) + break; + if (vb->count >= vb->maxCount) ret null; + nextTokenStart = ptr + delim.len; + bt tok = {.b = working, .len = ptr-working, .alloc = 0}; + vectorAppend(vb, tok); + i += tok.len + delim.len; + working = b.b + i; + } + } + if (vb->count >= vb->maxCount) ret null; + bt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0}; + vectorAppend(vb, tok); + + ret vb; +} + +/** + * split b in vb static vector + * the vector is not reallocated + */ +vbt *sasplitCharB(vbt *vb, const bt b, char *delim) { + bt d = ccharB(delim); + ret sasplitB(vb, b, d); +} + +/** + * split b in vb static vector + * the vector is not reallocated + */ +vbt *sasplitDPB(vbt *vb, const bt b, const bt *delim) { + if (!delim) ret null; + ret sasplitB(vb, b, *delim); +} + +/** + * split b in vb static vector + * the vector is not reallocated + */ +vbt *sasplitPB(vbt *vb, const bt *b, const bt delim) { + if (!b) ret null; + ret sasplitB(vb, *b, delim); +} + +/** + * split b in vb static vector + * the vector is not reallocated + */ +vbt *sasplitPCharB(vbt *vb, const bt *b, char *delim) { + if (!b) ret null; + ret sasplitCharB(vb, *b, delim); +} + +/** + * split b in vb static vector + * the vector is not reallocated + */ +vbt *sasplitPDPB(vbt *vb, const bt *b, const bt *delim) { + if (!b or !delim) ret null; + ret sasplitB(vb, *b, *delim); +} + +/** + * allocate elements + * only when the vector is full + */ +#undef vectorAlloc +#define vectorAlloc(name) do{\ + if (!(name)->array) {\ + (name)->array = malloc(vectorSz * sizeof (name)->array[0]);\ + (name)->maxCount = vectorSz;\ + }\ + else {\ + u32 length = (name)->count * sizeof (name)->array[0];\ + u32 alloc = (name)->maxCount * sizeof (name)->array[0];\ + u32 addlength = sizeof (name)->array[0];\ + u32 newsize = makeRoom(length,\ + alloc,\ + addlength\ + );\ + (name)->maxCount = newsize / sizeof (name)->array[0];\ + (name)->array = realloc((name)->array, newsize);\ + }\ + } while(0) + +/** + * split b in vb vector + */ +vbt *asplitB(vbt *vb, const bt b, const bt delim) { + if (!vb or !b.b or !delim.b) ret null; + + vb->count = 0; + + if (!delim.len or !b.len) { + // empty delimiter empty string, return string in a list + vectorAppend(vb, b); + ret vb; + } + + u8 *working = b.b; + u8 *nextTokenStart = working; + u32 i = 0; + if (delim.len == 1) { + while (i < b.len) { + u8 *ptr = memchr(working, delim.b[0], b.len-i); + if (!ptr) + break; + nextTokenStart = ptr + 1; + bt tok = {.b = working, .len = ptr-working, .alloc = 0}; + vectorAppend(vb, tok); + i += tok.len + delim.len; + working = b.b + i; + } + } + else { + while (i < b.len) { + u8 *ptr = memmem(working, b.len-i, delim.b, delim.len); + if (!ptr) + break; + nextTokenStart = ptr + delim.len; + bt tok = {.b = working, .len = ptr-working, .alloc = 0}; + vectorAppend(vb, tok); + i += tok.len + delim.len; + working = b.b + i; + } + } + bt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0}; + vectorAppend(vb, tok); + + ret vb; +} + +/** + * split b in vb vector + */ +vbt *asplitCharB(vbt *vb, const bt b, char *delim) { + bt d = ccharB(delim); + ret asplitB(vb, b, d); +} + +/** + * split b in vb vector + */ +vbt *asplitDPB(vbt *vb, const bt b, const bt *delim) { + if (!delim) ret null; + ret asplitB(vb, b, *delim); +} + +/** + * split b in vb vector + */ +vbt *asplitPB(vbt *vb, const bt *b, const bt delim) { + if (!b) ret null; + ret asplitB(vb, *b, delim); +} + +/** + * split b in vb vector + */ +vbt *asplitPCharB(vbt *vb, const bt *b, char *delim) { + if (!b) ret null; + ret asplitCharB(vb, *b, delim); +} + +/** + * split b in vb vector + */ +vbt *asplitPDPB(vbt *vb, const bt *b, const bt *delim) { + if (!b or !delim) ret null; + ret asplitB(vb, *b, *delim); +} + +/** + * return vbt vector with tokens from b + * this function has good performance for small element counts + */ +vbt splitB(const bt b, const bt delim) { + vbt r; + if (!b.b or !delim.b) ret emptyvbt; + + vectorInitCount(&r, 5); + + asplitB(&r, b, delim); + + ret r; +} + +/** + * return vbt vector with tokens from b + * this function has good performance for small element counts + */ +vbt splitCharB(const bt b, char *delim) { + vbt r; + + if (!b.b or !delim) ret emptyvbt; + + vectorInitCount(&r, 5); + + bt d = ccharB(delim); + asplitB(&r, b, d); + + ret r; +} + +/** + * split b in vb vector + */ +vbt splitDPB(const bt b, const bt *delim) { + if (!delim) ret emptyvbt; + ret splitB(b, *delim); +} + +/** + * split b in vb vector + */ +vbt splitPB(const bt *b, const bt delim) { + if (!b) ret emptyvbt; + ret splitB(*b, delim); +} + +/** + * return vbt vector with tokens from b + * this function has good performance for small element counts + */ +vbt splitPCharB(const bt *b, char *delim) { + if (!b) ret emptyvbt; + ret splitCharB(*b, delim); +} + +/** + * split b in vb vector + */ +vbt splitPDPB(const bt *b, const bt *delim) { + if (!b or !delim) ret emptyvbt; + ret splitB(*b, *delim); +} + +/** + * return dbt vector with tokens from b + * this function has good performance for large element counts + */ +dbt dsplitB(const bt b, const bt delim) { + dbt r; + + if (!b.b or !delim.b) ret emptydbt; + + dVectorInit(&r); + + if (!delim.len or !b.len) { + // empty delimiter empty string, return string in a list + dVectorAppend(&r, b); + ret r; + } + + u8 *working = b.b; + u8 *nextTokenStart = working; + u32 i = 0; + if (delim.len == 1) { + while (i < b.len) { + u8 *ptr = memchr(working, delim.b[0], b.len-i); + if (!ptr) + break; + nextTokenStart = ptr + 1; + bt tok = {.b = working, .len = ptr-working, .alloc = 0}; + dVectorAppend(&r, tok); + i += tok.len + delim.len; + working = b.b + i; + } + } + else { + while (i < b.len) { + u8 *ptr = memmem(working, b.len-i, delim.b, delim.len); + if (!ptr) + break; + nextTokenStart = ptr + delim.len; + bt tok = {.b = working, .len = ptr-working, .alloc = 0}; + dVectorAppend(&r, tok); + i += tok.len + delim.len; + working = b.b + i; + } + } + bt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0}; + dVectorAppend(&r, tok); + + ret r; +} + +/** + * return dbt vector with tokens from b + * this function has good performance for large element counts + */ +dbt dsplitCharB(const bt b, char *delim) { + bt d = ccharB(delim); + ret dsplitB(b, d); +} + +/** + * return dbt vector with tokens from b + * this function has good performance for large element counts + */ +dbt dsplitDPB(const bt b, const bt *delim) { + if (!delim) ret emptydbt; + ret dsplitB(b, *delim); +} + +/** + * return dbt vector with tokens from b + * this function has good performance for large element counts + */ +dbt dsplitPB(const bt *b, const bt delim) { + if (!b) ret emptydbt; + ret dsplitB(*b, delim); +} + +/** + * return dbt vector with tokens from b + * this function has good performance for large element counts + */ +dbt dsplitPCharB(const bt *b, char *delim) { + if (!b) ret emptydbt; + ret dsplitCharB(*b, delim); +} + +/** + * return dbt vector with tokens from b + * this function has good performance for large element counts + */ +dbt dsplitPDPB(const bt *b, const bt *delim) { + if (!b or !delim) ret emptydbt; + ret dsplitB(*b, *delim); +} + +/** + * slice String + * return a bt object which is the string between start and end + * negative indexes are allowed + */ +bt sliceB(const bt b, int64_t start, int64_t end) { + bt r = {0}; + if (!b.b) ret emptybt; + + #define checkRange(B, rval)\ + i64 len = (B).len;\ + if (start > len)\ + ret rval;\ + if (end > len)\ + end = len;\ + if (start <= -len)\ + start = -len;\ + if (end <= -len)\ + ret rval;\ + if (start < 0)\ + start = len + start;\ + if (end <= 0)\ + end = len + end;\ + if (end < start)\ + ret rval + checkRange(b, emptybt); + + r.b = b.b + start; + if (start == end) { + // empty string + r.len = 0; + } + else { + // start < end < len + r.len = end - start; + } + ret r; +} + +/** + * slice String + * update the b bt object and keep only the string between start and end + * negative indexes are allowed + */ +bt *bSliceB(bt *b, int64_t start, int64_t end) { + if (!b) ret null; + + checkRange(*b, null); + + if (start == end) { + // empty string + b->len = 0; + } + else { + // start < end < len + b->len = end - start; + if (start) + memmove(b->b, b->b+start, b->len); + } + ret b; +} + +/** + * slice String + * return a bt object which is the string between start and end + * negative indexes are allowed + */ +bt slicePB(const bt *b, int64_t start, int64_t end) { + if (!b) ret emptybt; + ret sliceB(*b, start, end); +} + +/** + * return a bt object without the leading and trailing spaces + */ +bt trimB(const bt b) { + bt r = {0}; + if (!b.b) ret emptybt; + + r.b = b.b; + + u32 i = 0; + + // remove leading spaces + while (i < b.len and isspace(*r.b)) { + i++; r.b++; + } + + if (i == b.len) { + // all spaces + r.b = b.b; + ret r; + } + + // remove trailing spaces + u8 *end = b.b + b.len - 1; + while (isspace(*end)) + end--; + + r.len = end - r.b + 1; + + ret r; +} + +/** + * update b bt object and remove the leading and trailing spaces + */ +// memmove data +bt *bTrimB(bt *b) { + if (!b or !b->b) ret null; + + bt t = trimB(*b); + + if (t.b != b->b) + memmove(b->b, t.b, t.len); + b->len = t.len; + + ret b; +} + +/** + * return a bt object without the leading and trailing spaces + */ +bt trimPB(const bt *b) { + if (!b) emptybt; + ret trimB(*b); +} + +void printB(const bt b) { + write(STDOUT_FILENO, b.b, b.len); +} + +void printDebugB(const bt b) { + write(STDOUT_FILENO, "\"", 1); + printB(b); + write(STDOUT_FILENO, "\"", 1); + put; +} + +void printDebugInfoB(const bt b) { + logD("b: %p, len: %"PRIu32", alloc: %"PRIu32, b.b, b.len, b.alloc); + printDebugB(b); +} +// vim: set expandtab ts=2 sw=2: diff --git a/release/libsheepyBt.h b/release/libsheepyBt.h @@ -0,0 +1,830 @@ +/* + * bt is a dynamic Byte buffer Type (Bytes Type) + * + * Status: under development, not tested, the comments don't match the implementation + * + * # How bt works + * + * When a bt object represents a string, it doesn't need to be NUL terminated, + * this allow spliting string more efficiently. + * + * - simple to use + * - binary safe + * - computationally efficient + * - works with memcheck + * + * + * # Advantages and disadvantages of bt + * + * bt is implemented using a structure defining the byte buffer like this: + * ``` + * struct { + * u8 *b; + * u32 len; + * u32 alloc; + * } bt; + * ``` + * The bt structure is managed by the *B functions. + * + * - Disadvantage 1: bt doesn't work with standard C string functions + * + * - Advantage 1: Giving the address of a bt to B functions, updates the bt in place: + * ``` + * pushBG(&b, s); + * ``` + * + * - Advantage 2: trimming and slicing buffers don't need memory allocations and spliting uses less memory allocations + * + * - Advantage 3: the index for accessing the bytes in bt is range check in the getB, setB functions and it works even the buffer in bt is reallocated + * + * + * # bt basics + * + * Here is how to declare a bt, assign a string (RO) and print it: + * + * ``` + * bt mystring = ccharB("Hello World!"); + * printB(mystring); + * + * output> Hello World! + * ``` + * + * The above small program shows a few important things about bt: + * - bt are stack allocated (or heap allocated) + * - printB prints the bt content + * - there is no memory allocations so there is no free. + * + * + * # Creating bt strings + * + * ``` + * bt mystring = ccharB("Hello World!"); + * bt mystring2 = charB(strdup("Hello World!"), true); + * bt mybuf = voidB("Binary", sizeof("Binary"), false); + * createCharB(mystring3, "bytes", false); + * // from another string: + * bt mirror = mystring; + * bt empty = {0}; + * // preallocate buf + * bt pre = newB(allocateSize); + * // allocate bt struct and buf + * bt *heap = allocNewB(allocateSize); + * + * // allocate and set string + * bt *new = allocB("STR", false); + * finishB(new); + * ``` + * + * # Obtaining the string length + * + * ``` + * int len = mystring.len; + * ``` + * + * + * # Destroying strings + * + * - freeB frees the buffer pointed by .b and can be called with non allocated bt objects (it does nothing) + * - terminateB frees the buffer if allocated and the bt struct + * - finishB frees the bt struct only (doesn't touch the .b buffer) + * + * + * # Concatenating strings + * + * ``` + * createCharB(str, strdup("Hello "), true); + * pushBG(&str, "World!"); + * printB(str); + * freeB(str); + * + * output> Hello World! + * ``` + * + * + * # TODO Formatting strings + * + * + * # Trimming and slicing + * + * ``` + * bt T = ccharB(" trim "); + * bt r = trimB(T); + * bt s = sliceB(T, 2, 6); + * ``` + * + * + * # String copying + * + * ``` + * // copy bt + * bt mystringCopy = copyB(mystring); + * // the buffer in mystringCopy is heap allocated + * freeB(mystringCopy); + * + * // duplicate bt + * bt *dup = dupB(mystring); + * // dup and the buffer in dup are heap allocated + * terminateB(dup); + * ``` + * + * # Splitting strings + * + * ``` + * bt ss = ccharB("Hello World!"); + * vbt lsspl = splitB(ss, " "); + * puts(""); + * vectorForEach(&ll, e) { + * printB(*e); + * puts(""); + * } + * vectorFree(&lsspl); + * ``` + * + * + * # Inner workings + * + * When alloc is 0 and len > 0, the buffer has not been allocated + * + * createCharB declares a bt object with the given string, there is no allocation + * + * Appending strings: + * s is updated, b or i are same + * bPushB(&s, "qwqw"); + * bPushManyB(&s, "qwqw", "qweqw"); + * + * New string: + * 1 malloc (better cache locality): + * bt s2 = pushB(s, "qweqwe"); + * bt s3 = pushManyB(s, "qweqwe", "wer"); + * + * //2 mallocs: + * //bt *s4 = appendB(s, "qweqwe"); + * //bt *s5 = appendManyB(s, "qweqwe", "wer"); + * + * bt s6 = catB("1","2"); + * + * pushB(&s, s2); + * + * Printing string: + * logI("%q", &s); + * printf("%c %c\n", s.b[0], s.b[1]); + * + * Spliting string doesn't require any buffer copying + * createCharB(h, "Hello World!", 0); + * + * bt h2 = {0}; + * h2.b = h.b+6; + * h2.len = 5; + * + * Example: + * Empty bt: + * bt s = {0}; + * Assign C string: + * s = charB("a string", no); + * s.b = "asdasd"; + * b.len = strlen(s.b); + * + */ +#pragma once + +#include "libsheepy.h" + +// bt bytes type +// point to a byte buffer at .b of length .len +// .alloc is the allocated size of the buffer +typ struct { + u8 *b; + u32 len; + u32 alloc; +} bt; + +typ struct { + u8 *b; + u64 len; + u64 alloc; +} b64t; +// TODO functions supporting b64t + +// vector of bt elements +// This data structure has good performance for small element counts +typ struct { + u32 count; + u32 maxCount; + bt *array; +} vbt; + +// dynamic segmented vector of bt elements +// This data structure has good performance for large element counts +typ struct { + u32 count; + u32 maxCount; + void** buffers; + bt element; +} dbt; + +// object returned by some functions +#define emptybt ((bt){0}) +#define emptyvbt ((vbt){0}) +#define emptydbt ((dbt){0}) + + +// assign a u8 a[count] array to bt object +// Example: +// u8 s[10] = {0}; +// bt b; +// arrayB(b, s); +#define arrayB(name, a)\ + (name).b = a; (name).len = 0; (name).alloc = ARRAY_SIZE(a) + +// declare name vbt object and assign the a array defined as bt a[maxCnt] with cnt element already initialized +#define vectorB(name, a, cnt, maxCnt)\ + vbt name; name.count = cnt; name.maxCount = maxCnt; name.array = a + +// declare name vbt object, declare the a array of count bt elements and assign it to name the vbt object +#define listB(name, a, maxCnt)\ + bt a[maxCnt] = {0}; vbt name; name.count = 0; name.maxCount = maxCnt; name.array = a + +// declare name vbt object and assign the empty a array defined as bt a[maxCnt] +#define listAB(name, a)\ + vbt name; name.count = 0; name.maxCount = ARRAY_SIZE(a); name.array = a + +// initialize a bt object with a heap allocated string +#define charB(string) (bt){.b = string, .len = strlen(string), .alloc = strlen(string)} +// initialize a bt object with a string that can't be reallocated +#define ccharB(string) (bt){.b = string, .len = strlen(string), .alloc = 0 } +// initialize a bt object with a heap allocated binary buffer +#define voidB( buf, length, allocated) (bt){.b = buf, .len = length, .alloc = (allocated) ? length : 0 } + + +/** + * declare pointer name with type bt and terminate name when it is out of scope + */ +#define cleanBP(name) bt *name CLEANUP(cleanUpTerminateB) + +/** + * allocate bt (pointer) and clean up when it is out of scope + */ +#define cleanAllocateB(obj) ;cleanBP(obj); obj = allocNewB(8) + +/** + * declare local object name with type bt and free name when it is out of scope + */ +#define cleanB(name) bt name CLEANUP(cleanUpFreeLocalB) + +/** + * declare pointer name with type bt and free name when it is out of scope + */ +#define cleanFreeBP(name) bt *name CLEANUP(cleanUpFreeB) + +/** + * declare pointer name with type bt and finish name when it is out of scope + */ +#define cleanFinishBP(name) bt *name CLEANUP(cleanUpFinishB) + +// create name bt object and initialize it with a string +// string is char* and is evaluated one time, allocated true/false +#define createCharB(name, string, allocated) bt name;u8 *UNIQVAR(s) = (u8*)string;name.b = UNIQVAR(s); name.len = strlen(UNIQVAR(s)); name.alloc = (allocated) ? name.len : 0 + +// create name bt object and initialize it with a binary buffer +#define createB(name, buf, length, allocated) bt name;name.b = buf; name.len = len; name.alloc = (allocated) ? name.length : 0 + +#define createAllocateCharB(name, string, allocated)\ + bt *name = malloc(sizeof(*name)); u8 *UNIQVAR(s) = (u8*)string;name->b = UNIQVAR(s); name->len = strlen(UNIQVAR(s)); name->alloc = (allocated) ? name->len : 0 + +#define createAllocateB(name, buf, length, allocated)\ + bt *name = malloc(sizeof(*name));name->b = buf; name->len = length; name->alloc = (allocated) ? name->len : 0 + +// create clean name bt object and initialize it with a string +// string is char* and is evaluated one time +#define cleanCharB(name, string) cleanB(name);u8 *UNIQVAR(s) = (u8*)string;name.b = UNIQVAR(s); name.len = strlen(UNIQVAR(s)); name.alloc = name.len + +// create clean name bt object and initialize it with a binary buffer +#define ccleanB(name, buf, length) cleanB(name);name.b = buf; name.len = len; name.alloc = name.length + +#define cleanAllocateCharB(name, string, allocated)\ + cleanBP(name) = malloc(sizeof(*name)); u8 *UNIQVAR(s) = (u8*)string;name->b = UNIQVAR(s); name->len = strlen(UNIQVAR(s)); name->alloc = (allocated) ? name->len : 0 + +#define ccleanAllocateB(name, buf, length, allocated)\ + cleanBP(name) = malloc(sizeof(*name));name->b = buf; name->len = length; name->alloc = (allocated) ? name->len : 0 + + +// return a bt object with s as buffer +bt initCharB(char *s); + +// return a bt object with s as buffer +// the buffer is not going to be reallocated +bt initCCharB(char *s); + +// return a bt object with buf as buffer +bt initB(void *buf, u32 len, bool allocated); + +// return a bt object with a heap allocated buffer of size allocateSize +bt newB(u32 allocateSize); + +// return a heap allocated bt object with a heap allocated buffer of size allocateSize +bt *allocNewB(u32 allocateSize); + +// return a heap allocated bt object with buf assigned to it +bt *allocCharB(char *buf); + +// return a heap allocated bt object with buf assigned to it +bt *allocCCharB(char *buf); + +bt *allocBufB(void *buf, u32 len, bool allocated); + +// return a heap allocated bt object with b assigned to it +bt *allocB(const bt b); + +/** + * return a heap allocated bt object with *b assigned to it + */ +bt *allocPB(const bt *b); + +#define allocBG(b) _Generic(b,\ + bt: allocB,\ + const bt: allocB,\ + bt*: allocPB,\ + const bt*: allocPB,\ + char*: allocCharB,\ + const char*: allocCCharB\ + )(b) + +// return a bt object with a heap allocated copy of b.b +bt copyB(const bt b); + +bt copyPB(bt *b); + +#define copyBG(b) _Generic(b,\ + bt: copyB,\ + bt*: copyPB\ + )(b) + +// return a heap allocated bt object with a heap allocated copy of b.b +bt *dupB(const bt b); + +bt *dupPB(bt *b); + +#define dupBG(b) _Generic(b,\ + bt: dupB,\ + bt*: dupPB\ + )(b) + +// TODO: +// ..lenB +// ..freeB +// ..terminateB(bt *b) +// ..pushBB +// ..pushManyBB +// // NO - growzero: memset 0 to new part +// ..slice +// ..trim +// formatB +// iFormatB +// bFormatB +// ..copyB +// ..splitB +// splitLenB +// listFreeB +// join +// toCharB convert to char* +// getB setB setBB set .b getBB get .b +// +// extra sds splitargs +// splitArgs quoted string, multiple spaces + + +// use b.b instead +// u8* bufferB(bt b) { +// ret b.b; +// } + +// use b.len instead +// size_t lenB(bt b) { +// ret b.len; +// } + +/** + * free heap allocated .b + * nothing if not heap allocated + */ +void freeB(bt b); + +/** + * free heap allocated .b and assign null to .b + * nothing if not heap allocated + */ +void freenB(bt *b); + +/** + * free the heap allocated bt object (container only, not .b) + */ +void finishB(bt **b); + +/** + * free the heap allocated bt object and free .b + */ +void terminateB(bt **b); + +// terminate val when it is out of scope +void cleanUpTerminateB(bt **val); + +// free local val when it is out of scope +void cleanUpFreeLocalB(bt *val); + +// free val when it is out of scope +void cleanUpFreeB(bt **val); + +// finish val when it is out of scope +void cleanUpFinishB(bt **val); + +// return a bt object with s appended to b +// b doesn't need to have a heap allocated buffer +#define appendB pushB +bt pushB(const bt b, const char *s); + +// TODO pushManyB + +// update b and append s +// b.b is reallocated +#define bAppendB bPushB +bt *bPushB(bt *b, const char *s); + +// TODO bPushManyB + +// return a bt object with s bt object appended to b +// b doesn't need to have a heap allocated buffer +#define appendBB pushBB +bt pushBB(const bt b, const bt s); + +// TODO bPushManyBB + +// update b and append s bt object +// b.b is reallocated +#define bAppendBB bPushBB +bt *bPushBB(bt *b, const bt s); + +// TODO bPushManyBB + +// return a bt object with *s bt object appended to b +// b doesn't need to have a heap allocated buffer +#define appendBPB pushBPB +bt pushBPB(const bt b, const bt *s); + +// TODO bPushManyBPB + +// update b and append *s bt object +// b.b is reallocated +#define bAppendBPB bPushBPB +bt *bPushBPB(bt *b, const bt *s); + +// TODO bPushManyBB + +// return a bt object with s appended to *b +// b doesn't need to have a heap allocated buffer +#define appendPB pushPB +bt pushPB(const bt *b, const char *s); +// TODO pushManyPB... + +// return a bt object with s bt object appended to *b +// b doesn't need to have a heap allocated buffer +#define appendPBB pushPBB +bt pushPBB(const bt *b, const bt s); +// TODO pushManyPBB... + +// return a bt object with *s bt object appended to *b +// b doesn't need to have a heap allocated buffer +#define appendPBPB pushPBPB +bt pushPBPB(const bt *b, const bt *s); +// TODO pushManyPBPB... + +#define appendBG pushBG +#define pushBG(b, s) _Generic( b,\ + bt: _Generic(s,\ + const char *: pushB,\ + char *: pushB,\ + const bt: pushBB,\ + bt: pushBB,\ + const bt*: pushBPB,\ + bt*: pushBPB\ + ),\ + bt*: _Generic(s,\ + const char *: bPushB,\ + char *: bPushB,\ + const bt: bPushBB,\ + bt: bPushBB,\ + const bt*: bPushBPB,\ + bt*: bPushBPB\ + ),\ + const bt*: _Generic(s,\ + const char *: pushPB,\ + char *: pushPB,\ + const bt: pushPBB,\ + bt: pushPBB,\ + const bt*: pushPBPB,\ + bt*: pushPBPB\ + )\ + )(b, s) + +// bt catBF(const char *paramType, ...) MUST_CHECK; +#define catB(...) catBF("", __VA_ARGS__, NULL) + +// add allocates bt object +// bt *addBF(const char *paramType, ...) MUST_CHECK; +#define addB(...) catBF("", __VA_ARGS__, NULL) + +// %q to print bt +// %Q to print bt* +// printB(char *fmt, ...) + +// register %q and %Q +// register_printf_specifier('q', print_q, print_q_arginfo); +// register_printf_specifier('Q', print_Q, print_Q_arginfo); + +/** + * %q printf type specifier, RGB foreground, uint32_t + */ +// int print_q(FILE *stream, const struct printf_info *info, const void *const *args) { +// u32 rgbColor; +// char b[20]; +// int len; +// +// rgbColor = *((const u32*) args[0]); +// snprintf(b, sizeof(b), TERMRGB "%u;%u;%um", rgbColor>>16, (rgbColor&0xFF00)>>8, rgbColor&0xFF); +// +// /* Pad to the minimum field width and print to the stream. */ +// //len = fprintf(stream, "%*s", (info->left ? -info->width : info->width), b) +// sheepyRGBFP; +// return(len); +// } + +/** + * procress printf argument + */ +// int print_q_arginfo(const struct printf_info *info UNUSED, size_t n, int *argtypes, int* size) { +// +// if (n > 0) { +// argtypes[0] = PA_POINTER; +// size[0] = sizeof(u32); +// } +// return(1); +// } + +// split b in vb static vector +// the vector is not reallocated +vbt *sasplitB(vbt *vb, const bt b, const bt delim); + +// split b in vb static vector +// the vector is not reallocated +vbt *sasplitCharB(vbt *vb, const bt b, char *delim); + +// split b in vb static vector +// the vector is not reallocated +vbt *sasplitDPB(vbt *vb, const bt b, const bt *delim); + +// split b in vb static vector +// the vector is not reallocated +vbt *sasplitPB(vbt *vb, const bt *b, const bt delim); + +// split b in vb static vector +// the vector is not reallocated +vbt *sasplitPCharB(vbt *vb, const bt *b, char *delim); + +// split b in vb static vector +// the vector is not reallocated +vbt *sasplitPDPB(vbt *vb, const bt *b, const bt *delim); + +#define sasplitBG(vb, b, delim) _Generic(b,\ + bt: _Generic(delim,\ + char*: sasplitCharB,\ + const char*: sasplitCharB,\ + bt: sasplitB,\ + const bt: sasplitB,\ + bt*: sasplitDPB,\ + const bt*: sasplitDPB),\ + const bt: _Generic(delim,\ + char*: sasplitCharB,\ + const char*: sasplitCharB,\ + bt: sasplitB,\ + const bt: sasplitB,\ + bt*: sasplitDPB,\ + const bt*: sasplitDPB),\ + bt*: _Generic(delim,\ + char*: sasplitPCharB,\ + const char*: sasplitPCharB,\ + bt: sasplitPB,\ + const bt: sasplitPB,\ + bt*: sasplitPDPB,\ + const bt*: sasplitPDPB),\ + const bt*: _Generic(delim,\ + char*: sasplitPCharB,\ + const char*: sasplitPCharB,\ + bt: sasplitPB,\ + const bt: sasplitPB,\ + bt*: sasplitPDPB,\ + const bt*: sasplitPDPB)\ + )(vb, b, delim) + +// split b in vb vector +vbt *asplitB(vbt *vb, const bt b, const bt delim); + +// split b in vb vector +vbt *asplitCharB(vbt *vb, const bt b, char *delim); + +// split b in vb vector +vbt *asplitDPB(vbt *vb, const bt b, const bt *delim); + +// split b in vb vector +vbt *asplitPB(vbt *vb, const bt *b, const bt delim); + +// split b in vb vector +vbt *asplitPCharB(vbt *vb, const bt *b, char *delim); + +// split b in vb vector +vbt *asplitPDPB(vbt *vb, const bt *b, const bt *delim); + +#define asplitBG(vb, b, delim) _Generic(b,\ + bt: _Generic(delim,\ + char*: asplitCharB,\ + const char*: asplitCharB,\ + bt: asplitB,\ + const bt: asplitB,\ + bt*: asplitDPB,\ + const bt*: asplitDPB),\ + const bt: _Generic(delim,\ + char*: asplitCharB,\ + const char*: asplitCharB,\ + bt: asplitB,\ + const bt: asplitB,\ + bt*: asplitDPB,\ + const bt*: asplitDPB),\ + bt*: _Generic(delim,\ + char*: asplitPCharB,\ + const char*: asplitPCharB,\ + bt: asplitPB,\ + const bt: asplitPB,\ + bt*: asplitPDPB,\ + const bt*: asplitPDPB),\ + const bt*: _Generic(delim,\ + char*: asplitPCharB,\ + const char*: asplitPCharB,\ + bt: asplitPB,\ + const bt: asplitPB,\ + bt*: asplitPDPB,\ + const bt*: asplitPDPB)\ + )(vb, b, delim) + +// return vbt vector with tokens from b +// this function has good performance for small element counts +vbt splitB(const bt b, const bt delim); + +// return vbt vector with tokens from b +// this function has good performance for small element counts +vbt splitCharB(const bt b, char *delim); + +// split b in vb vector +vbt splitDPB(const bt b, const bt *delim); + +// split b in vb vector +vbt splitPB(const bt *b, const bt delim); + +// return vbt vector with tokens from b +// this function has good performance for small element counts +vbt splitPCharB(const bt *b, char *delim); + +// split b in vb vector +vbt splitPDPB(const bt *b, const bt *delim); + +#define splitBG(b, delim) _Generic(b,\ + bt: _Generic(delim,\ + char*: splitCharB,\ + const char*: splitCharB,\ + bt: splitB,\ + const bt: splitB,\ + bt*: splitDPB,\ + const bt*: splitDPB),\ + const bt: _Generic(delim,\ + char*: splitCharB,\ + const char*: splitCharB,\ + bt: splitB,\ + const bt: splitB,\ + bt*: splitDPB,\ + const bt*: splitDPB),\ + bt*: _Generic(delim,\ + char*: splitPCharB,\ + const char*: splitPCharB,\ + bt: splitPB,\ + const bt: splitPB,\ + bt*: splitPDPB,\ + const bt*: splitPDPB),\ + const bt*: _Generic(delim,\ + char*: splitPCharB,\ + const char*: splitPCharB,\ + bt: splitPB,\ + const bt: splitPB,\ + bt*: splitPDPB,\ + const bt*: splitPDPB)\ + )(b, delim) + + + +// return dbt vector with tokens from b +// this function has good performance for large element counts +dbt dsplitB(const bt b, const bt delim); + +// return dbt vector with tokens from b +// this function has good performance for large element counts +dbt dsplitCharB(const bt b, char *delim); + +// return dbt vector with tokens from b +// this function has good performance for large element counts +dbt dsplitDPB(const bt b, const bt *delim); + +// return dbt vector with tokens from b +// this function has good performance for large element counts +dbt dsplitPB(const bt *b, const bt delim); + +// return dbt vector with tokens from b +// this function has good performance for large element counts +dbt dsplitPCharB(const bt *b, char *delim); + +// return dbt vector with tokens from b +// this function has good performance for large element counts +dbt dsplitPDPB(const bt *b, const bt *delim); + +#define dsplitBG(b, delim) _Generic(b,\ + bt: _Generic(delim,\ + char*: dsplitCharB,\ + const char*: dsplitCharB,\ + bt: dsplitB,\ + const bt: dsplitB,\ + bt*: dsplitDPB,\ + const bt*: dsplitDPB),\ + const bt: _Generic(delim,\ + char*: dsplitCharB,\ + const char*: dsplitCharB,\ + bt: dsplitB,\ + const bt: dsplitB,\ + bt*: dsplitDPB,\ + const bt*: dsplitDPB),\ + bt*: _Generic(delim,\ + char*: dsplitPCharB,\ + const char*: dsplitPCharB,\ + bt: dsplitPB,\ + const bt: dsplitPB,\ + bt*: dsplitPDPB,\ + const bt*: dsplitPDPB),\ + const bt*: _Generic(delim,\ + char*: dsplitPCharB,\ + const char*: dsplitPCharB,\ + bt: dsplitPB,\ + const bt: dsplitPB,\ + bt*: dsplitPDPB,\ + const bt*: dsplitPDPB)\ + )(b, delim) + + +// slice String +// return a bt object which is the string between start and end +// negative indexes are allowed +bt sliceB(const bt b, int64_t start, int64_t end); + +// slice String +// update the b bt object and keep only the string between start and end +// negative indexes are allowed +bt *bSliceB(bt *b, int64_t start, int64_t end); + +// slice String +// return a bt object which is the string between start and end +// negative indexes are allowed +bt slicePB(const bt *b, int64_t start, int64_t end); + +#define sliceBG(b, start, end) _Generic(b,\ + bt: sliceB,\ + const bt: sliceB,\ + bt*: bSliceB,\ + const bt*: slicePB\ + )(b, start, end); + +// return a bt object without the leading and trailing spaces +bt trimB(const bt b); + +// update b bt object and remove the leading and trailing spaces +bt *bTrimB(bt *b); + +// return a bt object without the leading and trailing spaces +bt trimPB(const bt *b); + +#define trimBG(b) _Generic(b,\ + bt: trimB,\ + const bt: trimB,\ + bt*: bTrimB,\ + const bt*: trimPB\ + )(b) + +void printB(const bt b); + +void printDebugB(const bt b); + +void printDebugInfoB(const bt b); + +// vim: set expandtab ts=2 sw=2: diff --git a/release/libsheepyObject.h b/release/libsheepyObject.h @@ -50,6 +50,7 @@ #include "libsheepy.h" #include "libsheepySmall.h" +#include "libsheepyBt.h" #if (!__OpenBSD__) && ! defined(__TINYC__) && (__GNUC__ > 4) #include "stdatomic.h" #endif diff --git a/src/libsheepyBt.c b/src/libsheepyBt.c @@ -0,0 +1,871 @@ +#include "libsheepyBt.h" + +#ifndef LIBSHEEPY_VERSION +#define libsheepyPrealloc (1024*1024) +#define makeRoom(length, alloc, addlength) funcbegin\ + typeof(alloc) r;\ + typeof(alloc) newlen = (length) + (addlength);\ + if (newlen < (alloc)) {\ + r = alloc;\ + } \ + else {\ + if (newlen < libsheepyPrealloc) {\ + r = newlen * 2;\ + }\ + else {\ + r = newlen + libsheepyPrealloc;\ + }\ + }\ + r;\ + funcend +#endif + +/** + * return a bt object with s as buffer + */ +bt initCharB(char *s) { + ret charB(s); +} + +/** + * return a bt object with s as buffer + * the buffer is not going to be reallocated + */ +bt initCCharB(char *s) { + ret ccharB(s); +} + +/** + * return a bt object with buf as buffer + */ +bt initB(void *buf, u32 len, bool allocated) { + ret voidB(buf, len, allocated); +} + +/** + * return a bt object with a heap allocated buffer of size allocateSize + */ +bt newB(u32 allocateSize) { + bt r = {.len = 0}; + r.b = malloc(allocateSize); + if (!r.b) ret emptybt; + r.alloc = allocateSize; + ret r; +} + +/** + * return a heap allocated bt object with a heap allocated buffer of size allocateSize + */ +bt *allocNewB(u32 allocateSize) { + bt *r = malloc(sizeof(*r)); + *r = newB(allocateSize); + ret r; +} + +// not needed, use charB or ccharB +// /** +// * set buf in the b bt object +// */ +// bt *setB(bt *b, char *buf, bool allocated) { +// if (!b or !buf) ret null; +// b->b = buf; +// b->len = strlen(buf); +// b->alloc = (allocated) ? b->len : 0; +// ret b; +// } + +/** + * return a heap allocated bt object with buf assigned to it + */ +bt *allocCharB(char *buf) { + if (!buf) ret null; + bt *r = malloc(sizeof(*r)); + if (!r) ret null; + *r = charB(buf); + ret r; +} + +/** + * return a heap allocated bt object with buf assigned to it + */ +bt *allocCCharB(char *buf) { + if (!buf) ret null; + bt *r = malloc(sizeof(*r)); + if (!r) ret null; + *r = ccharB(buf); + ret r; +} + +bt *allocBufB(void *buf, u32 len, bool allocated) { + if (!buf) ret null; + bt *r = malloc(sizeof(*r)); + if (!r) ret null; + *r = voidB(buf, len, allocated); + ret r; +} + +/** + * return a heap allocated bt object with b assigned to it + */ +bt *allocB(const bt b) { + bt *r = malloc(sizeof(*r)); + if (!r) ret null; + *r = b; + ret r; +} + +/** + * return a heap allocated bt object with *b assigned to it + */ +bt *allocPB(const bt *b) { + if (!b) ret null; + ret allocB(*b); +} + +/** + * return a bt object with a heap allocated copy of b.b + */ +bt copyB(const bt b) { + bt r = b; + r.b = malloc(b.len); + r.alloc = b.len; + memcpy(r.b, b.b, b.len); + ret r; +} + +bt copyPB(bt *b) { + if (!b) ret emptybt; + ret copyB(*b); +} + +/** + * return a heap allocated bt object with a heap allocated copy of b.b + */ +bt *dupB(const bt b) { + bt *r = malloc(sizeof(*r)); + *r = copyB(b); + ret r; +} + +bt *dupPB(bt *b) { + if (!b) ret null; + ret dupB(*b); +} + +/** + * free heap allocated .b + * nothing if not heap allocated + */ +void freeB(bt b) { + if (b.alloc) { + free(b.b); + } +} + +/** + * free heap allocated .b and assign null to .b + * nothing if not heap allocated + */ +void freenB(bt *b) { + if (b and b->alloc) { + freen(b->b); + b->len = 0; + b->alloc = 0; + } +} + +/** + * free the heap allocated bt object (container only, not .b) + */ +void finishB(bt **b) { + if (b) { + free(*b); + *b = null; + } +} + +/** + * free the heap allocated bt object and free .b + */ +void terminateB(bt **b) { + if (b) { + if (*b and (*b)->alloc) { + free((*b)->b); + } + free(*b); + *b = null; + } +} + +// terminate val when it is out of scope +void cleanUpTerminateB(bt **val) { + terminateB(val); +} + +// free local val when it is out of scope +void cleanUpFreeLocalB(bt *val) { + freeB(*val); +} + +// free val when it is out of scope +void cleanUpFreeB(bt **val) { + freeB(**val); +} + +// finish val when it is out of scope +void cleanUpFinishB(bt **val) { + finishB(val); +} + +/** + * return a bt object with s appended to b + * b doesn't need to have a heap allocated buffer + */ +bt pushB(const bt b, const char *s) { + // duplicate b.b + // copy s to b end + bt r = copyB(b); + bt *p = bPushB(&r, s); + if (p) ret r; + else { + freeB(r); + ret emptybt; + } +} + +// TODO pushManyB + +/** + * update b and append s + * b.b is reallocated + */ +bt *bPushB(bt *b, const char *s) { + if (!b or !b->b or !s) ret null; + + size_t len = strlen(s); + u32 newsize = makeRoom(b->len, b->alloc, len); + // check if there is enough space + if (newsize > b->alloc) { + u8 *tmp = realloc(b->b, newsize); + if (!tmp) ret null; + b->b = tmp; + b->alloc = newsize; + } + // copy s to b end + memcpy(b->b+b->len, s, len); + b->len += len; + ret b; +} + +// TODO bPushManyB + +/** + * return a bt object with s bt object appended to b + * b doesn't need to have a heap allocated buffer + */ +bt pushBB(const bt b, const bt s) { + // duplicate b.b + // copy s to b end + bt r = copyB(b); + bt *p = bPushBB(&r, s); + if (p) ret r; + else { + freeB(r); + ret emptybt; + } + ret r; +} + +// TODO bPushManyBB + +/** + * update b and append s bt object + * b.b is reallocated + */ +bt *bPushBB(bt *b, const bt s) { + + if (!b or !b->b or !s.b) ret null; + if (!s.len) ret b; + + u32 newsize = makeRoom(b->len, b->alloc, s.len); + // check if there is enough space + if (newsize > b->alloc) { + u8 *tmp = realloc(b->b, newsize); + if (!tmp) ret null; + b->b = tmp; + b->alloc = newsize; + } + // copy s to b end + memcpy(b->b+b->len, s.b, s.len); + b->len += s.len; + ret b; +} + +// TODO bPushManyBB + +/** + * return a bt object with *s bt object appended to b + * b doesn't need to have a heap allocated buffer + */ +bt pushBPB(const bt b, const bt *s) { + if (!s) ret emptybt; + // duplicate b.b + // copy s to b end + ret pushBB(b, *s); +} + +// TODO bPushManyBPB + +/** + * update b and append *s bt object + * b.b is reallocated + */ +bt *bPushBPB(bt *b, const bt *s) { + if (!s) ret null; + // copy s to b end + ret bPushBB(b, *s); +} + +// TODO bPushManyBB + +/** + * return a bt object with s appended to *b + * b doesn't need to have a heap allocated buffer + */ +bt pushPB(const bt *b, const char *s) { + if (!b) ret emptybt; + ret pushB(*b, s); +} +// TODO pushManyPB... + +/** + * return a bt object with s bt object appended to *b + * b doesn't need to have a heap allocated buffer + */ +bt pushPBB(const bt *b, const bt s) { + if (!b) ret emptybt; + ret pushBB(*b, s); +} +// TODO pushManyPBB... + +/** + * return a bt object with *s bt object appended to *b + * b doesn't need to have a heap allocated buffer + */ +bt pushPBPB(const bt *b, const bt *s) { + if (!b) ret emptybt; + ret pushBPB(*b, s); +} +// TODO pushManyPBPB... + +/** + * split b in vb static vector + * the vector is not reallocated + */ +vbt *sasplitB(vbt *vb, const bt b, const bt delim) { + if (!vb or !b.b or !delim.b) ret null; + + vb->count = 0; + + if (!delim.len or !b.len) { + // empty delimiter empty string, return string in a list + if (vb->count >= vb->maxCount) ret null; + vectorAppend(vb, b); + ret vb; + } + + u8 *working = b.b; + u8 *nextTokenStart = working; + u32 i = 0; + if (delim.len == 1) { + while (i < b.len) { + u8 *ptr = memchr(working, delim.b[0], b.len-i); + if (!ptr) + break; + if (vb->count >= vb->maxCount) ret null; + nextTokenStart = ptr + 1; + bt tok = {.b = working, .len = ptr-working, .alloc = 0}; + vectorAppend(vb, tok); + i += tok.len + delim.len; + working = b.b + i; + } + } + else { + while (i < b.len) { + u8 *ptr = memmem(working, b.len-i, delim.b, delim.len); + if (!ptr) + break; + if (vb->count >= vb->maxCount) ret null; + nextTokenStart = ptr + delim.len; + bt tok = {.b = working, .len = ptr-working, .alloc = 0}; + vectorAppend(vb, tok); + i += tok.len + delim.len; + working = b.b + i; + } + } + if (vb->count >= vb->maxCount) ret null; + bt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0}; + vectorAppend(vb, tok); + + ret vb; +} + +/** + * split b in vb static vector + * the vector is not reallocated + */ +vbt *sasplitCharB(vbt *vb, const bt b, char *delim) { + bt d = ccharB(delim); + ret sasplitB(vb, b, d); +} + +/** + * split b in vb static vector + * the vector is not reallocated + */ +vbt *sasplitDPB(vbt *vb, const bt b, const bt *delim) { + if (!delim) ret null; + ret sasplitB(vb, b, *delim); +} + +/** + * split b in vb static vector + * the vector is not reallocated + */ +vbt *sasplitPB(vbt *vb, const bt *b, const bt delim) { + if (!b) ret null; + ret sasplitB(vb, *b, delim); +} + +/** + * split b in vb static vector + * the vector is not reallocated + */ +vbt *sasplitPCharB(vbt *vb, const bt *b, char *delim) { + if (!b) ret null; + ret sasplitCharB(vb, *b, delim); +} + +/** + * split b in vb static vector + * the vector is not reallocated + */ +vbt *sasplitPDPB(vbt *vb, const bt *b, const bt *delim) { + if (!b or !delim) ret null; + ret sasplitB(vb, *b, *delim); +} + +/** + * allocate elements + * only when the vector is full + */ +#undef vectorAlloc +#define vectorAlloc(name) do{\ + if (!(name)->array) {\ + (name)->array = malloc(vectorSz * sizeof (name)->array[0]);\ + (name)->maxCount = vectorSz;\ + }\ + else {\ + u32 length = (name)->count * sizeof (name)->array[0];\ + u32 alloc = (name)->maxCount * sizeof (name)->array[0];\ + u32 addlength = sizeof (name)->array[0];\ + u32 newsize = makeRoom(length,\ + alloc,\ + addlength\ + );\ + (name)->maxCount = newsize / sizeof (name)->array[0];\ + (name)->array = realloc((name)->array, newsize);\ + }\ + } while(0) + +/** + * split b in vb vector + */ +vbt *asplitB(vbt *vb, const bt b, const bt delim) { + if (!vb or !b.b or !delim.b) ret null; + + vb->count = 0; + + if (!delim.len or !b.len) { + // empty delimiter empty string, return string in a list + vectorAppend(vb, b); + ret vb; + } + + u8 *working = b.b; + u8 *nextTokenStart = working; + u32 i = 0; + if (delim.len == 1) { + while (i < b.len) { + u8 *ptr = memchr(working, delim.b[0], b.len-i); + if (!ptr) + break; + nextTokenStart = ptr + 1; + bt tok = {.b = working, .len = ptr-working, .alloc = 0}; + vectorAppend(vb, tok); + i += tok.len + delim.len; + working = b.b + i; + } + } + else { + while (i < b.len) { + u8 *ptr = memmem(working, b.len-i, delim.b, delim.len); + if (!ptr) + break; + nextTokenStart = ptr + delim.len; + bt tok = {.b = working, .len = ptr-working, .alloc = 0}; + vectorAppend(vb, tok); + i += tok.len + delim.len; + working = b.b + i; + } + } + bt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0}; + vectorAppend(vb, tok); + + ret vb; +} + +/** + * split b in vb vector + */ +vbt *asplitCharB(vbt *vb, const bt b, char *delim) { + bt d = ccharB(delim); + ret asplitB(vb, b, d); +} + +/** + * split b in vb vector + */ +vbt *asplitDPB(vbt *vb, const bt b, const bt *delim) { + if (!delim) ret null; + ret asplitB(vb, b, *delim); +} + +/** + * split b in vb vector + */ +vbt *asplitPB(vbt *vb, const bt *b, const bt delim) { + if (!b) ret null; + ret asplitB(vb, *b, delim); +} + +/** + * split b in vb vector + */ +vbt *asplitPCharB(vbt *vb, const bt *b, char *delim) { + if (!b) ret null; + ret asplitCharB(vb, *b, delim); +} + +/** + * split b in vb vector + */ +vbt *asplitPDPB(vbt *vb, const bt *b, const bt *delim) { + if (!b or !delim) ret null; + ret asplitB(vb, *b, *delim); +} + +/** + * return vbt vector with tokens from b + * this function has good performance for small element counts + */ +vbt splitB(const bt b, const bt delim) { + vbt r; + if (!b.b or !delim.b) ret emptyvbt; + + vectorInitCount(&r, 5); + + asplitB(&r, b, delim); + + ret r; +} + +/** + * return vbt vector with tokens from b + * this function has good performance for small element counts + */ +vbt splitCharB(const bt b, char *delim) { + vbt r; + + if (!b.b or !delim) ret emptyvbt; + + vectorInitCount(&r, 5); + + bt d = ccharB(delim); + asplitB(&r, b, d); + + ret r; +} + +/** + * split b in vb vector + */ +vbt splitDPB(const bt b, const bt *delim) { + if (!delim) ret emptyvbt; + ret splitB(b, *delim); +} + +/** + * split b in vb vector + */ +vbt splitPB(const bt *b, const bt delim) { + if (!b) ret emptyvbt; + ret splitB(*b, delim); +} + +/** + * return vbt vector with tokens from b + * this function has good performance for small element counts + */ +vbt splitPCharB(const bt *b, char *delim) { + if (!b) ret emptyvbt; + ret splitCharB(*b, delim); +} + +/** + * split b in vb vector + */ +vbt splitPDPB(const bt *b, const bt *delim) { + if (!b or !delim) ret emptyvbt; + ret splitB(*b, *delim); +} + +/** + * return dbt vector with tokens from b + * this function has good performance for large element counts + */ +dbt dsplitB(const bt b, const bt delim) { + dbt r; + + if (!b.b or !delim.b) ret emptydbt; + + dVectorInit(&r); + + if (!delim.len or !b.len) { + // empty delimiter empty string, return string in a list + dVectorAppend(&r, b); + ret r; + } + + u8 *working = b.b; + u8 *nextTokenStart = working; + u32 i = 0; + if (delim.len == 1) { + while (i < b.len) { + u8 *ptr = memchr(working, delim.b[0], b.len-i); + if (!ptr) + break; + nextTokenStart = ptr + 1; + bt tok = {.b = working, .len = ptr-working, .alloc = 0}; + dVectorAppend(&r, tok); + i += tok.len + delim.len; + working = b.b + i; + } + } + else { + while (i < b.len) { + u8 *ptr = memmem(working, b.len-i, delim.b, delim.len); + if (!ptr) + break; + nextTokenStart = ptr + delim.len; + bt tok = {.b = working, .len = ptr-working, .alloc = 0}; + dVectorAppend(&r, tok); + i += tok.len + delim.len; + working = b.b + i; + } + } + bt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0}; + dVectorAppend(&r, tok); + + ret r; +} + +/** + * return dbt vector with tokens from b + * this function has good performance for large element counts + */ +dbt dsplitCharB(const bt b, char *delim) { + bt d = ccharB(delim); + ret dsplitB(b, d); +} + +/** + * return dbt vector with tokens from b + * this function has good performance for large element counts + */ +dbt dsplitDPB(const bt b, const bt *delim) { + if (!delim) ret emptydbt; + ret dsplitB(b, *delim); +} + +/** + * return dbt vector with tokens from b + * this function has good performance for large element counts + */ +dbt dsplitPB(const bt *b, const bt delim) { + if (!b) ret emptydbt; + ret dsplitB(*b, delim); +} + +/** + * return dbt vector with tokens from b + * this function has good performance for large element counts + */ +dbt dsplitPCharB(const bt *b, char *delim) { + if (!b) ret emptydbt; + ret dsplitCharB(*b, delim); +} + +/** + * return dbt vector with tokens from b + * this function has good performance for large element counts + */ +dbt dsplitPDPB(const bt *b, const bt *delim) { + if (!b or !delim) ret emptydbt; + ret dsplitB(*b, *delim); +} + +/** + * slice String + * return a bt object which is the string between start and end + * negative indexes are allowed + */ +bt sliceB(const bt b, int64_t start, int64_t end) { + bt r = {0}; + if (!b.b) ret emptybt; + + #define checkRange(B, rval)\ + i64 len = (B).len;\ + if (start > len)\ + ret rval;\ + if (end > len)\ + end = len;\ + if (start <= -len)\ + start = -len;\ + if (end <= -len)\ + ret rval;\ + if (start < 0)\ + start = len + start;\ + if (end <= 0)\ + end = len + end;\ + if (end < start)\ + ret rval + checkRange(b, emptybt); + + r.b = b.b + start; + if (start == end) { + // empty string + r.len = 0; + } + else { + // start < end < len + r.len = end - start; + } + ret r; +} + +/** + * slice String + * update the b bt object and keep only the string between start and end + * negative indexes are allowed + */ +bt *bSliceB(bt *b, int64_t start, int64_t end) { + if (!b) ret null; + + checkRange(*b, null); + + if (start == end) { + // empty string + b->len = 0; + } + else { + // start < end < len + b->len = end - start; + if (start) + memmove(b->b, b->b+start, b->len); + } + ret b; +} + +/** + * slice String + * return a bt object which is the string between start and end + * negative indexes are allowed + */ +bt slicePB(const bt *b, int64_t start, int64_t end) { + if (!b) ret emptybt; + ret sliceB(*b, start, end); +} + +/** + * return a bt object without the leading and trailing spaces + */ +bt trimB(const bt b) { + bt r = {0}; + if (!b.b) ret emptybt; + + r.b = b.b; + + u32 i = 0; + + // remove leading spaces + while (i < b.len and isspace(*r.b)) { + i++; r.b++; + } + + if (i == b.len) { + // all spaces + r.b = b.b; + ret r; + } + + // remove trailing spaces + u8 *end = b.b + b.len - 1; + while (isspace(*end)) + end--; + + r.len = end - r.b + 1; + + ret r; +} + +/** + * update b bt object and remove the leading and trailing spaces + */ +// memmove data +bt *bTrimB(bt *b) { + if (!b or !b->b) ret null; + + bt t = trimB(*b); + + if (t.b != b->b) + memmove(b->b, t.b, t.len); + b->len = t.len; + + ret b; +} + +/** + * return a bt object without the leading and trailing spaces + */ +bt trimPB(const bt *b) { + if (!b) emptybt; + ret trimB(*b); +} + +void printB(const bt b) { + write(STDOUT_FILENO, b.b, b.len); +} + +void printDebugB(const bt b) { + write(STDOUT_FILENO, "\"", 1); + printB(b); + write(STDOUT_FILENO, "\"", 1); + put; +} + +void printDebugInfoB(const bt b) { + logD("b: %p, len: %"PRIu32", alloc: %"PRIu32, b.b, b.len, b.alloc); + printDebugB(b); +} +// vim: set expandtab ts=2 sw=2: diff --git a/src/libsheepyBt.h b/src/libsheepyBt.h @@ -0,0 +1,830 @@ +/* + * bt is a dynamic Byte buffer Type (Bytes Type) + * + * Status: under development, not tested, the comments don't match the implementation + * + * # How bt works + * + * When a bt object represents a string, it doesn't need to be NUL terminated, + * this allow spliting string more efficiently. + * + * - simple to use + * - binary safe + * - computationally efficient + * - works with memcheck + * + * + * # Advantages and disadvantages of bt + * + * bt is implemented using a structure defining the byte buffer like this: + * ``` + * struct { + * u8 *b; + * u32 len; + * u32 alloc; + * } bt; + * ``` + * The bt structure is managed by the *B functions. + * + * - Disadvantage 1: bt doesn't work with standard C string functions + * + * - Advantage 1: Giving the address of a bt to B functions, updates the bt in place: + * ``` + * pushBG(&b, s); + * ``` + * + * - Advantage 2: trimming and slicing buffers don't need memory allocations and spliting uses less memory allocations + * + * - Advantage 3: the index for accessing the bytes in bt is range check in the getB, setB functions and it works even the buffer in bt is reallocated + * + * + * # bt basics + * + * Here is how to declare a bt, assign a string (RO) and print it: + * + * ``` + * bt mystring = ccharB("Hello World!"); + * printB(mystring); + * + * output> Hello World! + * ``` + * + * The above small program shows a few important things about bt: + * - bt are stack allocated (or heap allocated) + * - printB prints the bt content + * - there is no memory allocations so there is no free. + * + * + * # Creating bt strings + * + * ``` + * bt mystring = ccharB("Hello World!"); + * bt mystring2 = charB(strdup("Hello World!"), true); + * bt mybuf = voidB("Binary", sizeof("Binary"), false); + * createCharB(mystring3, "bytes", false); + * // from another string: + * bt mirror = mystring; + * bt empty = {0}; + * // preallocate buf + * bt pre = newB(allocateSize); + * // allocate bt struct and buf + * bt *heap = allocNewB(allocateSize); + * + * // allocate and set string + * bt *new = allocB("STR", false); + * finishB(new); + * ``` + * + * # Obtaining the string length + * + * ``` + * int len = mystring.len; + * ``` + * + * + * # Destroying strings + * + * - freeB frees the buffer pointed by .b and can be called with non allocated bt objects (it does nothing) + * - terminateB frees the buffer if allocated and the bt struct + * - finishB frees the bt struct only (doesn't touch the .b buffer) + * + * + * # Concatenating strings + * + * ``` + * createCharB(str, strdup("Hello "), true); + * pushBG(&str, "World!"); + * printB(str); + * freeB(str); + * + * output> Hello World! + * ``` + * + * + * # TODO Formatting strings + * + * + * # Trimming and slicing + * + * ``` + * bt T = ccharB(" trim "); + * bt r = trimB(T); + * bt s = sliceB(T, 2, 6); + * ``` + * + * + * # String copying + * + * ``` + * // copy bt + * bt mystringCopy = copyB(mystring); + * // the buffer in mystringCopy is heap allocated + * freeB(mystringCopy); + * + * // duplicate bt + * bt *dup = dupB(mystring); + * // dup and the buffer in dup are heap allocated + * terminateB(dup); + * ``` + * + * # Splitting strings + * + * ``` + * bt ss = ccharB("Hello World!"); + * vbt lsspl = splitB(ss, " "); + * puts(""); + * vectorForEach(&ll, e) { + * printB(*e); + * puts(""); + * } + * vectorFree(&lsspl); + * ``` + * + * + * # Inner workings + * + * When alloc is 0 and len > 0, the buffer has not been allocated + * + * createCharB declares a bt object with the given string, there is no allocation + * + * Appending strings: + * s is updated, b or i are same + * bPushB(&s, "qwqw"); + * bPushManyB(&s, "qwqw", "qweqw"); + * + * New string: + * 1 malloc (better cache locality): + * bt s2 = pushB(s, "qweqwe"); + * bt s3 = pushManyB(s, "qweqwe", "wer"); + * + * //2 mallocs: + * //bt *s4 = appendB(s, "qweqwe"); + * //bt *s5 = appendManyB(s, "qweqwe", "wer"); + * + * bt s6 = catB("1","2"); + * + * pushB(&s, s2); + * + * Printing string: + * logI("%q", &s); + * printf("%c %c\n", s.b[0], s.b[1]); + * + * Spliting string doesn't require any buffer copying + * createCharB(h, "Hello World!", 0); + * + * bt h2 = {0}; + * h2.b = h.b+6; + * h2.len = 5; + * + * Example: + * Empty bt: + * bt s = {0}; + * Assign C string: + * s = charB("a string", no); + * s.b = "asdasd"; + * b.len = strlen(s.b); + * + */ +#pragma once + +#include "libsheepy.h" + +// bt bytes type +// point to a byte buffer at .b of length .len +// .alloc is the allocated size of the buffer +typ struct { + u8 *b; + u32 len; + u32 alloc; +} bt; + +typ struct { + u8 *b; + u64 len; + u64 alloc; +} b64t; +// TODO functions supporting b64t + +// vector of bt elements +// This data structure has good performance for small element counts +typ struct { + u32 count; + u32 maxCount; + bt *array; +} vbt; + +// dynamic segmented vector of bt elements +// This data structure has good performance for large element counts +typ struct { + u32 count; + u32 maxCount; + void** buffers; + bt element; +} dbt; + +// object returned by some functions +#define emptybt ((bt){0}) +#define emptyvbt ((vbt){0}) +#define emptydbt ((dbt){0}) + + +// assign a u8 a[count] array to bt object +// Example: +// u8 s[10] = {0}; +// bt b; +// arrayB(b, s); +#define arrayB(name, a)\ + (name).b = a; (name).len = 0; (name).alloc = ARRAY_SIZE(a) + +// declare name vbt object and assign the a array defined as bt a[maxCnt] with cnt element already initialized +#define vectorB(name, a, cnt, maxCnt)\ + vbt name; name.count = cnt; name.maxCount = maxCnt; name.array = a + +// declare name vbt object, declare the a array of count bt elements and assign it to name the vbt object +#define listB(name, a, maxCnt)\ + bt a[maxCnt] = {0}; vbt name; name.count = 0; name.maxCount = maxCnt; name.array = a + +// declare name vbt object and assign the empty a array defined as bt a[maxCnt] +#define listAB(name, a)\ + vbt name; name.count = 0; name.maxCount = ARRAY_SIZE(a); name.array = a + +// initialize a bt object with a heap allocated string +#define charB(string) (bt){.b = string, .len = strlen(string), .alloc = strlen(string)} +// initialize a bt object with a string that can't be reallocated +#define ccharB(string) (bt){.b = string, .len = strlen(string), .alloc = 0 } +// initialize a bt object with a heap allocated binary buffer +#define voidB( buf, length, allocated) (bt){.b = buf, .len = length, .alloc = (allocated) ? length : 0 } + + +/** + * declare pointer name with type bt and terminate name when it is out of scope + */ +#define cleanBP(name) bt *name CLEANUP(cleanUpTerminateB) + +/** + * allocate bt (pointer) and clean up when it is out of scope + */ +#define cleanAllocateB(obj) ;cleanBP(obj); obj = allocNewB(8) + +/** + * declare local object name with type bt and free name when it is out of scope + */ +#define cleanB(name) bt name CLEANUP(cleanUpFreeLocalB) + +/** + * declare pointer name with type bt and free name when it is out of scope + */ +#define cleanFreeBP(name) bt *name CLEANUP(cleanUpFreeB) + +/** + * declare pointer name with type bt and finish name when it is out of scope + */ +#define cleanFinishBP(name) bt *name CLEANUP(cleanUpFinishB) + +// create name bt object and initialize it with a string +// string is char* and is evaluated one time, allocated true/false +#define createCharB(name, string, allocated) bt name;u8 *UNIQVAR(s) = (u8*)string;name.b = UNIQVAR(s); name.len = strlen(UNIQVAR(s)); name.alloc = (allocated) ? name.len : 0 + +// create name bt object and initialize it with a binary buffer +#define createB(name, buf, length, allocated) bt name;name.b = buf; name.len = len; name.alloc = (allocated) ? name.length : 0 + +#define createAllocateCharB(name, string, allocated)\ + bt *name = malloc(sizeof(*name)); u8 *UNIQVAR(s) = (u8*)string;name->b = UNIQVAR(s); name->len = strlen(UNIQVAR(s)); name->alloc = (allocated) ? name->len : 0 + +#define createAllocateB(name, buf, length, allocated)\ + bt *name = malloc(sizeof(*name));name->b = buf; name->len = length; name->alloc = (allocated) ? name->len : 0 + +// create clean name bt object and initialize it with a string +// string is char* and is evaluated one time +#define cleanCharB(name, string) cleanB(name);u8 *UNIQVAR(s) = (u8*)string;name.b = UNIQVAR(s); name.len = strlen(UNIQVAR(s)); name.alloc = name.len + +// create clean name bt object and initialize it with a binary buffer +#define ccleanB(name, buf, length) cleanB(name);name.b = buf; name.len = len; name.alloc = name.length + +#define cleanAllocateCharB(name, string, allocated)\ + cleanBP(name) = malloc(sizeof(*name)); u8 *UNIQVAR(s) = (u8*)string;name->b = UNIQVAR(s); name->len = strlen(UNIQVAR(s)); name->alloc = (allocated) ? name->len : 0 + +#define ccleanAllocateB(name, buf, length, allocated)\ + cleanBP(name) = malloc(sizeof(*name));name->b = buf; name->len = length; name->alloc = (allocated) ? name->len : 0 + + +// return a bt object with s as buffer +bt initCharB(char *s); + +// return a bt object with s as buffer +// the buffer is not going to be reallocated +bt initCCharB(char *s); + +// return a bt object with buf as buffer +bt initB(void *buf, u32 len, bool allocated); + +// return a bt object with a heap allocated buffer of size allocateSize +bt newB(u32 allocateSize); + +// return a heap allocated bt object with a heap allocated buffer of size allocateSize +bt *allocNewB(u32 allocateSize); + +// return a heap allocated bt object with buf assigned to it +bt *allocCharB(char *buf); + +// return a heap allocated bt object with buf assigned to it +bt *allocCCharB(char *buf); + +bt *allocBufB(void *buf, u32 len, bool allocated); + +// return a heap allocated bt object with b assigned to it +bt *allocB(const bt b); + +/** + * return a heap allocated bt object with *b assigned to it + */ +bt *allocPB(const bt *b); + +#define allocBG(b) _Generic(b,\ + bt: allocB,\ + const bt: allocB,\ + bt*: allocPB,\ + const bt*: allocPB,\ + char*: allocCharB,\ + const char*: allocCCharB\ + )(b) + +// return a bt object with a heap allocated copy of b.b +bt copyB(const bt b); + +bt copyPB(bt *b); + +#define copyBG(b) _Generic(b,\ + bt: copyB,\ + bt*: copyPB\ + )(b) + +// return a heap allocated bt object with a heap allocated copy of b.b +bt *dupB(const bt b); + +bt *dupPB(bt *b); + +#define dupBG(b) _Generic(b,\ + bt: dupB,\ + bt*: dupPB\ + )(b) + +// TODO: +// ..lenB +// ..freeB +// ..terminateB(bt *b) +// ..pushBB +// ..pushManyBB +// // NO - growzero: memset 0 to new part +// ..slice +// ..trim +// formatB +// iFormatB +// bFormatB +// ..copyB +// ..splitB +// splitLenB +// listFreeB +// join +// toCharB convert to char* +// getB setB setBB set .b getBB get .b +// +// extra sds splitargs +// splitArgs quoted string, multiple spaces + + +// use b.b instead +// u8* bufferB(bt b) { +// ret b.b; +// } + +// use b.len instead +// size_t lenB(bt b) { +// ret b.len; +// } + +/** + * free heap allocated .b + * nothing if not heap allocated + */ +void freeB(bt b); + +/** + * free heap allocated .b and assign null to .b + * nothing if not heap allocated + */ +void freenB(bt *b); + +/** + * free the heap allocated bt object (container only, not .b) + */ +void finishB(bt **b); + +/** + * free the heap allocated bt object and free .b + */ +void terminateB(bt **b); + +// terminate val when it is out of scope +void cleanUpTerminateB(bt **val); + +// free local val when it is out of scope +void cleanUpFreeLocalB(bt *val); + +// free val when it is out of scope +void cleanUpFreeB(bt **val); + +// finish val when it is out of scope +void cleanUpFinishB(bt **val); + +// return a bt object with s appended to b +// b doesn't need to have a heap allocated buffer +#define appendB pushB +bt pushB(const bt b, const char *s); + +// TODO pushManyB + +// update b and append s +// b.b is reallocated +#define bAppendB bPushB +bt *bPushB(bt *b, const char *s); + +// TODO bPushManyB + +// return a bt object with s bt object appended to b +// b doesn't need to have a heap allocated buffer +#define appendBB pushBB +bt pushBB(const bt b, const bt s); + +// TODO bPushManyBB + +// update b and append s bt object +// b.b is reallocated +#define bAppendBB bPushBB +bt *bPushBB(bt *b, const bt s); + +// TODO bPushManyBB + +// return a bt object with *s bt object appended to b +// b doesn't need to have a heap allocated buffer +#define appendBPB pushBPB +bt pushBPB(const bt b, const bt *s); + +// TODO bPushManyBPB + +// update b and append *s bt object +// b.b is reallocated +#define bAppendBPB bPushBPB +bt *bPushBPB(bt *b, const bt *s); + +// TODO bPushManyBB + +// return a bt object with s appended to *b +// b doesn't need to have a heap allocated buffer +#define appendPB pushPB +bt pushPB(const bt *b, const char *s); +// TODO pushManyPB... + +// return a bt object with s bt object appended to *b +// b doesn't need to have a heap allocated buffer +#define appendPBB pushPBB +bt pushPBB(const bt *b, const bt s); +// TODO pushManyPBB... + +// return a bt object with *s bt object appended to *b +// b doesn't need to have a heap allocated buffer +#define appendPBPB pushPBPB +bt pushPBPB(const bt *b, const bt *s); +// TODO pushManyPBPB... + +#define appendBG pushBG +#define pushBG(b, s) _Generic( b,\ + bt: _Generic(s,\ + const char *: pushB,\ + char *: pushB,\ + const bt: pushBB,\ + bt: pushBB,\ + const bt*: pushBPB,\ + bt*: pushBPB\ + ),\ + bt*: _Generic(s,\ + const char *: bPushB,\ + char *: bPushB,\ + const bt: bPushBB,\ + bt: bPushBB,\ + const bt*: bPushBPB,\ + bt*: bPushBPB\ + ),\ + const bt*: _Generic(s,\ + const char *: pushPB,\ + char *: pushPB,\ + const bt: pushPBB,\ + bt: pushPBB,\ + const bt*: pushPBPB,\ + bt*: pushPBPB\ + )\ + )(b, s) + +// bt catBF(const char *paramType, ...) MUST_CHECK; +#define catB(...) catBF("", __VA_ARGS__, NULL) + +// add allocates bt object +// bt *addBF(const char *paramType, ...) MUST_CHECK; +#define addB(...) catBF("", __VA_ARGS__, NULL) + +// %q to print bt +// %Q to print bt* +// printB(char *fmt, ...) + +// register %q and %Q +// register_printf_specifier('q', print_q, print_q_arginfo); +// register_printf_specifier('Q', print_Q, print_Q_arginfo); + +/** + * %q printf type specifier, RGB foreground, uint32_t + */ +// int print_q(FILE *stream, const struct printf_info *info, const void *const *args) { +// u32 rgbColor; +// char b[20]; +// int len; +// +// rgbColor = *((const u32*) args[0]); +// snprintf(b, sizeof(b), TERMRGB "%u;%u;%um", rgbColor>>16, (rgbColor&0xFF00)>>8, rgbColor&0xFF); +// +// /* Pad to the minimum field width and print to the stream. */ +// //len = fprintf(stream, "%*s", (info->left ? -info->width : info->width), b) +// sheepyRGBFP; +// return(len); +// } + +/** + * procress printf argument + */ +// int print_q_arginfo(const struct printf_info *info UNUSED, size_t n, int *argtypes, int* size) { +// +// if (n > 0) { +// argtypes[0] = PA_POINTER; +// size[0] = sizeof(u32); +// } +// return(1); +// } + +// split b in vb static vector +// the vector is not reallocated +vbt *sasplitB(vbt *vb, const bt b, const bt delim); + +// split b in vb static vector +// the vector is not reallocated +vbt *sasplitCharB(vbt *vb, const bt b, char *delim); + +// split b in vb static vector +// the vector is not reallocated +vbt *sasplitDPB(vbt *vb, const bt b, const bt *delim); + +// split b in vb static vector +// the vector is not reallocated +vbt *sasplitPB(vbt *vb, const bt *b, const bt delim); + +// split b in vb static vector +// the vector is not reallocated +vbt *sasplitPCharB(vbt *vb, const bt *b, char *delim); + +// split b in vb static vector +// the vector is not reallocated +vbt *sasplitPDPB(vbt *vb, const bt *b, const bt *delim); + +#define sasplitBG(vb, b, delim) _Generic(b,\ + bt: _Generic(delim,\ + char*: sasplitCharB,\ + const char*: sasplitCharB,\ + bt: sasplitB,\ + const bt: sasplitB,\ + bt*: sasplitDPB,\ + const bt*: sasplitDPB),\ + const bt: _Generic(delim,\ + char*: sasplitCharB,\ + const char*: sasplitCharB,\ + bt: sasplitB,\ + const bt: sasplitB,\ + bt*: sasplitDPB,\ + const bt*: sasplitDPB),\ + bt*: _Generic(delim,\ + char*: sasplitPCharB,\ + const char*: sasplitPCharB,\ + bt: sasplitPB,\ + const bt: sasplitPB,\ + bt*: sasplitPDPB,\ + const bt*: sasplitPDPB),\ + const bt*: _Generic(delim,\ + char*: sasplitPCharB,\ + const char*: sasplitPCharB,\ + bt: sasplitPB,\ + const bt: sasplitPB,\ + bt*: sasplitPDPB,\ + const bt*: sasplitPDPB)\ + )(vb, b, delim) + +// split b in vb vector +vbt *asplitB(vbt *vb, const bt b, const bt delim); + +// split b in vb vector +vbt *asplitCharB(vbt *vb, const bt b, char *delim); + +// split b in vb vector +vbt *asplitDPB(vbt *vb, const bt b, const bt *delim); + +// split b in vb vector +vbt *asplitPB(vbt *vb, const bt *b, const bt delim); + +// split b in vb vector +vbt *asplitPCharB(vbt *vb, const bt *b, char *delim); + +// split b in vb vector +vbt *asplitPDPB(vbt *vb, const bt *b, const bt *delim); + +#define asplitBG(vb, b, delim) _Generic(b,\ + bt: _Generic(delim,\ + char*: asplitCharB,\ + const char*: asplitCharB,\ + bt: asplitB,\ + const bt: asplitB,\ + bt*: asplitDPB,\ + const bt*: asplitDPB),\ + const bt: _Generic(delim,\ + char*: asplitCharB,\ + const char*: asplitCharB,\ + bt: asplitB,\ + const bt: asplitB,\ + bt*: asplitDPB,\ + const bt*: asplitDPB),\ + bt*: _Generic(delim,\ + char*: asplitPCharB,\ + const char*: asplitPCharB,\ + bt: asplitPB,\ + const bt: asplitPB,\ + bt*: asplitPDPB,\ + const bt*: asplitPDPB),\ + const bt*: _Generic(delim,\ + char*: asplitPCharB,\ + const char*: asplitPCharB,\ + bt: asplitPB,\ + const bt: asplitPB,\ + bt*: asplitPDPB,\ + const bt*: asplitPDPB)\ + )(vb, b, delim) + +// return vbt vector with tokens from b +// this function has good performance for small element counts +vbt splitB(const bt b, const bt delim); + +// return vbt vector with tokens from b +// this function has good performance for small element counts +vbt splitCharB(const bt b, char *delim); + +// split b in vb vector +vbt splitDPB(const bt b, const bt *delim); + +// split b in vb vector +vbt splitPB(const bt *b, const bt delim); + +// return vbt vector with tokens from b +// this function has good performance for small element counts +vbt splitPCharB(const bt *b, char *delim); + +// split b in vb vector +vbt splitPDPB(const bt *b, const bt *delim); + +#define splitBG(b, delim) _Generic(b,\ + bt: _Generic(delim,\ + char*: splitCharB,\ + const char*: splitCharB,\ + bt: splitB,\ + const bt: splitB,\ + bt*: splitDPB,\ + const bt*: splitDPB),\ + const bt: _Generic(delim,\ + char*: splitCharB,\ + const char*: splitCharB,\ + bt: splitB,\ + const bt: splitB,\ + bt*: splitDPB,\ + const bt*: splitDPB),\ + bt*: _Generic(delim,\ + char*: splitPCharB,\ + const char*: splitPCharB,\ + bt: splitPB,\ + const bt: splitPB,\ + bt*: splitPDPB,\ + const bt*: splitPDPB),\ + const bt*: _Generic(delim,\ + char*: splitPCharB,\ + const char*: splitPCharB,\ + bt: splitPB,\ + const bt: splitPB,\ + bt*: splitPDPB,\ + const bt*: splitPDPB)\ + )(b, delim) + + + +// return dbt vector with tokens from b +// this function has good performance for large element counts +dbt dsplitB(const bt b, const bt delim); + +// return dbt vector with tokens from b +// this function has good performance for large element counts +dbt dsplitCharB(const bt b, char *delim); + +// return dbt vector with tokens from b +// this function has good performance for large element counts +dbt dsplitDPB(const bt b, const bt *delim); + +// return dbt vector with tokens from b +// this function has good performance for large element counts +dbt dsplitPB(const bt *b, const bt delim); + +// return dbt vector with tokens from b +// this function has good performance for large element counts +dbt dsplitPCharB(const bt *b, char *delim); + +// return dbt vector with tokens from b +// this function has good performance for large element counts +dbt dsplitPDPB(const bt *b, const bt *delim); + +#define dsplitBG(b, delim) _Generic(b,\ + bt: _Generic(delim,\ + char*: dsplitCharB,\ + const char*: dsplitCharB,\ + bt: dsplitB,\ + const bt: dsplitB,\ + bt*: dsplitDPB,\ + const bt*: dsplitDPB),\ + const bt: _Generic(delim,\ + char*: dsplitCharB,\ + const char*: dsplitCharB,\ + bt: dsplitB,\ + const bt: dsplitB,\ + bt*: dsplitDPB,\ + const bt*: dsplitDPB),\ + bt*: _Generic(delim,\ + char*: dsplitPCharB,\ + const char*: dsplitPCharB,\ + bt: dsplitPB,\ + const bt: dsplitPB,\ + bt*: dsplitPDPB,\ + const bt*: dsplitPDPB),\ + const bt*: _Generic(delim,\ + char*: dsplitPCharB,\ + const char*: dsplitPCharB,\ + bt: dsplitPB,\ + const bt: dsplitPB,\ + bt*: dsplitPDPB,\ + const bt*: dsplitPDPB)\ + )(b, delim) + + +// slice String +// return a bt object which is the string between start and end +// negative indexes are allowed +bt sliceB(const bt b, int64_t start, int64_t end); + +// slice String +// update the b bt object and keep only the string between start and end +// negative indexes are allowed +bt *bSliceB(bt *b, int64_t start, int64_t end); + +// slice String +// return a bt object which is the string between start and end +// negative indexes are allowed +bt slicePB(const bt *b, int64_t start, int64_t end); + +#define sliceBG(b, start, end) _Generic(b,\ + bt: sliceB,\ + const bt: sliceB,\ + bt*: bSliceB,\ + const bt*: slicePB\ + )(b, start, end); + +// return a bt object without the leading and trailing spaces +bt trimB(const bt b); + +// update b bt object and remove the leading and trailing spaces +bt *bTrimB(bt *b); + +// return a bt object without the leading and trailing spaces +bt trimPB(const bt *b); + +#define trimBG(b) _Generic(b,\ + bt: trimB,\ + const bt: trimB,\ + bt*: bTrimB,\ + const bt*: trimPB\ + )(b) + +void printB(const bt b); + +void printDebugB(const bt b); + +void printDebugInfoB(const bt b); + +// vim: set expandtab ts=2 sw=2: diff --git a/src/libsheepyObject.h b/src/libsheepyObject.h @@ -50,6 +50,7 @@ #include "libsheepy.h" #include "libsheepySmall.h" +#include "libsheepyBt.h" #if (!__OpenBSD__) && ! defined(__TINYC__) && (__GNUC__ > 4) #include "stdatomic.h" #endif diff --git a/uninstall.sh b/uninstall.sh @@ -1,2 +1,2 @@ -rm -rf /usr/local/include/libsheepy.h /usr/local/include/libsheepySmall.h /usr/local/include/libsheepyObject.h /usr/local/include/tpool.h /usr/local/include/json /usr/local/lib/libsheepy.a /usr/local/lib/libsheepy.so /usr/local/lib/libsheepyAsan.a /usr/local/lib/libsheepyAsan.so +rm -rf /usr/local/include/libsheepy.h /usr/local/include/libsheepySmall.h /usr/local/include/libsheepyBt.h /usr/local/include/libsheepyObject.h /usr/local/include/tpool.h /usr/local/include/json /usr/local/lib/libsheepy.a /usr/local/lib/libsheepy.so /usr/local/lib/libsheepyAsan.a /usr/local/lib/libsheepyAsan.so