Start refactor, restructure basic
This commit is contained in:
422
src/basic/basic_string16.cpp
Normal file
422
src/basic/basic_string16.cpp
Normal file
@@ -0,0 +1,422 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
API int64_t WideLength(char16_t *string) {
|
||||
if (!string) return 0;
|
||||
int64_t len = 0;
|
||||
while (*string++ != 0)
|
||||
len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
API char16_t ToLowerCase(char16_t a) {
|
||||
if (a >= u'A' && a <= u'Z') a += 32;
|
||||
return a;
|
||||
}
|
||||
|
||||
API char16_t ToUpperCase(char16_t a) {
|
||||
if (a >= u'a' && a <= u'z') a -= 32;
|
||||
return a;
|
||||
}
|
||||
|
||||
API bool IsWhitespace(char16_t w) {
|
||||
bool result = w == u'\n' || w == u' ' || w == u'\t' || w == u'\v' || w == u'\r';
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsAlphabetic(char16_t a) {
|
||||
bool result = (a >= u'a' && a <= u'z') || (a >= u'A' && a <= u'Z');
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsIdent(char16_t a) {
|
||||
bool result = (a >= u'a' && a <= u'z') || (a >= u'A' && a <= u'Z') || a == u'_';
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsDigit(char16_t a) {
|
||||
bool result = a >= u'0' && a <= u'9';
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsAlphanumeric(char16_t a) {
|
||||
bool result = IsDigit(a) || IsAlphabetic(a);
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsSymbol(char16_t w) {
|
||||
bool result = (w >= u'!' && w <= u'/') || (w >= u':' && w <= u'@') || (w >= u'[' && w <= u'`') || (w >= u'{' && w <= u'~');
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsNonWord(char16_t w) {
|
||||
if (w == u'_') return false;
|
||||
bool result = IsSymbol(w) || IsWhitespace(w);
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsWord(char16_t w) {
|
||||
bool result = !IsNonWord(w);
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsBrace(char16_t c) {
|
||||
bool result = c == u'{' || c == u'}';
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsParen(char16_t c) {
|
||||
bool result = c == u'(' || c == u')';
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
API String16 Chop(String16 a, int64_t len) {
|
||||
len = ClampTop(len, a.len);
|
||||
String16 result = {a.data, a.len - len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 Skip(String16 a, int64_t len) {
|
||||
len = ClampTop(len, a.len);
|
||||
String16 result = {a.data + len, a.len - len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 GetPostfix(String16 a, int64_t len) {
|
||||
len = ClampTop(len, a.len);
|
||||
int64_t remain_len = a.len - len;
|
||||
String16 result = {a.data + remain_len, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 GetPrefix(String16 a, int64_t len) {
|
||||
len = ClampTop(len, a.len);
|
||||
String16 result = {a.data, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 GetSlice(String16 arr, int64_t first_index, int64_t one_past_last_index) {
|
||||
// Negative indexes work in python style, they return you the index counting from end of list
|
||||
if (one_past_last_index == SLICE_LAST) one_past_last_index = arr.len;
|
||||
if (one_past_last_index < 0) one_past_last_index = arr.len + one_past_last_index;
|
||||
|
||||
if (first_index == SLICE_LAST) first_index = arr.len;
|
||||
if (first_index < 0) first_index = arr.len + first_index;
|
||||
|
||||
String16 result = {arr.data, arr.len};
|
||||
if (arr.len > 0) {
|
||||
if (one_past_last_index > first_index) {
|
||||
first_index = ClampTop(first_index, arr.len - 1);
|
||||
one_past_last_index = ClampTop(one_past_last_index, arr.len);
|
||||
result.data += first_index;
|
||||
result.len = one_past_last_index - first_index;
|
||||
} else {
|
||||
result.len = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool AreEqual(String16 a, String16 b, unsigned ignore_case) {
|
||||
if (a.len != b.len) return false;
|
||||
for (int64_t i = 0; i < a.len; i++) {
|
||||
char16_t A = a.data[i];
|
||||
char16_t B = b.data[i];
|
||||
if (ignore_case) {
|
||||
A = ToLowerCase(A);
|
||||
B = ToLowerCase(B);
|
||||
}
|
||||
if (A != B)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
API bool EndsWith(String16 a, String16 end, unsigned ignore_case) {
|
||||
String16 a_end = GetPostfix(a, end.len);
|
||||
bool result = AreEqual(end, a_end, ignore_case);
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool StartsWith(String16 a, String16 start, unsigned ignore_case) {
|
||||
String16 a_start = GetPrefix(a, start.len);
|
||||
bool result = AreEqual(start, a_start, ignore_case);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 Trim(String16 string) {
|
||||
if (string.len == 0)
|
||||
return string;
|
||||
|
||||
int64_t whitespace_begin = 0;
|
||||
for (; whitespace_begin < string.len; whitespace_begin++) {
|
||||
if (!IsWhitespace(string.data[whitespace_begin])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t whitespace_end = string.len;
|
||||
for (; whitespace_end != whitespace_begin; whitespace_end--) {
|
||||
if (!IsWhitespace(string.data[whitespace_end - 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (whitespace_begin == whitespace_end) {
|
||||
string.len = 0;
|
||||
} else {
|
||||
string = GetSlice(string, whitespace_begin, whitespace_end);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
API String16 TrimEnd(String16 string) {
|
||||
int64_t whitespace_end = string.len;
|
||||
for (; whitespace_end != 0; whitespace_end--) {
|
||||
if (!IsWhitespace(string.data[whitespace_end - 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String16 result = GetPrefix(string, whitespace_end);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 Copy16(Allocator allocator, String16 string) {
|
||||
char16_t *copy = (char16_t *)AllocSize(allocator, sizeof(char16_t) * (string.len + 1));
|
||||
memcpy(copy, string.data, string.len);
|
||||
copy[string.len] = 0;
|
||||
String16 result = {copy, string.len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 Copy16(Allocator allocator, char16_t *string) {
|
||||
return Copy16(allocator, {string, (int64_t)WideLength(string)});
|
||||
}
|
||||
|
||||
API void NormalizePathInPlace(String16 s) {
|
||||
for (int64_t i = 0; i < s.len; i++) {
|
||||
if (s.data[i] == u'\\')
|
||||
s.data[i] = u'/';
|
||||
}
|
||||
}
|
||||
|
||||
API String16 NormalizePath(Allocator allocator, String16 s) {
|
||||
String16 copy = Copy16(allocator, s);
|
||||
NormalizePathInPlace(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
API bool Seek(String16 string, String16 find, int64_t *index_out, SeekFlag flags) {
|
||||
bool ignore_case = flags & SeekFlag_IgnoreCase ? true : false;
|
||||
bool result = false;
|
||||
if (flags & SeekFlag_MatchFindLast) {
|
||||
for (int64_t i = string.len; i != 0; i--) {
|
||||
int64_t index = i - 1;
|
||||
String16 substring = GetSlice(string, index, index + find.len);
|
||||
if (AreEqual(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = index;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int64_t i = 0; i < string.len; i++) {
|
||||
String16 substring = GetSlice(string, i, i + find.len);
|
||||
if (AreEqual(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = i;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 CutLastSlash(String16 *s) {
|
||||
String16 result = *s;
|
||||
Seek(*s, u"/", &s->len, SeekFlag_MatchFindLast);
|
||||
result = Skip(result, s->len);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 ChopLastSlash(String16 s) {
|
||||
String16 result = s;
|
||||
Seek(s, u"/", &result.len, SeekFlag_MatchFindLast);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 ChopLastPeriod(String16 s) {
|
||||
String16 result = s;
|
||||
Seek(s, u".", &result.len, SeekFlag_MatchFindLast);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 SkipToLastSlash(String16 s) {
|
||||
int64_t pos;
|
||||
String16 result = s;
|
||||
if (Seek(s, u"/", &pos, SeekFlag_MatchFindLast)) {
|
||||
result = Skip(result, pos + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 SkipToLastPeriod(String16 s) {
|
||||
int64_t pos;
|
||||
String16 result = s;
|
||||
if (Seek(s, u".", &pos, SeekFlag_MatchFindLast)) {
|
||||
result = Skip(result, pos + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 CutPrefix(String16 *string, int64_t len) {
|
||||
String16 result = GetPrefix(*string, len);
|
||||
*string = Skip(*string, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 CutPostfix(String16 *string, int64_t len) {
|
||||
String16 result = GetPostfix(*string, len);
|
||||
*string = Chop(*string, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 Format16V(Allocator allocator, const char *data, va_list args1) {
|
||||
Scratch scratch;
|
||||
va_list args2;
|
||||
va_copy(args2, args1);
|
||||
int64_t len = stbsp_vsnprintf(0, 0, data, args2);
|
||||
va_end(args2);
|
||||
|
||||
char *result = (char *)AllocSize(scratch, sizeof(char) * (len + 1));
|
||||
stbsp_vsnprintf(result, (int)(len + 1), data, args1);
|
||||
String res = {result, len};
|
||||
String16 res16 = ToString16(allocator, res);
|
||||
return res16;
|
||||
}
|
||||
|
||||
API String16 Format16(Allocator allocator, const char *data, ...) {
|
||||
Scratch scratch;
|
||||
STRING_FORMAT(scratch, data, result);
|
||||
String16 result16 = ToString16(allocator, result);
|
||||
return result16;
|
||||
}
|
||||
|
||||
API Array<String16> Split(Allocator allocator, String16 string, String16 delimiter) {
|
||||
Array<String16> result = {allocator};
|
||||
int64_t index = 0;
|
||||
while (Seek(string, delimiter, &index)) {
|
||||
String16 before_match = {string.data, index};
|
||||
Add(&result, before_match);
|
||||
string = Skip(string, index + delimiter.len);
|
||||
}
|
||||
Add(&result, string);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 Merge(Allocator allocator, Array<String16> list, String16 separator) {
|
||||
int64_t char_count = 0;
|
||||
For(list) char_count += it.len;
|
||||
if (char_count == 0) return {};
|
||||
int64_t node_count = list.len;
|
||||
|
||||
int64_t base_size = (char_count + 1);
|
||||
int64_t sep_size = (node_count - 1) * separator.len;
|
||||
int64_t size = base_size + sep_size;
|
||||
char16_t *buff = (char16_t *)AllocSize(allocator, sizeof(char16_t) * (size + 1));
|
||||
String16 string = {buff, 0};
|
||||
For(list) {
|
||||
Assert(string.len + it.len <= size);
|
||||
memcpy(string.data + string.len, it.data, it.len);
|
||||
string.len += it.len;
|
||||
if (!IsLast(list, it)) {
|
||||
memcpy(string.data + string.len, separator.data, separator.len);
|
||||
string.len += separator.len;
|
||||
}
|
||||
}
|
||||
Assert(string.len == size - 1);
|
||||
string.data[size] = 0;
|
||||
return string;
|
||||
}
|
||||
|
||||
API Int GetSize(Array<String16> array) {
|
||||
Int result = 0;
|
||||
For (array) result += it.len;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
API String16 SkipNumberEx(String16 *string) {
|
||||
String16 col = {string->data, 0};
|
||||
for (int64_t i = 0; i < string->len; i += 1) {
|
||||
if (IsDigit(string->data[i])) {
|
||||
col.len += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*string = Skip(*string, col.len);
|
||||
return col;
|
||||
}
|
||||
|
||||
API Int SkipNumber(String16 *string) {
|
||||
String16 col = SkipNumberEx(string);
|
||||
if (col.len == 0) return -1;
|
||||
Scratch scratch;
|
||||
String num_string = ToString(scratch, col);
|
||||
Int result = strtoll(num_string.data, NULL, 10);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 SkipUntil(String16 *string, String16 str) {
|
||||
String16 begin = *string;
|
||||
begin.len = 0;
|
||||
for (; string->len; begin.len += 1) {
|
||||
String16 match = GetPrefix(*string, str.len);
|
||||
if (StartsWith(match, str)) break;
|
||||
*string = Skip(*string, 1);
|
||||
}
|
||||
return begin;
|
||||
}
|
||||
|
||||
API String16 SkipWhitespace(String16 *string) {
|
||||
String16 begin = {string->data, 0};
|
||||
for (Int i = 0; i < string->len; i += 1) {
|
||||
if (!IsWhitespace(string->data[i])) break;
|
||||
*string = Skip(*string, 1);
|
||||
begin.len += 1;
|
||||
}
|
||||
return begin;
|
||||
}
|
||||
|
||||
// chop this - :324
|
||||
API String16 ChopNumberEx(String16 *string) {
|
||||
String16 col = {};
|
||||
for (int64_t i = string->len - 1; i >= 0; i -= 1) {
|
||||
if (IsDigit(string->data[i])) {
|
||||
col.data = string->data + i;
|
||||
col.len += 1;
|
||||
} else if (string->data[i] == L':') {
|
||||
break;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
*string = Chop(*string, col.len + 1);
|
||||
return col;
|
||||
}
|
||||
|
||||
API Int ChopNumber(String16 *string) {
|
||||
Scratch scratch;
|
||||
String16 col = ChopNumberEx(string);
|
||||
if (col.len == 0) return -1;
|
||||
String num_string = ToString(scratch, col);
|
||||
Int result = strtoll(num_string.data, NULL, 10) - 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user