Path: blob/master/dep/zydis/dependencies/zycore/src/String.c
4808 views
/***************************************************************************************************12Zyan Core Library (Zycore-C)34Original Author : Florian Bernd56* Permission is hereby granted, free of charge, to any person obtaining a copy7* of this software and associated documentation files (the "Software"), to deal8* in the Software without restriction, including without limitation the rights9* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell10* copies of the Software, and to permit persons to whom the Software is11* furnished to do so, subject to the following conditions:12*13* The above copyright notice and this permission notice shall be included in all14* copies or substantial portions of the Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR17* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,18* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE19* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER20* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,21* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE22* SOFTWARE.2324***************************************************************************************************/2526#include <Zycore/String.h>27#include <Zycore/LibC.h>2829/* ============================================================================================== */30/* Internal macros */31/* ============================================================================================== */3233/**34* Writes a terminating '\0' character at the end of the string data.35*/36#define ZYCORE_STRING_NULLTERMINATE(string) \37*(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) = '\0';3839/**40* Checks for a terminating '\0' character at the end of the string data.41*/42#define ZYCORE_STRING_ASSERT_NULLTERMINATION(string) \43ZYAN_ASSERT(*(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) == '\0');4445/* ============================================================================================== */46/* Exported functions */47/* ============================================================================================== */4849/* ---------------------------------------------------------------------------------------------- */50/* Constructor and destructor */51/* ---------------------------------------------------------------------------------------------- */5253#ifndef ZYAN_NO_LIBC5455ZyanStatus ZyanStringInit(ZyanString* string, ZyanUSize capacity)56{57return ZyanStringInitEx(string, capacity, ZyanAllocatorDefault(),58ZYAN_STRING_DEFAULT_GROWTH_FACTOR, ZYAN_STRING_DEFAULT_SHRINK_THRESHOLD);59}6061#endif // ZYAN_NO_LIBC6263ZyanStatus ZyanStringInitEx(ZyanString* string, ZyanUSize capacity, ZyanAllocator* allocator,64ZyanU8 growth_factor, ZyanU8 shrink_threshold)65{66if (!string)67{68return ZYAN_STATUS_INVALID_ARGUMENT;69}7071string->flags = 0;72capacity = ZYAN_MAX(ZYAN_STRING_MIN_CAPACITY, capacity) + 1;73ZYAN_CHECK(ZyanVectorInitEx(&string->vector, sizeof(char), capacity, ZYAN_NULL, allocator,74growth_factor, shrink_threshold));75ZYAN_ASSERT(string->vector.capacity >= capacity);76// Some of the string code relies on `sizeof(char) == 1`77ZYAN_ASSERT(string->vector.element_size == 1);7879*(char*)string->vector.data = '\0';80++string->vector.size;8182return ZYAN_STATUS_SUCCESS;83}8485ZyanStatus ZyanStringInitCustomBuffer(ZyanString* string, char* buffer, ZyanUSize capacity)86{87if (!string || !capacity)88{89return ZYAN_STATUS_INVALID_ARGUMENT;90}9192string->flags = ZYAN_STRING_HAS_FIXED_CAPACITY;93ZYAN_CHECK(ZyanVectorInitCustomBuffer(&string->vector, sizeof(char), (void*)buffer, capacity,94ZYAN_NULL));95ZYAN_ASSERT(string->vector.capacity == capacity);96// Some of the string code relies on `sizeof(char) == 1`97ZYAN_ASSERT(string->vector.element_size == 1);9899*(char*)string->vector.data = '\0';100++string->vector.size;101102return ZYAN_STATUS_SUCCESS;103}104105ZyanStatus ZyanStringDestroy(ZyanString* string)106{107if (!string)108{109return ZYAN_STATUS_INVALID_ARGUMENT;110}111if (string->flags & ZYAN_STRING_HAS_FIXED_CAPACITY)112{113return ZYAN_STATUS_SUCCESS;114}115116return ZyanVectorDestroy(&string->vector);117}118119/* ---------------------------------------------------------------------------------------------- */120/* Duplication */121/* ---------------------------------------------------------------------------------------------- */122123#ifndef ZYAN_NO_LIBC124125ZyanStatus ZyanStringDuplicate(ZyanString* destination, const ZyanStringView* source,126ZyanUSize capacity)127{128return ZyanStringDuplicateEx(destination, source, capacity, ZyanAllocatorDefault(),129ZYAN_STRING_DEFAULT_GROWTH_FACTOR, ZYAN_STRING_DEFAULT_SHRINK_THRESHOLD);130}131132#endif // ZYAN_NO_LIBC133134ZyanStatus ZyanStringDuplicateEx(ZyanString* destination, const ZyanStringView* source,135ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold)136{137if (!source || !source->string.vector.size)138{139return ZYAN_STATUS_INVALID_ARGUMENT;140}141142const ZyanUSize len = source->string.vector.size;143capacity = ZYAN_MAX(capacity, len - 1);144ZYAN_CHECK(ZyanStringInitEx(destination, capacity, allocator, growth_factor, shrink_threshold));145ZYAN_ASSERT(destination->vector.capacity >= len);146147ZYAN_MEMCPY(destination->vector.data, source->string.vector.data,148source->string.vector.size - 1);149destination->vector.size = len;150ZYCORE_STRING_NULLTERMINATE(destination);151152return ZYAN_STATUS_SUCCESS;153}154155ZyanStatus ZyanStringDuplicateCustomBuffer(ZyanString* destination, const ZyanStringView* source,156char* buffer, ZyanUSize capacity)157{158if (!source || !source->string.vector.size)159{160return ZYAN_STATUS_INVALID_ARGUMENT;161}162163const ZyanUSize len = source->string.vector.size;164if (capacity < len)165{166return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;167}168169ZYAN_CHECK(ZyanStringInitCustomBuffer(destination, buffer, capacity));170ZYAN_ASSERT(destination->vector.capacity >= len);171172ZYAN_MEMCPY(destination->vector.data, source->string.vector.data,173source->string.vector.size - 1);174destination->vector.size = len;175ZYCORE_STRING_NULLTERMINATE(destination);176177return ZYAN_STATUS_SUCCESS;178}179180/* ---------------------------------------------------------------------------------------------- */181/* Concatenation */182/* ---------------------------------------------------------------------------------------------- */183184#ifndef ZYAN_NO_LIBC185186ZyanStatus ZyanStringConcat(ZyanString* destination, const ZyanStringView* s1,187const ZyanStringView* s2, ZyanUSize capacity)188{189return ZyanStringConcatEx(destination, s1, s2, capacity, ZyanAllocatorDefault(),190ZYAN_STRING_DEFAULT_GROWTH_FACTOR, ZYAN_STRING_DEFAULT_SHRINK_THRESHOLD);191}192193#endif // ZYAN_NO_LIBC194195ZyanStatus ZyanStringConcatEx(ZyanString* destination, const ZyanStringView* s1,196const ZyanStringView* s2, ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor,197ZyanU8 shrink_threshold)198{199if (!s1 || !s2 || !s1->string.vector.size || !s2->string.vector.size)200{201return ZYAN_STATUS_INVALID_ARGUMENT;202}203204const ZyanUSize len = s1->string.vector.size + s2->string.vector.size - 1;205capacity = ZYAN_MAX(capacity, len - 1);206ZYAN_CHECK(ZyanStringInitEx(destination, capacity, allocator, growth_factor, shrink_threshold));207ZYAN_ASSERT(destination->vector.capacity >= len);208209ZYAN_MEMCPY(destination->vector.data, s1->string.vector.data, s1->string.vector.size - 1);210ZYAN_MEMCPY((char*)destination->vector.data + s1->string.vector.size - 1,211s2->string.vector.data, s2->string.vector.size - 1);212destination->vector.size = len;213ZYCORE_STRING_NULLTERMINATE(destination);214215return ZYAN_STATUS_SUCCESS;216}217218ZyanStatus ZyanStringConcatCustomBuffer(ZyanString* destination, const ZyanStringView* s1,219const ZyanStringView* s2, char* buffer, ZyanUSize capacity)220{221if (!s1 || !s2 || !s1->string.vector.size || !s2->string.vector.size)222{223return ZYAN_STATUS_INVALID_ARGUMENT;224}225226const ZyanUSize len = s1->string.vector.size + s2->string.vector.size - 1;227if (capacity < len)228{229return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;230}231232ZYAN_CHECK(ZyanStringInitCustomBuffer(destination, buffer, capacity));233ZYAN_ASSERT(destination->vector.capacity >= len);234235ZYAN_MEMCPY(destination->vector.data, s1->string.vector.data, s1->string.vector.size - 1);236ZYAN_MEMCPY((char*)destination->vector.data + s1->string.vector.size - 1,237s2->string.vector.data, s2->string.vector.size - 1);238destination->vector.size = len;239ZYCORE_STRING_NULLTERMINATE(destination);240241return ZYAN_STATUS_SUCCESS;242}243244/* ---------------------------------------------------------------------------------------------- */245/* Views */246/* ---------------------------------------------------------------------------------------------- */247248ZyanStatus ZyanStringViewInsideView(ZyanStringView* view, const ZyanStringView* source)249{250if (!view || !source)251{252return ZYAN_STATUS_INVALID_ARGUMENT;253}254255view->string.vector.data = source->string.vector.data;256view->string.vector.size = source->string.vector.size;257258return ZYAN_STATUS_SUCCESS;259}260261ZyanStatus ZyanStringViewInsideViewEx(ZyanStringView* view, const ZyanStringView* source,262ZyanUSize index, ZyanUSize count)263{264if (!view || !source)265{266return ZYAN_STATUS_INVALID_ARGUMENT;267}268269if (index + count >= source->string.vector.size)270{271return ZYAN_STATUS_OUT_OF_RANGE;272}273274view->string.vector.data = (void*)((char*)source->string.vector.data + index);275view->string.vector.size = count;276277return ZYAN_STATUS_SUCCESS;278}279280ZyanStatus ZyanStringViewInsideBuffer(ZyanStringView* view, const char* string)281{282if (!view || !string)283{284return ZYAN_STATUS_INVALID_ARGUMENT;285}286287view->string.vector.data = (void*)string;288view->string.vector.size = ZYAN_STRLEN(string) + 1;289290return ZYAN_STATUS_SUCCESS;291}292293ZyanStatus ZyanStringViewInsideBufferEx(ZyanStringView* view, const char* buffer, ZyanUSize length)294{295if (!view || !buffer || !length)296{297return ZYAN_STATUS_INVALID_ARGUMENT;298}299300view->string.vector.data = (void*)buffer;301view->string.vector.size = length + 1;302303return ZYAN_STATUS_SUCCESS;304}305306ZyanStatus ZyanStringViewGetSize(const ZyanStringView* view, ZyanUSize* size)307{308if (!view || !size)309{310return ZYAN_STATUS_INVALID_ARGUMENT;311}312313ZYAN_ASSERT(view->string.vector.size >= 1);314*size = view->string.vector.size - 1;315316return ZYAN_STATUS_SUCCESS;317}318319ZYCORE_EXPORT ZyanStatus ZyanStringViewGetData(const ZyanStringView* view, const char** buffer)320{321if (!view || !buffer)322{323return ZYAN_STATUS_INVALID_ARGUMENT;324}325326*buffer = view->string.vector.data;327328return ZYAN_STATUS_SUCCESS;329}330331/* ---------------------------------------------------------------------------------------------- */332/* Character access */333/* ---------------------------------------------------------------------------------------------- */334335ZyanStatus ZyanStringGetChar(const ZyanStringView* string, ZyanUSize index, char* value)336{337if (!string || !value)338{339return ZYAN_STATUS_INVALID_ARGUMENT;340}341342// Don't allow direct access to the terminating '\0' character343if (index + 1 >= string->string.vector.size)344{345return ZYAN_STATUS_OUT_OF_RANGE;346}347348const char* chr;349ZYAN_CHECK(ZyanVectorGetPointer(&string->string.vector, index, (const void**)&chr));350*value = *chr;351352return ZYAN_STATUS_SUCCESS;353}354355ZyanStatus ZyanStringGetCharMutable(ZyanString* string, ZyanUSize index, char** value)356{357if (!string)358{359return ZYAN_STATUS_INVALID_ARGUMENT;360}361362// Don't allow direct access to the terminating '\0' character363if (index + 1 >= string->vector.size)364{365return ZYAN_STATUS_OUT_OF_RANGE;366}367368return ZyanVectorGetPointerMutable(&string->vector, index, (void**)value);369}370371ZyanStatus ZyanStringSetChar(ZyanString* string, ZyanUSize index, char value)372{373if (!string)374{375return ZYAN_STATUS_INVALID_ARGUMENT;376}377378// Don't allow direct access to the terminating '\0' character379if (index + 1 >= string->vector.size)380{381return ZYAN_STATUS_OUT_OF_RANGE;382}383384return ZyanVectorSet(&string->vector, index, (void*)&value);385}386387/* ---------------------------------------------------------------------------------------------- */388/* Insertion */389/* ---------------------------------------------------------------------------------------------- */390391ZyanStatus ZyanStringInsert(ZyanString* destination, ZyanUSize index, const ZyanStringView* source)392{393if (!destination || !source || !source->string.vector.size)394{395return ZYAN_STATUS_INVALID_ARGUMENT;396}397398if (index == destination->vector.size)399{400return ZyanStringAppend(destination, source);401}402403// Don't allow insertion after the terminating '\0' character404if (index >= destination->vector.size)405{406return ZYAN_STATUS_OUT_OF_RANGE;407}408409ZYAN_CHECK(ZyanVectorInsertRange(&destination->vector, index, source->string.vector.data,410source->string.vector.size - 1));411ZYCORE_STRING_ASSERT_NULLTERMINATION(destination);412413return ZYAN_STATUS_SUCCESS;414}415416ZyanStatus ZyanStringInsertEx(ZyanString* destination, ZyanUSize destination_index,417const ZyanStringView* source, ZyanUSize source_index, ZyanUSize count)418{419if (!destination || !source || !source->string.vector.size)420{421return ZYAN_STATUS_INVALID_ARGUMENT;422}423424if (destination_index == destination->vector.size)425{426return ZyanStringAppendEx(destination, source, source_index, count);427}428429// Don't allow insertion after the terminating '\0' character430if (destination_index >= destination->vector.size)431{432return ZYAN_STATUS_OUT_OF_RANGE;433}434435// Don't allow access to the terminating '\0' character436if (source_index + count >= source->string.vector.size)437{438return ZYAN_STATUS_OUT_OF_RANGE;439}440441ZYAN_CHECK(ZyanVectorInsertRange(&destination->vector, destination_index,442(char*)source->string.vector.data + source_index, count));443ZYCORE_STRING_ASSERT_NULLTERMINATION(destination);444445return ZYAN_STATUS_SUCCESS;446}447448/* ---------------------------------------------------------------------------------------------- */449/* Appending */450/* ---------------------------------------------------------------------------------------------- */451452ZyanStatus ZyanStringAppend(ZyanString* destination, const ZyanStringView* source)453{454if (!destination || !source || !source->string.vector.size)455{456return ZYAN_STATUS_INVALID_ARGUMENT;457}458459const ZyanUSize len = destination->vector.size;460ZYAN_CHECK(ZyanVectorResize(&destination->vector, len + source->string.vector.size - 1));461ZYAN_MEMCPY((char*)destination->vector.data + len - 1, source->string.vector.data,462source->string.vector.size - 1);463ZYCORE_STRING_NULLTERMINATE(destination);464465return ZYAN_STATUS_SUCCESS;466}467468ZyanStatus ZyanStringAppendEx(ZyanString* destination, const ZyanStringView* source,469ZyanUSize source_index, ZyanUSize count)470{471if (!destination || !source || !source->string.vector.size)472{473return ZYAN_STATUS_INVALID_ARGUMENT;474}475476// Don't allow access to the terminating '\0' character477if (source_index + count >= source->string.vector.size)478{479return ZYAN_STATUS_OUT_OF_RANGE;480}481482const ZyanUSize len = destination->vector.size;483ZYAN_CHECK(ZyanVectorResize(&destination->vector, len + count));484ZYAN_MEMCPY((char*)destination->vector.data + len - 1,485(const char*)source->string.vector.data + source_index, count);486ZYCORE_STRING_NULLTERMINATE(destination);487488return ZYAN_STATUS_SUCCESS;489}490491/* ---------------------------------------------------------------------------------------------- */492/* Deletion */493/* ---------------------------------------------------------------------------------------------- */494495ZyanStatus ZyanStringDelete(ZyanString* string, ZyanUSize index, ZyanUSize count)496{497if (!string)498{499return ZYAN_STATUS_INVALID_ARGUMENT;500}501502// Don't allow removal of the terminating '\0' character503if (index + count >= string->vector.size)504{505return ZYAN_STATUS_OUT_OF_RANGE;506}507508ZYAN_CHECK(ZyanVectorDeleteRange(&string->vector, index, count));509ZYCORE_STRING_NULLTERMINATE(string);510511return ZYAN_STATUS_SUCCESS;512}513514ZyanStatus ZyanStringTruncate(ZyanString* string, ZyanUSize index)515{516if (!string)517{518return ZYAN_STATUS_INVALID_ARGUMENT;519}520521// Don't allow removal of the terminating '\0' character522if (index >= string->vector.size)523{524return ZYAN_STATUS_OUT_OF_RANGE;525}526527ZYAN_CHECK(ZyanVectorDeleteRange(&string->vector, index, string->vector.size - index - 1));528ZYCORE_STRING_NULLTERMINATE(string);529530return ZYAN_STATUS_SUCCESS;531}532533ZyanStatus ZyanStringClear(ZyanString* string)534{535if (!string)536{537return ZYAN_STATUS_INVALID_ARGUMENT;538}539540ZYAN_CHECK(ZyanVectorClear(&string->vector));541// `ZyanVector` guarantees a minimum capacity of 1 element/character542ZYAN_ASSERT(string->vector.capacity >= 1);543544*(char*)string->vector.data = '\0';545string->vector.size++;546547return ZYAN_STATUS_SUCCESS;548}549550/* ---------------------------------------------------------------------------------------------- */551/* Searching */552/* ---------------------------------------------------------------------------------------------- */553554ZyanStatus ZyanStringLPos(const ZyanStringView* haystack, const ZyanStringView* needle,555ZyanISize* found_index)556{557if (!haystack)558{559return ZYAN_STATUS_INVALID_ARGUMENT;560}561562return ZyanStringLPosEx(haystack, needle, found_index, 0, haystack->string.vector.size - 1);563}564565ZyanStatus ZyanStringLPosEx(const ZyanStringView* haystack, const ZyanStringView* needle,566ZyanISize* found_index, ZyanUSize index, ZyanUSize count)567{568if (!haystack || !needle || !found_index)569{570return ZYAN_STATUS_INVALID_ARGUMENT;571}572573// Don't allow access to the terminating '\0' character574if (index + count >= haystack->string.vector.size)575{576return ZYAN_STATUS_OUT_OF_RANGE;577}578579if ((haystack->string.vector.size == 1) || (needle->string.vector.size == 1) ||580(haystack->string.vector.size < needle->string.vector.size))581{582*found_index = -1;583return ZYAN_STATUS_FALSE;584}585586const char* s = (const char*)haystack->string.vector.data + index;587const char* b = (const char*)needle->string.vector.data;588for (; s + 1 < (const char*)haystack->string.vector.data + haystack->string.vector.size; ++s)589{590if (*s != *b)591{592continue;593}594const char* a = s;595for (;;)596{597if ((ZyanUSize)(a - (const char*)haystack->string.vector.data) > index + count)598{599*found_index = -1;600return ZYAN_STATUS_FALSE;601}602if (*b == 0)603{604*found_index = (ZyanISize)(s - (const char*)haystack->string.vector.data);605return ZYAN_STATUS_TRUE;606}607if (*a++ != *b++)608{609break;610}611}612b = (char*)needle->string.vector.data;613}614615*found_index = -1;616return ZYAN_STATUS_FALSE;617}618619ZyanStatus ZyanStringLPosI(const ZyanStringView* haystack, const ZyanStringView* needle,620ZyanISize* found_index)621{622if (!haystack)623{624return ZYAN_STATUS_INVALID_ARGUMENT;625}626627return ZyanStringLPosIEx(haystack, needle, found_index, 0, haystack->string.vector.size - 1);628}629630ZyanStatus ZyanStringLPosIEx(const ZyanStringView* haystack, const ZyanStringView* needle,631ZyanISize* found_index, ZyanUSize index, ZyanUSize count)632{633// This solution assumes that characters are represented using ASCII representation, i.e.,634// codes for 'a', 'b', 'c', .. 'z' are 97, 98, 99, .. 122 respectively. And codes for 'A',635// 'B', 'C', .. 'Z' are 65, 66, .. 95 respectively.636637if (!haystack || !needle || !found_index)638{639return ZYAN_STATUS_INVALID_ARGUMENT;640}641642// Don't allow access to the terminating '\0' character643if (index + count >= haystack->string.vector.size)644{645return ZYAN_STATUS_OUT_OF_RANGE;646}647648if ((haystack->string.vector.size == 1) || (needle->string.vector.size == 1) ||649(haystack->string.vector.size < needle->string.vector.size))650{651*found_index = -1;652return ZYAN_STATUS_FALSE;653}654655const char* s = (const char*)haystack->string.vector.data + index;656const char* b = (const char*)needle->string.vector.data;657for (; s + 1 < (const char*)haystack->string.vector.data + haystack->string.vector.size; ++s)658{659if ((*s != *b) && ((*s ^ 32) != *b))660{661continue;662}663const char* a = s;664for (;;)665{666if ((ZyanUSize)(a - (const char*)haystack->string.vector.data) > index + count)667{668*found_index = -1;669return ZYAN_STATUS_FALSE;670}671if (*b == 0)672{673*found_index = (ZyanISize)(s - (const char*)haystack->string.vector.data);674return ZYAN_STATUS_TRUE;675}676const char c1 = *a++;677const char c2 = *b++;678if ((c1 != c2) && ((c1 ^ 32) != c2))679{680break;681}682}683b = (char*)needle->string.vector.data;684}685686*found_index = -1;687return ZYAN_STATUS_FALSE;688}689690ZyanStatus ZyanStringRPos(const ZyanStringView* haystack, const ZyanStringView* needle,691ZyanISize* found_index)692{693if (!haystack)694{695return ZYAN_STATUS_INVALID_ARGUMENT;696}697698return ZyanStringRPosEx(haystack, needle, found_index, haystack->string.vector.size - 1,699haystack->string.vector.size - 1);700}701702ZyanStatus ZyanStringRPosEx(const ZyanStringView* haystack, const ZyanStringView* needle,703ZyanISize* found_index, ZyanUSize index, ZyanUSize count)704{705if (!haystack || !needle || !found_index)706{707return ZYAN_STATUS_INVALID_ARGUMENT;708}709710// Don't allow access to the terminating '\0' character711if ((index >= haystack->string.vector.size) || (count > index))712{713return ZYAN_STATUS_OUT_OF_RANGE;714}715716if (!index || !count ||717(haystack->string.vector.size == 1) || (needle->string.vector.size == 1) ||718(haystack->string.vector.size < needle->string.vector.size))719{720*found_index = -1;721return ZYAN_STATUS_FALSE;722}723724const char* s = (const char*)haystack->string.vector.data + index - 1;725const char* b = (const char*)needle->string.vector.data + needle->string.vector.size - 2;726for (; s >= (const char*)haystack->string.vector.data; --s)727{728if (*s != *b)729{730continue;731}732const char* a = s;733for (;;)734{735if (b < (const char*)needle->string.vector.data)736{737*found_index = (ZyanISize)(a - (const char*)haystack->string.vector.data + 1);738return ZYAN_STATUS_TRUE;739}740if (a < (const char*)haystack->string.vector.data + index - count)741{742*found_index = -1;743return ZYAN_STATUS_FALSE;744}745if (*a-- != *b--)746{747break;748}749}750b = (char*)needle->string.vector.data + needle->string.vector.size - 2;751}752753*found_index = -1;754return ZYAN_STATUS_FALSE;755}756757ZyanStatus ZyanStringRPosI(const ZyanStringView* haystack, const ZyanStringView* needle,758ZyanISize* found_index)759{760if (!haystack)761{762return ZYAN_STATUS_INVALID_ARGUMENT;763}764765return ZyanStringRPosIEx(haystack, needle, found_index, haystack->string.vector.size - 1,766haystack->string.vector.size - 1);767}768769ZyanStatus ZyanStringRPosIEx(const ZyanStringView* haystack, const ZyanStringView* needle,770ZyanISize* found_index, ZyanUSize index, ZyanUSize count)771{772// This solution assumes that characters are represented using ASCII representation, i.e.,773// codes for 'a', 'b', 'c', .. 'z' are 97, 98, 99, .. 122 respectively. And codes for 'A',774// 'B', 'C', .. 'Z' are 65, 66, .. 95 respectively.775776if (!haystack || !needle || !found_index)777{778return ZYAN_STATUS_INVALID_ARGUMENT;779}780781// Don't allow access to the terminating '\0' character782if ((index >= haystack->string.vector.size) || (count > index))783{784return ZYAN_STATUS_OUT_OF_RANGE;785}786787if (!index || !count ||788(haystack->string.vector.size == 1) || (needle->string.vector.size == 1) ||789(haystack->string.vector.size < needle->string.vector.size))790{791*found_index = -1;792return ZYAN_STATUS_FALSE;793}794795const char* s = (const char*)haystack->string.vector.data + index - 1;796const char* b = (const char*)needle->string.vector.data + needle->string.vector.size - 2;797for (; s >= (const char*)haystack->string.vector.data; --s)798{799if ((*s != *b) && ((*s ^ 32) != *b))800{801continue;802}803const char* a = s;804for (;;)805{806if (b < (const char*)needle->string.vector.data)807{808*found_index = (ZyanISize)(a - (const char*)haystack->string.vector.data + 1);809return ZYAN_STATUS_TRUE;810}811if (a < (const char*)haystack->string.vector.data + index - count)812{813*found_index = -1;814return ZYAN_STATUS_FALSE;815}816const char c1 = *a--;817const char c2 = *b--;818if ((c1 != c2) && ((c1 ^ 32) != c2))819{820break;821}822}823b = (char*)needle->string.vector.data + needle->string.vector.size - 2;824}825826*found_index = -1;827return ZYAN_STATUS_FALSE;828}829830/* ---------------------------------------------------------------------------------------------- */831/* Comparing */832/* ---------------------------------------------------------------------------------------------- */833834ZyanStatus ZyanStringCompare(const ZyanStringView* s1, const ZyanStringView* s2, ZyanI32* result)835{836if (!s1 || !s2)837{838return ZYAN_STATUS_INVALID_ARGUMENT;839}840841if (s1->string.vector.size < s2->string.vector.size)842{843*result = -1;844return ZYAN_STATUS_FALSE;845}846if (s1->string.vector.size > s2->string.vector.size)847{848*result = 1;849return ZYAN_STATUS_FALSE;850}851852const char* const a = (char*)s1->string.vector.data;853const char* const b = (char*)s2->string.vector.data;854ZyanUSize i;855for (i = 0; (i + 1 < s1->string.vector.size) && (i + 1 < s2->string.vector.size); ++i)856{857if (a[i] == b[i])858{859continue;860}861break;862}863864if (a[i] == b[i])865{866*result = 0;867return ZYAN_STATUS_TRUE;868}869870if ((a[i] | 32) < (b[i] | 32))871{872*result = -1;873return ZYAN_STATUS_FALSE;874}875876*result = 1;877return ZYAN_STATUS_FALSE;878}879880ZyanStatus ZyanStringCompareI(const ZyanStringView* s1, const ZyanStringView* s2, ZyanI32* result)881{882// This solution assumes that characters are represented using ASCII representation, i.e.,883// codes for 'a', 'b', 'c', .. 'z' are 97, 98, 99, .. 122 respectively. And codes for 'A',884// 'B', 'C', .. 'Z' are 65, 66, .. 95 respectively.885886if (!s1 || !s2)887{888return ZYAN_STATUS_INVALID_ARGUMENT;889}890891if (s1->string.vector.size < s2->string.vector.size)892{893*result = -1;894return ZYAN_STATUS_FALSE;895}896if (s1->string.vector.size > s2->string.vector.size)897{898*result = 1;899return ZYAN_STATUS_FALSE;900}901902const char* const a = (char*)s1->string.vector.data;903const char* const b = (char*)s2->string.vector.data;904ZyanUSize i;905for (i = 0; (i + 1 < s1->string.vector.size) && (i + 1 < s2->string.vector.size); ++i)906{907if ((a[i] == b[i]) || ((a[i] ^ 32) == b[i]))908{909continue;910}911break;912}913914if (a[i] == b[i])915{916*result = 0;917return ZYAN_STATUS_TRUE;918}919920if ((a[i] | 32) < (b[i] | 32))921{922*result = -1;923return ZYAN_STATUS_FALSE;924}925926*result = 1;927return ZYAN_STATUS_FALSE;928}929930/* ---------------------------------------------------------------------------------------------- */931/* Case conversion */932/* ---------------------------------------------------------------------------------------------- */933934ZyanStatus ZyanStringToLowerCase(ZyanString* string)935{936if (!string)937{938return ZYAN_STATUS_INVALID_ARGUMENT;939}940941return ZyanStringToLowerCaseEx(string, 0, string->vector.size - 1);942}943944ZyanStatus ZyanStringToLowerCaseEx(ZyanString* string, ZyanUSize index, ZyanUSize count)945{946// This solution assumes that characters are represented using ASCII representation, i.e.,947// codes for 'a', 'b', 'c', .. 'z' are 97, 98, 99, .. 122 respectively. And codes for 'A',948// 'B', 'C', .. 'Z' are 65, 66, .. 95 respectively.949950if (!string)951{952return ZYAN_STATUS_INVALID_ARGUMENT;953}954955// Don't allow access to the terminating '\0' character956if (index + count >= string->vector.size)957{958return ZYAN_STATUS_OUT_OF_RANGE;959}960961char* s = (char*)string->vector.data + index;962for (ZyanUSize i = index; i < index + count; ++i)963{964const char c = *s;965if ((c >= 'A') && (c <= 'Z'))966{967*s = c | 32;968}969++s;970}971972return ZYAN_STATUS_SUCCESS;973}974975ZyanStatus ZyanStringToUpperCase(ZyanString* string)976{977if (!string)978{979return ZYAN_STATUS_INVALID_ARGUMENT;980}981982return ZyanStringToUpperCaseEx(string, 0, string->vector.size - 1);983}984985ZyanStatus ZyanStringToUpperCaseEx(ZyanString* string, ZyanUSize index, ZyanUSize count)986{987// This solution assumes that characters are represented using ASCII representation, i.e.,988// codes for 'a', 'b', 'c', .. 'z' are 97, 98, 99, .. 122 respectively. And codes for 'A',989// 'B', 'C', .. 'Z' are 65, 66, .. 95 respectively.990991if (!string)992{993return ZYAN_STATUS_INVALID_ARGUMENT;994}995996// Don't allow access to the terminating '\0' character997if (index + count >= string->vector.size)998{999return ZYAN_STATUS_OUT_OF_RANGE;1000}10011002char* s = (char*)string->vector.data + index;1003for (ZyanUSize i = index; i < index + count; ++i)1004{1005const char c = *s;1006if ((c >= 'a') && (c <= 'z'))1007{1008*s = c & ~32;1009}1010++s;1011}10121013return ZYAN_STATUS_SUCCESS;1014}10151016/* ---------------------------------------------------------------------------------------------- */1017/* Memory management */1018/* ---------------------------------------------------------------------------------------------- */10191020ZyanStatus ZyanStringResize(ZyanString* string, ZyanUSize size)1021{1022if (!string)1023{1024return ZYAN_STATUS_INVALID_ARGUMENT;1025}10261027ZYAN_CHECK(ZyanVectorResize(&string->vector, size + 1));1028ZYCORE_STRING_NULLTERMINATE(string);10291030return ZYAN_STATUS_SUCCESS;1031}10321033ZyanStatus ZyanStringReserve(ZyanString* string, ZyanUSize capacity)1034{1035if (!string)1036{1037return ZYAN_STATUS_INVALID_ARGUMENT;1038}10391040return ZyanVectorReserve(&string->vector, capacity);1041}10421043ZyanStatus ZyanStringShrinkToFit(ZyanString* string)1044{1045if (!string)1046{1047return ZYAN_STATUS_INVALID_ARGUMENT;1048}10491050return ZyanVectorShrinkToFit(&string->vector);1051}10521053/* ---------------------------------------------------------------------------------------------- */1054/* Information */1055/* ---------------------------------------------------------------------------------------------- */10561057ZyanStatus ZyanStringGetCapacity(const ZyanString* string, ZyanUSize* capacity)1058{1059if (!string)1060{1061return ZYAN_STATUS_INVALID_ARGUMENT;1062}10631064ZYAN_ASSERT(string->vector.capacity >= 1);1065*capacity = string->vector.capacity - 1;10661067return ZYAN_STATUS_SUCCESS;1068}10691070ZyanStatus ZyanStringGetSize(const ZyanString* string, ZyanUSize* size)1071{1072if (!string)1073{1074return ZYAN_STATUS_INVALID_ARGUMENT;1075}10761077ZYAN_ASSERT(string->vector.size >= 1);1078*size = string->vector.size - 1;10791080return ZYAN_STATUS_SUCCESS;1081}10821083ZyanStatus ZyanStringGetData(const ZyanString* string, const char** value)1084{1085if (!string)1086{1087return ZYAN_STATUS_INVALID_ARGUMENT;1088}10891090*value = string->vector.data;10911092return ZYAN_STATUS_SUCCESS;1093}10941095/* ---------------------------------------------------------------------------------------------- */10961097/* ============================================================================================== */109810991100