aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--src/string.c157
-rw-r--r--tests/string_tests.c45
3 files changed, 154 insertions, 50 deletions
diff --git a/README.md b/README.md
index 660a8e7..2015f71 100644
--- a/README.md
+++ b/README.md
@@ -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");