tlibc/src/string/str.c

179 lines
4.5 KiB
C
Executable File

#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;
}
}