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,16 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#define TM_UNREACHABLE() \
|
|
4
|
+
{ \
|
|
5
|
+
fprintf(stderr, "panic: unreachable in %s#%d\n", __FILE__, __LINE__); \
|
|
6
|
+
abort(); \
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
#define TM_NOT_YET_IMPLEMENTED(msg, ...) \
|
|
10
|
+
{ \
|
|
11
|
+
fprintf(stderr, "NOT YET IMPLEMENTED in %s#%d: " msg, __FILE__, __LINE__, ##__VA_ARGS__); \
|
|
12
|
+
fprintf(stderr, "\n"); \
|
|
13
|
+
abort(); \
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#define TM_UNUSED(var) (void)var
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <assert.h>
|
|
4
|
+
#include <stdio.h>
|
|
5
|
+
|
|
6
|
+
namespace TM {
|
|
7
|
+
|
|
8
|
+
template <typename T>
|
|
9
|
+
class Optional {
|
|
10
|
+
public:
|
|
11
|
+
/**
|
|
12
|
+
* Constructs a new Optional with a value.
|
|
13
|
+
*
|
|
14
|
+
* ```
|
|
15
|
+
* auto obj = Thing(1);
|
|
16
|
+
* auto opt = Optional<Thing>(obj);
|
|
17
|
+
* assert(opt);
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
Optional(T value)
|
|
21
|
+
: m_present { true }
|
|
22
|
+
, m_value { value } { }
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Constructs a new Optional without a value.
|
|
26
|
+
*
|
|
27
|
+
* ```
|
|
28
|
+
* auto opt = Optional<Thing>();
|
|
29
|
+
* assert_not(opt);
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
Optional()
|
|
33
|
+
: m_present { false } { }
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Copies the given Optional.
|
|
37
|
+
*
|
|
38
|
+
* ```
|
|
39
|
+
* auto obj = Thing(1);
|
|
40
|
+
* auto opt1 = Optional<Thing>(obj);
|
|
41
|
+
* auto opt2 = Optional<Thing>(opt1);
|
|
42
|
+
* assert_eq(obj, opt1.value());
|
|
43
|
+
* assert_eq(obj, opt2.value());
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
Optional(const Optional &other)
|
|
47
|
+
: m_present { other.m_present } {
|
|
48
|
+
if (m_present)
|
|
49
|
+
m_value = other.m_value;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
~Optional() {
|
|
53
|
+
clear();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Overwrites this Optional with the given one.
|
|
58
|
+
*
|
|
59
|
+
* ```
|
|
60
|
+
* auto obj1 = Thing(1);
|
|
61
|
+
* auto obj2 = Thing(2);
|
|
62
|
+
* auto opt1 = Optional<Thing>(obj1);
|
|
63
|
+
* auto opt2 = Optional<Thing>(obj2);
|
|
64
|
+
* opt1 = opt2;
|
|
65
|
+
* assert_eq(obj2, opt1.value());
|
|
66
|
+
* assert_eq(obj2, opt2.value());
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
Optional<T> &operator=(const Optional<T> &other) {
|
|
70
|
+
m_present = other.m_present;
|
|
71
|
+
if (m_present)
|
|
72
|
+
m_value = other.m_value;
|
|
73
|
+
return *this;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Overwrites this Optional with the given moved value.
|
|
78
|
+
*
|
|
79
|
+
* ```
|
|
80
|
+
* auto obj1 = Thing(1);
|
|
81
|
+
* auto obj2 = Thing(2);
|
|
82
|
+
* auto opt = Optional<Thing>(obj1);
|
|
83
|
+
* opt = std::move(obj2);
|
|
84
|
+
* assert_eq(obj2, opt.value());
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
Optional<T> &operator=(T &&value) {
|
|
88
|
+
m_present = true;
|
|
89
|
+
m_value = value;
|
|
90
|
+
return *this;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Returns a reference to the underlying value.
|
|
95
|
+
*
|
|
96
|
+
* ```
|
|
97
|
+
* auto obj = Thing(1);
|
|
98
|
+
* auto opt = Optional<Thing>(obj);
|
|
99
|
+
* assert_eq(obj, opt.value());
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* This method aborts if the value not present.
|
|
103
|
+
*
|
|
104
|
+
* ```should_abort
|
|
105
|
+
* auto opt = Optional<Thing>();
|
|
106
|
+
* opt.value();
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
T &value() {
|
|
110
|
+
assert(m_present);
|
|
111
|
+
return m_value;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Returns a reference to the underlying value.
|
|
116
|
+
*
|
|
117
|
+
* ```
|
|
118
|
+
* auto obj = Thing(1);
|
|
119
|
+
* auto opt = Optional<Thing>(obj);
|
|
120
|
+
* assert_eq(obj, opt.value());
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* This method aborts if the value not present.
|
|
124
|
+
*
|
|
125
|
+
* ```should_abort
|
|
126
|
+
* auto opt = Optional<Thing>();
|
|
127
|
+
* opt.value();
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
T const &value() const {
|
|
131
|
+
assert(m_present);
|
|
132
|
+
return m_value;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Returns a reference to the underlying value or
|
|
137
|
+
* the given fallback value.
|
|
138
|
+
*
|
|
139
|
+
* ```
|
|
140
|
+
* auto obj = Thing(1);
|
|
141
|
+
* auto opt = Optional<Thing>(obj);
|
|
142
|
+
* assert_eq(Thing(1), opt.value_or(Thing(2)));
|
|
143
|
+
* ```
|
|
144
|
+
*
|
|
145
|
+
* If we don't have a value present, then the fallback
|
|
146
|
+
* is returned.
|
|
147
|
+
*
|
|
148
|
+
* ```
|
|
149
|
+
* auto opt = Optional<Thing>();
|
|
150
|
+
* assert_eq(Thing(2), opt.value_or(Thing(2)));
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
T const &value_or(const T &fallback) const {
|
|
154
|
+
if (present())
|
|
155
|
+
return value();
|
|
156
|
+
else
|
|
157
|
+
return fallback;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Returns a reference to the underlying value.
|
|
162
|
+
*
|
|
163
|
+
* ```
|
|
164
|
+
* auto obj = Thing(1);
|
|
165
|
+
* auto opt = Optional<Thing>(obj);
|
|
166
|
+
* assert_eq(obj, *opt);
|
|
167
|
+
* ```
|
|
168
|
+
*
|
|
169
|
+
* This method aborts if the value not present.
|
|
170
|
+
*
|
|
171
|
+
* ```should_abort
|
|
172
|
+
* auto opt = Optional<Thing>();
|
|
173
|
+
* *opt;
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
T operator*() {
|
|
177
|
+
assert(m_present);
|
|
178
|
+
return m_value;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Sets the Optional to not present.
|
|
183
|
+
*
|
|
184
|
+
* ```
|
|
185
|
+
* auto opt = Optional<Thing>(Thing(1));
|
|
186
|
+
* assert(opt);
|
|
187
|
+
* opt.clear();
|
|
188
|
+
* assert_not(opt);
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
void clear() { m_present = false; }
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Returns true if the Optional contains a value.
|
|
195
|
+
*
|
|
196
|
+
* ```
|
|
197
|
+
* auto opt1 = Optional<Thing>(Thing(1));
|
|
198
|
+
* auto opt2 = Optional<Thing>();
|
|
199
|
+
* assert(opt1);
|
|
200
|
+
* assert_not(opt2);
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
operator bool() const { return m_present; }
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Returns true if the Optional contains a value.
|
|
207
|
+
*
|
|
208
|
+
* ```
|
|
209
|
+
* auto opt1 = Optional<Thing>(Thing(1));
|
|
210
|
+
* auto opt2 = Optional<Thing>();
|
|
211
|
+
* assert(opt1.present());
|
|
212
|
+
* assert_not(opt2.present());
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
bool present() const { return m_present; }
|
|
216
|
+
|
|
217
|
+
private:
|
|
218
|
+
bool m_present;
|
|
219
|
+
|
|
220
|
+
T m_value {};
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <assert.h>
|
|
4
|
+
|
|
5
|
+
namespace TM {
|
|
6
|
+
|
|
7
|
+
template <typename T>
|
|
8
|
+
class OwnedPtr {
|
|
9
|
+
public:
|
|
10
|
+
/**
|
|
11
|
+
* Constructs a null OwnedPtr.
|
|
12
|
+
*
|
|
13
|
+
* ```
|
|
14
|
+
* auto ptr = OwnedPtr<Thing>();
|
|
15
|
+
* assert(!ptr);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
OwnedPtr()
|
|
19
|
+
: m_ptr { nullptr } { }
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Constructs an OwnedPtr with the given raw pointer.
|
|
23
|
+
*
|
|
24
|
+
* ```
|
|
25
|
+
* auto ptr = OwnedPtr<Thing>(new Thing(1));
|
|
26
|
+
* assert(ptr);
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* Alternative syntax:
|
|
30
|
+
*
|
|
31
|
+
* ```
|
|
32
|
+
* OwnedPtr<Thing> ptr = new Thing(1);
|
|
33
|
+
* assert(ptr);
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
OwnedPtr(T *ptr)
|
|
37
|
+
: m_ptr { ptr } { }
|
|
38
|
+
|
|
39
|
+
~OwnedPtr() {
|
|
40
|
+
delete m_ptr;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
OwnedPtr(const OwnedPtr &other) = delete;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Moves the given OwnedPtr's raw pointer into a
|
|
47
|
+
* new OwnedPtr and invalidates the old one
|
|
48
|
+
* (sets it to nullptr).
|
|
49
|
+
*
|
|
50
|
+
* ```
|
|
51
|
+
* OwnedPtr<Thing> obj1 = new Thing(1);
|
|
52
|
+
* OwnedPtr<Thing> obj2 = std::move(obj1);
|
|
53
|
+
* assert(!obj1);
|
|
54
|
+
* assert(obj2);
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
OwnedPtr(OwnedPtr &&other)
|
|
58
|
+
: m_ptr { other.m_ptr } {
|
|
59
|
+
other.m_ptr = nullptr;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Overwrites this OwnedPtr with a new raw pointer,
|
|
64
|
+
* destroying our existing held object, if any.
|
|
65
|
+
*
|
|
66
|
+
* ```
|
|
67
|
+
* auto obj1 = new Thing(1);
|
|
68
|
+
* auto ptr = OwnedPtr<Thing>(obj1);
|
|
69
|
+
* ptr = new Thing(2);
|
|
70
|
+
* // obj1 has been destroyed
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
OwnedPtr<T> &operator=(T *ptr) {
|
|
74
|
+
if (ptr != m_ptr)
|
|
75
|
+
delete m_ptr;
|
|
76
|
+
m_ptr = ptr;
|
|
77
|
+
return *this;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
OwnedPtr<T> &operator=(const OwnedPtr<T> &other) = delete;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Returns true if this OwnedPtr is not null.
|
|
84
|
+
*
|
|
85
|
+
* ```
|
|
86
|
+
* auto ptr1 = OwnedPtr<Thing>(new Thing(1));
|
|
87
|
+
* auto ptr2 = OwnedPtr<Thing>();
|
|
88
|
+
* assert(ptr1);
|
|
89
|
+
* assert(!ptr2);
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
operator bool() const {
|
|
93
|
+
return !!m_ptr;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Returns a reference to the underlying raw pointer.
|
|
98
|
+
*
|
|
99
|
+
* ```
|
|
100
|
+
* auto raw = new Thing(1);
|
|
101
|
+
* auto ptr = OwnedPtr<Thing>(raw);
|
|
102
|
+
* assert_eq(*raw, *ptr);
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* This method aborts if the pointer is null.
|
|
106
|
+
*
|
|
107
|
+
* ```should_abort
|
|
108
|
+
* auto ptr = OwnedPtr<Thing>();
|
|
109
|
+
* *ptr;
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
const T &operator*() const {
|
|
113
|
+
assert(m_ptr);
|
|
114
|
+
return *m_ptr;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Returns a reference to the underlying raw pointer.
|
|
119
|
+
*
|
|
120
|
+
* ```
|
|
121
|
+
* auto raw = new Thing(1);
|
|
122
|
+
* auto ptr = OwnedPtr<Thing>(raw);
|
|
123
|
+
* assert_eq(*raw, ptr.ref());
|
|
124
|
+
* ```
|
|
125
|
+
*
|
|
126
|
+
* This method aborts if the pointer is null.
|
|
127
|
+
*
|
|
128
|
+
* ```should_abort
|
|
129
|
+
* auto ptr = OwnedPtr<Thing>();
|
|
130
|
+
* ptr.ref();
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
T &ref() const {
|
|
134
|
+
assert(m_ptr);
|
|
135
|
+
return *m_ptr;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Dereferences the underlying raw pointer for
|
|
140
|
+
* chained member reference.
|
|
141
|
+
*
|
|
142
|
+
* ```
|
|
143
|
+
* auto raw = new Thing(1);
|
|
144
|
+
* auto ptr = OwnedPtr<Thing>(raw);
|
|
145
|
+
* assert_eq(1, ptr->value());
|
|
146
|
+
* ```
|
|
147
|
+
*
|
|
148
|
+
* This method aborts if the pointer is null.
|
|
149
|
+
*
|
|
150
|
+
* ```should_abort
|
|
151
|
+
* auto ptr = OwnedPtr<Thing>();
|
|
152
|
+
* ptr->value();
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
T *operator->() const {
|
|
156
|
+
assert(m_ptr);
|
|
157
|
+
return m_ptr;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Returns the underlying raw pointer and
|
|
162
|
+
* releases ownership. When this OwnedPtr is
|
|
163
|
+
* destroyed later, the underlying pointer will
|
|
164
|
+
* not be deleted.
|
|
165
|
+
*
|
|
166
|
+
* ```
|
|
167
|
+
* Thing *ptr;
|
|
168
|
+
* {
|
|
169
|
+
* OwnedPtr<Thing> op = new Thing(1);
|
|
170
|
+
* ptr = op.release();
|
|
171
|
+
* }
|
|
172
|
+
* assert(ptr);
|
|
173
|
+
* delete ptr;
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
T *release() {
|
|
177
|
+
auto ptr = m_ptr;
|
|
178
|
+
m_ptr = nullptr;
|
|
179
|
+
return ptr;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private:
|
|
183
|
+
T *m_ptr;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "tm/defer.hpp"
|
|
4
|
+
#include "tm/hashmap.hpp"
|
|
5
|
+
#include <assert.h>
|
|
6
|
+
|
|
7
|
+
namespace TM {
|
|
8
|
+
|
|
9
|
+
class RecursionGuard {
|
|
10
|
+
public:
|
|
11
|
+
/**
|
|
12
|
+
* Constructs a new RecursionGuard that guards against
|
|
13
|
+
* calling the same code recursively in relation to the given
|
|
14
|
+
* object pointer.
|
|
15
|
+
*
|
|
16
|
+
* ```
|
|
17
|
+
* auto obj = Thing(1);
|
|
18
|
+
* RecursionGuard guard { &obj };
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
RecursionGuard(void *instance)
|
|
22
|
+
: m_instance { instance } {
|
|
23
|
+
assert(m_instance);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Runs the given lambda or callable type, passing boolean true
|
|
28
|
+
* if the object was seen already.
|
|
29
|
+
*
|
|
30
|
+
* ```
|
|
31
|
+
* auto obj = Thing(1);
|
|
32
|
+
* RecursionGuard guard { &obj };
|
|
33
|
+
*
|
|
34
|
+
* guard.run([&](bool is_recursive) {
|
|
35
|
+
* if (is_recursive) {
|
|
36
|
+
* printf("recursive!\n");
|
|
37
|
+
* } else {
|
|
38
|
+
* printf("normal work here, possibly recursive\n");
|
|
39
|
+
* }
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
template <typename F>
|
|
44
|
+
auto run(F callback) {
|
|
45
|
+
if (seen())
|
|
46
|
+
return callback(true);
|
|
47
|
+
|
|
48
|
+
mark();
|
|
49
|
+
Defer on_close([&]() { clear(); });
|
|
50
|
+
return callback(false);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private:
|
|
54
|
+
void *m_instance { nullptr };
|
|
55
|
+
|
|
56
|
+
bool seen() {
|
|
57
|
+
return s_did_run.get(m_instance) != nullptr;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
void mark() {
|
|
61
|
+
s_did_run.set(m_instance);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
void clear() {
|
|
65
|
+
s_did_run.remove(m_instance);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static inline TM::Hashmap<void *> s_did_run {};
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
class PairedRecursionGuard {
|
|
72
|
+
public:
|
|
73
|
+
/**
|
|
74
|
+
* Constructs a new PairedRecursionGuard that guards against
|
|
75
|
+
* calling the same code recursively in relation to the given
|
|
76
|
+
* two object pointers. This guards against mutual recursion.
|
|
77
|
+
*
|
|
78
|
+
* ```
|
|
79
|
+
* auto obj1 = Thing(1);
|
|
80
|
+
* auto obj2 = Thing(2);
|
|
81
|
+
* PairedRecursionGuard guard { &obj1, &obj2 };
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
PairedRecursionGuard(void *instance, void *other_instance)
|
|
85
|
+
: m_instance { instance }
|
|
86
|
+
, m_other_instance { other_instance } {
|
|
87
|
+
assert(m_instance);
|
|
88
|
+
assert(m_other_instance);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Runs the given lambda or callable type, passing boolean true
|
|
93
|
+
* if the object pair was seen already.
|
|
94
|
+
*
|
|
95
|
+
* ```
|
|
96
|
+
* auto obj1 = Thing(1);
|
|
97
|
+
* auto obj2 = Thing(2);
|
|
98
|
+
* PairedRecursionGuard guard { &obj1, &obj2 };
|
|
99
|
+
*
|
|
100
|
+
* guard.run([&](bool is_recursive) {
|
|
101
|
+
* if (is_recursive) {
|
|
102
|
+
* printf("recursive!\n");
|
|
103
|
+
* } else {
|
|
104
|
+
* printf("normal work here, possibly recursive\n");
|
|
105
|
+
* }
|
|
106
|
+
* });
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
template <typename F>
|
|
110
|
+
auto run(F callback) {
|
|
111
|
+
if (seen())
|
|
112
|
+
return callback(true);
|
|
113
|
+
|
|
114
|
+
mark();
|
|
115
|
+
Defer on_close([&]() { clear(); });
|
|
116
|
+
return callback(false);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private:
|
|
120
|
+
void *m_instance { nullptr };
|
|
121
|
+
void *m_other_instance { nullptr };
|
|
122
|
+
|
|
123
|
+
bool seen() {
|
|
124
|
+
auto companions = s_did_run.get(m_instance);
|
|
125
|
+
if (!companions)
|
|
126
|
+
return false;
|
|
127
|
+
return companions->get(m_other_instance) != nullptr;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
void mark() {
|
|
131
|
+
auto companions = s_did_run.get(m_instance);
|
|
132
|
+
if (!companions) {
|
|
133
|
+
companions = new TM::Hashmap<void *> {};
|
|
134
|
+
s_did_run.put(m_instance, companions);
|
|
135
|
+
}
|
|
136
|
+
companions->set(m_other_instance);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
void clear() {
|
|
141
|
+
auto companions = s_did_run.get(m_instance);
|
|
142
|
+
if (!companions) {
|
|
143
|
+
s_did_run.remove(m_instance);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
companions->remove(m_other_instance);
|
|
147
|
+
if (companions->is_empty()) {
|
|
148
|
+
delete companions;
|
|
149
|
+
s_did_run.remove(m_instance);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
static inline TM::Hashmap<void *, TM::Hashmap<void *> *> s_did_run {};
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
}
|