This repository has been archived on 2025-02-04. You can view files and clone it, but cannot push or open issues or pull requests.
helpless/oogabooga/string.c

212 lines
5 KiB
C
Raw Normal View History

/*
*/
ogb_instance void* talloc(u64);
typedef struct string {
u64 count;
u8 *data;
} string;
2024-07-15 21:40:27 +02:00
const string null_string = {0, 0};
#define fixed_string STR
#define STR(s) ((string){ length_of_null_terminated_string((const char*)s), (u8*)s })
2024-07-19 16:45:58 +02:00
inline u64
length_of_null_terminated_string(const char* cstring) {
u64 len = 0;
while (*cstring != 0) {
len += 1;
cstring += 1;
}
return len;
}
2024-07-19 16:45:58 +02:00
string
alloc_string(Allocator allocator, u64 count) {
string s;
s.count = count;
2024-07-01 13:10:06 +02:00
s.data = cast(u8*)alloc(allocator, count);
return s;
}
2024-07-19 16:45:58 +02:00
void
dealloc_string(Allocator allocator, string s) {
2024-07-15 21:40:27 +02:00
assert(s.count > 0 && s.data, "You tried to deallocate an empty string. That's doesn't make sense.");
2024-07-01 13:10:06 +02:00
dealloc(allocator, s.data);
}
2024-07-19 16:45:58 +02:00
string
talloc_string(u64 count) {
string s = alloc_string(get_temporary_allocator(), count);
return s;
}
2024-07-19 16:45:58 +02:00
string
string_concat(const string left, const string right, Allocator allocator) {
2024-07-15 21:40:27 +02:00
if (right.count + left.count == 0) return null_string;
if (left.count == 0) return right;
if (right.count == 0) return left;
string result;
result.count = left.count + right.count;
2024-07-01 13:10:06 +02:00
result.data = cast(u8*)alloc(allocator, result.count);
memcpy(result.data, left.data, left.count);
memcpy(result.data+left.count, right.data, right.count);
return result;
}
2024-07-19 16:45:58 +02:00
char *
convert_to_null_terminated_string(const string s, Allocator allocator) {
2024-07-01 13:10:06 +02:00
char *cstring = cast(char*)alloc(allocator, s.count+1);
memcpy(cstring, s.data, s.count);
cstring[s.count] = 0;
return cstring;
}
2024-07-19 16:45:58 +02:00
char *
temp_convert_to_null_terminated_string(const string s) {
char *c = convert_to_null_terminated_string(s, get_temporary_allocator());
return c;
}
2024-07-19 16:45:58 +02:00
bool
strings_match(string a, string b) {
if (a.count != b.count) return false;
// Count match, pointer match: they are the same
if (a.data == b.data) return true;
return memcmp(a.data, b.data, a.count) == 0;
}
2024-07-19 16:45:58 +02:00
string
string_view(string s, u64 start_index, u64 count) {
assert(start_index < s.count, "array_view start_index % out of range for string count %", start_index, s.count);
assert(count > 0, "array_view count must be more than 0");
assert(start_index + count <= s.count, "array_view start_index + count is out of range");
string result;
result.data = s.data+start_index;
result.count = count;
return result;
}
// Returns first index from left where "sub" matches in "s". Returns -1 if no match is found.
2024-07-19 16:45:58 +02:00
s64
string_find_from_left(string s, string sub) {
for (s64 i = 0; i <= s.count-sub.count; i++) {
if (strings_match(string_view(s, i, sub.count), sub)) {
return i;
}
}
return -1;
}
// Returns first index from right where "sub" matches in "s" Returns -1 if no match is found.
2024-07-19 16:45:58 +02:00
s64
string_find_from_right(string s, string sub) {
for (s64 i = s.count-sub.count; i >= 0 ; i--) {
if (strings_match(string_view(s, i, sub.count), sub)) {
return i;
}
}
return -1;
}
2024-07-19 16:45:58 +02:00
bool
string_starts_with(string s, string sub) {
2024-07-08 15:33:01 +02:00
if (s.count < sub.count) return false;
s.count = sub.count;
return strings_match(s, sub);
2024-07-19 16:45:58 +02:00
}
string
string_copy(string s, Allocator allocator) {
string c = alloc_string(allocator, s.count);
memcpy(c.data, s.data, s.count);
return c;
}
typedef struct String_Builder {
union {
struct {u64 count;u8 *buffer;};
string result;
};
u64 buffer_capacity;
Allocator allocator;
} String_Builder;
void
string_builder_reserve(String_Builder *b, u64 required_capacity) {
if (b->buffer_capacity >= required_capacity) return;
u64 new_capacity = max(b->buffer_capacity*2, (u64)(required_capacity*1.5));
u8 *new_buffer = alloc(b->allocator, new_capacity);
if (b->buffer) {
memcpy(new_buffer, b->buffer, b->count);
dealloc(b->allocator, b->buffer);
}
b->buffer = new_buffer;
b->buffer_capacity = new_capacity;
}
void
string_builder_init_reserve(String_Builder *b, u64 reserved_capacity, Allocator allocator) {
reserved_capacity = max(reserved_capacity, 128);
b->allocator = allocator;
b->buffer_capacity = 0;
b->buffer = 0;
string_builder_reserve(b, reserved_capacity);
b->count = 0;
}
void
string_builder_init(String_Builder *b, Allocator allocator) {
string_builder_init_reserve(b, 128, allocator);
}
void
string_builder_append(String_Builder *b, string s) {
assert(b->allocator.proc, "String_Builder is missing allocator");
string_builder_reserve(b, b->count+s.count);
memcpy(b->buffer+b->count, s.data, s.count);
b->count += s.count;
}
string
string_builder_get_string(String_Builder b) {
return b.result;
}
string
string_replace_all(string s, string old, string new, Allocator allocator) {
if (!s.data || !s.count) return string_copy(null_string, allocator);
String_Builder builder;
string_builder_init_reserve(&builder, s.count, allocator);
while (s.count > 0) {
if (s.count >= old.count && strings_match(string_view(s, 0, old.count), old)) {
if (new.count != 0) string_builder_append(&builder, new);
s.data += old.count;
s.count -= old.count;
} else {
string_builder_append(&builder, string_view(s, 0, 1));
s.data += 1;
s.count -= 1;
}
}
return string_builder_get_string(builder);
}