#include "tlibc/string/str.h" #include "tlibc/string/StringBuilder.h" str str_copy(const str self){ if(self.data == NULL || self.len == 0) return self; str copy = str_construct((char*)malloc(self.len + 1), self.len, true); memcpy(copy.data, self.data, self.len); copy.data[copy.len] = '\0'; return copy; } bool str_equals(const str self, const str other){ if(self.len != other.len) return false; if(self.data == other.data) return true; /* BENCHMARK: str_equals64: 2.967s strcmp: 4.143s strncmp: 1.611s memcmp: 0.710s */ return memcmp(self.data, other.data, self.len) == 0; } str str_reverse(str s){ if(s.data == NULL || s.len == 0) return s; str r = str_construct(malloc(s.len), s.len, s.isZeroTerminated); for(u32 i = 0; i < s.len; i++ ) r.data[i] = s.data[s.len - i - 1]; return r; } i32 str_seek(const str src, const str fragment, u32 startIndex){ if(src.len == 0 || fragment.len == 0) return -1; for(u32 i = startIndex; i < src.len - fragment.len + 1; i++){ for(u32 j = 0;; j++){ if(j == fragment.len) return i; if(src.data[i + j] != fragment.data[j]) break; } } return -1; } i32 str_seekReverse(const str src, const str fragment, u32 startIndex){ if(src.len == 0 || fragment.len == 0) return -1; if(startIndex > src.len - 1) startIndex = src.len - 1; for(u32 i = startIndex; i >= fragment.len - 1; i--){ for(u32 j = 0;; j++){ if(j == fragment.len) return i - j + 1; if(src.data[i - j] != fragment.data[fragment.len - 1 - j]) break; } } return -1; } i32 str_seekChar(const str src, char c, u32 startIndex){ for(u32 i = startIndex; i < src.len; i++){ if(src.data[i] == c) return i; } return -1; } i32 str_seekCharReverse(const str src, char c, u32 startIndex){ if(startIndex > src.len - 1) startIndex = src.len - 1; for(u32 i = startIndex; i != (u32)-1; i--){ if(src.data[i] == c) return i; } return -1; } bool str_startsWith(const str src, const str fragment){ if(src.len < fragment.len) return false; str src_fragment = str_null; src_fragment.data = src.data; src_fragment.len = fragment.len; return str_equals(src_fragment, fragment); } bool str_endsWith(const str src, const str fragment){ if(src.len < fragment.len) return false; str src_fragment = str_null; src_fragment.data = (char*)(src.data + src.len - fragment.len); src_fragment.len = fragment.len; return str_equals(src_fragment, fragment); } u32 str_hash32(const str s){ u8* ubuf = (u8*)s.data; u32 hash=0; for (u32 i = 0; i < s.len; i++) hash = (hash<<6) + (hash<<16) - hash + ubuf[i]; return hash; } str str_toUpper(const str src){ str r = str_copy(src); for (u32 i = 0; i < r.len; i++){ if(char_isLatinLower(r.data[i])) r.data[i] = r.data[i] - 'a' + 'A'; } return r; } str str_toLower(const str src){ str r = str_copy(src); for (u32 i = 0; i < r.len; i++){ if(char_isLatinUpper(r.data[i])) r.data[i] = r.data[i] - 'A' + 'a'; } return r; } str hex_to_str(Array(u8) buf, bool uppercase){ StringBuilder sb = StringBuilder_alloc(buf.len * 2 + 1); StringBuilder_append_memory(&sb, buf, uppercase); return StringBuilder_getStr(&sb); } void str_trim(str* line, bool set_zero_at_end){ // loop forward bool stop = false; while(line->len > 0 && !stop){ char first_char = line->data[0]; switch(first_char){ case '\0': case '\r': case '\n': case '\t': case ' ': line->data++; line->len--; break; default: stop = true; break; } } // loop backward stop = false; while(line->len > 0 && !stop) { char last_char = line->data[line->len - 1]; switch(last_char){ case '\0': case '\r': case '\n': case '\t': case ' ': line->len--; break; default: stop = true; break; } } if(set_zero_at_end){ line->data[line->len] = '\0'; line->isZeroTerminated = true; } }