-
Notifications
You must be signed in to change notification settings - Fork 0
/
newstring.h
229 lines (186 loc) · 6.85 KB
/
newstring.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/*
A string is a sequence of characters. Here we represent the string as an array of bytes (u8).
Our strings are not zero-terminated.
Currently, we don't support UTF-8.
There functions that allows conversion from our strings to the C-style string for printing!
@Important: Strings are immutable, to change value of the string, either:
- Copy its data into allocated memory on the stack or heap.
- Use copy_string() to copy the string to the heap.
- Sometimes use sprint() will solve your needs.
*/
#pragma once
#include "common.h"
// This is for the comparisons
struct String;
bool equal(String a, String b);
bool equal(char a, char b);
// Again, Strings are immutable (saying it twice because I will definitely forget)
struct String
{
i64 count = 0; // Amount of characters in the string
u8 *data = NULL; // Pointer to the start of the characters
//
// Helper functions below this line
//
explicit String()
{
}
// This function only creates strings that exists on the stack
explicit String(const char c_string[]) // creates String from a string constant
{
if (c_string == NULL) return;
count = strlen(c_string);
// Because we are making strings on the stack here,
// we straight up assign the data pointer to the pointer
// of the given c_string
data = (u8*)c_string; // Safe cast
}
// explicit String(my_string std_string)
// {
// // Figure this out later
// // Because std::string are allocatd on the stack but its memory lives
// // in the heap, doing this is quite difficult.
// // The best solution is to not use std::string at all
// assert(0);
// }
u8 *begin() { assert((data != NULL) & (count > 0)); return &data[0]; }
u8 *end() { assert((data != NULL) & (count > 0)); return &data[count]; }
operator bool() { return count > 0; };
String &operator=(const char c_string[]) // assigns string constant to String
{
if (c_string == NULL) count = 0;
else count = strlen(c_string);
data = (u8*)c_string;
return *this;
}
u8 operator[](i64 index)
{
assert(index < count);
assert(index >= 0);
assert(data != NULL);
return data[index];
}
bool operator==(String rhs) {return equal(*this, rhs);}
bool operator!=(String rhs) {return !equal(*this, rhs);}
};
//
// Comparisons
bool equal(String a, String b); // case sensitive
bool equal_nocase(String a, String b); // case insensitive
i32 compare(String a, String b); // case sensitive
i32 compare_nocase(String a, String b); // case insensitive
bool contains(String str, String substring);
bool contains(String str, u8 byte);
bool begins_with(String str, String prefix);
bool ends_with(String str, String suffix);
inline __attribute__((always_inline))
bool ends_with(String str, u8 suffix)
{
if (!str) return false;
return str.data[str.count - 1] == suffix;
}
inline __attribute__((always_inline))
void free_string(String *s)
{
my_free((void*)s->data);
s->count = 0;
}
//
// Find
i64 find_index_from_left(String str, u8 byte);
// i64 find_index_from_left(String str, String substring);
i64 find_index_from_right(String str, u8 byte);
// i64 find_index_from_right(String str, String substring);
//
// Allocation
// @Important: need to free the returned c_string
u8 *to_c_string(String s, Allocator allocator = {});
// Uses temporary storage
u8 *temp_c_string(String s);
Allocator get_allocator(Allocator parameter_allocator = {},
_type_Type type = _make_Type(void));
String alloc_string(i64 nbytes_excluding_zero,
Allocator allocator);
void *__temporary_allocator(Allocator_Mode mode,
i64 size, i64 old_size,
void *old_memory, void *allocator_data);
// Uses temporary storage
inline
String talloc_string(i64 nbytes_excluding_zero)
{
Allocator a = {global_context.temporary_storage, __temporary_allocator};
return alloc_string(nbytes_excluding_zero, a);
}
inline __attribute__((always_inline))
String empty(bool null_terminate)
{
if (null_terminate)
{
auto a = get_allocator();
auto empty = alloc_string(1, a);
empty.data[0] = '\0';
return empty;
}
else
{
return String("");
}
}
// Copy string
// @Important: REMEMBER TO ASSIGN AND FREE WHEN USED
String copy_string(String str, Allocator allocator = {}, bool null_terminate = false);
//
// Join
// Forward declare some stuff here because of circular dependency
template <typename V>
struct Resizable_Array;
template <typename V>
using RArr = Resizable_Array<V>;
struct Allocator;
// @Important: REMEMBER TO ASSIGN AND FREE WHEN USED
__attribute__((warn_unused_result))
String join(RArr<String> inputs,
Allocator allocator = {},
bool null_terminate = false);
// @Important: REMEMBER TO ASSIGN AND FREE WHEN USED
__attribute__((warn_unused_result))
String join(RArr<String> inputs, String separator,
Allocator allocator = {}, bool null_terminate = false);
//
// Split
RArr<String> split(String text, String separator, bool reversed = false, i64 max_results = 0,
bool skip_empty = false, bool keep_separator = false, Allocator = {}) __attribute__((warn_unused_result));
//
// sprint
// @Important: REMEMBER TO ASSIGN AND FREE WHEN USED
template <typename... Args>
__attribute__((warn_unused_result))
String sprint(String fmt, Args... args) // Hastily done because snprintf is very complicated :(
{
// @Fixme: For now, it uses the context allocator
Allocator a = get_allocator();
String result;
const i64 RESULTING_LENGTH = snprintf(NULL, 0, (char*)(fmt.data), args...);
result.data = (unsigned char*)(a.proc(Allocator_Mode::ALLOCATE, RESULTING_LENGTH + 1, 0, NULL, a.data));
result.count = RESULTING_LENGTH;
assert((snprintf((char*)(result.data), RESULTING_LENGTH + 1,
(char*)(fmt.data), args...) == result.count));
return result;
}
//
// tprint: uses the temporary storage allocator
template <typename... Args>
__attribute__((warn_unused_result))
String tprint(String fmt, Args... args)
{
Allocator a = {global_context.temporary_storage, __temporary_allocator};
String result;
const i64 RESULTING_LENGTH = snprintf(NULL, 0, (char*)(fmt.data), args...);
result.data = (unsigned char*)(a.proc(Allocator_Mode::ALLOCATE, RESULTING_LENGTH + 1, 0, NULL, a.data));
result.count = RESULTING_LENGTH;
assert((snprintf((char*)(result.data), RESULTING_LENGTH + 1,
(char*)(fmt.data), args...) == result.count));
return result;
}
__attribute__((warn_unused_result))
my_pair<String, bool> copy_substring(String s, i64 index, i64 bytes, Allocator allocator = {});