1 /***************************************************************************************************
2 
3   Zyan Core Library (Zycore-C)
4 
5   Original Author : Florian Bernd
6 
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24 
25 ***************************************************************************************************/
26 
27 /**
28  * @file
29  * @brief   Implements a string type.
30  */
31 
32 #ifndef ZYCORE_STRING_H
33 #define ZYCORE_STRING_H
34 
35 #include "zydis/ZycoreExportConfig.h"
36 #include "zydis/Zycore/Allocator.h"
37 #include "zydis/Zycore/Status.h"
38 #include "zydis/Zycore/Types.h"
39 #include "zydis/Zycore/Vector.h"
40 
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44 
45 /* ============================================================================================== */
46 /* Constants                                                                                      */
47 /* ============================================================================================== */
48 
49 /**
50  * @brief   The initial minimum capacity (number of characters) for all dynamically allocated
51  *          string instances - not including the terminating '\0'-character.
52  */
53 #define ZYAN_STRING_MIN_CAPACITY                32
54 
55 /**
56  * @brief   The default growth factor for all string instances.
57  */
58 #define ZYAN_STRING_DEFAULT_GROWTH_FACTOR       2.00f
59 
60 /**
61  * @brief   The default shrink threshold for all string instances.
62  */
63 #define ZYAN_STRING_DEFAULT_SHRINK_THRESHOLD    0.25f
64 
65 /* ============================================================================================== */
66 /* Enums and types                                                                                */
67 /* ============================================================================================== */
68 
69 /* ---------------------------------------------------------------------------------------------- */
70 /* String flags                                                                                   */
71 /* ---------------------------------------------------------------------------------------------- */
72 
73 /**
74  * @brief   Defines the `ZyanStringFlags` datatype.
75  */
76 typedef ZyanU8 ZyanStringFlags;
77 
78 /**
79  * @brief   The string uses a custom user-defined buffer with a fixed capacity.
80  */
81 #define ZYAN_STRING_HAS_FIXED_CAPACITY  0x01 // (1 << 0)
82 
83 /* ---------------------------------------------------------------------------------------------- */
84 /* String                                                                                         */
85 /* ---------------------------------------------------------------------------------------------- */
86 
87 /**
88  * @brief   Defines the `ZyanString` struct.
89  *
90  * The `ZyanString` type is implemented as a size-prefixed string - which allows for a lot of
91  * performance optimizations.
92  * Nevertheless null-termination is guaranteed at all times to provide maximum compatibility with
93  * default C-style strings (use `ZyanStringGetData` to access the C-style string).
94  *
95  * All fields in this struct should be considered as "private". Any changes may lead to unexpected
96  * behavior.
97  */
98 typedef struct ZyanString_
99 {
100     /**
101      * @brief   String flags.
102      */
103     ZyanStringFlags flags;
104     /**
105      * @brief   The vector that contains the actual string.
106      */
107     ZyanVector vector;
108 } ZyanString;
109 
110 /* ---------------------------------------------------------------------------------------------- */
111 /* View                                                                                           */
112 /* ---------------------------------------------------------------------------------------------- */
113 
114 /**
115  * @brief   Defines the `ZyanStringView` struct.
116  *
117  * The `ZyanStringView` type provides a view inside a string (`ZyanString` instances, null-
118  * terminated C-style strings, or even not-null-terminated custom strings). A view is immutable
119  * by design and can't be directly converted to a C-style string.
120  *
121  * Views might become invalid (e.g. pointing to invalid memory), if the underlying string gets
122  * destroyed or resized.
123  *
124  * The `ZYAN_STRING_TO_VIEW` macro can be used to cast a `ZyanString` to a `ZyanStringView` pointer
125  * without any runtime overhead.
126  * Casting a view to a normal string is not supported and will lead to unexpected behavior (use
127  * `ZyanStringDuplicate` to create a deep-copy instead).
128  *
129  * All fields in this struct should be considered as "private". Any changes may lead to unexpected
130  * behavior.
131  */
132 typedef struct ZyanStringView_
133 {
134     /**
135      * @brief   The string data.
136      *
137      * The view internally re-uses the normal string struct to allow casts without any runtime
138      * overhead.
139      */
140     ZyanString string;
141 } ZyanStringView;
142 
143 /* ---------------------------------------------------------------------------------------------- */
144 
145 /* ============================================================================================== */
146 /* Macros                                                                                         */
147 /* ============================================================================================== */
148 
149 /* ---------------------------------------------------------------------------------------------- */
150 /* General                                                                                        */
151 /* ---------------------------------------------------------------------------------------------- */
152 
153 /**
154  * @brief   Defines an uninitialized `ZyanString` instance.
155  */
156 #define ZYAN_STRING_INITIALIZER \
157     { \
158         /* flags  */ 0, \
159         /* vector */ ZYAN_VECTOR_INITIALIZER \
160     }
161 
162 /* ---------------------------------------------------------------------------------------------- */
163 /* Helper macros                                                                                  */
164 /* ---------------------------------------------------------------------------------------------- */
165 
166 /**
167  * @brief   Casts a `ZyanString` pointer to a constant `ZyanStringView` pointer.
168  */
169 #define ZYAN_STRING_TO_VIEW(string) (const ZyanStringView*)(string)
170 
171 /**
172  * @brief   Defines a `ZyanStringView` struct that provides a view into a static C-style string.
173  *
174  * @param   string  The C-style string.
175  */
176 #define ZYAN_DEFINE_STRING_VIEW(string) \
177     { \
178         /* string */ \
179         { \
180             /* flags  */ 0, \
181             /* vector */ \
182             { \
183                 /* allocator        */ ZYAN_NULL, \
184                 /* growth_factor    */ 1.0f, \
185                 /* shrink_threshold */ 0.0f, \
186                 /* size             */ sizeof(string), \
187                 /* capacity         */ sizeof(string), \
188                 /* element_size     */ sizeof(char), \
189                 /* destructor       */ ZYAN_NULL, \
190                 /* data             */ (char*)(string) \
191             } \
192         } \
193     }
194 
195 /* ---------------------------------------------------------------------------------------------- */
196 
197 /* ============================================================================================== */
198 /* Exported functions                                                                             */
199 /* ============================================================================================== */
200 
201 /* ---------------------------------------------------------------------------------------------- */
202 /* Constructor and destructor                                                                     */
203 /* ---------------------------------------------------------------------------------------------- */
204 
205 #ifndef ZYAN_NO_LIBC
206 
207 /**
208  * @brief   Initializes the given `ZyanString` instance.
209  *
210  * @param   string          A pointer to the `ZyanString` instance.
211  * @param   capacity        The initial capacity (number of characters).
212  *
213  * @return  A zyan status code.
214  *
215  * The memory for the string is dynamically allocated by the default allocator using the default
216  * growth factor of `2.0f` and the default shrink threshold of `0.25f`.
217  *
218  * The allocated buffer will be at least one character larger than the given `capacity`, to reserve
219  * space for the terminating '\0'.
220  *
221  * Finalization with `ZyanStringDestroy` is required for all strings created by this function.
222  */
223 ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringInit(ZyanString* string, ZyanUSize capacity);
224 
225 #endif // ZYAN_NO_LIBC
226 
227 /**
228  * @brief   Initializes the given `ZyanString` instance and sets a custom `allocator` and memory
229  *          allocation/deallocation parameters.
230  *
231  * @param   string              A pointer to the `ZyanString` instance.
232  * @param   capacity            The initial capacity (number of characters).
233  * @param   allocator           A pointer to a `ZyanAllocator` instance.
234  * @param   growth_factor       The growth factor (from `1.0f` to `x.xf`).
235  * @param   shrink_threshold    The shrink threshold (from `0.0f` to `1.0f`).
236  *
237  * @return  A zyan status code.
238  *
239  * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables
240  * dynamic shrinking.
241  *
242  * The allocated buffer will be at least one character larger than the given `capacity`, to reserve
243  * space for the terminating '\0'.
244  *
245  * Finalization with `ZyanStringDestroy` is required for all strings created by this function.
246  */
247 ZYCORE_EXPORT ZyanStatus ZyanStringInitEx(ZyanString* string, ZyanUSize capacity,
248     ZyanAllocator* allocator, float growth_factor, float shrink_threshold);
249 
250 /**
251  * @brief   Initializes the given `ZyanString` instance and configures it to use a custom user
252  *          defined buffer with a fixed size.
253  *
254  * @param   string          A pointer to the `ZyanString` instance.
255  * @param   buffer          A pointer to the buffer that is used as storage for the string.
256  * @param   capacity        The maximum capacity (number of characters) of the buffer, including
257  *                          the terminating '\0'.
258  *
259  * @return  A zyan status code.
260  *
261  * Finalization is not required for strings created by this function.
262  */
263 ZYCORE_EXPORT ZyanStatus ZyanStringInitCustomBuffer(ZyanString* string, char* buffer,
264     ZyanUSize capacity);
265 
266 /**
267  * @brief   Destroys the given `ZyanString` instance.
268  *
269  * @param   string  A pointer to the `ZyanString` instance.
270  *
271  * @return  A zyan status code.
272  *
273  */
274 ZYCORE_EXPORT ZyanStatus ZyanStringDestroy(ZyanString* string);
275 
276 /* ---------------------------------------------------------------------------------------------- */
277 /* Duplication                                                                                    */
278 /* ---------------------------------------------------------------------------------------------- */
279 
280 #ifndef ZYAN_NO_LIBC
281 
282 /**
283  * @brief   Initializes a new `ZyanString` instance by duplicating an existing string.
284  *
285  * @param   destination A pointer to the (uninitialized) destination `ZyanString` instance.
286  * @param   source      A pointer to the source string.
287  * @param   capacity    The initial capacity (number of characters).
288  *
289  *                      This value is automatically adjusted to the size of the source string, if
290  *                      a smaller value was passed.
291  *
292  * @return  A zyan status code.
293  *
294  * The behavior of this function is undefined, if `source` is a view into the `destination`
295  * string or `destination` points to an already initialized `ZyanString` instance.
296  *
297  * The memory for the string is dynamically allocated by the default allocator using the default
298  * growth factor of `2.0f` and the default shrink threshold of `0.25f`.
299  *
300  * The allocated buffer will be at least one character larger than the given `capacity`, to reserve
301  * space for the terminating '\0'.
302  *
303  * Finalization with `ZyanStringDestroy` is required for all strings created by this function.
304  */
305 ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringDuplicate(ZyanString* destination,
306     const ZyanStringView* source, ZyanUSize capacity);
307 
308 #endif // ZYAN_NO_LIBC
309 
310 /**
311  * @brief   Initializes a new `ZyanString` instance by duplicating an existing string and sets a
312  *          custom `allocator` and memory allocation/deallocation parameters.
313  *
314  * @param   destination         A pointer to the (uninitialized) destination `ZyanString` instance.
315  * @param   source              A pointer to the source string.
316  * @param   capacity            The initial capacity (number of characters).
317 
318  *                              This value is automatically adjusted to the size of the source
319  *                              string, if a smaller value was passed.
320  * @param   allocator           A pointer to a `ZyanAllocator` instance.
321  * @param   growth_factor       The growth factor (from `1.0f` to `x.xf`).
322  * @param   shrink_threshold    The shrink threshold (from `0.0f` to `1.0f`).
323  *
324  * @return  A zyan status code.
325  *
326  * The behavior of this function is undefined, if `source` is a view into the `destination`
327  * string or `destination` points to an already initialized `ZyanString` instance.
328  *
329  * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables
330  * dynamic shrinking.
331  *
332  * The allocated buffer will be at least one character larger than the given `capacity`, to reserve
333  * space for the terminating '\0'.
334  *
335  * Finalization with `ZyanStringDestroy` is required for all strings created by this function.
336  */
337 ZYCORE_EXPORT ZyanStatus ZyanStringDuplicateEx(ZyanString* destination,
338     const ZyanStringView* source, ZyanUSize capacity, ZyanAllocator* allocator,
339     float growth_factor, float shrink_threshold);
340 
341 /**
342  * @brief   Initializes a new `ZyanString` instance by duplicating an existing string and
343  *          configures it to use a custom user defined buffer with a fixed size.
344  *
345  * @param   destination A pointer to the (uninitialized) destination `ZyanString` instance.
346  * @param   source      A pointer to the source string.
347  * @param   buffer      A pointer to the buffer that is used as storage for the string.
348  * @param   capacity    The maximum capacity (number of characters) of the buffer, including the
349  *                      terminating '\0'.
350 
351  *                      This function will fail, if the capacity of the buffer is less or equal to
352  *                      the size of the source string.
353  *
354  * @return  A zyan status code.
355  *
356  * The behavior of this function is undefined, if `source` is a view into the `destination`
357  * string or `destination` points to an already initialized `ZyanString` instance.
358  *
359  * Finalization is not required for strings created by this function.
360  */
361 ZYCORE_EXPORT ZyanStatus ZyanStringDuplicateCustomBuffer(ZyanString* destination,
362     const ZyanStringView* source, char* buffer, ZyanUSize capacity);
363 
364 /* ---------------------------------------------------------------------------------------------- */
365 /* Concatenation                                                                                  */
366 /* ---------------------------------------------------------------------------------------------- */
367 
368 #ifndef ZYAN_NO_LIBC
369 
370 /**
371  * @brief   Initializes a new `ZyanString` instance by concatenating two existing strings.
372  *
373  * @param   destination A pointer to the (uninitialized) destination `ZyanString` instance.
374  *
375  *                      This function will fail, if the destination `ZyanString` instance equals
376  *                      one of the source strings.
377  * @param   s1          A pointer to the first source string.
378  * @param   s2          A pointer to the second source string.
379  * @param   capacity    The initial capacity (number of characters).
380 
381  *                      This value is automatically adjusted to the combined size of the source
382  *                      strings, if a smaller value was passed.
383  *
384  * @return  A zyan status code.
385  *
386  * The behavior of this function is undefined, if `s1` or `s2` are views into the `destination`
387  * string or `destination` points to an already initialized `ZyanString` instance.
388  *
389  * The memory for the string is dynamically allocated by the default allocator using the default
390  * growth factor of `2.0f` and the default shrink threshold of `0.25f`.
391  *
392  * The allocated buffer will be at least one character larger than the given `capacity`, to reserve
393  * space for the terminating '\0'.
394  *
395  * Finalization with `ZyanStringDestroy` is required for all strings created by this function.
396  */
397 ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringConcat(ZyanString* destination,
398     const ZyanStringView* s1, const ZyanStringView* s2, ZyanUSize capacity);
399 
400 #endif // ZYAN_NO_LIBC
401 
402 /**
403  * @brief   Initializes a new `ZyanString` instance by concatenating two existing strings and sets
404  *          a custom `allocator` and memory allocation/deallocation parameters.
405  *
406  * @param   destination         A pointer to the (uninitialized) destination `ZyanString` instance.
407  *
408  *                              This function will fail, if the destination `ZyanString` instance
409  *                              equals one of the source strings.
410  * @param   s1                  A pointer to the first source string.
411  * @param   s2                  A pointer to the second source string.
412  * @param   capacity            The initial capacity (number of characters).
413  *
414  *                              This value is automatically adjusted to the combined size of the
415  *                              source strings, if a smaller value was passed.
416  * @param   allocator           A pointer to a `ZyanAllocator` instance.
417  * @param   growth_factor       The growth factor (from `1.0f` to `x.xf`).
418  * @param   shrink_threshold    The shrink threshold (from `0.0f` to `1.0f`).
419  *
420  * @return  A zyan status code.
421  *
422  * The behavior of this function is undefined, if `s1` or `s2` are views into the `destination`
423  * string or `destination` points to an already initialized `ZyanString` instance.
424  *
425  * A growth factor of `1.0f` disables overallocation and a shrink threshold of `0.0f` disables
426  * dynamic shrinking.
427  *
428  * The allocated buffer will be at least one character larger than the given `capacity`, to reserve
429  * space for the terminating '\0'.
430  *
431  * Finalization with `ZyanStringDestroy` is required for all strings created by this function.
432  */
433 ZYCORE_EXPORT ZyanStatus ZyanStringConcatEx(ZyanString* destination, const ZyanStringView* s1,
434     const ZyanStringView* s2, ZyanUSize capacity, ZyanAllocator* allocator, float growth_factor,
435     float shrink_threshold);
436 
437 /**
438  * @brief   Initializes a new `ZyanString` instance by concatenating two existing strings and
439  *          configures it to use a custom user defined buffer with a fixed size.
440  *
441  * @param   destination A pointer to the (uninitialized) destination `ZyanString` instance.
442  *
443  *                      This function will fail, if the destination `ZyanString` instance equals
444  *                      one of the source strings.
445  * @param   s1          A pointer to the first source string.
446  * @param   s2          A pointer to the second source string.
447  * @param   buffer      A pointer to the buffer that is used as storage for the string.
448  * @param   capacity    The maximum capacity (number of characters) of the buffer.
449  *
450  *                      This function will fail, if the capacity of the buffer is less or equal to
451  *                      the combined size of the source strings.
452  *
453  * @return  A zyan status code.
454  *
455  * The behavior of this function is undefined, if `s1` or `s2` are views into the `destination`
456  * string or `destination` points to an already initialized `ZyanString` instance.
457  *
458  * Finalization is not required for strings created by this function.
459  */
460 ZYCORE_EXPORT ZyanStatus ZyanStringConcatCustomBuffer(ZyanString* destination,
461     const ZyanStringView* s1, const ZyanStringView* s2, char* buffer, ZyanUSize capacity);
462 
463 /* ---------------------------------------------------------------------------------------------- */
464 /* Views                                                                                          */
465 /* ---------------------------------------------------------------------------------------------- */
466 
467 /**
468  * @brief   Returns a view inside an existing view/string.
469  *
470  * @param   view    A pointer to the `ZyanStringView` instance.
471  * @param   source  A pointer to the source string.
472  *
473  * @return  A zyan status code.
474  *
475  * The `ZYAN_STRING_TO_VEW` macro can be used to pass any `ZyanString` instance as value for the
476  * `source` string.
477  */
478 ZYCORE_EXPORT ZyanStatus ZyanStringViewInsideView(ZyanStringView* view,
479     const ZyanStringView* source);
480 
481 /**
482  * @brief   Returns a view inside an existing view/string starting from the given `index`.
483  *
484  * @param   view    A pointer to the `ZyanStringView` instance.
485  * @param   source  A pointer to the source string.
486  * @param   index   The start index.
487  * @param   count   The number of characters.
488  *
489  * @return  A zyan status code.
490  *
491  * The `ZYAN_STRING_TO_VEW` macro can be used to pass any `ZyanString` instance as value for the
492  * `source` string.
493  */
494 ZYCORE_EXPORT ZyanStatus ZyanStringViewInsideViewEx(ZyanStringView* view,
495     const ZyanStringView* source, ZyanUSize index, ZyanUSize count);
496 
497 /**
498  * @brief   Returns a view inside a null-terminated C-style string.
499  *
500  * @param   view    A pointer to the `ZyanStringView` instance.
501  * @param   string  The C-style string.
502  *
503  * @return  A zyan status code.
504  */
505 ZYCORE_EXPORT ZyanStatus ZyanStringViewInsideBuffer(ZyanStringView* view, const char* string);
506 
507 /**
508  * @brief   Returns a view inside a character buffer with custom length.
509  *
510  * @param   view    A pointer to the `ZyanStringView` instance.
511  * @param   buffer  A pointer to the buffer containing the string characters.
512  * @param   length  The length of the string (number of characters).
513  *
514  * @return  A zyan status code.
515  */
516 ZYCORE_EXPORT ZyanStatus ZyanStringViewInsideBufferEx(ZyanStringView* view, const char* buffer,
517     ZyanUSize length);
518 
519 /**
520  * @brief   Returns the size (number of characters) of the view.
521  *
522  * @param   view    A pointer to the `ZyanStringView` instance.
523  * @param   size    Receives the size (number of characters) of the view.
524  *
525  * @return  A zyan status code.
526  */
527 ZYCORE_EXPORT ZyanStatus ZyanStringViewGetSize(const ZyanStringView* view, ZyanUSize* size);
528 
529 /**
530  * @brief   Returns the C-style string of the given `ZyanString` instance.
531  *
532  * @warning The string is not guaranteed to be null terminated!
533  *
534  * @param   string  A pointer to the `ZyanStringView` instance.
535  * @param   value   Receives a pointer to the C-style string.
536  *
537  * @return  A zyan status code.
538  */
539 ZYCORE_EXPORT ZyanStatus ZyanStringViewGetData(const ZyanStringView* view, const char** buffer);
540 
541 /* ---------------------------------------------------------------------------------------------- */
542 /* Character access                                                                               */
543 /* ---------------------------------------------------------------------------------------------- */
544 
545 /**
546  * @brief   Returns the character at the given `index`.
547  *
548  * @param   string  A pointer to the `ZyanStringView` instance.
549  * @param   index   The character index.
550  * @param   value   Receives the desired character of the string.
551  *
552  * @return  A zyan status code.
553  */
554 ZYCORE_EXPORT ZyanStatus ZyanStringGetChar(const ZyanStringView* string, ZyanUSize index,
555     char* value);
556 
557 /**
558  * @brief   Returns a pointer to the character at the given `index`.
559  *
560  * @param   string  A pointer to the `ZyanString` instance.
561  * @param   index   The character index.
562  * @param   value   Receives a pointer to the desired character in the string.
563  *
564  * @return  A zyan status code.
565  */
566 ZYCORE_EXPORT ZyanStatus ZyanStringGetCharMutable(ZyanString* string, ZyanUSize index,
567     char** value);
568 
569 /**
570  * @brief   Assigns a new value to the character at the given `index`.
571  *
572  * @param   string  A pointer to the `ZyanString` instance.
573  * @param   index   The character index.
574  * @param   value   The character to assign.
575  *
576  * @return  A zyan status code.
577  */
578 ZYCORE_EXPORT ZyanStatus ZyanStringSetChar(ZyanString* string, ZyanUSize index, char value);
579 
580 /* ---------------------------------------------------------------------------------------------- */
581 /* Insertion                                                                                      */
582 /* ---------------------------------------------------------------------------------------------- */
583 
584 /**
585  * @brief   Inserts the content of the source string in the destination string at the given `index`.
586  *
587  * @param   destination The destination string.
588  * @param   index       The insert index.
589  * @param   source      The source string.
590  *
591  * @return  A zyan status code.
592  */
593 ZYCORE_EXPORT ZyanStatus ZyanStringInsert(ZyanString* destination, ZyanUSize index,
594     const ZyanStringView* source);
595 
596 /**
597  * @brief   Inserts `count` characters of the source string in the destination string at the given
598  *          `index`.
599  *
600  * @param   destination         The destination string.
601  * @param   destination_index   The insert index.
602  * @param   source              The source string.
603  * @param   source_index        The index of the first character to be inserted from the source
604  *                              string.
605  * @param   count               The number of chars to insert from the source string.
606  *
607  * @return  A zyan status code.
608  */
609 ZYCORE_EXPORT ZyanStatus ZyanStringInsertEx(ZyanString* destination, ZyanUSize destination_index,
610     const ZyanStringView* source, ZyanUSize source_index, ZyanUSize count);
611 
612 /* ---------------------------------------------------------------------------------------------- */
613 /* Appending                                                                                      */
614 /* ---------------------------------------------------------------------------------------------- */
615 
616 /**
617  * @brief   Appends the content of the source string to the end of the destination string.
618  *
619  * @param   destination The destination string.
620  * @param   source      The source string.
621  *
622  * @return  A zyan status code.
623  */
624 ZYCORE_EXPORT ZyanStatus ZyanStringAppend(ZyanString* destination, const ZyanStringView* source);
625 
626 /**
627  * @brief   Appends `count` characters of the source string to the end of the destination string.
628  *
629  * @param   destination     The destination string.
630  * @param   source          The source string.
631  * @param   source_index    The index of the first character to be appended from the source string.
632  * @param   count           The number of chars to append from the source string.
633  *
634  * @return  A zyan status code.
635  */
636 ZYCORE_EXPORT ZyanStatus ZyanStringAppendEx(ZyanString* destination, const ZyanStringView* source,
637     ZyanUSize source_index, ZyanUSize count);
638 
639 /* ---------------------------------------------------------------------------------------------- */
640 /* Deletion                                                                                       */
641 /* ---------------------------------------------------------------------------------------------- */
642 
643 /**
644  * @brief   Deletes characters from the given string, starting at `index`.
645  *
646  * @param   string  A pointer to the `ZyanString` instance.
647  * @param   index   The index of the first character to delete.
648  * @param   count   The number of characters to delete.
649  *
650  * @return  A zyan status code.
651  */
652 ZYCORE_EXPORT ZyanStatus ZyanStringDelete(ZyanString* string, ZyanUSize index, ZyanUSize count);
653 
654 /**
655  * @brief   Deletes all remaining characters from the given string, starting at `index`.
656  *
657  * @param   string  A pointer to the `ZyanString` instance.
658  * @param   index   The index of the first character to delete.
659  *
660  * @return  A zyan status code.
661  */
662 ZYCORE_EXPORT ZyanStatus ZyanStringTruncate(ZyanString* string, ZyanUSize index);
663 
664 /**
665  * @brief   Erases the given string.
666  *
667  * @param   string  A pointer to the `ZyanString` instance.
668  *
669  * @return  A zyan status code.
670  */
671 ZYCORE_EXPORT ZyanStatus ZyanStringClear(ZyanString* string);
672 
673 /* ---------------------------------------------------------------------------------------------- */
674 /* Searching                                                                                      */
675 /* ---------------------------------------------------------------------------------------------- */
676 
677 /**
678  * @brief   Searches for the first occurrence of `needle` in the given `haystack` starting from the
679  *          left.
680  *
681  * @param   haystack    The string to search in.
682  * @param   needle      The sub-string to search for.
683  * @param   found_index A pointer to a variable that receives the index of the first occurrence of
684  *                      `needle`.
685  *
686  * @return  `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another
687  *          zyan status code, if an error occured.
688  *
689  * The `found_index` is set to `-1`, if the needle was not found.
690  */
691 ZYCORE_EXPORT ZyanStatus ZyanStringLPos(const ZyanStringView* haystack,
692     const ZyanStringView* needle, ZyanISize* found_index);
693 
694 /**
695  * @brief   Searches for the first occurrence of `needle` in the given `haystack` starting from the
696  *          left.
697  *
698  * @param   haystack    The string to search in.
699  * @param   needle      The sub-string to search for.
700  * @param   found_index A pointer to a variable that receives the index of the first occurrence of
701  *                      `needle`.
702  * @param   index       The start index.
703  * @param   count       The maximum number of characters to iterate, beginning from the start
704  *                      `index`.
705  *
706  * @return  `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another
707  *          zyan status code, if an error occured.
708  *
709  * The `found_index` is set to `-1`, if the needle was not found.
710  */
711 ZYCORE_EXPORT ZyanStatus ZyanStringLPosEx(const ZyanStringView* haystack,
712     const ZyanStringView* needle, ZyanISize* found_index, ZyanUSize index, ZyanUSize count);
713 
714 /**
715  * @brief   Performs a case-insensitive search for the first occurrence of `needle` in the given
716  *          `haystack` starting from the left.
717  *
718  * @param   haystack    The string to search in.
719  * @param   needle      The sub-string to search for.
720  * @param   found_index A pointer to a variable that receives the index of the first occurrence of
721  *                      `needle`.
722  *
723  * @return  `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another
724  *          zyan status code, if an error occured.
725  *
726  * The `found_index` is set to `-1`, if the needle was not found.
727  */
728 ZYCORE_EXPORT ZyanStatus ZyanStringLPosI(const ZyanStringView* haystack,
729     const ZyanStringView* needle, ZyanISize* found_index);
730 
731 /**
732  * @brief   Performs a case-insensitive search for the first occurrence of `needle` in the given
733  *          `haystack` starting from the left.
734  *
735  * @param   haystack    The string to search in.
736  * @param   needle      The sub-string to search for.
737  * @param   found_index A pointer to a variable that receives the index of the first occurrence of
738  *                      `needle`.
739  * @param   index       The start index.
740  * @param   count       The maximum number of characters to iterate, beginning from the start
741  *                      `index`.
742  *
743  * @return  `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another
744  *          zyan status code, if an error occured.
745  *
746  * The `found_index` is set to `-1`, if the needle was not found.
747  */
748 ZYCORE_EXPORT ZyanStatus ZyanStringLPosIEx(const ZyanStringView* haystack,
749     const ZyanStringView* needle, ZyanISize* found_index, ZyanUSize index, ZyanUSize count);
750 
751 /**
752  * @brief   Searches for the first occurrence of `needle` in the given `haystack` starting from the
753  *          right.
754  *
755  * @param   haystack    The string to search in.
756  * @param   needle      The sub-string to search for.
757  * @param   found_index A pointer to a variable that receives the index of the first occurrence of
758  *                      `needle`.
759  *
760  * @return  `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another
761  *          zyan status code, if an error occured.
762  *
763  * The `found_index` is set to `-1`, if the needle was not found.
764  */
765 ZYCORE_EXPORT ZyanStatus ZyanStringRPos(const ZyanStringView* haystack,
766     const ZyanStringView* needle, ZyanISize* found_index);
767 
768 /**
769  * @brief   Searches for the first occurrence of `needle` in the given `haystack` starting from the
770  *          right.
771  *
772  * @param   haystack    The string to search in.
773  * @param   needle      The sub-string to search for.
774  * @param   found_index A pointer to a variable that receives the index of the first occurrence of
775  *                      `needle`.
776  * @param   index       The start index.
777  * @param   count       The maximum number of characters to iterate, beginning from the start
778  *                      `index`.
779  *
780  * @return  `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another
781  *          zyan status code, if an error occured.
782  *
783  * The `found_index` is set to `-1`, if the needle was not found.
784  */
785 ZYCORE_EXPORT ZyanStatus ZyanStringRPosEx(const ZyanStringView* haystack,
786     const ZyanStringView* needle, ZyanISize* found_index, ZyanUSize index, ZyanUSize count);
787 
788 /**
789  * @brief   Performs a case-insensitive search for the first occurrence of `needle` in the given
790  *          `haystack` starting from the right.
791  *
792  * @param   haystack    The string to search in.
793  * @param   needle      The sub-string to search for.
794  * @param   found_index A pointer to a variable that receives the index of the first occurrence of
795  *                      `needle`.
796  *
797  * @return  `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another
798  *          zyan status code, if an error occured.
799  *
800  * The `found_index` is set to `-1`, if the needle was not found.
801  */
802 ZYCORE_EXPORT ZyanStatus ZyanStringRPosI(const ZyanStringView* haystack,
803     const ZyanStringView* needle, ZyanISize* found_index);
804 
805 /**
806  * @brief   Performs a case-insensitive search for the first occurrence of `needle` in the given
807  *          `haystack` starting from the right.
808  *
809  * @param   haystack    The string to search in.
810  * @param   needle      The sub-string to search for.
811  * @param   found_index A pointer to a variable that receives the index of the first occurrence of
812  *                      `needle`.
813  * @param   index       The start index.
814  * @param   count       The maximum number of characters to iterate, beginning from the start
815  *                      `index`.
816  *
817  * @return  `ZYAN_STATUS_TRUE`, if the needle was found, `ZYAN_STATUS_FALSE`, if not, or another
818  *          zyan status code, if an error occured.
819  *
820  * The `found_index` is set to `-1`, if the needle was not found.
821  */
822 ZYCORE_EXPORT ZyanStatus ZyanStringRPosIEx(const ZyanStringView* haystack,
823     const ZyanStringView* needle, ZyanISize* found_index, ZyanUSize index, ZyanUSize count);
824 
825 /* ---------------------------------------------------------------------------------------------- */
826 /* Comparing                                                                                      */
827 /* ---------------------------------------------------------------------------------------------- */
828 
829 /**
830  * @brief   Compares two strings.
831  *
832  * @param   s1      The first string
833  * @param   s2      The second string.
834  * @param   result  Receives the comparison result.
835  *
836  *                  Values:
837  *                  - `result  < 0` -> The first character that does not match has a lower value
838  *                    in `s1` than in `s2`.
839  *                  - `result == 0` -> The contents of both strings are equal.
840  *                  - `result  > 0` -> The first character that does not match has a greater value
841  *                    in `s1` than in `s2`.
842  *
843  * @return  `ZYAN_STATUS_TRUE`, if the strings are equal, `ZYAN_STATUS_FALSE`, if not, or another
844  *          zyan status code, if an error occured.
845  */
846 ZYCORE_EXPORT ZyanStatus ZyanStringCompare(const ZyanStringView* s1, const ZyanStringView* s2,
847     ZyanI32* result);
848 
849 /**
850  * @brief   Performs a case-insensitive comparison of two strings.
851  *
852  * @param   s1      The first string
853  * @param   s2      The second string.
854  * @param   result  Receives the comparison result.
855  *
856  *                  Values:
857  *                  - `result  < 0` -> The first character that does not match has a lower value
858  *                    in `s1` than in `s2`.
859  *                  - `result == 0` -> The contents of both strings are equal.
860  *                  - `result  > 0` -> The first character that does not match has a greater value
861  *                    in `s1` than in `s2`.
862  *
863  * @return  `ZYAN_STATUS_TRUE`, if the strings are equal, `ZYAN_STATUS_FALSE`, if not, or another
864  *          zyan status code, if an error occured.
865  */
866 ZYCORE_EXPORT ZyanStatus ZyanStringCompareI(const ZyanStringView* s1, const ZyanStringView* s2,
867     ZyanI32* result);
868 
869 /* ---------------------------------------------------------------------------------------------- */
870 /* Case conversion                                                                                */
871 /* ---------------------------------------------------------------------------------------------- */
872 
873 /**
874  * @brief   Converts the given string to lowercase letters.
875  *
876  * @param   string      A pointer to the `ZyanString` instance.
877  *
878  * @return  A zyan status code.
879  *
880  * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
881  * `ZyanString` instance.
882  */
883 ZYCORE_EXPORT ZyanStatus ZyanStringToLowerCase(ZyanString* string);
884 
885 /**
886  * @brief   Converts `count` characters of the given string to lowercase letters.
887  *
888  * @param   string  A pointer to the `ZyanString` instance.
889  * @param   index   The start index.
890  * @param   count   The number of characters to convert, beginning from the start `index`.
891  *
892  * @return  A zyan status code.
893  *
894  * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
895  * `ZyanString` instance.
896  */
897 ZYCORE_EXPORT ZyanStatus ZyanStringToLowerCaseEx(ZyanString* string, ZyanUSize index,
898     ZyanUSize count);
899 
900 /**
901  * @brief   Converts the given string to uppercase letters.
902  *
903  * @param   string      A pointer to the `ZyanString` instance.
904  *
905  * @return  A zyan status code.
906  *
907  * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
908  * `ZyanString` instance.
909  */
910 ZYCORE_EXPORT ZyanStatus ZyanStringToUpperCase(ZyanString* string);
911 
912 /**
913  * @brief   Converts `count` characters of the given string to uppercase letters.
914  *
915  * @param   string  A pointer to the `ZyanString` instance.
916  * @param   index   The start index.
917  * @param   count   The number of characters to convert, beginning from the start `index`.
918  *
919  * @return  A zyan status code.
920  *
921  * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
922  * `ZyanString` instance.
923  */
924 ZYCORE_EXPORT ZyanStatus ZyanStringToUpperCaseEx(ZyanString* string, ZyanUSize index,
925     ZyanUSize count);
926 
927 /* ---------------------------------------------------------------------------------------------- */
928 /* Memory management                                                                              */
929 /* ---------------------------------------------------------------------------------------------- */
930 
931 /**
932  * @brief   Resizes the given `ZyanString` instance.
933  *
934  * @param   string  A pointer to the `ZyanString` instance.
935  * @param   size    The new size of the string.
936  *
937  * @return  A zyan status code.
938  *
939  * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
940  * `ZyanString` instance.
941  */
942 ZYCORE_EXPORT ZyanStatus ZyanStringResize(ZyanString* string, ZyanUSize size);
943 
944 /**
945  * @brief   Changes the capacity of the given `ZyanString` instance.
946  *
947  * @param   string      A pointer to the `ZyanString` instance.
948  * @param   capacity    The new minimum capacity of the string.
949  *
950  * @return  A zyan status code.
951  *
952  * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
953  * `ZyanString` instance.
954  */
955 ZYCORE_EXPORT ZyanStatus ZyanStringReserve(ZyanString* string, ZyanUSize capacity);
956 
957 /**
958  * @brief   Shrinks the capacity of the given string to match it's size.
959  *
960  * @param   string  A pointer to the `ZyanString` instance.
961  *
962  * @return  A zyan status code.
963  *
964  * This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
965  * `ZyanString` instance.
966  */
967 ZYCORE_EXPORT ZyanStatus ZyanStringShrinkToFit(ZyanString* string);
968 
969 /* ---------------------------------------------------------------------------------------------- */
970 /* Information                                                                                    */
971 /* ---------------------------------------------------------------------------------------------- */
972 
973 /**
974  * @brief   Returns the current capacity of the string.
975  *
976  * @param   string      A pointer to the `ZyanString` instance.
977  * @param   capacity    Receives the size of the string.
978  *
979  * @return  A zyan status code.
980  */
981 ZYCORE_EXPORT ZyanStatus ZyanStringGetCapacity(const ZyanString* string, ZyanUSize* capacity);
982 
983 /**
984  * @brief   Returns the current size (number of characters) of the string (excluding the
985  *          terminating zero character).
986  *
987  * @param   string  A pointer to the `ZyanString` instance.
988  * @param   size    Receives the size (number of characters) of the string.
989  *
990  * @return  A zyan status code.
991  */
992 ZYCORE_EXPORT ZyanStatus ZyanStringGetSize(const ZyanString* string, ZyanUSize* size);
993 
994 /**
995  * @brief   Returns the C-style string of the given `ZyanString` instance.
996  *
997  * @param   string  A pointer to the `ZyanString` instance.
998  * @param   value   Receives a pointer to the C-style string.
999  *
1000  * @return  A zyan status code.
1001  */
1002 ZYCORE_EXPORT ZyanStatus ZyanStringGetData(const ZyanString* string, const char** value);
1003 
1004 /* ---------------------------------------------------------------------------------------------- */
1005 
1006 /* ============================================================================================== */
1007 
1008 #ifdef __cplusplus
1009 }
1010 #endif
1011 
1012 #endif // ZYCORE_STRING_H
1013