diff options
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | src/string.c | 157 | ||||
| -rw-r--r-- | tests/string_tests.c | 45 |
3 files changed, 154 insertions, 50 deletions
@@ -7,8 +7,8 @@ Defnitely not the best implementations ever made, but they're mine, so idc. - "safe" wrappers for "unsafe" functions - testing framework - dynamic array implementation +- length aware string slices ## Planned: -- length aware string slices - hashmap implementation - a bunch of other stuff most certainly diff --git a/src/string.c b/src/string.c index 02aa141..c26e3bd 100644 --- a/src/string.c +++ b/src/string.c @@ -1,113 +1,216 @@ #define MOS_FORCE_PREFIXES +#define _GNU_SOURCE #include "moslib/string.h" +#include <ctype.h> +#include <string.h> + +#include "moslib/ds/array.h" + MosStringSlice mos_ss_from_str(const char *str) { - return (MosStringSlice){0}; + return mos_ss_from_vars(str, strlen(str)); } MosStringSlice mos_ss_copy(MosStringSlice ss) { - return (MosStringSlice){0}; + return mos_ss_from_vars(ss.data, ss.len); } MosStringSlice mos_ss_from_arr(char *arr) { - return (MosStringSlice){0}; + return mos_ss_from_vars(arr, mos_arr_len(arr)); } MosStringSlice mos_ss_from_vars(const char *str, size_t len) { - return (MosStringSlice){0}; + return (MosStringSlice){.data = str, .len = len}; } void mos_ss_print(MosStringSlice ss) { + printf(MOS_SS_FMT, MOS_SS_ARGS(ss)); } int mos_ss_eq(MosStringSlice ss1, MosStringSlice ss2) { - return 0; + if (ss1.len != ss2.len) + return 0; + + return memcmp(ss1.data, ss2.data, ss1.len) == 0; } int mos_ss_eq_str(MosStringSlice ss, const char *str) { - return 0; + return mos_ss_eq(ss, mos_ss_from_str(str)); } MosStringSlice mos_ss_trim(MosStringSlice ss) { - return (MosStringSlice){0}; + return mos_ss_trim_right(mos_ss_trim_left(ss)); } MosStringSlice mos_ss_trim_left(MosStringSlice ss) { - return (MosStringSlice){0}; + size_t i = 0; + while (i < ss.len && isspace(ss.data[i])) { + i++; + } + + ss.data += i; + ss.len -= i; + return ss; } MosStringSlice mos_ss_trim_right(MosStringSlice ss) { - return (MosStringSlice){0}; + size_t i = ss.len; + while (i-- > 0 && isspace(ss.data[i])) + ; + + ss.len = i + 1; + return ss; } int mos_ss_starts_with(MosStringSlice ss, MosStringSlice prefix) { - return 0; + if (prefix.len > ss.len) + return 0; + + return memcmp(ss.data, prefix.data, prefix.len) == 0; } int mos_ss_ends_with(MosStringSlice ss, MosStringSlice suffix) { - return 0; + if (suffix.len > ss.len) + return 0; + + return memcmp(ss.data + ss.len - suffix.len, suffix.data, suffix.len) == 0; } int mos_ss_starts_with_str(MosStringSlice ss, const char *prefix) { - return 0; + return mos_ss_starts_with(ss, mos_ss_from_str(prefix)); } int mos_ss_ends_with_str(MosStringSlice ss, const char *suffix) { - return 0; + return mos_ss_ends_with(ss, mos_ss_from_str(suffix)); } size_t mos_ss_del_left(MosStringSlice *ss, size_t n) { - return 0; + if (n > ss->len) + n = ss->len; + + ss->data += n; + ss->len -= n; + return n; } size_t mos_ss_del_right(MosStringSlice *ss, size_t n) { - return 0; + if (n > ss->len) + n = ss->len; + + ss->len -= n; + return n; } int mos_ss_del_prefix(MosStringSlice *ss, MosStringSlice prefix) { - return 0; + if (!mos_ss_starts_with(*ss, prefix)) + return 0; + + mos_ss_del_left(ss, prefix.len); + return 1; } int mos_ss_del_suffix(MosStringSlice *ss, MosStringSlice suffix) { - return 0; + if (!mos_ss_ends_with(*ss, suffix)) + return 0; + + mos_ss_del_right(ss, suffix.len); + return 1; } int mos_ss_del_prefix_str(MosStringSlice *ss, char *prefix) { - return 0; + return mos_ss_del_prefix(ss, mos_ss_from_str(prefix)); } int mos_ss_del_suffix_str(MosStringSlice *ss, char *suffix) { - return 0; + return mos_ss_del_suffix(ss, mos_ss_from_str(suffix)); } MosStringSlice mos_ss_split(MosStringSlice *ss, char delim) { - return (MosStringSlice){0}; + size_t i = 0; + while (i < ss->len && ss->data[i] != delim) + i++; + + if (i >= ss->len) { + MosStringSlice res = mos_ss_copy(*ss); + ss->len = 0; + return res; + } + + MosStringSlice res = mos_ss_from_vars(ss->data, i); + ss->data += i + 1; + ss->len -= i + 1; + return res; } MosStringSlice mos_ss_split_str(MosStringSlice *ss, const char *delim) { - return (MosStringSlice){0}; + return mos_ss_split_ss(ss, mos_ss_from_str(delim)); } MosStringSlice mos_ss_split_ss(MosStringSlice *ss, MosStringSlice delim) { - return (MosStringSlice){0}; + if (delim.len == 0) + return MOS_SS_LIT(""); + + const char *found = memmem(ss->data, ss->len, delim.data, delim.len); + if (!found) { + MosStringSlice res = mos_ss_copy(*ss); + ss->len = 0; + return res; + } + + size_t i = found - ss->data; + MosStringSlice res = mos_ss_from_vars(ss->data, i); + ss->data += i + delim.len; + ss->len -= i + delim.len; + return res; } MosStringSlice mos_ss_split_left(MosStringSlice *ss, size_t n) { - return (MosStringSlice){0}; + if (n > ss->len) + n = ss->len; + + MosStringSlice left = mos_ss_from_vars(ss->data, n); + ss->data += n; + ss->len -= n; + return left; } MosStringSlice mos_ss_split_right(MosStringSlice *ss, size_t n) { - return (MosStringSlice){0}; + if (n > ss->len) + n = ss->len; + + MosStringSlice right = mos_ss_from_vars(ss->data + ss->len - n, n); + ss->len -= n; + return right; } MosStringSlice mos_ss_find(MosStringSlice ss, MosStringSlice target) { - return (MosStringSlice){0}; + if (target.len == 0) + return ss; + + const char *found = memmem(ss.data, ss.len, target.data, target.len); + if (!found) + return MOS_SS_LIT(""); + + return mos_ss_from_vars(found, ss.len - (found - ss.data)); } MosStringSlice mos_ss_find_str(MosStringSlice ss, const char *target) { - return (MosStringSlice){0}; + return mos_ss_find(ss, mos_ss_from_str(target)); } size_t mos_ss_utf8_len(MosStringSlice ss) { - return 0; + size_t utf8_len = ss.len; + for (size_t i = 0; i < ss.len; i++) { + char c = ss.data[i]; + if ((c & 0xC0) != 0xC0) + continue; + + if ((c & 0xE0) == 0xC0) + utf8_len -= 1; + else if ((c & 0xF0) == 0xE0) + utf8_len -= 2; + else if ((c & 0xF8) == 0xF0) + utf8_len -= 3; + } + return utf8_len; } diff --git a/tests/string_tests.c b/tests/string_tests.c index 57fe82e..4cb6372 100644 --- a/tests/string_tests.c +++ b/tests/string_tests.c @@ -17,9 +17,10 @@ Test creating() { test_assert(ss1.data == str && ss1.len == str_len, "ss_from_str created wrong slice"); char *arr = NULL; - arr_append_n(arr, str, 13); + arr_append_n(arr, str, 5); + arr_append_n(arr, str + 5, 8); StringSlice ss2 = ss_from_arr(arr); - test_assert(ss2.data == str && ss2.len == str_len, "ss_from_arr created wrong slice"); + test_assert(ss2.data == arr && ss2.len == str_len, "ss_from_arr created wrong slice"); StringSlice ss3 = ss_from_vars(str, 13); test_assert(ss3.data == str && ss3.len == str_len, "ss_from_vars created wrong slice"); @@ -85,17 +86,17 @@ Test trimming() { Test prefix_suffix() { StringSlice ss = ss_from_str("pre mid suf"); - test_assert(ss_starts_with(ss, ss_from_str("pre")), "slice doesn't start with its prefix"); - test_assert(ss_starts_with(ss, ss_from_str("suf")) == 0, "slice starts with not prefix"); + test_assert(ss_starts_with(ss, ss_from_str("pre")), "slice doesn't start with its slice prefix"); + test_assert(ss_starts_with(ss, ss_from_str("suf")) == 0, "slice starts with not slice prefix"); - test_assert(ss_ends_with(ss, ss_from_str("suf")), "slice doesn't end with its suffix"); - test_assert(ss_ends_with(ss, ss_from_str("pre")) == 0, "slice ends with not suffix"); + test_assert(ss_ends_with(ss, ss_from_str("suf")), "slice doesn't end with its slice suffix"); + test_assert(ss_ends_with(ss, ss_from_str("pre")) == 0, "slice ends with not slice suffix"); - test_assert(ss_starts_with_str(ss, "pre mid"), "slice doesn't start with its prefix"); - test_assert(ss_starts_with_str(ss, "suf") == 0, "slice starts with not prefix"); + test_assert(ss_starts_with_str(ss, "pre mid"), "slice doesn't start with its string prefix"); + test_assert(ss_starts_with_str(ss, "suf") == 0, "slice starts with not string prefix"); - test_assert(ss_ends_with_str(ss, "mid suf"), "slice doesn't end with its suffix"); - test_assert(ss_ends_with_str(ss, "pre") == 0, "slice ends with not suffix"); + test_assert(ss_ends_with_str(ss, "mid suf"), "slice doesn't end with its string suffix"); + test_assert(ss_ends_with_str(ss, "pre") == 0, "slice ends with not string suffix"); StringSlice ss2 = ss_from_str(""); test_assert(ss_starts_with(ss2, ss_from_str("")), "starts_with breaks for empty slice and prefix"); @@ -121,29 +122,29 @@ Test deleting() { test_assert(deleted == 0, "ss_del_right returned wrong deleted count (n > len)"); test_assert(ss_eq_str(ss, ""), "del_right deleted wrong chars (n > len)"); - ss = ss_from_str("prepre sufsuf"); + ss = ss_from_str("preprepre sufsufsuf"); StringSlice pre = ss_from_str("pre"); StringSlice suf = ss_from_str("suf"); int flag = ss_del_prefix(&ss, pre); - test_assert(flag && ss.len == 10, "del_prefix didn't work properly for found prefix"); + test_assert(flag && ss.len == 16, "del_prefix didn't work properly for found prefix"); flag = ss_del_prefix(&ss, suf); - test_assert(!flag && ss.len == 10, "del_prefix didn't work properly for not found prefix"); + test_assert(!flag && ss.len == 16, "del_prefix didn't work properly for not found prefix"); flag = ss_del_suffix(&ss, suf); - test_assert(flag && ss.len == 7, "del_suffix didn't work properly for found suffix"); - flag = ss_del_prefix(&ss, pre); - test_assert(!flag && ss.len == 7, "del_suffix didn't work properly for not found suffix"); + test_assert(flag && ss.len == 13, "del_suffix didn't work properly for found suffix"); + flag = ss_del_suffix(&ss, pre); + test_assert(!flag && ss.len == 13, "del_suffix didn't work properly for not found suffix"); flag = ss_del_prefix_str(&ss, "pre"); - test_assert(flag && ss.len == 4, "del_prefix_str didn't work properly for found prefix"); + test_assert(flag && ss.len == 10, "del_prefix_str didn't work properly for found prefix"); flag = ss_del_prefix_str(&ss, "suf"); - test_assert(!flag && ss.len == 4, "del_prefix_str didn't work properly for not found prefix"); + test_assert(!flag && ss.len == 10, "del_prefix_str didn't work properly for not found prefix"); flag = ss_del_suffix_str(&ss, "suf"); - test_assert(flag && ss.len == 1, "del_suffix_str didn't work properly for found suffix"); - flag = ss_del_prefix_str(&ss, "pre"); - test_assert(!flag && ss.len == 1, "del_suffix_str didn't work properly for not found suffix"); + test_assert(flag && ss.len == 7, "del_suffix_str didn't work properly for found suffix"); + flag = ss_del_suffix_str(&ss, "pre"); + test_assert(!flag && ss.len == 7, "del_suffix_str didn't work properly for not found suffix"); } Test splitting() { @@ -156,7 +157,7 @@ Test splitting() { test_assert(ss_eq_str(ss3, "He") && ss_eq_str(ss2, "o"), "ss_split_str didn't split proprely"); StringSlice ss4 = ss_split_ss(&ss1, SS_LIT("rld")); - test_assert(ss_eq_str(ss4, "Wo") && ss_eq_str(ss1, "!"), "ss_split_ss didn't split proprely"); + test_assert(ss_eq_str(ss4, " Wo") && ss_eq_str(ss1, "!"), "ss_split_ss didn't split proprely"); ss1 = ss_from_str("hiii"); |
