Skip to content

Commit

Permalink
Add new methods
Browse files Browse the repository at this point in the history
  • Loading branch information
dr8co committed Apr 11, 2024
1 parent bc0757a commit d3c73e4
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 5 deletions.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ with a focus on simplicity, performance, and ease of use.

LiteString is written in C and can be used in both C and C++ projects.

The current implementation does not support Unicode or multibyte characters.

## Features

- Simple and easy to use
Expand Down Expand Up @@ -129,6 +131,9 @@ A lite_string object is allocated on the heap and must be freed when no longer n
lite_string *string_new()
// Creates a new string with an initial capacity of 16.

lite_string *string_new_cstr(const char *restrict cstr);
// Creates a new string from a C-string.

void string_free(lite_string *const restrict s)
// Frees the memory used by a string.
```
Expand Down Expand Up @@ -195,6 +200,9 @@ bool string_insert_range(lite_string *const restrict s, const lite_string *const
bool string_erase(lite_string *const restrict s, const size_t index)
// Removes the character at a given index in the string.
bool string_erase_range(lite_string *restrict s, size_t start, size_t count)
// Removes a specified number of characters from a string, starting from a specified index.
bool string_push_back(lite_string *const restrict s, const char c)
// Appends a character to the end of a string.
Expand Down Expand Up @@ -227,6 +235,30 @@ bool string_copy(const lite_string *const restrict src, lite_string *const restr
bool string_swap(lite_string *const restrict s1, lite_string *const restrict s2)
// Swaps the contents of two strings.
bool string_replace(lite_string *restrict s, const lite_string *restrict old_sub,
const lite_string *restrict new_sub)
// Replaces all occurrences of a substring in a string with another substring.
void string_replace_char(const lite_string *restrict s, char old_char, char new_char)
// Replaces all occurrences of a character in a string with another character.
bool string_replace_cstr(lite_string *restrict s, const char *restrict old_cstr,
const char *restrict new_cstr)
// Replaces all occurrences of a C-string in a string with another C-string.
```

### Conversion

```c
void string_to_lower(const lite_string *restrict s);
// Converts a string to lowercase.

void string_to_upper(const lite_string *restrict s);
// Converts a string to uppercase.

void string_to_title(const lite_string *restrict s);
// Converts a string to title case.
```
### Search
Expand Down
165 changes: 162 additions & 3 deletions lite_string.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,37 @@ char string_front(const lite_string *const restrict s) {
return s && s->size ? s->data[0] : '\0';
}

/**
* @brief Erases a range of characters from a string.
*
* @param s A pointer to the string from which the characters will be removed.
* @param start The starting index of the range to be removed.
* @param count The number of characters to be removed.
* @return true if the characters were successfully removed, false otherwise.
*/
bool string_erase_range(lite_string *const restrict s, const size_t start, const size_t count) {
if (s && start < s->size) {
if (count == 0) return true;
#if (__GNUC__ || __clang__) && __has_builtin(__builtin_add_overflow)
size_t end;
if (!__builtin_uaddl_overflow(start, count, &end) && end <= s->size) {
#else
if (count < s->size && start + count <= s->size) {
#endif
// Copy the characters after the range to overwrite the characters to be removed
memmove(s->data + start * sizeof(char), s->data + (start + count) * sizeof(char),
(s->size - start - count) * sizeof(char));
s->size -= count;

// Fill the remaining space with null characters
memset(s->data + s->size, '\0', s->capacity - s->size);
return true;
}
}
return false;
}


/**
* @brief Removes the character at a given index in the string.
*
Expand Down Expand Up @@ -447,7 +478,7 @@ string_insert_string(lite_string *const restrict s, const lite_string *const res
* @note The returned pointer must be freed by the caller, using \p string_free
*/
[[nodiscard]] lite_string *string_concat(const lite_string *const restrict s1,
const lite_string *const restrict s2) {
const lite_string *const restrict s2) {
if (s1 && s2) {
lite_string *s = string_new();
if (s) {
Expand Down Expand Up @@ -756,7 +787,7 @@ bool string_contains_char(const lite_string *const restrict s, const char c) {
* @return The index of the first occurrence of the substring in the string, or \p SIZE_MAX if the substring was not found.
*/
size_t string_find_from(const lite_string *const restrict s, const lite_string *const restrict sub,
const size_t start) {
const size_t start) {
if (s && sub && start < s->size) {
if (sub->size == 0) return start;
if (sub->size > s->size) return SIZE_MAX;
Expand Down Expand Up @@ -825,7 +856,7 @@ size_t string_rfind(const lite_string *const restrict s, const lite_string *cons
* @return The index of the first occurrence of the C-string in the string, or \p SIZE_MAX if the C-string was not found.
*/
size_t string_find_cstr_from(const lite_string *const restrict s, const char *const restrict cstr,
const size_t start) {
const size_t start) {
// The string and the C-string must be valid
if (s && cstr) {
const size_t len = strlen(cstr);
Expand Down Expand Up @@ -1014,3 +1045,131 @@ void string_to_lower(const lite_string *const restrict s) {
}
}
}

/**
* @brief Converts all the lowercase characters in a string to uppercase.
*
* @param s A pointer to the string to be converted to uppercase.
*/
void string_to_upper(const lite_string *const restrict s) {
if (s) {
for (size_t i = 0; i < s->size; ++i) {
if (s->data[i] >= 'a' && s->data[i] <= 'z')
s->data[i] -= 32;
}
}
}

/**
* @brief Converts a string to title case.
*
* @param s A pointer to the string to be converted to title case.
*/
void string_to_title(const lite_string *const restrict s) {
if (s) {
if (s->data[0] >= 'a' && s->data[0] <= 'z')
s->data[0] -= 32;

// Iterate over the rest of the string
for (size_t i = 1; i < s->size; ++i) {
if (s->data[i] == ' ' && s->data[i + 1] >= 'a' && s->data[i + 1] <= 'z')
s->data[i + 1] -= 32;
}
}
}

/**
* @brief Replaces all occurrences of a substring in a string with another substring.
*
* @param s A pointer to the string where the substrings will be replaced.
* @param old_sub A pointer to the substring to be replaced.
* @param new_sub A pointer to the substring that will replace the old substring.
* @return true if the substrings were successfully replaced, false otherwise.
*/
bool string_replace(lite_string *const restrict s, const lite_string *const restrict old_sub,
const lite_string *const restrict new_sub) {
if (s && old_sub && new_sub) {
if (old_sub->size == 0) return true;
if (old_sub->size > s->size) return false;

size_t count = 0;
size_t start = 0;
while ((start = string_find_from(s, old_sub, start)) != SIZE_MAX) {
if (string_erase_range(s, start, old_sub->size)) {
if (!string_insert_range(s, new_sub, start, new_sub->size)) return false;
start += new_sub->size;
++count;
}
}
return count > 0;
}
return false;
}


/**
* @brief Replaces all occurrences of a character in a string with another character.
*
* @param s A pointer to the string where the characters will be replaced.
* @param old_char The character to be replaced.
* @param new_char The character to replace the old character.
*/
void string_replace_char(const lite_string *const restrict s, const char old_char, const char new_char) {
if (s && old_char != new_char) {
for (size_t i = 0; i < s->size; ++i) {
if (s->data[i] == old_char)
s->data[i] = new_char;
}
}
}

/**
* @brief Replaces all occurrences of a C-string in a string with another C-string.
*
* @param s A pointer to the string where the C-strings will be replaced.
* @param old_cstr The C-string to be replaced.
* @param new_cstr The C-string that will replace the old C-string.
* @return true if the C-strings were successfully replaced, false otherwise.
*/
bool string_replace_cstr(lite_string *const restrict s, const char *const restrict old_cstr,
const char *const restrict new_cstr) {
if (s && old_cstr && new_cstr) {
const size_t old_len = strlen(old_cstr);
const size_t new_len = strlen(new_cstr);
if (old_len == 0) return true;
if (old_len > s->size) return false;

size_t count = 0;
size_t start = 0;
while ((start = string_find_cstr_from(s, old_cstr, start)) != SIZE_MAX) {
if (string_erase_range(s, start, old_len)) {
if (!string_insert_cstr_range(s, new_cstr, start, new_len)) return false;
start += new_len;
++count;
}
}
return count > 0;
}
return false;
}

/**
* @brief Duplicates a string.
*
* @param s A pointer to the string to be duplicated.
* @return A pointer to the new string, or NULL if the duplication failed.
*
* @note The returned pointer must be freed by the caller, using the \p string_free() function.
*/
lite_string *string_duplicate(const lite_string *const restrict s) {
if (s) {
lite_string *dup = string_new();
if (dup) {
if (string_copy(s, dup)) {
return dup;
}
string_free(dup);
}
}
return nullptr;
}
19 changes: 17 additions & 2 deletions lite_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ extern "C" {
* When the size reaches the capacity, the string is resized to a larger capacity to accommodate more characters.
*/
struct lite_string {
char *data; ///< A pointer to the character data.
size_t size; ///< The number of characters in the string, not including the null character.
char *data; ///< A pointer to the character data.
size_t size; ///< The number of characters in the string, not including the null character.
size_t capacity; ///< The total number of characters that the string can hold.
};

Expand Down Expand Up @@ -168,8 +168,23 @@ bool string_shrink_to_fit(lite_string *restrict s);

void string_to_lower(const lite_string *restrict s);

void string_to_upper(const lite_string *restrict s);

void string_to_title(const lite_string *restrict s);

[[nodiscard]] lite_string *string_new_cstr(const char *restrict cstr);

bool string_replace(lite_string *restrict s, const lite_string *restrict old_sub,
const lite_string *restrict new_sub);

void string_replace_char(const lite_string *restrict s, char old_char, char new_char);

bool string_replace_cstr(lite_string *restrict s, const char *restrict old_cstr,
const char *restrict new_cstr);

bool string_erase_range(lite_string *restrict s, size_t start, size_t count);

lite_string *string_duplicate(const lite_string *restrict s);
#if __cplusplus
}
#endif

0 comments on commit d3c73e4

Please sign in to comment.