179 lines
4.5 KiB
C
Executable File
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;
|
|
}
|
|
}
|