Skip to content

Latest commit

 

History

History

string

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

String Library in C

Author: amin tahmasebi Release Date: 2023 License: ISC License

The String library is a part of a project to reimplement C++ standard library features in C. It provides a generic container that encapsulates dynamic size arrays, offering similar functionality to std::string in C++.

Compilation

To compile the String library along with your main program, use the following GCC command: if you need other lib just you can add name of libs .c

gcc -std=c11 -O3 -march=native -flto -funroll-loops -Wall -Wextra -pedantic -s -o main ./main.c ./string/string.c

Ensure you have the GCC compiler installed on your system and that all source files are in the correct directory structure as shown in the project.

Usage

To use the String library in your project, include the string.h header file in your source code.

Absolutely, adding a brief description for each function at the top of your README can greatly enhance its clarity and usability. Here's how you might structure this section:


Function Descriptions

Constants

  • STRING_ASCII_LETTERS
  • STRING_ASCII_LOWERCASE
  • STRING_ASCII_UPPERCASE
  • STRING_DIGITS
  • STRING_HEXDIGITS
  • STRING_WHITESPACE
  • STRING_PUNCTUATION

String Creation and Management

  • string_create(const char*): Creates a new String object with an initial value.
  • string_create_with_pool(size_t): Creates a new String object with a specified memory pool size.
  • string_deallocate(String*): Deallocates the memory used by a String object.
  • string_clear(String*): Clears the contents of a String object.

String Manipulation

  • string_push_back(String*, char): Appends a character to the end of a String.
  • string_append(String*, const char*): Appends a string to the end of a String.
  • string_assign(String*, const char*): Assigns a new value to a String.
  • string_insert(String*, size_t, const char*): Inserts a string at a specified position.
  • string_erase(String*, size_t, size_t): Erases a portion of a String.
  • string_replace(String*, const char*, const char*): Replaces occurrences of a substring.
  • string_concatenate(String*, const String*): Concatenates two String objects.
  • string_swap(String*, String*): Swaps the contents of two String objects.
  • string_reverse(String*): Reverses the content of a String.
  • string_substr(String*, size_t, size_t): Creates a substring from a String object.
  • string_pop_back(String*): Removes the last character of a String.
  • string_resize(String*, size_t): Resizes a String to a specified size.
  • string_shrink_to_fit(String*): Reduces the capacity of a String to fit its size.
  • string_replace_all(String *, const char *, const char *): Replace occurrences of all substr in String object.
  • string_trim_left(String *str): This function trims leading whitespace characters from the beginning of the String object str.
  • string_trim_right(String *str): This function trims trailing whitespace characters from the end of the String object str

String Comparison

  • string_is_equal(String*, String*): Checks if two Strings are equal.
  • string_is_less(String*, String*): Checks if the first String is less than the second.
  • string_is_greater(String*, String*): Checks if the first String is greater than the second.
  • string_is_less_or_equal(String*, String*): Checks if the first String is less than or equal to the second.
  • string_is_greater_or_equal(String*, String*): Checks if the first String is greater than or equal to the second.
  • string_is_not_equal(String*, String*): Checks if two Strings are not equal.
  • string_compare(String*, String*): Compares two Strings.
  • string_compare_ignore_case(String*, String*): Compares two Strings, ignoring case differences.

String Information and Properties

  • string_length(String*): Returns the length of a String.
  • string_capacity(String*): Returns the capacity of a String.
  • string_max_size(String*): Returns the maximum size of a String.
  • string_empty(String*): Checks if a String is empty.
  • string_contains(String*, const char*): Checks if a String contains a specific substring.
  • string_count(Strin*, char*) : count number of substr appears in String object 'str'.
  • string_length_cstr(const char*) : Returns the length of a char*.
  • string_length_utf(const char*) : Return the length of utf-8 char*.
  • string_utf8_char_len(char ) : Return the len of each unicode character.

String Characteristics

  • string_is_alpha(String*): Checks if a String contains only alphabetic characters.
  • string_is_digit(String*): Checks if a String contains only digits.
  • string_is_lower(String*): Checks if all characters in a String are lowercase.
  • string_is_upper(String*): Checks if all characters in a String are uppercase.

String Access and Iteration

  • string_begin(String*): Returns an iterator to the beginning.
  • string_end(String*): Returns an iterator to the end.
  • string_rbegin(String*): Returns a reverse iterator to the beginning.
  • string_rend(String*): Returns a reverse iterator to the end.
  • string_cbegin(String*): Returns a constant iterator to the beginning.
  • string_cend(String*): Returns a constant iterator to the end.
  • string_crbegin(String*): Returns a constant reverse iterator to the beginning.
  • string_crend(String*): Returns a constant reverse iterator to the end.

String Data Access

  • string_data(String*): Returns a pointer to the data stored in a String.
  • string_c_str(String*): Returns a pointer to the null-terminated sequence of characters.
  • string_at(String*, size_t): Returns a reference to the character at a specified index.
  • string_back(String*): Returns a reference to the last character.
  • string_front(String*): Returns a reference to the first character.

String Conversion Functions

  • string_to_int(String*): Converts a String to an integer.
  • string_to_float(String*): Converts a String to a float.
  • string_to_double(String*): Converts a String to a double.
  • string_from_int(int): Creates a String from an integer.
  • string_from_float(float): Creates a String from a float.
  • string_from_double(double): Creates a String from a double.

Unicode Handling

  • string_to_unicode(const char*): Converts a regular string to a wide string.
  • string_from_unicode(const wchar_t*): Converts a wide string back to a regular string.

String Case and Encoding Operations

  • string_to_upper(String*): Converts a String to uppercase.
  • string_to_lower(String*): Converts a String to lowercase.
  • string_to_casefold(String*): Converts a String to casefolded form.
  • string_swap_case(String*): Swaps the case of each character in a String.

String Search and Replace

  • string_find_first_of(String*, const char*, size_t): Finds the first occurrence of any of the characters in the given string.
  • string_find_last_of(String*, const char*, size_t): Finds the last occurrence of any of the characters in the given string.
  • string_find_first_not_of(String*, const char*, size_t): Finds the first character that does not match any of the characters in the given string.
  • string_find_last_not_of(String*, const char*, size_t): Finds the last character that does not match any of the characters in the given string.
  • string_replace_all(String*, const char*, const char*): Replaces all occurrences of a substring.
  • string_remove(String*, const char*): Removes all occurrences of a substring.

Advanced String Operations

  • string_split(String*, const char*, int*): Splits a String into an array of String objects.
  • string_join(String**, int, const char*): Joins several String objects into one.
  • string_trim(String*): Trims whitespace from both ends of a String.
  • string_pad_left(String*, size_t, char): Pads a String from the left.
  • string_pad_right(String*, size_t, char): Pads a String from the right.
  • string_repeat(const String*, size_t): Creates a new String by repeating the original String a specified number of times.
  • string_join_variadic(size_t, ...): Concatenates multiple Strings (variadic function).
  • string_trim_characters(String*, const char*): Trims specified characters from both ends of a String.
  • string_shuffle(String*): Randomly shuffle character of String object
  • string_format(String*, const char*, ...): Formats a String using given format specifiers.
  • string_to_title(String*): Converts each word in the String to title case.
  • string_to_capitalize(String*): Capitalizes the first character of a String.
  • string_to_casefold(String*): Converts a String to a case-insensitive form for comparisons.
  • string_remove_range(String* str, size_t startPos, size_t endPos): Removes a range of characters from a String object, starting from startPos and ending at endPos.
  • string_starts_with(String*, const char*): Checks if a String starts with a specified substring.
  • string_ends_with(String*, const char*): Checks if a String ends with a specified substring.
  • string_base64_encode(const String*): Encodes a String to base64 format.
  • string_base64_decode(const String*): Decodes a base64 encoded String.
  • string_remove(String*, const char*): Removes all occurrences of a substring.
  • string_set_pool_size(String*, size_t): Sets the size of the memory pool for a String.
  • string_tokenize(String*, const char* , int*): This function splits a string into tokens based on multiple delimiters.
  • string_create_from_initializer : The string_create_from_initializer function dynamically creates an array of String pointers, each initialized with a string passed as a variadic argument.

String Encoding Functions

  • string_to_hex(String*): Converts a String to its hexadecimal representation.
  • string_from_hex(String*): Converts a hexadecimal String back to the original string.
#include "string/std_string.h"

Example 1: how to create String obj and use string_push_back, string_append, string_at, string_clear, string_length, string_capacity also string_deallocate

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* myString = string_create("");
   
    // Push back a new character
    string_push_back(myString, '!');
    fmt_printf("String after push_back: %s\n", myString->dataStr);

    // Access a character
    char ch = string_at(myString, 0);
    fmt_printf("Character at index 1: %c\n", ch);

    // Print length and capacity
    fmt_printf("Length: %zu, Capacity: %zu\n", string_length(myString), string_capacity(myString));

    // Clear the string
    string_clear(myString);
    fmt_printf("String after clear: %s\n", myString->dataStr);

    // Clean up
    string_clear(myString);
    string_append(myString, "Hello C Programmers");
        
    fmt_printf("%s\n", string_c_str(myString));

    string_deallocate(myString);
    return 0;
}

Result:

String after push_back: !
Character at index 1: !
Length: 1, Capacity: 32
Info : String object is null no need to clear in string_clear.
String after clear:
Info : String object is null no need to clear in string_clear.
Hello C Programmers

Example 2: string_shrink_to_fit, string_resize

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *myString = string_create("Hello");

    // Append a string
    string_append(myString, ", World!");
    fmt_printf("String after append: %s\n", myString->dataStr);

    // Resize the string
    string_resize(myString, 5);  // Resize to "Hello"
    fmt_printf("String after resize: %s\n", myString->dataStr);

    // Shrink to fit
    string_shrink_to_fit(myString);
    fmt_printf("String capacity after shrink to fit: %zu\n", string_capacity(myString));

    // clean up and dellocate
    string_clear(myString);
    string_deallocate(myString);

    return 0;
}

Result:

String after append: Hello, World!
String after resize: Hello
String capacity after shrink to fit: 6
Info : String object is null no need to clear in string_clear.

Example 3: how to string_assign new string and string_erase some part of String obj also string_insert new ...

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *myString = string_create("Hello World");

    // Assign a new string
    string_assign(myString, "New String");
    fmt_printf("String after assign: %s\n", myString->dataStr);

    // Insert a string
    string_insert(myString, 4, "Test ");
    fmt_printf("String after insert: %s\n", myString->dataStr);

    // Erase a portion of the string
    string_erase(myString, 0, 5);  // Erase "New T"
    fmt_printf("String after erase: %s\n", myString->dataStr);

    // Deallocate and clean up
    string_clear(myString);
    string_deallocate(myString);

    return 0;
}

Result:

String after assign: New String
String after insert: New Test String
String after erase: est String
Info : String object is null no need to clear in string_clear.

Example 4: string_replace Strings

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *str1 = string_create("Hello World");
    string_replace(str1, "World", "There");
        
    fmt_printf("After replace: %s\n", str1->dataStr);

    string_deallocate(str1);
    return 0;
}

Result:

After replace: Hello There

Example 5: string_swap two String obj and also string_pop_back

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *str1 = string_create("Hello World");
    string_replace(str1, "World", "There");
        
    fmt_printf("After replace: %s\n", str1->dataStr);

    // Swap example
    String *str2 = string_create("Sample Text");
    string_swap(str1, str2);

    fmt_printf("After swap, str1: %s, str2: %s\n", str1->dataStr, str2->dataStr);

    // Pop back example
    string_pop_back(str2);
    fmt_printf("After pop back: %s\n", str2->dataStr);

    string_deallocate(str1);
    string_deallocate(str2);

    return 0;
}

Result:

After replace: Hello There
After swap, str1: Sample Text, str2: Hello There
After pop back: Hello Ther

Example 6: string_back and string_front return ref to front and last char of String

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *myString = string_create("Hello World");
    char lastChar = *(char*)string_back(myString); // Get the last character

    fmt_printf("Last character : %c\n", lastChar);
    // its just syntax !!!
    *(char*)string_back(myString) = 'a';
    fmt_printf("Wowww: %c\n", *(char*)string_back(myString));

    // Get the first character
    char firstChar = *(char*)string_front(myString);
    fmt_printf("First character: %c\n", firstChar);
    fmt_printf("Max size is %zu\n", string_max_size(myString));
        
    // Deallocate and clean up
    string_clear(myString);
    string_deallocate(myString);

    return 0;
}

Result:

Last character : d
Wowww: a
First character: H
Max size is 18446744073709551615
Info : String object is null no need to clear in string_clear.

Example 7 : string_copy how to copy some part of String

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *myString = string_create("Hello, World!");

    // Copy example
    char buffer[50];
    size_t copied = string_copy(myString, buffer, 7, 5);
    fmt_printf("Copied '%s' (%zu characters)\n", buffer, copied);

    string_deallocate(myString);
    return 0;
}

Result:

Copied 'World' (5 characters)

Example 8 : string_find find string in String and return position

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *myString = string_create("Hello, World!");

    // Find example
    int findPos = string_find(myString, "World", 0);
    fmt_printf("Found 'World' at position: %d\n", findPos);

    string_deallocate(myString);
    return 0;
}

Result:

Found 'World' at position: 7

Example 9 : how to use string_rfind, string_find_first_of, string_find_last_of

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *myString = string_create("Hello, World!");

    // rfind example
    int rfindPos = string_rfind(myString, "o,", string_length(myString) - 1);
    fmt_printf("Last 'o' found at position: %d\n", rfindPos);

    int findFirstOfPos = string_find_first_of(myString, "World", 0);
    fmt_printf("First occurrence of 'World' found at position: %d\n", findFirstOfPos);

    // find_last_of example
    int findLastOfPos = string_find_last_of(myString, "World", string_length(myString) - 1);
    fmt_printf("Last occurrence of 'World' found at position: %d\n", findLastOfPos);

    // Deallocate and clean up
    string_clear(myString);
    string_deallocate(myString);

    return 0;
}

Result:

Last 'o' found at position: 4
First occurrence of 'World' found at position: 7
Last occurrence of 'World' found at position: 7
Info : String object is null no need to clear in string_clear.

Example 10 : string_find_first_not_of, string_find_last_not_of

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *myString = string_create("Hello, World!");

    // find_first_not_of example
    int firstNotOfPos = string_find_first_not_of(myString, "Hello", 0);
    fmt_printf("First position not matching 'Hello': %d\n", firstNotOfPos);

    // find_last_not_of example
    int lastNotOfPos = string_find_last_not_of(myString, "World", string_length(myString) - 1);
    fmt_printf("Last position not matching 'World': %d\n", lastNotOfPos);

    string_deallocate(myString);
    return 0;
}

Result:

First position not matching 'Hello': 1
Last position not matching 'World': 8

Example 11 : string_data return pointer to String sequence

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *myString = string_create("Hello, World!");
        
    // Data example
    const char *data = string_data(myString);
    fmt_printf("Data: %s\n", data);

    // Deallocate and clean up
    string_clear(myString);
    string_deallocate(myString);

    return 0;
}

Result:

Data: Hello, World!
Info : String object is null no need to clear in string_clear.

Example 12 : string_begin, string_end return iterator pointer from begin and end of String sequence

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *myString = string_create("Hello amin");

    for (char* it = string_begin(myString); it != string_end(myString); it++) {
        fmt_printf("%c", *it);
    }
    
    fmt_printf("\n");

    string_clear(myString);
    string_deallocate(myString);

    return 0;
}

Result:

Hello amin
Info : String object is null no need to clear in string_clear.

Example 13 : string_rbeing, string_rend return reverse iterator

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *myString = string_create("Hello amin");

    // Reverse iteration using rbegin and rend
    fmt_printf("String in reverse: ");
    for (char* it = string_rbegin(myString); it != string_rend(myString); --it) { 
        fmt_printf("%c", *it);
    }   
    fmt_printf("\n");

    // Clean up
    string_clear(myString);
    string_deallocate(myString);

    return 0;
}

Result:

String in reverse: nima olleH
Info : String object is null no need to clear in string_clear.

Example 14 : string_cbegin, string_cend

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *myString = string_create("Hello, World!");

    // Iterate using cbegin and cend
    fmt_printf("String using cbegin and cend: ");
    for (const char* it = string_cbegin(myString); it != string_cend(myString); ++it) { 
        fmt_printf("%c", *it);
    }
    fmt_printf("\n");

    string_deallocate(myString);
    return 0;
}

Result:

String using cbegin and cend: Hello, World!

Example 15 : string_crbegin, string_crend

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *myString = string_create("Hello, World!");

    // Reverse iterate using crbegin and crend
    fmt_printf("String in reverse using crbegin and crend: ");
    for (const char* it = string_crbegin(myString); it != string_crend(myString); --it) { 
        fmt_printf("%c", *it);
    }
    fmt_printf("\n");

    string_deallocate(myString);
    return 0;
}

Result:

String in reverse using crbegin and crend: !dlroW ,olleH

Example 16 : how to use relationals operators in String

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* str1 = string_create("Hello");
    String* str2 = string_create("World");

    if (string_is_equal(str1, str2)) {
        fmt_printf("Strings are equal\n");
    }   
    if (string_is_less(str1, str2)) { 
        fmt_printf("String 1 is less than String 2\n");
    }
    if (string_is_greater(str1, str2)) {
        fmt_printf("String1 is greater that String2\n");
    }
    if (string_is_less_or_equal(str1, str2)) {
        fmt_printf("String1 is less than or equal String2\n");
    }
    if (string_is_greater_or_equal(str1, str2)) {
        fmt_printf("String1 is greater than or equal String2\n");
    }

    string_deallocate(str1);
    string_deallocate(str2);

    return 0;
}

Result:

String 1 is less than String 2
String1 is less than or equal String2

Example 17: Manipulate Multiple String

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    // Creating string objects
    String* greeting = string_create("Hello");
    String* name = string_create("Alice");
    String* sentence = string_create("");

    // Concatenate 'greeting' and ', '
    string_append(greeting, ", ");
    fmt_printf("Greeting: %s\n", greeting->dataStr);

    // Append 'name' to 'greeting'
    string_append(greeting, name->dataStr);
    fmt_printf("Greeting with name: %s\n", greeting->dataStr);

    // Create a substring of 'greeting' and assign it to 'sentence'
    String* tempSubstr = string_substr(greeting, 0, 5); // Extract "Hello"
    string_assign(sentence, tempSubstr->dataStr);
    string_deallocate(tempSubstr);

    // Append '!' to 'sentence'
    string_push_back(sentence, '!');
    fmt_printf("Sentence: %s\n", sentence->dataStr);

    // Compare 'greeting' and 'sentence'
    if (string_is_less(sentence, greeting)) {
        fmt_printf("Sentence is less than greeting.\n"); 
    }
    else {
        fmt_printf("Sentence is not less than greeting.\n");
    }

    string_deallocate(greeting);
    string_deallocate(name);
    string_deallocate(sentence);

    return 0;
}

Result:

Greeting: Hello, 
Greeting with name: Hello, Alice
Sentence: Hello!
Sentence is less than greeting.

Example 18: 2D String Array using Custom String Struct

#include "string/std_string.h"
#include "fmt/fmt.h"
#include <stdlib.h>

String*** create_2d_string_array(const size_t rows, const size_t cols) {
    String*** array = malloc(rows * sizeof(String**));

    for (size_t i = 0; i < rows; ++i) {
        array[i] = malloc(cols * sizeof(String*));

        for (size_t j = 0; j < cols; ++j) { 
            array[i][j] = string_create("");  // Initialize with empty strings
        }
    }
    return array;
}

void deallocate_2d_string_array(String*** array, const size_t rows, const size_t cols) {
    for (size_t i = 0; i < rows; ++i) {
        for (size_t j = 0; j < cols; ++j) {
            string_deallocate(array[i][j]);
        }
        free(array[i]);
    }
    free(array);
}

int main() {
    const size_t rows = 2;
    const size_t cols = 3;
    String*** my2DString = create_2d_string_array(rows, cols);

    // Example usage
    string_assign(my2DString[0][0], "Hello");
    string_assign(my2DString[0][1], "World");
    string_assign(my2DString[0][2], "!");

    string_assign(my2DString[1][0], "Goodbye");
    string_assign(my2DString[1][1], "Cruel");
    string_assign(my2DString[1][2], "World");

    // Print the 2D array
    for (size_t i = 0; i < rows; ++i) {
        for (size_t j = 0; j < cols; ++j) {
            fmt_printf("%s ", string_c_str(my2DString[i][j]));
        }
        fmt_printf("\n");
    }
    // Clean up
    deallocate_2d_string_array(my2DString, rows, cols);
    return 0;
}

Result:

Hello World ! 
Goodbye Cruel World

Example 19 : bench mark operation in String and std::string

gcc -std=c11 -O3 -march=native -flto -funroll-loops -Wall -Wextra -pedantic -s -o main .\main.c .\string\string.c Time taken (Custom String): 0.286000 seconds

#include "string/std_string.h"
#include "fmt/fmt.h"
#include <stdlib.h>
#include <time.h>

#define ARRAY_SIZE 100000
#define OPERATIONS 100

int main() {
    struct timespec start, end;
    String** stringArray = malloc(ARRAY_SIZE * sizeof(String*));

    if (!stringArray) {
        fmt_fprintf(stderr, "Failed to allocate memory for stringArray");
        return 1; // Or handle error appropriately
    }

    clock_gettime(CLOCK_MONOTONIC, &start);
    for (int i = 0; i < ARRAY_SIZE; i++) {
        // stringArray[i] = string_create_with_pool(100000000); // if you use this method for largeArray speed efficient but need to large memory
        stringArray[i] = string_create(""); // but this one is more slower than create_pool
    }
    
    for (int i = 0; i < ARRAY_SIZE; i++) {
        for (int j = 0; j < OPERATIONS; j++) { 
            string_push_back(stringArray[i], 'a');
        } 
    }
    clock_gettime(CLOCK_MONOTONIC, &end);
    double time_in_sec = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1000000000.0;
    fmt_printf("Average Custom Vector Time: %f seconds\n", time_in_sec);

    for (int i = 0; i < ARRAY_SIZE; i++) { 
        string_deallocate(stringArray[i]);
    }

    return 0;
}

Result in C:

Average Custom Vector Time: 0.007211 seconds
#include <iostream>
#include <string>
#include <chrono>

#define ARRAY_SIZE 1000000
#define OPERATIONS 100

int main() {
    std::string *stringArray = new std::string[ARRAY_SIZE];
    
    auto start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < ARRAY_SIZE; i++) {
        for (int j = 0; j < OPERATIONS; j++) {
            stringArray[i] += 'a';
        }
    }

    auto end = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> elapsed = end - start;
    std::cout << "Time taken (std::string): " << elapsed.count() << " seconds\n";

    return 0;
}

Result in C++:

Time taken (std::string): 0.81031 seconds

Example 20 : benchmark of String and std::string

#include "string/std_string.h"
#include "fmt/fmt.h"
#include <time.h>

#define ARRAY_SIZE 10000
#define OPERATIONS 100

int main() {
    struct timespec start, end;
    String* stringArray = string_create("");
    
    if (!stringArray) {
        fmt_fprintf(stderr, "Failed to allocate memory for stringArray.\n");
        return 1; // Or handle error appropriately
    }
    
    if (string_set_pool_size(stringArray, 10000000)) {
        fmt_printf("create pool\n");
    }

    clock_gettime(CLOCK_MONOTONIC, &start);
    for (int i = 0; i < ARRAY_SIZE; i++) {
        string_push_back(stringArray, 'a'); 
    }
    clock_gettime(CLOCK_MONOTONIC, &end);
    
    double time_in_sec = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1000000000.0;
    fmt_printf("Average Custom Vector Time: %f seconds\n", time_in_sec);

    for (int i = 0; i < ARRAY_SIZE; i++) {
        string_deallocate(stringArray);
    }

    return 0;
}

Result in C:

create pool
Average Custom Vector Time: 0.000034 seconds

Cpp Code

#include <iostream>
#include <string>
#include <chrono>

#define ARRAY_SIZE 1000000
#define OPERATIONS 100

int main() {
    std::string *stringArray = new std::string[ARRAY_SIZE];
    
    auto start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < ARRAY_SIZE; i++) {
        stringArray[i] += 'a';
    }
    auto end = std::chrono::high_resolution_clock::now();
    
    std::chrono::duration<double> elapsed = end - start;
    std::cout << "Time taken (std::string): " << elapsed.count() << " seconds\n";

    return 0;
}

Result in C++:

Time taken (std::string): 0.0065333 seconds

Example 21 : string to Lower or Upper

#include "string/std_string.h"
#include "fmt/fmt.h"
#include <stdlib.h>

int main() {
    String* str = string_create("Hello World");
    char* toUpper = string_to_upper(str); // convert str to upper case and return as char*
    char* toLower = string_to_lower(str); // convert str to lower case and return as char* 

    if (toUpper) {   
        fmt_printf("To Upper is -> %s\n", toUpper);
        free(toUpper);
    }
    if (toLower) {
        fmt_printf("To Lower is -> %s\n", toLower);
        free(toLower);
    }

    string_deallocate(str);
    return 0;
}

Result:

To Upper is -> HELLO WORLD
To Lower is -> hello world

Example 22 : Reverse String with string_reverse

#include "string/std_string.h"
#include "fmt/fmt.h"
#include <stdlib.h>

int main() {
    String* str = string_create("Hello World");

    if (string_contains(str, "Hello")) { 
        fmt_printf("Yes 'Hello' exists in str\n");
    }
    
    string_reverse(str); // reverse String 
    fmt_printf("Reverse String is %s\n", string_c_str(str));

    string_deallocate(str);
    return 0;
}

Result:

Yes 'Hello' exists in str
Reverse String is dlroW olleH

Example 23 : string_is_digit

#include "string/std_string.h" 
#include "fmt/fmt.h"

int main() {
    String* myString = string_create("123456");

    if (string_is_digit(myString)) {
        fmt_printf("The string contains only digits.\n");
    }
    else {
        fmt_printf("The string contains non-digit characters or is not a string.\n");
    }

    string_deallocate(myString);
    return 0;
}

Result:

The string contains only digits.

Example 24 : string_is_lower

#include "string/std_string.h"
#include "fmt/fmt.h" 
#include <stdlib.h>

int main() {
    String* myString = string_create("Hello World");
    
    char* upper = string_to_upper(myString);
    fmt_printf("Uppercase: %s\n", upper);
    free(upper); // Remember to free the memory allocated by string_to_upper

    char* lower = string_to_lower(myString);
    fmt_printf("Lowercase: %s\n", lower);
    free(lower); // Remember to free the memory allocated by string_to_lower

    string_deallocate(myString);
    return 0;
}

Result:

Uppercase: HELLO WORLD
Lowercase: hello world

Example 25 : concatenate two String with string_concatenate

#include "string/std_string.h"
#include "fmt/fmt.h"
#include <stdlib.h>

int main() {
    String* str1 = string_create("Hello");
    String* str2 = string_create(" World");

    string_concatenate(str1, str2);
    fmt_printf("Concatenated string: %s\n", string_c_str(str1));

    string_deallocate(str1);
    string_deallocate(str2);

    return 0;
}

Result:

Concatenated string: Hello World

Example 26 : trim String from start, end or both

#include "string/std_string.h"
#include "fmt/fmt.h"
#include <stdlib.h>

int main() {
    String* str = string_create("   Hello World   ");

    string_trim_left(str);
    fmt_printf("Trimmed Start: '%s'\n", string_c_str(str));

    string_trim_right(str);
    fmt_printf("Trimmed End: '%s'\n", string_c_str(str));

    string_clear(str);
    string_assign(str, "   Hello World   ");
    string_trim(str);
    
    fmt_printf("Trimmed Both: '%s'\n", string_c_str(str));

    string_deallocate(str);
    return 0;
}

Result:

Trimmed Start: 'Hello World   '
Trimmed End: 'Hello World'
Info : String object is null no need to clear in string_clear.
Trimmed Both: 'Hello World'

Example 27 : split String with string_split

#include "string/std_string.h"
#include "fmt/fmt.h"
#include <stdlib.h>

int main() {
    String* str = string_create("Hello,World,This,Is,A,Test");
    int count = 0;
    String** splits = string_split(str, ",", &count);

    for (int i = 0; i < count; i++) {
        fmt_printf("Split %d: %s\n", i, string_c_str(splits[i]));
        string_deallocate(splits[i]);
    }
    free(splits);

    string_deallocate(str);
    return 0;
}

Result:

Split 0: Hello
Split 1: World
Split 2: This
Split 3: Is
Split 4: A
Split 5: Test

Example 28 : joins several String objects with string_join

#include "string/std_string.h"
#include "fmt/fmt.h"
#include <stdlib.h>

int main() {
    String* parts[3];

    parts[0] = string_create("Hello");
    parts[1] = string_create("World");
    parts[2] = string_create("Again");

    String* joined = string_join(parts, 3, " ");
    fmt_printf("Joined string: %s\n", string_c_str(joined));

    for (int i = 0; i < 3; i++) {
        string_deallocate(parts[i]);
    }

    string_deallocate(joined);
    return 0;
}

Result:

Joined string: Hello World Again

Example 29 : replace_all

#include "string/std_string.h"
#include "fmt/fmt.h"
#include <stdlib.h>

int main() {
    String* str = string_create("This is a test. This is only a test.");

    string_replace_all(str, "test", "example");
    fmt_printf("Replaced string: %s\n", string_c_str(str));

    string_deallocate(str);
    return 0;
}

Result:

Replaced string: This is a example. This is only a example.

Example 30: string_to_int

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *str = string_create("12345");
    int intValue = string_to_int(str);

    fmt_printf("Integer value: %d\n", intValue);

    string_deallocate(str);
    return 0;
}

Result:

Integer value: 12345

Example 31: string_to_float

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *str = string_create("123.45");
    float floatValue = string_to_float(str);

    fmt_printf("Float value: %.2f\n", floatValue);

    string_deallocate(str);
    return 0;
}

Result:

Float value: 123.45

Example 32: string_pad_left

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *str = string_create("hello");
    string_pad_left(str, 10, '*'); // Pads with '*' to a total length of 10

    fmt_printf("Padded String (Start): '%s'\n", str->dataStr);

    string_deallocate(str);
    return 0;
}

Result:

Padded String (Start): '*****hello'

Example 33: string_pad_right

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *str = string_create("world");
    string_pad_right(str, 10, '-'); // Pads with '-' to a total length of 10

    fmt_printf("Padded String (End): '%s'\n", str->dataStr);

    string_deallocate(str);
    return 0;
}

Result:

Padded String (End): 'world-----'

Example 34 : string_to_hex

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *originalStr = string_create("Hello");
    String *hexStr = string_to_hex(originalStr);

    fmt_printf("Original String: %s\n", originalStr->dataStr);
    fmt_printf("Hexadecimal Representation: %s\n", hexStr->dataStr);

    string_deallocate(originalStr);
    string_deallocate(hexStr);

    return 0;
}

Result:

Original String: Hello
Hexadecimal Representation: 48656c6c6f

Example 35 : string_from_hex

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String *hexStr = string_create("48656c6c6f"); // Hexadecimal representation of "Hello"
    String *convertedStr = string_from_hex(hexStr);

    fmt_printf("Hexadecimal String: %s\n", hexStr->dataStr);
    fmt_printf("Converted String: %s\n", convertedStr->dataStr);

    string_deallocate(hexStr);
    string_deallocate(convertedStr);

    return 0;
}

Result:

Hexadecimal String: 48656c6c6f
Converted String: Hello

Example 36 : string_count

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* str = string_create("Hello World, World!");
    const char* substr = "World";

    size_t count = string_count(str, substr);
    fmt_printf("The substring '%s' appears %zu times in '%s'.\n", substr, count, str->dataStr);

    string_deallocate(str);
    return 0;
}

Result:

The substring 'World' appears 2 times in 'Hello World, World!'.

Example 37 : string_remove

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* str = string_create("Hello World, World!");
    const char* substr = "World";

    fmt_printf("Original string: %s\n", str->dataStr);
    string_remove(str, substr);
    fmt_printf("String after removal: %s\n", str->dataStr);

    string_deallocate(str);
    return 0;
}

Result:

Original string: Hello World, World!
String after removal: Hello , !

Example 38 : string_from_int

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    int value = 123;
    String* str = string_from_int(value);

    fmt_printf("Integer %d converted to string: %s\n", value, str->dataStr);

    string_deallocate(str);
    return 0;
}

Result:

Integer 123 converted to string: 123

Example 39 : string_from_float

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    float value = 123.456;
    String* str = string_from_float(value);

    fmt_printf("Float %.3f converted to string: %s\n", value, str->dataStr);

    string_deallocate(str);
    return 0;
}

Result:

Float 123.456 converted to string: 123.456001

Example 40 : string_tokenize

#include "string/std_string.h"
#include "fmt/fmt.h"
#include <stdlib.h>

int main() {
    String* str = string_create("Hello,World-This.Is;A-Test");
    int count = 0;
    String** tokens = string_tokenize(str, ",.-;", &count);

    for (int i = 0; i < count; i++) {
        fmt_printf("Token %d: %s\n", i, tokens[i]->dataStr);
        string_deallocate(tokens[i]);
    }
    free(tokens);

    string_deallocate(str);
    return 0;
}

Result:

Token 0: Hello
Token 1: World
Token 2: This
Token 3: Is
Token 4: A
Token 5: Test

Example 40 : string_to_double

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* str = string_create("123.456");
    double value = string_to_double(str);

    fmt_printf("Double value: %f\n", value);
    
    string_deallocate(str);
    return 0;
}

Result:

Double value: 123.456000

Example 41 : string_from_double

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    double value = 123.456;
    String* str = string_from_double(value);

    fmt_printf("String from double: %s\n", str->dataStr);

    string_deallocate(str);
    return 0;
}

Result:

String from double: 123.456000

Example 42 : string_compare_ignore_case

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* str1 = string_create("Hello");
    String* str2 = string_create("hello");

    if (string_compare_ignore_case(str1, str2) == 0) { 
        fmt_printf("Strings are equal (ignoring case)\n");
    }
    else { 
        fmt_printf("Strings are not equal\n");
    }

    string_deallocate(str1);
    string_deallocate(str2);

    return 0;
}

Result:

Strings are equal (ignoring case)

Example 43 : string_base64_encode and string_base64_decode

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    const char* sampleText = "Hello, World!";
    
    String* originalStr = string_create(sampleText);
    fmt_printf("Original String: %s\n", originalStr->dataStr);

    // Encode the string
    String* encodedStr = string_base64_encode(originalStr);
    fmt_printf("Base64 Encoded: %s\n", encodedStr->dataStr);

    // Decode the string back
    String* decodedStr = string_base64_decode(encodedStr);
    fmt_printf("Base64 Decoded: %s\n", decodedStr->dataStr);

    string_deallocate(originalStr);
    string_deallocate(encodedStr);
    string_deallocate(decodedStr);

    return 0;
}

Result:

Original String: Hello, World!
Base64 Encoded: SGVsbG8sIFdvcmxkIQ==
Base64 Decoded: Hello, World!

Example 44 : string_format

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* str = string_create("");
    
    // Format the string with some arguments
    string_format(str, "Hello, %s! You have %d new messages.", "Alice", 5);
    fmt_printf("%s\n", str->dataStr);

    string_deallocate(str);
    return 0;
}

Result:

Hello, Alice! You have 5 new messages.

Example 45 : string_repeat

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* original = string_create("Hello ");
    String* repeated = string_repeat(original, 3);

    fmt_printf("Repeated String: %s\n", repeated->dataStr);

    string_deallocate(original);
    string_deallocate(repeated);

    return 0;
}

Result:

Repeated String: Hello Hello Hello

Example 46 : string_join_variadic

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* part1 = string_create("Hello");
    String* part2 = string_create(", ");
    String* part3 = string_create("World!");

    String* joined = string_join_variadic(3, part1, part2, part3);
    fmt_printf("Joined String: %s\n", joined->dataStr);

    string_deallocate(part1);
    string_deallocate(part2);
    string_deallocate(part3);
    string_deallocate(joined);

    return 0;
}

Result:

Joined String: Hello, World!

Example 47 : string_trim_characters

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* str = string_create("##Hello, World!##");
    
    string_trim_characters(str, "#");
    fmt_printf("Trimmed String: %s\n", str->dataStr);

    string_deallocate(str);
    return 0;
}

Result:

Trimmed String: Hello, World!

Example 48 : string_shuffle

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* myStr = string_create("Hello, World!");
    fmt_printf("Original String: %s\n", myStr->dataStr);

    string_shuffle(myStr);
    fmt_printf("Shuffled String: %s\n", myStr->dataStr);

    string_deallocate(myStr);
    return 0;
}

Result:

Original String: Hello, World!
Shuffled String: l,lerdlW!oH o

Example 49 : string_to_title

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* str = string_create("hello world");

    string_to_title(str);
    fmt_printf("Title Case: %s\n", str->dataStr);

    string_deallocate(str);
    return 0;
}

Result:

Title Case: Hello World

Example 50 : string_to_casefold

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* str = string_create("HeLLo WoRLd");

    string_to_casefold(str);
    fmt_printf("Casefolded: %s\n", str->dataStr);
    
    string_deallocate(str);
    return 0;
}

Result:

Casefolded: hello world

Example 51 : string_remove_range

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* str = string_create("Hello, World!");

    string_remove_range(str, 5, 7); 
    fmt_printf("After removal: %s\n", str->dataStr);

    string_deallocate(str);
    return 0;
}

Result:

After removal: HelloWorld!

Example 52 : string_starts_with

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* str = string_create("Hello, World!");
    bool startsWithHello = string_starts_with(str, "Hello");

    fmt_printf("Starts with 'Hello': %s\n", startsWithHello ? "true" : "false");

    string_deallocate(str);
    return 0;
}

Result:

Starts with 'Hello': true

Example 53 : string_ends_with

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* str = string_create("Hello, World!");
    bool endsWithWorld = string_ends_with(str, "World!");

    fmt_printf("Ends with 'World!': %s\n", endsWithWorld ? "true" : "false");
    
    string_deallocate(str);
    return 0;
}

Result:

Ends with 'World!': true

Example 54 : string_to_capitalize

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* str = string_create("hello world");

    string_to_capitalize(str);
    fmt_printf("Capitalized: %s\n", str->dataStr);

    string_deallocate(str);
    return 0;
}

Result:

Capitalized: Hello world

Example 55 : string_swap_case

#include "string/std_string.h"
#include "fmt/fmt.h"

int main() {
    String* str = string_create("Hello World");

    string_swap_case(str);
    fmt_printf("Swapped Case: %s\n", str->dataStr);

    string_deallocate(str);
    return 0;
}

Result:

Swapped Case: hELLO wORLD

Example 56 : string_to_unicode and string_from_unicode

#include "string/std_string.h"
#include "fmt/fmt.h"
#include <wchar.h>
#include <stdlib.h>

int main() {
    char* originalStr = u8"Привет, мир! مرحبا بالعالم"; // "Hello, world!" in Russian and Arabic

    // Convert to wide string (Unicode)
    wchar_t* unicodeStr = string_to_unicode(originalStr);
    if (unicodeStr == NULL) {
        printf("Conversion to wide string failed.\n");
        return 1;
    }

    fmt_printf("Unicode String: %ls\n", unicodeStr);

    // Convert back to String object
    String* convertedStr = string_from_unicode(unicodeStr);
    if (convertedStr == NULL) {
        fmt_fprintf(stderr, "Conversion from wide string failed.\n");
        free(unicodeStr);
        return 1;
    }
    fmt_printf("Converted String: %s\n", convertedStr->dataStr);

    // Clean up
    free(unicodeStr);
    string_deallocate(convertedStr);
    
    return 0;
}

Result:

Unicode String: Привет, мир! مرحبا بالعالم
Converted String: Привет, мир! مرحبا بالعالم

Example 57 : define different kind of constants strings

#include "fmt/fmt.h"
#include "string/std_string.h"

int main() {
    fmt_printf("ASCII Letters: %s\n", STRING_ASCII_LETTERS);
    fmt_printf("ASCII Lowercase: %s\n", STRING_ASCII_LOWERCASE);

    return 0;
}

Result:

ASCII Letters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
ASCII Lowercase: abcdefghijklmnopqrstuvwxyz

Example 58 : How to use string_length_cstr and string_length_utf8

#include "fmt/fmt.h"
#include "string/std_string.h"

int main() {
    const char* str = "سلام دنیا";
    const char* cstr = "Hello World";
    
    fmt_printf("Size of ASCII string is %zu\n", string_length_cstr(cstr));
    fmt_printf("Size of unicode string is %zu\n", string_length_utf8(str));

    return 0;
}

Result:

Size of ASCII string is 11
Size of unicode string is 9