natalie_parser 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +22 -0
- data/Dockerfile +26 -0
- data/Gemfile +10 -0
- data/LICENSE +21 -0
- data/README.md +55 -0
- data/Rakefile +242 -0
- data/ext/natalie_parser/extconf.rb +9 -0
- data/ext/natalie_parser/mri_creator.hpp +139 -0
- data/ext/natalie_parser/natalie_parser.cpp +144 -0
- data/include/natalie_parser/creator/debug_creator.hpp +113 -0
- data/include/natalie_parser/creator.hpp +108 -0
- data/include/natalie_parser/lexer/interpolated_string_lexer.hpp +64 -0
- data/include/natalie_parser/lexer/regexp_lexer.hpp +37 -0
- data/include/natalie_parser/lexer/word_array_lexer.hpp +57 -0
- data/include/natalie_parser/lexer.hpp +135 -0
- data/include/natalie_parser/node/alias_node.hpp +35 -0
- data/include/natalie_parser/node/arg_node.hpp +74 -0
- data/include/natalie_parser/node/array_node.hpp +34 -0
- data/include/natalie_parser/node/array_pattern_node.hpp +28 -0
- data/include/natalie_parser/node/assignment_node.hpp +34 -0
- data/include/natalie_parser/node/back_ref_node.hpp +28 -0
- data/include/natalie_parser/node/begin_block_node.hpp +25 -0
- data/include/natalie_parser/node/begin_node.hpp +52 -0
- data/include/natalie_parser/node/begin_rescue_node.hpp +47 -0
- data/include/natalie_parser/node/bignum_node.hpp +37 -0
- data/include/natalie_parser/node/block_node.hpp +55 -0
- data/include/natalie_parser/node/block_pass_node.hpp +33 -0
- data/include/natalie_parser/node/break_node.hpp +32 -0
- data/include/natalie_parser/node/call_node.hpp +85 -0
- data/include/natalie_parser/node/case_in_node.hpp +40 -0
- data/include/natalie_parser/node/case_node.hpp +52 -0
- data/include/natalie_parser/node/case_when_node.hpp +43 -0
- data/include/natalie_parser/node/class_node.hpp +39 -0
- data/include/natalie_parser/node/colon2_node.hpp +44 -0
- data/include/natalie_parser/node/colon3_node.hpp +34 -0
- data/include/natalie_parser/node/constant_node.hpp +26 -0
- data/include/natalie_parser/node/def_node.hpp +55 -0
- data/include/natalie_parser/node/defined_node.hpp +33 -0
- data/include/natalie_parser/node/encoding_node.hpp +26 -0
- data/include/natalie_parser/node/end_block_node.hpp +25 -0
- data/include/natalie_parser/node/evaluate_to_string_node.hpp +37 -0
- data/include/natalie_parser/node/false_node.hpp +23 -0
- data/include/natalie_parser/node/fixnum_node.hpp +36 -0
- data/include/natalie_parser/node/float_node.hpp +36 -0
- data/include/natalie_parser/node/hash_node.hpp +34 -0
- data/include/natalie_parser/node/hash_pattern_node.hpp +27 -0
- data/include/natalie_parser/node/identifier_node.hpp +123 -0
- data/include/natalie_parser/node/if_node.hpp +43 -0
- data/include/natalie_parser/node/infix_op_node.hpp +46 -0
- data/include/natalie_parser/node/interpolated_node.hpp +33 -0
- data/include/natalie_parser/node/interpolated_regexp_node.hpp +28 -0
- data/include/natalie_parser/node/interpolated_shell_node.hpp +22 -0
- data/include/natalie_parser/node/interpolated_string_node.hpp +31 -0
- data/include/natalie_parser/node/interpolated_symbol_key_node.hpp +18 -0
- data/include/natalie_parser/node/interpolated_symbol_node.hpp +28 -0
- data/include/natalie_parser/node/iter_node.hpp +45 -0
- data/include/natalie_parser/node/keyword_arg_node.hpp +25 -0
- data/include/natalie_parser/node/keyword_splat_node.hpp +38 -0
- data/include/natalie_parser/node/logical_and_node.hpp +40 -0
- data/include/natalie_parser/node/logical_or_node.hpp +40 -0
- data/include/natalie_parser/node/match_node.hpp +38 -0
- data/include/natalie_parser/node/module_node.hpp +32 -0
- data/include/natalie_parser/node/multiple_assignment_arg_node.hpp +32 -0
- data/include/natalie_parser/node/multiple_assignment_node.hpp +37 -0
- data/include/natalie_parser/node/next_node.hpp +37 -0
- data/include/natalie_parser/node/nil_node.hpp +23 -0
- data/include/natalie_parser/node/nil_sexp_node.hpp +23 -0
- data/include/natalie_parser/node/node.hpp +155 -0
- data/include/natalie_parser/node/node_with_args.hpp +47 -0
- data/include/natalie_parser/node/not_match_node.hpp +35 -0
- data/include/natalie_parser/node/not_node.hpp +37 -0
- data/include/natalie_parser/node/nth_ref_node.hpp +27 -0
- data/include/natalie_parser/node/op_assign_accessor_node.hpp +74 -0
- data/include/natalie_parser/node/op_assign_and_node.hpp +34 -0
- data/include/natalie_parser/node/op_assign_node.hpp +47 -0
- data/include/natalie_parser/node/op_assign_or_node.hpp +34 -0
- data/include/natalie_parser/node/pin_node.hpp +33 -0
- data/include/natalie_parser/node/range_node.hpp +52 -0
- data/include/natalie_parser/node/redo_node.hpp +20 -0
- data/include/natalie_parser/node/regexp_node.hpp +36 -0
- data/include/natalie_parser/node/retry_node.hpp +20 -0
- data/include/natalie_parser/node/return_node.hpp +34 -0
- data/include/natalie_parser/node/safe_call_node.hpp +31 -0
- data/include/natalie_parser/node/sclass_node.hpp +37 -0
- data/include/natalie_parser/node/self_node.hpp +23 -0
- data/include/natalie_parser/node/shadow_arg_node.hpp +40 -0
- data/include/natalie_parser/node/shell_node.hpp +32 -0
- data/include/natalie_parser/node/splat_node.hpp +39 -0
- data/include/natalie_parser/node/splat_value_node.hpp +32 -0
- data/include/natalie_parser/node/stabby_proc_node.hpp +29 -0
- data/include/natalie_parser/node/string_node.hpp +42 -0
- data/include/natalie_parser/node/super_node.hpp +44 -0
- data/include/natalie_parser/node/symbol_key_node.hpp +19 -0
- data/include/natalie_parser/node/symbol_node.hpp +30 -0
- data/include/natalie_parser/node/to_array_node.hpp +33 -0
- data/include/natalie_parser/node/true_node.hpp +23 -0
- data/include/natalie_parser/node/unary_op_node.hpp +41 -0
- data/include/natalie_parser/node/undef_node.hpp +31 -0
- data/include/natalie_parser/node/until_node.hpp +21 -0
- data/include/natalie_parser/node/while_node.hpp +52 -0
- data/include/natalie_parser/node/yield_node.hpp +29 -0
- data/include/natalie_parser/node.hpp +89 -0
- data/include/natalie_parser/parser.hpp +218 -0
- data/include/natalie_parser/token.hpp +842 -0
- data/include/tm/defer.hpp +34 -0
- data/include/tm/hashmap.hpp +826 -0
- data/include/tm/macros.hpp +16 -0
- data/include/tm/optional.hpp +223 -0
- data/include/tm/owned_ptr.hpp +186 -0
- data/include/tm/recursion_guard.hpp +156 -0
- data/include/tm/shared_ptr.hpp +259 -0
- data/include/tm/string.hpp +1447 -0
- data/include/tm/tests.hpp +78 -0
- data/include/tm/vector.hpp +796 -0
- data/lib/natalie_parser/sexp.rb +36 -0
- data/lib/natalie_parser/version.rb +5 -0
- data/lib/natalie_parser.rb +3 -0
- data/natalie_parser.gemspec +23 -0
- data/src/lexer/interpolated_string_lexer.cpp +88 -0
- data/src/lexer/regexp_lexer.cpp +95 -0
- data/src/lexer/word_array_lexer.cpp +134 -0
- data/src/lexer.cpp +1703 -0
- data/src/node/alias_node.cpp +11 -0
- data/src/node/assignment_node.cpp +33 -0
- data/src/node/begin_node.cpp +29 -0
- data/src/node/begin_rescue_node.cpp +33 -0
- data/src/node/class_node.cpp +22 -0
- data/src/node/interpolated_regexp_node.cpp +19 -0
- data/src/node/interpolated_shell_node.cpp +25 -0
- data/src/node/interpolated_string_node.cpp +111 -0
- data/src/node/interpolated_symbol_node.cpp +25 -0
- data/src/node/match_node.cpp +14 -0
- data/src/node/module_node.cpp +21 -0
- data/src/node/multiple_assignment_node.cpp +37 -0
- data/src/node/node.cpp +10 -0
- data/src/node/node_with_args.cpp +35 -0
- data/src/node/op_assign_node.cpp +36 -0
- data/src/node/string_node.cpp +33 -0
- data/src/parser.cpp +2972 -0
- data/src/token.cpp +27 -0
- metadata +186 -0
|
@@ -0,0 +1,796 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <assert.h>
|
|
5
|
+
#include <initializer_list>
|
|
6
|
+
#include <stddef.h>
|
|
7
|
+
#include <string.h>
|
|
8
|
+
#include <type_traits>
|
|
9
|
+
|
|
10
|
+
namespace TM {
|
|
11
|
+
|
|
12
|
+
const int VECTOR_GROW_FACTOR = 2;
|
|
13
|
+
const int VECTOR_MIN_CAPACITY = 10;
|
|
14
|
+
|
|
15
|
+
template <typename T>
|
|
16
|
+
class Vector {
|
|
17
|
+
public:
|
|
18
|
+
/**
|
|
19
|
+
* Constructs an empty vector with the default capacity.
|
|
20
|
+
*
|
|
21
|
+
* ```
|
|
22
|
+
* auto vec = Vector<char> {};
|
|
23
|
+
* assert_eq(0, vec.size());
|
|
24
|
+
* assert_eq(10, vec.capacity());
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
Vector()
|
|
28
|
+
: m_capacity { VECTOR_MIN_CAPACITY }
|
|
29
|
+
, m_data { array_of_size(VECTOR_MIN_CAPACITY) } { }
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Constructs an empty vector with the given capacity.
|
|
33
|
+
*
|
|
34
|
+
* ```
|
|
35
|
+
* auto vec = Vector<char>(1);
|
|
36
|
+
* assert_eq(0, vec.size());
|
|
37
|
+
* assert_eq(1, vec.capacity());
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
Vector(size_t initial_capacity)
|
|
41
|
+
: m_capacity { initial_capacity }
|
|
42
|
+
, m_data { array_of_size(initial_capacity) } { }
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Constructs a vector with the given size
|
|
46
|
+
* and every slot filled with the given filler object.
|
|
47
|
+
*
|
|
48
|
+
* ```
|
|
49
|
+
* auto vec = Vector<char>(10, 'a');
|
|
50
|
+
* assert_eq(10, vec.size());
|
|
51
|
+
* assert_eq('a', vec[0]);
|
|
52
|
+
* assert_eq('a', vec[9]);
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
Vector(size_t size, T filler)
|
|
56
|
+
: m_size { size }
|
|
57
|
+
, m_capacity { size }
|
|
58
|
+
, m_data { array_of_size(size) } {
|
|
59
|
+
fill(0, size, filler);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Constructs a vector with the given list of items.
|
|
64
|
+
*
|
|
65
|
+
* ```
|
|
66
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
67
|
+
* assert_eq(3, vec.size());
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
Vector(std::initializer_list<T> list)
|
|
71
|
+
: m_capacity { list.size() }
|
|
72
|
+
, m_data { array_of_size(list.size()) } {
|
|
73
|
+
for (auto v : list) {
|
|
74
|
+
push(v);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Constructs a vector by copying data from another vector.
|
|
80
|
+
*
|
|
81
|
+
* ```
|
|
82
|
+
* auto vec1 = Vector<char> { 'a', 'b', 'c' };
|
|
83
|
+
* auto vec2 = Vector<char>(vec1);
|
|
84
|
+
* assert_eq(3, vec2.size());
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
Vector(const Vector &other)
|
|
88
|
+
: m_size { other.m_size }
|
|
89
|
+
, m_capacity { other.m_size }
|
|
90
|
+
, m_data { array_of_size(other.m_size) } {
|
|
91
|
+
copy_data(m_data, other.m_data, other.m_size);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
~Vector() {
|
|
95
|
+
delete_memory();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Deletes all the items in the vector.
|
|
100
|
+
*
|
|
101
|
+
* ```
|
|
102
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
103
|
+
* vec.clear();
|
|
104
|
+
* assert_eq(0, vec.size());
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
void clear() { m_size = 0; }
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Returns a new vector from the given offset and count.
|
|
111
|
+
*
|
|
112
|
+
* ```
|
|
113
|
+
* auto vec1 = Vector<char> { 'a', 'b', 'c', 'd', 'e' };
|
|
114
|
+
* auto vec2 = vec1.slice(2, 2);
|
|
115
|
+
* assert_eq(2, vec2.size());
|
|
116
|
+
* assert_eq('c', vec2[0]);
|
|
117
|
+
* assert_eq('d', vec2[1]);
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* If `count` is not specified, then the returned vector
|
|
121
|
+
* will include all items from the index to the end.
|
|
122
|
+
*
|
|
123
|
+
* ```
|
|
124
|
+
* auto vec1 = Vector<char> { 'a', 'b', 'c', 'd', 'e' };
|
|
125
|
+
* auto vec2 = vec1.slice(2);
|
|
126
|
+
* assert_eq(3, vec2.size());
|
|
127
|
+
* assert_eq('c', vec2[0]);
|
|
128
|
+
* assert_eq('d', vec2[1]);
|
|
129
|
+
* assert_eq('e', vec2[2]);
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
Vector slice(size_t offset, size_t count = 0) {
|
|
133
|
+
if (count == 0 || offset + count > m_size) {
|
|
134
|
+
count = m_size - offset;
|
|
135
|
+
}
|
|
136
|
+
if (offset >= m_size || count == 0) {
|
|
137
|
+
return {};
|
|
138
|
+
}
|
|
139
|
+
T *data = array_of_size(count);
|
|
140
|
+
copy_data(data, m_data + offset, count);
|
|
141
|
+
return { count, count, data };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Overwrites the vector data with that of another vector.
|
|
146
|
+
*
|
|
147
|
+
* ```
|
|
148
|
+
* auto vec1 = Vector<char> { 'a', 'b', 'c' };
|
|
149
|
+
* auto vec2 = Vector<char> { 'x', 'y', 'z' };
|
|
150
|
+
* vec1 = vec2;
|
|
151
|
+
* assert_eq('y', vec1[1]);
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* This method handles non-trivially-copyable types as well:
|
|
155
|
+
*
|
|
156
|
+
* ```
|
|
157
|
+
* auto t1 = Thing(1);
|
|
158
|
+
* auto t2 = Thing(2);
|
|
159
|
+
* auto t3 = Thing(3);
|
|
160
|
+
* auto vec1 = Vector<Thing> { t1, t2, t3 };
|
|
161
|
+
* auto vec2 = Vector<Thing> { t3, t2, t1 };
|
|
162
|
+
* vec1 = vec2;
|
|
163
|
+
* assert_eq(3, vec1.size());
|
|
164
|
+
* assert_eq(t3, vec1[0]);
|
|
165
|
+
* assert_eq(t2, vec1[1]);
|
|
166
|
+
* assert_eq(t1, vec1[2]);
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
Vector &operator=(Vector &other) {
|
|
170
|
+
clear();
|
|
171
|
+
grow_at_least(other.m_size);
|
|
172
|
+
copy_data(m_data, other.m_data, other.m_size);
|
|
173
|
+
m_size = other.m_size;
|
|
174
|
+
return *this;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Moves another vector's data into this one.
|
|
179
|
+
* The other vector is left empty.
|
|
180
|
+
*
|
|
181
|
+
* ```
|
|
182
|
+
* auto vec1 = Vector<char> { 'a', 'b', 'c' };
|
|
183
|
+
* auto vec2 = Vector<char> { 'x', 'y', 'z' };
|
|
184
|
+
* vec1 = std::move(vec2);
|
|
185
|
+
* assert_eq('y', vec1[1]);
|
|
186
|
+
* assert_eq(0, vec2.size());
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
Vector &operator=(Vector &&other) {
|
|
190
|
+
delete_memory();
|
|
191
|
+
m_size = other.m_size;
|
|
192
|
+
m_capacity = other.m_capacity;
|
|
193
|
+
m_data = other.m_data;
|
|
194
|
+
other.m_data = nullptr;
|
|
195
|
+
other.m_size = 0;
|
|
196
|
+
other.m_capacity = 0;
|
|
197
|
+
return *this;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Returns a reference to the value at the given index.
|
|
202
|
+
*
|
|
203
|
+
* ```
|
|
204
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
205
|
+
* assert_eq('b', vec[1]);
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* WARNING: This method does *not* check that the given
|
|
209
|
+
* index is within the bounds of the vector!
|
|
210
|
+
*/
|
|
211
|
+
T &operator[](size_t index) const {
|
|
212
|
+
return m_data[index];
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Returns a reference to the value at the given index.
|
|
217
|
+
*
|
|
218
|
+
* ```
|
|
219
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
220
|
+
* assert_eq('b', vec.at(1));
|
|
221
|
+
* ```
|
|
222
|
+
*
|
|
223
|
+
* If the vector is empty, then this method aborts.
|
|
224
|
+
*
|
|
225
|
+
* ```should_abort
|
|
226
|
+
* auto vec = Vector<char> {};
|
|
227
|
+
* vec.at(0);
|
|
228
|
+
* ```
|
|
229
|
+
*/
|
|
230
|
+
T &at(size_t index) const {
|
|
231
|
+
assert(index < m_size);
|
|
232
|
+
return m_data[index];
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Returns the value at the front (index 0).
|
|
237
|
+
*
|
|
238
|
+
* ```
|
|
239
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
240
|
+
* assert_eq('a', vec.first());
|
|
241
|
+
* ```
|
|
242
|
+
*
|
|
243
|
+
* If the vector is empty, then this method aborts.
|
|
244
|
+
*
|
|
245
|
+
* ```should_abort
|
|
246
|
+
* auto vec = Vector<char> {};
|
|
247
|
+
* vec.first();
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
T &first() const {
|
|
251
|
+
assert(m_size != 0);
|
|
252
|
+
return m_data[0];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Returns the value at the end (at index size() - 1).
|
|
257
|
+
*
|
|
258
|
+
* ```
|
|
259
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
260
|
+
* assert_eq('c', vec.last());
|
|
261
|
+
* ```
|
|
262
|
+
*
|
|
263
|
+
* If the vector is empty, then this method aborts.
|
|
264
|
+
*
|
|
265
|
+
* ```should_abort
|
|
266
|
+
* auto vec = Vector<char> {};
|
|
267
|
+
* vec.last();
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
T &last() const {
|
|
271
|
+
assert(m_size != 0);
|
|
272
|
+
return m_data[m_size - 1];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Removes and returns the value at the end (at index size() - 1).
|
|
277
|
+
*
|
|
278
|
+
* ```
|
|
279
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
280
|
+
* assert_eq('c', vec.pop());
|
|
281
|
+
* ```
|
|
282
|
+
*
|
|
283
|
+
* If the vector is empty, then this method aborts.
|
|
284
|
+
*
|
|
285
|
+
* ```should_abort
|
|
286
|
+
* auto vec = Vector<char> {};
|
|
287
|
+
* vec.pop();
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
T pop() {
|
|
291
|
+
assert(m_size != 0);
|
|
292
|
+
return m_data[--m_size];
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Pushes (appends) a value at the end (at index size()).
|
|
297
|
+
*
|
|
298
|
+
* ```
|
|
299
|
+
* auto vec = Vector<char> { 'a' };
|
|
300
|
+
* vec.push('b');
|
|
301
|
+
* assert_eq('a', vec[0]);
|
|
302
|
+
* assert_eq('b', vec[1]);
|
|
303
|
+
* ```
|
|
304
|
+
*/
|
|
305
|
+
void push(T val) {
|
|
306
|
+
size_t len = m_size;
|
|
307
|
+
if (m_size >= m_capacity) {
|
|
308
|
+
grow_at_least(m_size + 1);
|
|
309
|
+
}
|
|
310
|
+
m_size++;
|
|
311
|
+
m_data[len] = val;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Pushes (inserts) a value at the front (index 0).
|
|
316
|
+
*
|
|
317
|
+
* ```
|
|
318
|
+
* auto vec = Vector<char> { 'b' };
|
|
319
|
+
* vec.push_front('a');
|
|
320
|
+
* assert_eq('a', vec[0]);
|
|
321
|
+
* ```
|
|
322
|
+
*/
|
|
323
|
+
void push_front(T val) {
|
|
324
|
+
insert(0, val);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Inserts a value at the given index.
|
|
329
|
+
* Index must be <= the size of the vector,
|
|
330
|
+
* i.e. you can only increase the vector size by one.
|
|
331
|
+
*
|
|
332
|
+
* ```
|
|
333
|
+
* auto vec = Vector<char>(0);
|
|
334
|
+
* vec.insert(0, 'a');
|
|
335
|
+
* vec.insert(1, 'b');
|
|
336
|
+
* vec.insert(0, 'c');
|
|
337
|
+
* assert_eq(3, vec.size());
|
|
338
|
+
* assert_eq('c', vec[0]);
|
|
339
|
+
* assert_eq('a', vec[1]);
|
|
340
|
+
* assert_eq('b', vec[2]);
|
|
341
|
+
* ```
|
|
342
|
+
*
|
|
343
|
+
* This method aborts if the given index is more than 1
|
|
344
|
+
* past the end.
|
|
345
|
+
*
|
|
346
|
+
* ```should_abort
|
|
347
|
+
* auto vec = Vector<char> { 0 };
|
|
348
|
+
* vec.insert(25, 'z'); // beyond the end
|
|
349
|
+
* ```
|
|
350
|
+
*
|
|
351
|
+
* This method handles non-trivially-copyable types as well:
|
|
352
|
+
*
|
|
353
|
+
* ```
|
|
354
|
+
* auto t1 = Thing(1);
|
|
355
|
+
* auto t2 = Thing(2);
|
|
356
|
+
* auto t3 = Thing(3);
|
|
357
|
+
* auto vec = Vector<Thing> { t1, t2 };
|
|
358
|
+
* vec.insert(0, t3);
|
|
359
|
+
* assert_eq(3, vec.size());
|
|
360
|
+
* assert_eq(t3, vec[0]);
|
|
361
|
+
* assert_eq(t1, vec[1]);
|
|
362
|
+
* assert_eq(t2, vec[2]);
|
|
363
|
+
* ```
|
|
364
|
+
*/
|
|
365
|
+
void insert(size_t index, T val) {
|
|
366
|
+
assert(index <= m_size);
|
|
367
|
+
grow_at_least(m_size + 1);
|
|
368
|
+
|
|
369
|
+
if (index == m_size) {
|
|
370
|
+
m_size++;
|
|
371
|
+
m_data[index] = val;
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if constexpr (std::is_trivially_copyable<T>::value) {
|
|
376
|
+
memmove(m_data + index + 1, m_data + index, (m_size - index) * sizeof(T));
|
|
377
|
+
} else {
|
|
378
|
+
for (size_t i = m_size - 1; i > index; --i)
|
|
379
|
+
m_data[i + 1] = m_data[i];
|
|
380
|
+
m_data[index + 1] = m_data[index];
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
m_data[index] = val;
|
|
384
|
+
m_size++;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Removes the item from the front (index 0)
|
|
389
|
+
* and shifts all remaining items over.
|
|
390
|
+
*
|
|
391
|
+
* ```
|
|
392
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
393
|
+
* assert_eq('a', vec.pop_front());
|
|
394
|
+
* ```
|
|
395
|
+
*
|
|
396
|
+
* This method aborts if the vector is empty.
|
|
397
|
+
*
|
|
398
|
+
* ```should_abort
|
|
399
|
+
* auto vec = Vector<char> {};
|
|
400
|
+
* vec.pop_front();
|
|
401
|
+
* ```
|
|
402
|
+
*/
|
|
403
|
+
T pop_front() {
|
|
404
|
+
T val = m_data[0];
|
|
405
|
+
remove(0);
|
|
406
|
+
return val;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Removes an item from the vector at the given index;
|
|
411
|
+
*
|
|
412
|
+
* ```
|
|
413
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
414
|
+
* vec.remove(1);
|
|
415
|
+
* assert_eq('c', vec[1]);
|
|
416
|
+
* ```
|
|
417
|
+
*
|
|
418
|
+
* This method aborts if the index is past the end.
|
|
419
|
+
*
|
|
420
|
+
* ```should_abort
|
|
421
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
422
|
+
* vec.remove(3);
|
|
423
|
+
* ```
|
|
424
|
+
*
|
|
425
|
+
* This method handles non-trivially-copyable types as well:
|
|
426
|
+
*
|
|
427
|
+
* ```
|
|
428
|
+
* auto t1 = Thing(1);
|
|
429
|
+
* auto t2 = Thing(2);
|
|
430
|
+
* auto vec = Vector<Thing> { t1, t2 };
|
|
431
|
+
* vec.remove(0);
|
|
432
|
+
* assert_eq(1, vec.size());
|
|
433
|
+
* assert_eq(t2, vec[0]);
|
|
434
|
+
* ```
|
|
435
|
+
*/
|
|
436
|
+
void remove(size_t index) {
|
|
437
|
+
assert(m_size > index);
|
|
438
|
+
|
|
439
|
+
--m_size;
|
|
440
|
+
|
|
441
|
+
if (index == m_size)
|
|
442
|
+
return;
|
|
443
|
+
|
|
444
|
+
if constexpr (std::is_trivially_copyable<T>::value) {
|
|
445
|
+
memmove(m_data + index, m_data + index + 1, (m_size - index) * sizeof(T));
|
|
446
|
+
} else {
|
|
447
|
+
for (size_t i = index; i < m_size; ++i)
|
|
448
|
+
m_data[i] = m_data[i + 1];
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Returns true if the vector has no items.
|
|
454
|
+
*
|
|
455
|
+
* ```
|
|
456
|
+
* auto vec1 = Vector<char> { 'a', 'b', 'c' };
|
|
457
|
+
* assert_eq(false, vec1.is_empty());
|
|
458
|
+
*
|
|
459
|
+
* auto vec2 = Vector<char> {};
|
|
460
|
+
* assert_eq(true, vec2.is_empty());
|
|
461
|
+
* ```
|
|
462
|
+
*/
|
|
463
|
+
bool is_empty() const { return m_size == 0; }
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Returns the number of items stored in the vector.
|
|
467
|
+
*
|
|
468
|
+
* ```
|
|
469
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
470
|
+
* assert_eq(3, vec.size());
|
|
471
|
+
* ```
|
|
472
|
+
*/
|
|
473
|
+
size_t size() const { return m_size; }
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Returns the size of the currently allocated storage array.
|
|
477
|
+
*
|
|
478
|
+
* ```
|
|
479
|
+
* auto vec = Vector<char>(10);
|
|
480
|
+
* assert_eq(10, vec.capacity());
|
|
481
|
+
* ```
|
|
482
|
+
*/
|
|
483
|
+
size_t capacity() const { return m_capacity; }
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Return a pointer to the underlying storage array.
|
|
487
|
+
*
|
|
488
|
+
* ```
|
|
489
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
490
|
+
* char *ary = vec.data();
|
|
491
|
+
* assert_eq('b', ary[1]);
|
|
492
|
+
* ```
|
|
493
|
+
*/
|
|
494
|
+
T *data() { return m_data; }
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Fill the given range with a filler value.
|
|
498
|
+
*
|
|
499
|
+
* The 'to' index is exclusive.
|
|
500
|
+
*
|
|
501
|
+
* ```
|
|
502
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
503
|
+
* vec.fill(1, 3, 'z');
|
|
504
|
+
* assert_eq('a', vec[0]);
|
|
505
|
+
* assert_eq('z', vec[1]);
|
|
506
|
+
* assert_eq('z', vec[2]);
|
|
507
|
+
* ```
|
|
508
|
+
*
|
|
509
|
+
* This method aborts if the 'to' index is past the end.
|
|
510
|
+
*
|
|
511
|
+
* ```should_abort
|
|
512
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
513
|
+
* vec.fill(0, 10, 'z');
|
|
514
|
+
* ```
|
|
515
|
+
*/
|
|
516
|
+
void fill(size_t from, size_t to_exclusive, T filler) {
|
|
517
|
+
assert(to_exclusive <= m_size);
|
|
518
|
+
for (size_t i = from; i < to_exclusive; i++) {
|
|
519
|
+
m_data[i] = filler;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Shrink the vector.
|
|
525
|
+
*
|
|
526
|
+
* ```
|
|
527
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
528
|
+
* vec.set_size(2);
|
|
529
|
+
* assert_eq(2, vec.size());
|
|
530
|
+
* assert_eq('a', vec[0]);
|
|
531
|
+
* assert_eq('b', vec[1]);
|
|
532
|
+
* ```
|
|
533
|
+
*
|
|
534
|
+
* This method aborts if the new size is larger.
|
|
535
|
+
*
|
|
536
|
+
* ```should_abort
|
|
537
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
538
|
+
* vec.set_size(10);
|
|
539
|
+
* ```
|
|
540
|
+
*/
|
|
541
|
+
void set_size(size_t new_size) {
|
|
542
|
+
assert(new_size <= m_size);
|
|
543
|
+
grow(new_size);
|
|
544
|
+
m_size = new_size;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Grow or shrink the vector.
|
|
549
|
+
* New slots will be filled with the param `filler`.
|
|
550
|
+
*
|
|
551
|
+
* ```
|
|
552
|
+
* auto vec = Vector<char> { 'a', 'b', 'c' };
|
|
553
|
+
* vec.set_size(10, 'z'); // grow
|
|
554
|
+
* assert_eq('z', vec[9]);
|
|
555
|
+
*
|
|
556
|
+
* vec.set_size(2, 'x'); // shrink
|
|
557
|
+
* assert_eq(2, vec.size());
|
|
558
|
+
* assert_eq('a', vec[0]);
|
|
559
|
+
* assert_eq('b', vec[1]);
|
|
560
|
+
* ```
|
|
561
|
+
*/
|
|
562
|
+
void set_size(size_t new_size, T filler) {
|
|
563
|
+
grow(new_size);
|
|
564
|
+
size_t old_size = m_size;
|
|
565
|
+
m_size = new_size;
|
|
566
|
+
fill(old_size, new_size, filler);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Grow the capacity (allocated memory) of the vector.
|
|
571
|
+
*
|
|
572
|
+
* ```
|
|
573
|
+
* auto vec = Vector<char> {};
|
|
574
|
+
* vec.set_capacity(100);
|
|
575
|
+
* assert_eq(100, vec.capacity());
|
|
576
|
+
* ```
|
|
577
|
+
*/
|
|
578
|
+
void set_capacity(size_t new_size) {
|
|
579
|
+
grow_at_least(new_size);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
class iterator {
|
|
583
|
+
public:
|
|
584
|
+
iterator(const Vector<T> *vector, size_t index)
|
|
585
|
+
: m_vector { vector }
|
|
586
|
+
, m_index { index } { }
|
|
587
|
+
|
|
588
|
+
iterator operator++() {
|
|
589
|
+
m_index++;
|
|
590
|
+
return *this;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
iterator operator++(int) {
|
|
594
|
+
iterator i = *this;
|
|
595
|
+
m_index++;
|
|
596
|
+
return i;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
T &operator*() { return m_vector->m_data[m_index]; }
|
|
600
|
+
T *operator->() { return m_vector->m_data[m_index]; }
|
|
601
|
+
|
|
602
|
+
friend bool operator==(const iterator &i1, const iterator &i2) {
|
|
603
|
+
return i1.m_vector == i2.m_vector && i1.m_index == i2.m_index;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
friend bool operator!=(const iterator &i1, const iterator &i2) {
|
|
607
|
+
return i1.m_vector != i2.m_vector || i1.m_index != i2.m_index;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
private:
|
|
611
|
+
const Vector<T> *m_vector;
|
|
612
|
+
size_t m_index { 0 };
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Returns an iterator over the vector.
|
|
617
|
+
*
|
|
618
|
+
* ```
|
|
619
|
+
* auto vec1 = Vector<char> { 'a', 'b', 'c' };
|
|
620
|
+
* auto vec2 = Vector<char> {};
|
|
621
|
+
* for (auto c : vec1) {
|
|
622
|
+
* vec2.push(c);
|
|
623
|
+
* }
|
|
624
|
+
* assert_eq('a', vec2[0]);
|
|
625
|
+
* assert_eq('b', vec2[1]);
|
|
626
|
+
* assert_eq('c', vec2[2]);
|
|
627
|
+
* ```
|
|
628
|
+
*/
|
|
629
|
+
iterator begin() {
|
|
630
|
+
return iterator { this, 0 };
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
iterator begin() const {
|
|
634
|
+
return iterator { this, 0 };
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
iterator end() {
|
|
638
|
+
return iterator { this, m_size };
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
iterator end() const {
|
|
642
|
+
return iterator { this, m_size };
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Sorts the vector using the given lambda or callable type.
|
|
647
|
+
*
|
|
648
|
+
* ```
|
|
649
|
+
* auto vec = Vector<char> { 'b', 'c', 'a' };
|
|
650
|
+
* vec.sort([](char a, char b) { return a - b < 0; });
|
|
651
|
+
* assert_eq('a', vec[0]);
|
|
652
|
+
* assert_eq('b', vec[1]);
|
|
653
|
+
* assert_eq('c', vec[2]);
|
|
654
|
+
* ```
|
|
655
|
+
*/
|
|
656
|
+
template <typename F>
|
|
657
|
+
void sort(F cmp) {
|
|
658
|
+
quicksort(0, m_size - 1, cmp);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
protected:
|
|
662
|
+
Vector(size_t size, size_t capacity, T *data)
|
|
663
|
+
: m_size(size)
|
|
664
|
+
, m_capacity(capacity)
|
|
665
|
+
, m_data(data) { }
|
|
666
|
+
|
|
667
|
+
static T *array_of_size(size_t size) {
|
|
668
|
+
if constexpr (std::is_trivially_copyable<T>::value)
|
|
669
|
+
return reinterpret_cast<T *>(malloc(size * sizeof(T)));
|
|
670
|
+
else
|
|
671
|
+
return new T[size] {};
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
void grow(size_t capacity) {
|
|
675
|
+
if (m_capacity >= capacity)
|
|
676
|
+
return;
|
|
677
|
+
if constexpr (std::is_trivially_copyable<T>::value) {
|
|
678
|
+
m_data = static_cast<T *>(realloc(m_data, capacity * sizeof(T)));
|
|
679
|
+
} else {
|
|
680
|
+
auto old_data = m_data;
|
|
681
|
+
m_data = new T[capacity] {};
|
|
682
|
+
for (size_t i = 0; i < m_size; ++i)
|
|
683
|
+
m_data[i] = old_data[i];
|
|
684
|
+
delete[] old_data;
|
|
685
|
+
}
|
|
686
|
+
m_capacity = capacity;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
void grow_at_least(size_t min_capacity) {
|
|
690
|
+
if (m_capacity >= min_capacity) {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
if (m_capacity > 0 && min_capacity <= m_capacity * VECTOR_GROW_FACTOR) {
|
|
694
|
+
grow(m_capacity * VECTOR_GROW_FACTOR);
|
|
695
|
+
} else {
|
|
696
|
+
grow(min_capacity);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
template <typename F>
|
|
701
|
+
void quicksort(int start, int end, F cmp) {
|
|
702
|
+
if (start >= end) return;
|
|
703
|
+
int p_index = quicksort_partition(start, end, cmp);
|
|
704
|
+
quicksort(start, p_index - 1, cmp);
|
|
705
|
+
quicksort(p_index + 1, end, cmp);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
template <typename F>
|
|
709
|
+
int quicksort_partition(int start, int end, F cmp) {
|
|
710
|
+
T pivot = m_data[end];
|
|
711
|
+
int p_index = start;
|
|
712
|
+
T temp;
|
|
713
|
+
|
|
714
|
+
for (int i = start; i < end; i++) {
|
|
715
|
+
if (cmp(m_data[i], pivot)) {
|
|
716
|
+
temp = m_data[i];
|
|
717
|
+
m_data[i] = m_data[p_index];
|
|
718
|
+
m_data[p_index] = temp;
|
|
719
|
+
p_index++;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
temp = m_data[end];
|
|
723
|
+
m_data[end] = m_data[p_index];
|
|
724
|
+
m_data[p_index] = temp;
|
|
725
|
+
return p_index;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
void copy_data(T *dest, T *src, size_t size) {
|
|
729
|
+
if constexpr (std::is_trivially_copyable<T>::value) {
|
|
730
|
+
memcpy(dest, src, sizeof(T) * size);
|
|
731
|
+
} else {
|
|
732
|
+
for (size_t i = 0; i < size; ++i)
|
|
733
|
+
dest[i] = src[i];
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
void delete_memory() {
|
|
738
|
+
if constexpr (std::is_trivially_copyable<T>::value)
|
|
739
|
+
free(m_data);
|
|
740
|
+
else
|
|
741
|
+
delete[] m_data;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
size_t m_size { 0 };
|
|
745
|
+
size_t m_capacity { 0 };
|
|
746
|
+
T *m_data { nullptr };
|
|
747
|
+
};
|
|
748
|
+
|
|
749
|
+
template <typename T>
|
|
750
|
+
class OwnedVector : public Vector<T> {
|
|
751
|
+
public:
|
|
752
|
+
/**
|
|
753
|
+
* Constructs an empty OwnedVector with the default capacity.
|
|
754
|
+
*
|
|
755
|
+
* ```
|
|
756
|
+
* {
|
|
757
|
+
* auto vec = OwnedVector<Thing*> {};
|
|
758
|
+
* vec.push(new Thing(1));
|
|
759
|
+
* }
|
|
760
|
+
* // Thing was deleted
|
|
761
|
+
* ```
|
|
762
|
+
*/
|
|
763
|
+
~OwnedVector() {
|
|
764
|
+
if (!m_released) {
|
|
765
|
+
for (auto item : *this) {
|
|
766
|
+
delete item;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* Releases the objects being stored in the vector so they
|
|
773
|
+
* are not destroyed when this OwnedVector is deleted.
|
|
774
|
+
* Calling this effectively turns this OwnedVector into a
|
|
775
|
+
* plain Vector<T>.
|
|
776
|
+
*
|
|
777
|
+
* ```
|
|
778
|
+
* auto thing = new Thing(1);
|
|
779
|
+
* {
|
|
780
|
+
* auto vec = OwnedVector<Thing*> {};
|
|
781
|
+
* vec.push(thing);
|
|
782
|
+
* vec.relese();
|
|
783
|
+
* }
|
|
784
|
+
* assert_eq(1, thing.value());
|
|
785
|
+
* ```
|
|
786
|
+
*/
|
|
787
|
+
Vector<T> *release() {
|
|
788
|
+
m_released = true;
|
|
789
|
+
return static_cast<Vector<T> *>(this);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
private:
|
|
793
|
+
bool m_released { false };
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
}
|