cstring

Lightweight string library for C
git clone git://git.christosmarg.xyz/cstring.git
Log | Files | Refs | README | LICENSE

commit 918f03bbaf5cad59a306b006cab74674014c8fdf
parent 3cac34409d90fffc98ef2639a2af4c24616c814f
Author: Christos Margiolis <christos@margiolis.net>
Date:   Sun, 16 Aug 2020 19:52:14 +0300

improved memory management, minimized some function calls

Diffstat:
MREADME.md | 4++--
Mcstring.c | 61++++++++++++++++++++++++++++++++++---------------------------
Mcstring.h | 3++-
Mtest.c | 18+++++++++---------
4 files changed, 47 insertions(+), 39 deletions(-)

diff --git a/README.md b/README.md @@ -20,9 +20,9 @@ along with your other files. * `cstring_front`: Returns the first character of the string * `cstring_back`: Returns the last character of the string * `cstring_empty`: Checks if the string is empty -* `cstring_len`: Returns the length of the string * `cstring_copy`: Makes a copy of a given `const char *` * `cstring_resize`: Resizes the array stored inside the string `struct` +* `cstring_len`: Returns the length of the string * `cstring_equals`: True if the strings are equal * `cstring_not_equals`: True if the strings are not equal * `cstring_greater`: True if the left hand string is greater than the right hand one @@ -34,7 +34,7 @@ along with your other files. A recommended way of using this string is to **always** call the `cstring_delete` function when you're done working with it, in order not to cause any memory leaks, as there's no *destructor* to do it for you. -Open `test.c` for more. +See `test.c` for more. ```c #include <stdio.h> diff --git a/cstring.c b/cstring.c @@ -5,7 +5,8 @@ cstring_init(const char *s) { cstring cs; cs.str = cstring_copy(s); - cs.len = cstring_len(&cs); + cs.len = strlen(s); + cstring_resize(&cs, cs.len << 1); return cs; } @@ -15,28 +16,33 @@ cstring_delete(cstring *cs) if (!cstring_empty(cs)) { free(cs->str); - cs->str = NULL; - cs->len = 0; + cs->str = NULL; + cs->len = 0; + cs->capacity = 0; } } void cstring_assign(cstring *cs, const char *s) { + size_t newlen = strlen(s); if (!cstring_empty(cs)) free(cs->str); cs->str = cstring_copy(s); - cs->len = cstring_len(cs); + cs->len = newlen; + if (newlen >= cs->capacity) cstring_resize(cs, newlen << 1); } void cstring_append(cstring *cs, const char *s) { + size_t newlen = cs->len + strlen(s); if (!cstring_empty(cs)) { - cstring_resize(cs, strlen(s)); + if (newlen >= cs->capacity) + cstring_resize(cs, newlen << 1); strcat(cs->str, s); } - cs->len = cstring_len(cs); + cs->len = newlen; } void @@ -44,11 +50,13 @@ cstring_insert(cstring *cs, const char *s, size_t i) { if (!cstring_empty(cs) && i < cs->len) { + /* TODO minimize function calls */ char *tmp1 = (char *)malloc(i + 1); char *tmp2 = (char *)malloc(cs->len - i + 1); memcpy(tmp1, cs->str, i + 1); memcpy(tmp2, cs->str + i, cs->len + 1); - cstring_resize(cs, strlen(s)); + if (cs->len + strlen(s) >= cs->capacity) + cstring_resize(cs, (cs->len + strlen(s)) << 1); memcpy(cs->str, tmp1, i + 1); memcpy(cs->str + i, s, strlen(s) + 1); memcpy(cs->str + strlen(s) + i, tmp2, cs->len - i + 1); @@ -62,16 +70,16 @@ cstring_insert(cstring *cs, const char *s, size_t i) void cstring_push_back(cstring *cs, char c) { - cstring_resize(cs, 1); + if (cs->len + 1 >= cs->capacity) + cstring_resize(cs, (cs->len + 1) << 1); cs->str[cs->len] = c; - cs->str[cs->len + 1] = '\0'; - cs->len = cstring_len(cs); + cs->str[++cs->len] = '\0'; } void cstring_pop_back(cstring *cs) { - if (cs->len - 1 > 0) + if (cs->len > 0) { char *tmp = (char *)malloc(cs->len); memcpy(tmp, cs->str, cs->len); @@ -121,37 +129,36 @@ cstring_empty(const cstring *cs) return (cs->len == 0 || cs->str == NULL); } -size_t -cstring_len(const cstring *cs) -{ - return strlen(cs->str); -} - char * cstring_copy(const char *s) { - size_t l = strlen(s); - char *tmp = (char *)malloc(l + 1); - memcpy(tmp, s, l + 1); - tmp[l] = '\0'; + size_t len = strlen(s); + char *tmp = (char *)malloc(len + 1); + memcpy(tmp, s, len + 1); + tmp[len] = '\0'; return tmp; } void -cstring_resize(cstring *cs, size_t n) +cstring_resize(cstring *cs, size_t new_capacity) { - if (cstring_empty(cs)) + if (!cstring_empty(cs)) { - size_t l = cs->len + n; - char *tmp = (char *)malloc(l + 1); + char *tmp = (char *)malloc(new_capacity + 1); memcpy(tmp, cs->str, cs->len + 1); free(cs->str); - tmp[l] = '\0'; + tmp[cs->len] = '\0'; cs->str = tmp; - cs->len = cstring_len(cs); + cs->capacity = new_capacity; } } +size_t +cstring_len(const cstring *cs) +{ + return strlen(cs->str); +} + int cstring_equals(const cstring *lhs, const cstring *rhs) { diff --git a/cstring.h b/cstring.h @@ -7,6 +7,7 @@ typedef struct { char *str; size_t len; + size_t capacity; } cstring; extern cstring cstring_init(const char *s); @@ -22,11 +23,11 @@ extern int cstring_exists(const cstring *cs, const char *s); extern char cstring_front(const cstring *cs); extern char cstring_back(const cstring *cs); extern int cstring_empty(const cstring *cs); -extern size_t cstring_len(const cstring *cs); extern char *cstring_copy(const char *s); extern void cstring_resize(cstring *cs, size_t n); /* might be useless */ +extern size_t cstring_len(const cstring *cs); extern int cstring_equals(const cstring *lhs, const cstring *rhs); extern int cstring_not_equals(const cstring *lhs, const cstring *rhs); extern int cstring_greater(const cstring *lhs, const cstring *rhs); diff --git a/test.c b/test.c @@ -5,36 +5,36 @@ int main(int argc, char **argv) { cstring s = cstring_init("Hello world"); - printf("cstring_init: %s (%ld)\n", s.str, s.len); + printf("cstring_init: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); cstring_append(&s, "Append"); - printf("cstring_append: %s (%ld)\n", s.str, s.len); + printf("cstring_append: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); cstring_assign(&s, "New string"); - printf("cstring_assign: %s (%ld)\n", s.str, s.len); + printf("cstring_assign: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); if (cstring_exists(&s, "string")) printf("cstring_exists: \"string\" exists!\n"); cstring_push_back(&s, 'c'); - printf("cstring_push_back: %s (%ld)\n", s.str, s.len); + printf("cstring_push_back: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); cstring_insert(&s, "Inserted text", 4); - printf("cstring_insert: %s (%ld)\n", s.str, s.len); + printf("cstring_insert: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); cstring_pop_back(&s); - printf("cstring_pop_back: %s (%ld)\n", s.str, s.len); + printf("cstring_pop_back: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); cstring_clear(&s); - printf("cstring_clear: %s (%ld)\n", s.str, s.len); + printf("cstring_clear: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); cstring_assign(&s, "CSTRING"); - printf("cstring_assign: %s (%ld)\n", s.str, s.len); + printf("cstring_assign: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); printf("cstring_front: %c\n", cstring_front(&s)); printf("cstring_back: %c\n", cstring_back(&s)); cstring_replace(&s, 3, 'x'); - printf("cstring_replace: %s (%ld)\n", s.str, s.len); + printf("cstring_replace: %s (Len: %ld, Capacity: %ld)\n", s.str, s.len, s.capacity); cstring_delete(&s); if (cstring_empty(&s)) printf("cstring_delete: Deleted string.\n");