/home/uke/oil/mycpp/mylib_leaky.h
Line | Count | Source (jump to first uncovered line) |
1 | | // mylib_leaky.h |
2 | | |
3 | | #ifndef MYLIB_H |
4 | | #define MYLIB_H |
5 | | |
6 | | #include <assert.h> |
7 | | #include <ctype.h> // isalpha(), isdigit() |
8 | | #include <stdlib.h> // malloc |
9 | | #include <string.h> // strlen |
10 | | |
11 | | #include <algorithm> // sort() is templated |
12 | | // https://stackoverflow.com/questions/3882346/forward-declare-file |
13 | | #include <climits> // CHAR_BIT |
14 | | #include <cstdint> |
15 | | #include <cstdio> // FILE* |
16 | | #include <initializer_list> |
17 | | #include <vector> |
18 | | |
19 | | #include "common.h" |
20 | | |
21 | | // if this file is even included, we're using the old mylib |
22 | | #define MYLIB_LEAKY 1 |
23 | | #include "gc_heap.h" // for Obj |
24 | | |
25 | | #ifdef DUMB_ALLOC |
26 | | #include "cpp/leaky_dumb_alloc.h" |
27 | 186 | #define malloc dumb_malloc |
28 | 6 | #define free dumb_free |
29 | | #endif |
30 | | |
31 | | class Str; |
32 | | |
33 | | template <class T> |
34 | | class List; |
35 | | |
36 | | template <class K, class V> |
37 | | class Dict; |
38 | | |
39 | | template <class K, class V> |
40 | | class DictIter; |
41 | | |
42 | | bool are_equal(Str* left, Str* right); |
43 | | bool str_equals(Str* left, Str* right); |
44 | | |
45 | | namespace mylib { |
46 | | template <typename V> |
47 | | void dict_remove(Dict<Str*, V>* haystack, Str* needle); |
48 | | |
49 | | template <typename V> |
50 | | void dict_remove(Dict<int, V>* haystack, int needle); |
51 | | |
52 | | }; // namespace mylib |
53 | | |
54 | | extern Str* kEmptyString; |
55 | | |
56 | | void print(Str* s); |
57 | | |
58 | | // log() generates code that writes this |
59 | | void println_stderr(Str* s); |
60 | | |
61 | | class IndexError {}; |
62 | | class ValueError {}; |
63 | | class KeyError {}; |
64 | | |
65 | | class EOFError {}; |
66 | | |
67 | | class NotImplementedError { |
68 | | public: |
69 | 0 | NotImplementedError() { |
70 | 0 | } |
71 | 0 | explicit NotImplementedError(int i) { // e.g. in expr_to_ast |
72 | 0 | } |
73 | 0 | explicit NotImplementedError(const char* s) { |
74 | 0 | } |
75 | 0 | explicit NotImplementedError(Str* s) { |
76 | 0 | } |
77 | | }; |
78 | | |
79 | | class AssertionError { |
80 | | public: |
81 | 0 | AssertionError() { |
82 | 0 | } |
83 | 0 | explicit AssertionError(int i) { // e.g. in expr_to_ast |
84 | 0 | } |
85 | 0 | explicit AssertionError(const char* s) { |
86 | 0 | } |
87 | 0 | explicit AssertionError(Str* s) { |
88 | 0 | } |
89 | | }; |
90 | | |
91 | | // Python's RuntimeError looks like this. . libc::regex_match and other |
92 | | // bindings raise it. |
93 | | class RuntimeError { |
94 | | public: |
95 | 0 | RuntimeError(Str* message) : message(message) { |
96 | 0 | } |
97 | | Str* message; |
98 | | }; |
99 | | |
100 | | // |
101 | | // Data Types |
102 | | // |
103 | | |
104 | | #ifdef MYLIB_LEAKY |
105 | | class Str : public gc_heap::Obj { |
106 | | public: |
107 | | Str(const char* data, int len) |
108 | | : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), |
109 | | len_(len), |
110 | 614 | data_(data) { |
111 | 614 | } |
112 | | |
113 | 238 | explicit Str(const char* data) : Str(data, strlen(data)) { |
114 | 238 | } |
115 | | |
116 | | // emulating gc_heap API |
117 | 1 | void SetObjLenFromStrLen(int len) { |
118 | 1 | len_ = len; |
119 | 1 | } |
120 | | |
121 | | // Usage: |
122 | | // Str* s = OverAllocatedStr(10); |
123 | | // strcpy(s->data(), "foo"); |
124 | 36 | char* data() { |
125 | 36 | return const_cast<char*>(data_); |
126 | 36 | } |
127 | | |
128 | | // Important invariant: the buffer is of size len+1, so data[len] is OK to |
129 | | // access! Not just data[len-1]. We use that to test if it's a C string. |
130 | | // note: "foo" and "foo\0" are both NUL-terminated. |
131 | 49 | bool IsNulTerminated() { |
132 | 49 | return data_[len_] == '\0'; |
133 | 49 | } |
134 | | |
135 | | // Get a string with one character |
136 | 0 | Str* index_(int i) { |
137 | 0 | if (i < 0) { |
138 | 0 | i = len_ + i; |
139 | 0 | } |
140 | 0 | assert(i >= 0); |
141 | 0 | assert(i < len_); // had a problem here! |
142 | 0 |
|
143 | 0 | char* buf = static_cast<char*>(malloc(2)); |
144 | 0 | buf[0] = data_[i]; |
145 | 0 | buf[1] = '\0'; |
146 | 0 | return new Str(buf, 1); |
147 | 0 | } |
148 | | |
149 | | // s[begin:] |
150 | 0 | Str* slice(int begin) { |
151 | 0 | if (begin == 0) { |
152 | 0 | return this; // s[i:] where i == 0 is common in here docs |
153 | 0 | } |
154 | 0 | if (begin < 0) { |
155 | 0 | begin = len_ + begin; |
156 | 0 | } |
157 | 0 | return slice(begin, len_); |
158 | 0 | } |
159 | | // s[begin:end] |
160 | 307 | Str* slice(int begin, int end) { |
161 | 307 | begin = std::min(begin, len_); |
162 | 307 | end = std::min(end, len_); |
163 | | |
164 | 307 | assert(begin <= len_); |
165 | 0 | assert(end <= len_); |
166 | | |
167 | 307 | if (begin < 0) { |
168 | 140 | begin = len_ + begin; |
169 | 140 | } |
170 | | |
171 | 307 | if (end < 0) { |
172 | 140 | end = len_ + end; |
173 | 140 | } |
174 | | |
175 | 307 | begin = std::min(begin, len_); |
176 | 307 | end = std::min(end, len_); |
177 | | |
178 | 307 | begin = std::max(begin, 0); |
179 | 307 | end = std::max(end, 0); |
180 | | |
181 | 307 | assert(begin >= 0); |
182 | 0 | assert(begin <= len_); |
183 | | |
184 | 0 | assert(end >= 0); |
185 | 0 | assert(end <= len_); |
186 | | |
187 | 0 | int new_len = end - begin; |
188 | | |
189 | | // Tried to use std::clamp() here but we're not compiling against cxx-17 |
190 | 307 | new_len = std::max(new_len, 0); |
191 | 307 | new_len = std::min(new_len, len_); |
192 | | |
193 | | /* printf("len(%d) [%d, %d] newlen(%d)\n", len_, begin, end, new_len); */ |
194 | | |
195 | 307 | assert(new_len >= 0); |
196 | 0 | assert(new_len <= len_); |
197 | | |
198 | 0 | char* buf = static_cast<char*>(malloc(new_len + 1)); |
199 | 307 | memcpy(buf, data_ + begin, new_len); |
200 | | |
201 | 307 | buf[new_len] = '\0'; |
202 | 307 | return new Str(buf, new_len); |
203 | 307 | } |
204 | | |
205 | | // Helper for lstrip() and strip() |
206 | 5 | int _strip_left_pos() { |
207 | 5 | assert(len_ > 0); |
208 | | |
209 | 0 | int i = 0; |
210 | 5 | bool done = false; |
211 | 10 | while (i < len_ && !done) { |
212 | 5 | switch (data_[i]) { |
213 | 0 | case ' ': |
214 | 0 | case '\t': |
215 | 0 | case '\r': |
216 | 0 | case '\n': |
217 | 0 | i++; |
218 | 5 | default: |
219 | 5 | done = true; |
220 | 5 | break; |
221 | 5 | } |
222 | 5 | } |
223 | 5 | return i; |
224 | 5 | } |
225 | | |
226 | | // Helper for rstrip() and strip() |
227 | 5 | int _strip_right_pos() { |
228 | 5 | assert(len_ > 0); |
229 | | |
230 | 0 | int last = len_ - 1; |
231 | 5 | int i = last; |
232 | 5 | bool done = false; |
233 | 10 | while (i > 0 && !done) { |
234 | 5 | switch (data_[i]) { |
235 | 5 | case ' ': |
236 | 5 | case '\t': |
237 | 5 | case '\r': |
238 | 5 | case '\n': |
239 | 5 | i--; |
240 | 5 | default: |
241 | 5 | done = true; |
242 | 5 | break; |
243 | 5 | } |
244 | 5 | } |
245 | 5 | return i; |
246 | 5 | } |
247 | | |
248 | 5 | Str* strip() { |
249 | 5 | if (len_ == 0) { |
250 | 0 | return this; |
251 | 0 | } |
252 | 5 | int left_pos = _strip_left_pos(); |
253 | 5 | int right_pos = _strip_right_pos(); |
254 | | |
255 | 5 | if (left_pos == 0 && right_pos == len_ - 1) { |
256 | 0 | return this; |
257 | 0 | } |
258 | | |
259 | | // cstring-NOTE: This returns a SLICE, not a copy, unlike rstrip() |
260 | | // TODO: make them consistent. |
261 | 5 | int len = right_pos - left_pos + 1; |
262 | 5 | return new Str(data_ + left_pos, len); |
263 | 5 | } |
264 | | |
265 | | // Used for CommandSub in osh/cmd_exec.py |
266 | 0 | Str* rstrip(Str* chars) { |
267 | 0 | assert(chars->len_ == 1); |
268 | 0 | char c = chars->data_[0]; |
269 | 0 |
|
270 | 0 | int last = len_ - 1; |
271 | 0 | int i = last; |
272 | 0 | bool done = false; |
273 | 0 | while (i > 0 && !done) { |
274 | 0 | if (data_[i] == c) { |
275 | 0 | i--; |
276 | 0 | } else { |
277 | 0 | done = true; |
278 | 0 | break; |
279 | 0 | } |
280 | 0 | } |
281 | 0 | if (i == last) { // nothing stripped |
282 | 0 | return this; |
283 | 0 | } |
284 | 0 | int new_len = i + 1; |
285 | 0 | char* buf = static_cast<char*>(malloc(new_len + 1)); |
286 | 0 | memcpy(buf, data_, new_len); |
287 | 0 | buf[new_len] = '\0'; |
288 | 0 | return new Str(buf, new_len); |
289 | 0 | } |
290 | | |
291 | 0 | Str* rstrip() { |
292 | 0 | if (len_ == 0) { |
293 | 0 | return this; |
294 | 0 | } |
295 | 0 | int right_pos = _strip_right_pos(); |
296 | 0 | if (right_pos == len_ - 1) { // nothing stripped |
297 | 0 | return this; |
298 | 0 | } |
299 | 0 | int new_len = right_pos + 1; |
300 | 0 | char* buf = static_cast<char*>(malloc(new_len + 1)); |
301 | 0 | memcpy(buf, data_, new_len); |
302 | 0 | buf[new_len] = '\0'; |
303 | 0 | return new Str(buf, new_len); |
304 | 0 | } |
305 | | |
306 | 0 | bool startswith(Str* s) { |
307 | 0 | if (s->len_ > len_) { |
308 | 0 | return false; |
309 | 0 | } |
310 | 0 | return memcmp(data_, s->data_, s->len_) == 0; |
311 | 0 | } |
312 | 0 | bool endswith(Str* s) { |
313 | 0 | if (s->len_ > len_) { |
314 | 0 | return false; |
315 | 0 | } |
316 | 0 | const char* start = data_ + len_ - s->len_; |
317 | 0 | return memcmp(start, s->data_, s->len_) == 0; |
318 | 0 | } |
319 | 0 | bool isdigit() { |
320 | 0 | if (len_ == 0) { |
321 | 0 | return false; // special case |
322 | 0 | } |
323 | 0 | for (int i = 0; i < len_; ++i) { |
324 | 0 | if (!::isdigit(data_[i])) { |
325 | 0 | return false; |
326 | 0 | } |
327 | 0 | } |
328 | 0 | return true; |
329 | 0 | } |
330 | 0 | bool isalpha() { |
331 | 0 | if (len_ == 0) { |
332 | 0 | return false; // special case |
333 | 0 | } |
334 | 0 | for (int i = 0; i < len_; ++i) { |
335 | 0 | if (!::isalpha(data_[i])) { |
336 | 0 | return false; |
337 | 0 | } |
338 | 0 | } |
339 | 0 | return true; |
340 | 0 | } |
341 | | // e.g. for osh/braces.py |
342 | 0 | bool isupper() { |
343 | 0 | if (len_ == 0) { |
344 | 0 | return false; // special case |
345 | 0 | } |
346 | 0 | for (int i = 0; i < len_; ++i) { |
347 | 0 | if (!::isupper(data_[i])) { |
348 | 0 | return false; |
349 | 0 | } |
350 | 0 | } |
351 | 0 | return true; |
352 | 0 | } |
353 | | |
354 | | List<Str*>* split(Str* sep); |
355 | | List<Str*>* splitlines(bool keep); |
356 | | Str* join(List<Str*>* items); |
357 | | |
358 | | Str* replace(Str* old, Str* new_str); |
359 | | |
360 | 0 | int find(Str* needle, int pos = 0) { |
361 | 0 | assert(needle->len_ == 1); // Oil's usage |
362 | 0 | char c = needle->data_[0]; |
363 | 0 | for (int i = pos; i < len_; ++i) { |
364 | 0 | if (data_[i] == c) { |
365 | 0 | return i; |
366 | 0 | } |
367 | 0 | } |
368 | 0 | return -1; |
369 | 0 | } |
370 | | |
371 | 0 | int rfind(Str* needle) { |
372 | 0 | assert(needle->len_ == 1); // Oil's usage |
373 | 0 | char c = needle->data_[0]; |
374 | 0 | for (int i = len_ - 1; i >= 0; --i) { |
375 | 0 | if (data_[i] == c) { |
376 | 0 | return i; |
377 | 0 | } |
378 | 0 | } |
379 | 0 | return -1; |
380 | 0 | } |
381 | | |
382 | | Str* upper(); |
383 | | Str* lower(); |
384 | | Str* ljust(int width, Str* fillchar); |
385 | | Str* rjust(int width, Str* fillchar); |
386 | | |
387 | | int len_; // reorder for alignment |
388 | | const char* data_; |
389 | | |
390 | | DISALLOW_COPY_AND_ASSIGN(Str) |
391 | | }; |
392 | | |
393 | | // NOTE: This iterates over bytes. |
394 | | class StrIter { |
395 | | public: |
396 | 0 | explicit StrIter(Str* s) : s_(s), i_(0) { |
397 | 0 | } |
398 | | void Next() { |
399 | | i_++; |
400 | | } |
401 | | bool Done() { |
402 | | return i_ >= s_->len_; |
403 | | } |
404 | | Str* Value(); |
405 | | |
406 | | private: |
407 | | Str* s_; |
408 | | int i_; |
409 | | |
410 | | DISALLOW_COPY_AND_ASSIGN(StrIter) |
411 | | }; |
412 | | |
413 | | // TODO: Rewrite without vector<>, so we don't depend on libstdc++. |
414 | | // |
415 | | // TODO(Jesse): I like the sound of getting rid of std:vector |
416 | | // |
417 | | template <class T> |
418 | | class List : public gc_heap::Obj { |
419 | | public: |
420 | | // Note: constexpr doesn't work because the std::vector destructor is |
421 | | // nontrivial |
422 | 17 | List() : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), v_() { |
423 | | // Note: this seems to INCREASE the number of 'new' calls. I guess because |
424 | | // many 'spids' lists aren't used? |
425 | | // v_.reserve(64); |
426 | 17 | } Line | Count | Source | 422 | 16 | List() : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), v_() { | 423 | | // Note: this seems to INCREASE the number of 'new' calls. I guess because | 424 | | // many 'spids' lists aren't used? | 425 | | // v_.reserve(64); | 426 | 16 | } |
Line | Count | Source | 422 | 1 | List() : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), v_() { | 423 | | // Note: this seems to INCREASE the number of 'new' calls. I guess because | 424 | | // many 'spids' lists aren't used? | 425 | | // v_.reserve(64); | 426 | 1 | } |
Unexecuted instantiation: _ZN4ListIP6Tuple2IiP3StrEEC2Ev |
427 | | |
428 | | // Used by list_repeat |
429 | | List(T item, int n) |
430 | 2 | : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), v_(n, item) { |
431 | 2 | } Line | Count | Source | 430 | 1 | : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), v_(n, item) { | 431 | 1 | } |
Line | Count | Source | 430 | 1 | : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), v_(n, item) { | 431 | 1 | } |
|
432 | | |
433 | | List(std::initializer_list<T> init) |
434 | 8 | : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), v_() { |
435 | 23 | for (T item : init) { |
436 | 23 | v_.push_back(item); |
437 | 23 | } |
438 | 8 | } _ZN4ListIiEC2ESt16initializer_listIiE Line | Count | Source | 434 | 7 | : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), v_() { | 435 | 20 | for (T item : init) { | 436 | 20 | v_.push_back(item); | 437 | 20 | } | 438 | 7 | } |
_ZN4ListIdEC2ESt16initializer_listIdE Line | Count | Source | 434 | 1 | : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), v_() { | 435 | 3 | for (T item : init) { | 436 | 3 | v_.push_back(item); | 437 | 3 | } | 438 | 1 | } |
Unexecuted instantiation: _ZN4ListIP3StrEC2ESt16initializer_listIS1_E |
439 | | |
440 | | // a[-1] = 42 becomes a->set(-1, 42); |
441 | 2 | void set(int index, T value) { |
442 | 2 | if (index < 0) { |
443 | 0 | index = v_.size() + index; |
444 | 0 | } |
445 | 2 | v_[index] = value; |
446 | 2 | } |
447 | | |
448 | | // L[i] |
449 | 51 | T index_(int i) const { |
450 | 51 | if (i < 0) { |
451 | | // User code doesn't result in mylist[-1], but Oil's own code does |
452 | 0 | int j = v_.size() + i; |
453 | 0 | return v_.at(j); |
454 | 0 | } |
455 | 51 | return v_.at(i); // checked version |
456 | 51 | } Line | Count | Source | 449 | 25 | T index_(int i) const { | 450 | 25 | if (i < 0) { | 451 | | // User code doesn't result in mylist[-1], but Oil's own code does | 452 | 0 | int j = v_.size() + i; | 453 | 0 | return v_.at(j); | 454 | 0 | } | 455 | 25 | return v_.at(i); // checked version | 456 | 25 | } |
Line | Count | Source | 449 | 2 | T index_(int i) const { | 450 | 2 | if (i < 0) { | 451 | | // User code doesn't result in mylist[-1], but Oil's own code does | 452 | 0 | int j = v_.size() + i; | 453 | 0 | return v_.at(j); | 454 | 0 | } | 455 | 2 | return v_.at(i); // checked version | 456 | 2 | } |
Line | Count | Source | 449 | 4 | T index_(int i) const { | 450 | 4 | if (i < 0) { | 451 | | // User code doesn't result in mylist[-1], but Oil's own code does | 452 | 0 | int j = v_.size() + i; | 453 | 0 | return v_.at(j); | 454 | 0 | } | 455 | 4 | return v_.at(i); // checked version | 456 | 4 | } |
_ZNK4ListIP3StrE6index_Ei Line | Count | Source | 449 | 20 | T index_(int i) const { | 450 | 20 | if (i < 0) { | 451 | | // User code doesn't result in mylist[-1], but Oil's own code does | 452 | 0 | int j = v_.size() + i; | 453 | 0 | return v_.at(j); | 454 | 0 | } | 455 | 20 | return v_.at(i); // checked version | 456 | 20 | } |
|
457 | | |
458 | | // L.index(i) -- Python method |
459 | | int index(T value) const { |
460 | | int len = v_.size(); |
461 | | for (int i = 0; i < len; i++) { |
462 | | // TODO: this doesn't work for strings! |
463 | | if (v_[i] == value) { |
464 | | return i; |
465 | | } |
466 | | } |
467 | | throw new ValueError(); |
468 | | } |
469 | | |
470 | | // L[begin:] |
471 | | List* slice(int begin) { |
472 | | if (begin == 0) { |
473 | | return this; |
474 | | } |
475 | | if (begin < 0) { |
476 | | begin = v_.size() + begin; |
477 | | } |
478 | | |
479 | | List* result = new List(); |
480 | | int len = v_.size(); |
481 | | for (int i = begin; i < len; i++) { |
482 | | result->v_.push_back(v_[i]); |
483 | | } |
484 | | return result; |
485 | | } |
486 | | // L[begin:end] |
487 | | // TODO: Can this be optimized? |
488 | | List* slice(int begin, int end) { |
489 | | if (begin < 0) { |
490 | | begin = v_.size() + begin; |
491 | | } |
492 | | if (end < 0) { |
493 | | end = v_.size() + end; |
494 | | } |
495 | | |
496 | | List* result = new List(); |
497 | | for (int i = begin; i < end; i++) { |
498 | | result->v_.push_back(v_[i]); |
499 | | } |
500 | | return result; |
501 | | } |
502 | | |
503 | 38 | void append(T item) { |
504 | | #ifdef ALLOC_LOG |
505 | | // we can post process this format to find large lists |
506 | | // except when they're constants, but that's OK? |
507 | | printf("%p %zu\n", this, v_.size()); |
508 | | #endif |
509 | | |
510 | 38 | v_.push_back(item); |
511 | 38 | } Line | Count | Source | 503 | 4 | void append(T item) { | 504 | | #ifdef ALLOC_LOG | 505 | | // we can post process this format to find large lists | 506 | | // except when they're constants, but that's OK? | 507 | | printf("%p %zu\n", this, v_.size()); | 508 | | #endif | 509 | | | 510 | 4 | v_.push_back(item); | 511 | 4 | } |
_ZN4ListIP3StrE6appendES1_ Line | Count | Source | 503 | 34 | void append(T item) { | 504 | | #ifdef ALLOC_LOG | 505 | | // we can post process this format to find large lists | 506 | | // except when they're constants, but that's OK? | 507 | | printf("%p %zu\n", this, v_.size()); | 508 | | #endif | 509 | | | 510 | 34 | v_.push_back(item); | 511 | 34 | } |
Unexecuted instantiation: _ZN4ListIP6Tuple2IiP3StrEE6appendES4_ |
512 | | |
513 | | void extend(List<T>* items) { |
514 | | // Note: C++ idioms would be v_.insert() or std::copy, but we're keeping it |
515 | | // simple. |
516 | | // |
517 | | // We could optimize this for the small cases Oil has? I doubt it's a |
518 | | // bottleneck anywhere. |
519 | | int len = items->v_.size(); |
520 | | for (int i = 0; i < len; ++i) { |
521 | | v_.push_back(items->v_[i]); |
522 | | } |
523 | | } |
524 | | |
525 | | // Reconsider? |
526 | | // https://stackoverflow.com/questions/12600330/pop-back-return-value |
527 | | T pop() { |
528 | | assert(!v_.empty()); |
529 | | T result = v_.back(); |
530 | | v_.pop_back(); |
531 | | return result; |
532 | | } |
533 | | |
534 | | // Used in osh/word_parse.py to remove from front |
535 | | // TODO: Don't accept arbitrary index? |
536 | 1 | T pop(int index) { |
537 | 1 | if (v_.size() == 0) { |
538 | | // TODO(Jesse): Probably shouldn't crash if we try to pop a List with |
539 | | // nothing on it |
540 | 0 | InvalidCodePath(); |
541 | 0 | } |
542 | | |
543 | 0 | T result = v_.at(index); |
544 | 1 | v_.erase(v_.begin() + index); |
545 | 1 | return result; |
546 | | |
547 | | /* |
548 | | Implementation without std::vector |
549 | | assert(index == 0); |
550 | | for (int i = 1; i < v_.size(); ++i) { |
551 | | v_[i-1] = v_[i]; |
552 | | } |
553 | | v_.pop_back(); |
554 | | */ |
555 | 1 | } |
556 | | |
557 | | void clear() { |
558 | | v_.clear(); |
559 | | } |
560 | | |
561 | 2 | void sort() { |
562 | 2 | mysort(&v_); |
563 | 2 | } |
564 | | |
565 | | // in osh/string_ops.py |
566 | 2 | void reverse() { |
567 | 2 | int n = v_.size(); |
568 | 4 | for (int i = 0; i < n / 2; ++i) { |
569 | | // log("swapping %d and %d", i, n-i); |
570 | 2 | T tmp = v_[i]; |
571 | 2 | int j = n - 1 - i; |
572 | 2 | v_[i] = v_[j]; |
573 | 2 | v_[j] = tmp; |
574 | 2 | } |
575 | 2 | } |
576 | | |
577 | | // private: |
578 | | std::vector<T> v_; // ''.join accesses this directly |
579 | | }; |
580 | | |
581 | | template <class T> |
582 | | class ListIter { |
583 | | public: |
584 | 1 | explicit ListIter(List<T>* L) : L_(L), i_(0) { |
585 | 1 | } |
586 | 16 | void Next() { |
587 | 16 | i_++; |
588 | 16 | } |
589 | 21 | bool Done() { |
590 | | // "unsigned size_t was a mistake" |
591 | 21 | return i_ >= static_cast<int>(L_->v_.size()); |
592 | 21 | } |
593 | 16 | T Value() { |
594 | 16 | return L_->v_[i_]; |
595 | 16 | } |
596 | | |
597 | | private: |
598 | | List<T>* L_; |
599 | | int i_; |
600 | | }; |
601 | | |
602 | | // TODO: Does using pointers rather than indices make this more efficient? |
603 | | template <class T> |
604 | | class ReverseListIter { |
605 | | public: |
606 | 1 | explicit ReverseListIter(List<T>* L) : L_(L), i_(L_->v_.size() - 1) { |
607 | 1 | } |
608 | 3 | void Next() { |
609 | 3 | i_--; |
610 | 3 | } |
611 | 4 | bool Done() { |
612 | 4 | return i_ < 0; |
613 | 4 | } |
614 | 3 | T Value() { |
615 | 3 | return L_->v_[i_]; |
616 | 3 | } |
617 | | |
618 | | private: |
619 | | List<T>* L_; |
620 | | int i_; |
621 | | }; |
622 | | |
623 | | // TODO: A proper dict index should get rid of this unusual sentinel scheme. |
624 | | // The index can be -1 on deletion, regardless of the type of the key. |
625 | | |
626 | | template <class K, class V> |
627 | | void dict_next(DictIter<K, V>* it, const std::vector<std::pair<K, V>>& items) { |
628 | | ++it->i_; |
629 | | } |
630 | | |
631 | | template <class V> |
632 | | void dict_next(DictIter<Str*, V>* it, |
633 | 2 | const std::vector<std::pair<Str*, V>>& items) { |
634 | 2 | while (true) { |
635 | 2 | ++it->i_; |
636 | 2 | if (it->Done()) { |
637 | 1 | break; |
638 | 1 | } |
639 | 1 | if (items[it->i_].first) { // not nullptr |
640 | 1 | break; |
641 | 1 | } |
642 | 1 | } |
643 | 2 | } _Z9dict_nextIiEvP8DictIterIP3StrT_ERKSt6vectorISt4pairIS2_S3_ESaIS8_EE Line | Count | Source | 633 | 2 | const std::vector<std::pair<Str*, V>>& items) { | 634 | 2 | while (true) { | 635 | 2 | ++it->i_; | 636 | 2 | if (it->Done()) { | 637 | 1 | break; | 638 | 1 | } | 639 | 1 | if (items[it->i_].first) { // not nullptr | 640 | 1 | break; | 641 | 1 | } | 642 | 1 | } | 643 | 2 | } |
Unexecuted instantiation: _Z9dict_nextIP3StrEvP8DictIterIS1_T_ERKSt6vectorISt4pairIS1_S3_ESaIS8_EE |
644 | | |
645 | | template <class K, class V> |
646 | | bool dict_done(DictIter<K, V>* it, const std::vector<std::pair<K, V>>& items) { |
647 | | int n = items.size(); |
648 | | return it->i_ >= n; |
649 | | } |
650 | | |
651 | | template <class V> |
652 | | bool dict_done(DictIter<Str*, V>* it, |
653 | 7 | const std::vector<std::pair<Str*, V>>& items) { |
654 | 7 | int n = items.size(); |
655 | 7 | if (it->i_ >= n) { |
656 | 1 | return true; |
657 | 1 | } |
658 | 9 | for (int j = it->i_; j < n; ++j) { |
659 | 6 | if (items[j].first) { // there's still something left |
660 | 3 | return false; |
661 | 3 | } |
662 | 6 | } |
663 | 3 | return true; |
664 | 6 | } _Z9dict_doneIiEbP8DictIterIP3StrT_ERKSt6vectorISt4pairIS2_S3_ESaIS8_EE Line | Count | Source | 653 | 6 | const std::vector<std::pair<Str*, V>>& items) { | 654 | 6 | int n = items.size(); | 655 | 6 | if (it->i_ >= n) { | 656 | 1 | return true; | 657 | 1 | } | 658 | 7 | for (int j = it->i_; j < n; ++j) { | 659 | 5 | if (items[j].first) { // there's still something left | 660 | 3 | return false; | 661 | 3 | } | 662 | 5 | } | 663 | 2 | return true; | 664 | 5 | } |
_Z9dict_doneIP3StrEbP8DictIterIS1_T_ERKSt6vectorISt4pairIS1_S3_ESaIS8_EE Line | Count | Source | 653 | 1 | const std::vector<std::pair<Str*, V>>& items) { | 654 | 1 | int n = items.size(); | 655 | 1 | if (it->i_ >= n) { | 656 | 0 | return true; | 657 | 0 | } | 658 | 2 | for (int j = it->i_; j < n; ++j) { | 659 | 1 | if (items[j].first) { // there's still something left | 660 | 0 | return false; | 661 | 0 | } | 662 | 1 | } | 663 | 1 | return true; | 664 | 1 | } |
|
665 | | |
666 | | template <class K, class V> |
667 | | class DictIter { |
668 | | public: |
669 | 3 | explicit DictIter(Dict<K, V>* D) : D_(D), i_(0) { |
670 | 3 | } _ZN8DictIterIP3StriEC2EP4DictIS1_iE Line | Count | Source | 669 | 2 | explicit DictIter(Dict<K, V>* D) : D_(D), i_(0) { | 670 | 2 | } |
_ZN8DictIterIP3StrS1_EC2EP4DictIS1_S1_E Line | Count | Source | 669 | 1 | explicit DictIter(Dict<K, V>* D) : D_(D), i_(0) { | 670 | 1 | } |
|
671 | 2 | void Next() { |
672 | 2 | dict_next(this, D_->items_); |
673 | 2 | } _ZN8DictIterIP3StriE4NextEv Line | Count | Source | 671 | 2 | void Next() { | 672 | 2 | dict_next(this, D_->items_); | 673 | 2 | } |
Unexecuted instantiation: _ZN8DictIterIP3StrS1_E4NextEv |
674 | 7 | bool Done() { |
675 | 7 | return dict_done(this, D_->items_); |
676 | 7 | } _ZN8DictIterIP3StriE4DoneEv Line | Count | Source | 674 | 6 | bool Done() { | 675 | 6 | return dict_done(this, D_->items_); | 676 | 6 | } |
_ZN8DictIterIP3StrS1_E4DoneEv Line | Count | Source | 674 | 1 | bool Done() { | 675 | 1 | return dict_done(this, D_->items_); | 676 | 1 | } |
|
677 | 2 | K Key() { |
678 | 2 | return D_->items_[i_].first; |
679 | 2 | } _ZN8DictIterIP3StriE3KeyEv Line | Count | Source | 677 | 2 | K Key() { | 678 | 2 | return D_->items_[i_].first; | 679 | 2 | } |
Unexecuted instantiation: _ZN8DictIterIP3StrS1_E3KeyEv |
680 | 0 | V Value() { |
681 | 0 | return D_->items_[i_].second; |
682 | 0 | } |
683 | | |
684 | | Dict<K, V>* D_; |
685 | | int i_; |
686 | | }; |
687 | | |
688 | | // Specialized functions |
689 | | template <class V> |
690 | 29 | int find_by_key(const std::vector<std::pair<Str*, V>>& items, Str* key) { |
691 | 29 | int n = items.size(); |
692 | 87 | for (int i = 0; i < n; ++i) { |
693 | 66 | Str* s = items[i].first; // nullptr for deleted entries |
694 | 66 | if (s && str_equals(s, key)) { |
695 | 8 | return i; |
696 | 8 | } |
697 | 66 | } |
698 | 21 | return -1; |
699 | 29 | } _Z11find_by_keyIiEiRKSt6vectorISt4pairIP3StrT_ESaIS5_EES3_ Line | Count | Source | 690 | 15 | int find_by_key(const std::vector<std::pair<Str*, V>>& items, Str* key) { | 691 | 15 | int n = items.size(); | 692 | 34 | for (int i = 0; i < n; ++i) { | 693 | 26 | Str* s = items[i].first; // nullptr for deleted entries | 694 | 26 | if (s && str_equals(s, key)) { | 695 | 7 | return i; | 696 | 7 | } | 697 | 26 | } | 698 | 8 | return -1; | 699 | 15 | } |
_Z11find_by_keyIP3StrEiRKSt6vectorISt4pairIS1_T_ESaIS5_EES1_ Line | Count | Source | 690 | 2 | int find_by_key(const std::vector<std::pair<Str*, V>>& items, Str* key) { | 691 | 2 | int n = items.size(); | 692 | 2 | for (int i = 0; i < n; ++i) { | 693 | 1 | Str* s = items[i].first; // nullptr for deleted entries | 694 | 1 | if (s && str_equals(s, key)) { | 695 | 1 | return i; | 696 | 1 | } | 697 | 1 | } | 698 | 1 | return -1; | 699 | 2 | } |
_Z11find_by_keyIPN12runtime_asdl7value_tEEiRKSt6vectorISt4pairIP3StrT_ESaIS8_EES6_ Line | Count | Source | 690 | 12 | int find_by_key(const std::vector<std::pair<Str*, V>>& items, Str* key) { | 691 | 12 | int n = items.size(); | 692 | 51 | for (int i = 0; i < n; ++i) { | 693 | 39 | Str* s = items[i].first; // nullptr for deleted entries | 694 | 39 | if (s && str_equals(s, key)) { | 695 | 0 | return i; | 696 | 0 | } | 697 | 39 | } | 698 | 12 | return -1; | 699 | 12 | } |
|
700 | | |
701 | | template <class V> |
702 | 6 | int find_by_key(const std::vector<std::pair<int, V>>& items, int key) { |
703 | 6 | int n = items.size(); |
704 | 8 | for (int i = 0; i < n; ++i) { |
705 | 5 | if (items[i].first == key) { |
706 | 3 | return i; |
707 | 3 | } |
708 | 5 | } |
709 | 3 | return -1; |
710 | 6 | } |
711 | | |
712 | | template <class V> |
713 | 4 | List<Str*>* dict_keys(const std::vector<std::pair<Str*, V>>& items) { |
714 | 4 | auto result = new List<Str*>(); |
715 | 4 | int n = items.size(); |
716 | 14 | for (int i = 0; i < n; ++i) { |
717 | 10 | Str* s = items[i].first; // nullptr for deleted entries |
718 | 10 | if (s) { |
719 | 10 | result->append(s); |
720 | 10 | } |
721 | 10 | } |
722 | 4 | return result; |
723 | 4 | } _Z9dict_keysIiEP4ListIP3StrERKSt6vectorISt4pairIS2_T_ESaIS8_EE Line | Count | Source | 713 | 3 | List<Str*>* dict_keys(const std::vector<std::pair<Str*, V>>& items) { | 714 | 3 | auto result = new List<Str*>(); | 715 | 3 | int n = items.size(); | 716 | 12 | for (int i = 0; i < n; ++i) { | 717 | 9 | Str* s = items[i].first; // nullptr for deleted entries | 718 | 9 | if (s) { | 719 | 9 | result->append(s); | 720 | 9 | } | 721 | 9 | } | 722 | 3 | return result; | 723 | 3 | } |
_Z9dict_keysIP3StrEP4ListIS1_ERKSt6vectorISt4pairIS1_T_ESaIS8_EE Line | Count | Source | 713 | 1 | List<Str*>* dict_keys(const std::vector<std::pair<Str*, V>>& items) { | 714 | 1 | auto result = new List<Str*>(); | 715 | 1 | int n = items.size(); | 716 | 2 | for (int i = 0; i < n; ++i) { | 717 | 1 | Str* s = items[i].first; // nullptr for deleted entries | 718 | 1 | if (s) { | 719 | 1 | result->append(s); | 720 | 1 | } | 721 | 1 | } | 722 | 1 | return result; | 723 | 1 | } |
|
724 | | |
725 | | template <class V> |
726 | 2 | List<V>* dict_values(const std::vector<std::pair<Str*, V>>& items) { |
727 | 2 | auto result = new List<V>(); |
728 | 2 | int n = items.size(); |
729 | 6 | for (int i = 0; i < n; ++i) { |
730 | 4 | auto& pair = items[i]; |
731 | 4 | if (pair.first) { |
732 | 4 | result->append(pair.second); |
733 | 4 | } |
734 | 4 | } |
735 | 2 | return result; |
736 | 2 | } _Z11dict_valuesIiEP4ListIT_ERKSt6vectorISt4pairIP3StrS1_ESaIS8_EE Line | Count | Source | 726 | 1 | List<V>* dict_values(const std::vector<std::pair<Str*, V>>& items) { | 727 | 1 | auto result = new List<V>(); | 728 | 1 | int n = items.size(); | 729 | 4 | for (int i = 0; i < n; ++i) { | 730 | 3 | auto& pair = items[i]; | 731 | 3 | if (pair.first) { | 732 | 3 | result->append(pair.second); | 733 | 3 | } | 734 | 3 | } | 735 | 1 | return result; | 736 | 1 | } |
_Z11dict_valuesIP3StrEP4ListIT_ERKSt6vectorISt4pairIS1_S3_ESaIS8_EE Line | Count | Source | 726 | 1 | List<V>* dict_values(const std::vector<std::pair<Str*, V>>& items) { | 727 | 1 | auto result = new List<V>(); | 728 | 1 | int n = items.size(); | 729 | 2 | for (int i = 0; i < n; ++i) { | 730 | 1 | auto& pair = items[i]; | 731 | 1 | if (pair.first) { | 732 | 1 | result->append(pair.second); | 733 | 1 | } | 734 | 1 | } | 735 | 1 | return result; | 736 | 1 | } |
|
737 | | |
738 | | // Dict currently implemented by VECTOR OF PAIRS. TODO: Use a real hash table, |
739 | | // and measure performance. The hash table has to beat this for small cases! |
740 | | template <class K, class V> |
741 | | class Dict : public gc_heap::Obj { |
742 | | public: |
743 | 10 | Dict() : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), items_() { |
744 | 10 | } Line | Count | Source | 743 | 1 | Dict() : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), items_() { | 744 | 1 | } |
Line | Count | Source | 743 | 2 | Dict() : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), items_() { | 744 | 2 | } |
Line | Count | Source | 743 | 1 | Dict() : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), items_() { | 744 | 1 | } |
_ZN4DictIP3StrPN4args7_ActionEEC2Ev Line | Count | Source | 743 | 4 | Dict() : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), items_() { | 744 | 4 | } |
_ZN4DictIP3StrPN12runtime_asdl7value_tEEC2Ev Line | Count | Source | 743 | 2 | Dict() : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), items_() { | 744 | 2 | } |
|
745 | | |
746 | | // Dummy |
747 | | Dict(std::initializer_list<K> keys, std::initializer_list<V> values) |
748 | | : gc_heap::Obj(Tag::FixedSize, gc_heap::kZeroMask, 0), items_() { |
749 | | } |
750 | | |
751 | | // d[key] in Python: raises KeyError if not found |
752 | 5 | V index_(K key) { |
753 | 5 | int pos = find(key); |
754 | 5 | if (pos == -1) { |
755 | 0 | throw new KeyError(); |
756 | 5 | } else { |
757 | 5 | return items_[pos].second; |
758 | 5 | } |
759 | 5 | } _ZN4DictIiP3StrE6index_Ei Line | Count | Source | 752 | 1 | V index_(K key) { | 753 | 1 | int pos = find(key); | 754 | 1 | if (pos == -1) { | 755 | 0 | throw new KeyError(); | 756 | 1 | } else { | 757 | 1 | return items_[pos].second; | 758 | 1 | } | 759 | 1 | } |
_ZN4DictIP3StriE6index_ES1_ Line | Count | Source | 752 | 4 | V index_(K key) { | 753 | 4 | int pos = find(key); | 754 | 4 | if (pos == -1) { | 755 | 0 | throw new KeyError(); | 756 | 4 | } else { | 757 | 4 | return items_[pos].second; | 758 | 4 | } | 759 | 4 | } |
Unexecuted instantiation: _ZN4DictIP3StrPN12runtime_asdl7value_tEE6index_ES1_ |
760 | | |
761 | | // Get a key. |
762 | | // Returns nullptr if not found (Can't use this for non-pointer types?) |
763 | 2 | V get(K key) { |
764 | 2 | int pos = find(key); |
765 | 2 | if (pos == -1) { |
766 | 1 | return nullptr; |
767 | 1 | } else { |
768 | 1 | return items_[pos].second; |
769 | 1 | } |
770 | 2 | } Line | Count | Source | 763 | 2 | V get(K key) { | 764 | 2 | int pos = find(key); | 765 | 2 | if (pos == -1) { | 766 | 1 | return nullptr; | 767 | 1 | } else { | 768 | 1 | return items_[pos].second; | 769 | 1 | } | 770 | 2 | } |
Unexecuted instantiation: _ZN4DictIP3StrS1_E3getES1_ |
771 | | |
772 | | // Get a key, but return a default if not found. |
773 | | // expr_parse.py uses this with OTHER_BALANCE |
774 | | V get(K key, V default_val) { |
775 | | int pos = find(key); |
776 | | if (pos == -1) { |
777 | | return default_val; |
778 | | } else { |
779 | | return items_[pos].second; |
780 | | } |
781 | | } |
782 | | |
783 | | // d->set(key, val) is like (*d)[key] = val; |
784 | 20 | void set(K key, V val) { |
785 | 20 | int pos = find(key); |
786 | 20 | if (pos == -1) { |
787 | 20 | items_.push_back(std::make_pair(key, val)); |
788 | 20 | } else { |
789 | 0 | items_[pos].second = val; |
790 | 0 | } |
791 | 20 | } _ZN4DictIiP3StrE3setEiS1_ Line | Count | Source | 784 | 1 | void set(K key, V val) { | 785 | 1 | int pos = find(key); | 786 | 1 | if (pos == -1) { | 787 | 1 | items_.push_back(std::make_pair(key, val)); | 788 | 1 | } else { | 789 | 0 | items_[pos].second = val; | 790 | 0 | } | 791 | 1 | } |
_ZN4DictIP3StriE3setES1_i Line | Count | Source | 784 | 6 | void set(K key, V val) { | 785 | 6 | int pos = find(key); | 786 | 6 | if (pos == -1) { | 787 | 6 | items_.push_back(std::make_pair(key, val)); | 788 | 6 | } else { | 789 | 0 | items_[pos].second = val; | 790 | 0 | } | 791 | 6 | } |
_ZN4DictIP3StrS1_E3setES1_S1_ Line | Count | Source | 784 | 1 | void set(K key, V val) { | 785 | 1 | int pos = find(key); | 786 | 1 | if (pos == -1) { | 787 | 1 | items_.push_back(std::make_pair(key, val)); | 788 | 1 | } else { | 789 | 0 | items_[pos].second = val; | 790 | 0 | } | 791 | 1 | } |
_ZN4DictIP3StrPN12runtime_asdl7value_tEE3setES1_S4_ Line | Count | Source | 784 | 12 | void set(K key, V val) { | 785 | 12 | int pos = find(key); | 786 | 12 | if (pos == -1) { | 787 | 12 | items_.push_back(std::make_pair(key, val)); | 788 | 12 | } else { | 789 | 0 | items_[pos].second = val; | 790 | 0 | } | 791 | 12 | } |
|
792 | | |
793 | 2 | void remove(K key) { |
794 | 2 | mylib::dict_remove(this, key); |
795 | 2 | } _ZN4DictIP3StriE6removeES1_ Line | Count | Source | 793 | 1 | void remove(K key) { | 794 | 1 | mylib::dict_remove(this, key); | 795 | 1 | } |
_ZN4DictIP3StrS1_E6removeES1_ Line | Count | Source | 793 | 1 | void remove(K key) { | 794 | 1 | mylib::dict_remove(this, key); | 795 | 1 | } |
|
796 | | |
797 | 4 | List<K>* keys() { |
798 | 4 | return dict_keys(items_); |
799 | 4 | } Line | Count | Source | 797 | 3 | List<K>* keys() { | 798 | 3 | return dict_keys(items_); | 799 | 3 | } |
_ZN4DictIP3StrS1_E4keysEv Line | Count | Source | 797 | 1 | List<K>* keys() { | 798 | 1 | return dict_keys(items_); | 799 | 1 | } |
|
800 | | |
801 | | // For AssocArray transformations |
802 | 2 | List<V>* values() { |
803 | 2 | return dict_values(items_); |
804 | 2 | } _ZN4DictIP3StriE6valuesEv Line | Count | Source | 802 | 1 | List<V>* values() { | 803 | 1 | return dict_values(items_); | 804 | 1 | } |
_ZN4DictIP3StrS1_E6valuesEv Line | Count | Source | 802 | 1 | List<V>* values() { | 803 | 1 | return dict_values(items_); | 804 | 1 | } |
|
805 | | |
806 | 1 | void clear() { |
807 | 1 | items_.clear(); |
808 | 1 | } |
809 | | |
810 | | // std::unordered_map<K, V> m_; |
811 | | std::vector<std::pair<K, V>> items_; |
812 | | |
813 | | private: |
814 | | // returns the position in the array |
815 | 27 | int find(K key) { |
816 | 27 | return find_by_key(items_, key); |
817 | 27 | } Line | Count | Source | 815 | 4 | int find(K key) { | 816 | 4 | return find_by_key(items_, key); | 817 | 4 | } |
_ZN4DictIP3StriE4findES1_ Line | Count | Source | 815 | 10 | int find(K key) { | 816 | 10 | return find_by_key(items_, key); | 817 | 10 | } |
_ZN4DictIP3StrS1_E4findES1_ Line | Count | Source | 815 | 1 | int find(K key) { | 816 | 1 | return find_by_key(items_, key); | 817 | 1 | } |
_ZN4DictIP3StrPN12runtime_asdl7value_tEE4findES1_ Line | Count | Source | 815 | 12 | int find(K key) { | 816 | 12 | return find_by_key(items_, key); | 817 | 12 | } |
|
818 | | }; |
819 | | |
820 | | template <typename K, typename V> |
821 | | Dict<K, V>* NewDict() { |
822 | | auto self = gc_heap::Alloc<Dict<K, V>>(); |
823 | | return self; |
824 | | } |
825 | | |
826 | | template <typename K, typename V> |
827 | | Dict<K, V>* NewDict(std::initializer_list<K> keys, |
828 | | std::initializer_list<V> values) { |
829 | | // TODO(Jesse): Is this NotImplemented() or InvalidCodePath() ? |
830 | | assert(0); // Uncalled |
831 | | } |
832 | | |
833 | | #endif // MYLIB_LEAKY |
834 | | |
835 | | template <class A, class B> |
836 | | class Tuple2 { |
837 | | public: |
838 | 20 | Tuple2(A a, B b) : a_(a), b_(b) { |
839 | 20 | } Line | Count | Source | 838 | 9 | Tuple2(A a, B b) : a_(a), b_(b) { | 839 | 9 | } |
_ZN6Tuple2IiP3StrEC2EiS1_ Line | Count | Source | 838 | 7 | Tuple2(A a, B b) : a_(a), b_(b) { | 839 | 7 | } |
_ZN6Tuple2IP3StrS1_EC2ES1_S1_ Line | Count | Source | 838 | 4 | Tuple2(A a, B b) : a_(a), b_(b) { | 839 | 4 | } |
Unexecuted instantiation: _ZN6Tuple2IPN4args11_AttributesEPNS0_6ReaderEEC2ES2_S4_ |
840 | 20 | A at0() { |
841 | 20 | return a_; |
842 | 20 | } _ZN6Tuple2IP3StrS1_E3at0Ev Line | Count | Source | 840 | 4 | A at0() { | 841 | 4 | return a_; | 842 | 4 | } |
Line | Count | Source | 840 | 9 | A at0() { | 841 | 9 | return a_; | 842 | 9 | } |
Line | Count | Source | 840 | 7 | A at0() { | 841 | 7 | return a_; | 842 | 7 | } |
Unexecuted instantiation: _ZN6Tuple2IP3StriE3at0Ev |
843 | 19 | B at1() { |
844 | 19 | return b_; |
845 | 19 | } _ZN6Tuple2IP3StrS1_E3at1Ev Line | Count | Source | 843 | 4 | B at1() { | 844 | 4 | return b_; | 845 | 4 | } |
Line | Count | Source | 843 | 9 | B at1() { | 844 | 9 | return b_; | 845 | 9 | } |
Line | Count | Source | 843 | 6 | B at1() { | 844 | 6 | return b_; | 845 | 6 | } |
Unexecuted instantiation: _ZN6Tuple2IP3StriE3at1Ev |
846 | | |
847 | | private: |
848 | | A a_; |
849 | | B b_; |
850 | | }; |
851 | | |
852 | | template <class A, class B, class C> |
853 | | class Tuple3 { |
854 | | public: |
855 | 1 | Tuple3(A a, B b, C c) : a_(a), b_(b), c_(c) { |
856 | 1 | } _ZN6Tuple3IiP3StrS1_EC2EiS1_S1_ Line | Count | Source | 855 | 1 | Tuple3(A a, B b, C c) : a_(a), b_(b), c_(c) { | 856 | 1 | } |
Unexecuted instantiation: _ZN6Tuple3IdddEC2Eddd |
857 | 1 | A at0() { |
858 | 1 | return a_; |
859 | 1 | } |
860 | 1 | B at1() { |
861 | 1 | return b_; |
862 | 1 | } |
863 | 1 | C at2() { |
864 | 1 | return c_; |
865 | 1 | } |
866 | | |
867 | | private: |
868 | | A a_; |
869 | | B b_; |
870 | | C c_; |
871 | | }; |
872 | | |
873 | | template <class A, class B, class C, class D> |
874 | | class Tuple4 { |
875 | | public: |
876 | 1 | Tuple4(A a, B b, C c, D d) : a_(a), b_(b), c_(c), d_(d) { |
877 | 1 | } |
878 | 1 | A at0() { |
879 | 1 | return a_; |
880 | 1 | } |
881 | 1 | B at1() { |
882 | 1 | return b_; |
883 | 1 | } |
884 | 1 | C at2() { |
885 | 1 | return c_; |
886 | 1 | } |
887 | 1 | D at3() { |
888 | 1 | return d_; |
889 | 1 | } |
890 | | |
891 | | private: |
892 | | A a_; |
893 | | B b_; |
894 | | C c_; |
895 | | D d_; |
896 | | }; |
897 | | |
898 | | // |
899 | | // Overloaded free function len() |
900 | | // |
901 | | |
902 | | #ifdef MYLIB_LEAKY |
903 | 23 | inline int len(const Str* s) { |
904 | 23 | return s->len_; |
905 | 23 | } |
906 | | |
907 | | template <typename T> |
908 | 30 | inline int len(const List<T>* L) { |
909 | | // inline int len(List<T>* L) { |
910 | 30 | return L->v_.size(); |
911 | 30 | } Line | Count | Source | 908 | 17 | inline int len(const List<T>* L) { | 909 | | // inline int len(List<T>* L) { | 910 | 17 | return L->v_.size(); | 911 | 17 | } |
Line | Count | Source | 908 | 1 | inline int len(const List<T>* L) { | 909 | | // inline int len(List<T>* L) { | 910 | 1 | return L->v_.size(); | 911 | 1 | } |
_Z3lenIP3StrEiPK4ListIT_E Line | Count | Source | 908 | 12 | inline int len(const List<T>* L) { | 909 | | // inline int len(List<T>* L) { | 910 | 12 | return L->v_.size(); | 911 | 12 | } |
|
912 | | |
913 | | template <typename K, typename V> |
914 | | inline int len(const Dict<K, V>* d) { |
915 | | assert(0); |
916 | | } |
917 | | |
918 | | template <typename V> |
919 | 7 | inline int len(const Dict<Str*, V>* d) { |
920 | 7 | int len = 0; |
921 | 7 | int n = d->items_.size(); |
922 | 21 | for (int i = 0; i < n; ++i) { |
923 | 14 | Str* s = d->items_[i].first; // nullptr for deleted entries |
924 | 14 | if (s) { |
925 | 10 | len++; |
926 | 10 | } |
927 | 14 | } |
928 | 7 | return len; |
929 | 7 | } _Z3lenIiEiPK4DictIP3StrT_E Line | Count | Source | 919 | 5 | inline int len(const Dict<Str*, V>* d) { | 920 | 5 | int len = 0; | 921 | 5 | int n = d->items_.size(); | 922 | 17 | for (int i = 0; i < n; ++i) { | 923 | 12 | Str* s = d->items_[i].first; // nullptr for deleted entries | 924 | 12 | if (s) { | 925 | 9 | len++; | 926 | 9 | } | 927 | 12 | } | 928 | 5 | return len; | 929 | 5 | } |
_Z3lenIP3StrEiPK4DictIS1_T_E Line | Count | Source | 919 | 2 | inline int len(const Dict<Str*, V>* d) { | 920 | 2 | int len = 0; | 921 | 2 | int n = d->items_.size(); | 922 | 4 | for (int i = 0; i < n; ++i) { | 923 | 2 | Str* s = d->items_[i].first; // nullptr for deleted entries | 924 | 2 | if (s) { | 925 | 1 | len++; | 926 | 1 | } | 927 | 2 | } | 928 | 2 | return len; | 929 | 2 | } |
|
930 | | #endif |
931 | | |
932 | | // |
933 | | // Free functions |
934 | | // |
935 | | |
936 | | Str* str_concat(Str* a, Str* b); // a + b when a and b are strings |
937 | | Str* str_concat3(Str* a, Str* b, Str* c); // for os_path::join() |
938 | | |
939 | | Str* str_repeat(Str* s, int times); // e.g. ' ' * 3 |
940 | | |
941 | | #if MYLIB_LEAKY |
942 | 132 | inline bool str_equals(Str* left, Str* right) { |
943 | 132 | if (left->len_ == right->len_) { |
944 | 127 | return memcmp(left->data_, right->data_, left->len_) == 0; |
945 | 127 | } else { |
946 | 5 | return false; |
947 | 5 | } |
948 | 132 | } |
949 | | |
950 | | namespace id_kind_asdl { |
951 | | enum class Kind; |
952 | | }; |
953 | | |
954 | | inline bool are_equal(id_kind_asdl::Kind left, id_kind_asdl::Kind right); |
955 | | |
956 | 8 | inline bool are_equal(int left, int right) { |
957 | 8 | return left == right; |
958 | 0 | ; |
959 | 0 | } |
960 | | |
961 | 9 | inline bool are_equal(Str* left, Str* right) { |
962 | 9 | return str_equals(left, right); |
963 | 9 | } |
964 | | |
965 | 0 | inline bool are_equal(Tuple2<Str*, int>* t1, Tuple2<Str*, int>* t2) { |
966 | 0 | bool result = are_equal(t1->at0(), t2->at0()); |
967 | 0 | result = result && (t1->at1() == t2->at1()); |
968 | 0 | return result; |
969 | 0 | } |
970 | | #endif |
971 | | |
972 | 94 | inline bool str_equals0(const char* c_string, Str* s) { |
973 | 94 | int n = strlen(c_string); |
974 | 94 | if (s->len_ == n) { |
975 | 14 | return memcmp(s->data_, c_string, n) == 0; |
976 | 80 | } else { |
977 | 80 | return false; |
978 | 80 | } |
979 | 94 | } |
980 | | |
981 | 0 | inline bool maybe_str_equals(Str* left, Str* right) { |
982 | 0 | if (left && right) { |
983 | 0 | return str_equals(left, right); |
984 | 0 | } |
985 | 0 |
|
986 | 0 | if (!left && !right) { |
987 | 0 | return true; // None == None |
988 | 0 | } |
989 | 0 |
|
990 | 0 | return false; // one is None and one is a Str* |
991 | 0 | } |
992 | | |
993 | | inline Str* chr(int i) { |
994 | | char* buf = static_cast<char*>(malloc(2)); |
995 | | buf[0] = i; |
996 | | buf[1] = '\0'; |
997 | | return new Str(buf, 1); |
998 | | } |
999 | | |
1000 | 0 | inline int ord(Str* s) { |
1001 | 0 | assert(s->len_ == 1); |
1002 | 0 | // signed to unsigned conversion, so we don't get values like -127 |
1003 | 0 | uint8_t c = static_cast<uint8_t>(s->data_[0]); |
1004 | 0 | return c; |
1005 | 0 | } |
1006 | | |
1007 | | // https://stackoverflow.com/questions/3919995/determining-sprintf-buffer-size-whats-the-standard/11092994#11092994 |
1008 | | // Notes: |
1009 | | // - Python 2.7's intobject.c has an erroneous +6 |
1010 | | // - This is 13, but len('-2147483648') is 11, which means we only need 12? |
1011 | | // - This formula is valid for octal(), because 2^(3 bits) = 8 |
1012 | | const int kIntBufSize = CHAR_BIT * sizeof(int) / 3 + 3; |
1013 | | |
1014 | | inline Str* str(int i) { |
1015 | | char* buf = static_cast<char*>(malloc(kIntBufSize)); |
1016 | | int len = snprintf(buf, kIntBufSize, "%d", i); |
1017 | | return new Str(buf, len); |
1018 | | } |
1019 | | |
1020 | 0 | inline Str* str(double f) { // TODO: should be double |
1021 | 0 | NotImplemented(); // Uncalled |
1022 | 0 | } |
1023 | | |
1024 | | // Display a quoted representation of a string. word_.Pretty() uses it. |
1025 | | Str* repr(Str* s); |
1026 | | |
1027 | | // TODO: There should be one str() and one repr() for every sum type, that |
1028 | | // dispatches on tag? Or just repr()? |
1029 | | |
1030 | | // Will need it for dict, but not tuple. |
1031 | | // inline int len(Dict* D) { |
1032 | | // } |
1033 | | |
1034 | | bool _str_to_int(Str* s, int* result, int base); // for testing only |
1035 | | int to_int(Str* s); |
1036 | | int to_int(Str* s, int base); |
1037 | | |
1038 | | // int(a == b) used in arithmetic evaluator |
1039 | 0 | inline int to_int(bool b) { |
1040 | 0 | return b; |
1041 | 0 | } |
1042 | | |
1043 | | inline bool to_bool(int i) { |
1044 | | return i != 0; |
1045 | | } |
1046 | | |
1047 | 0 | inline bool to_bool(Str* s) { |
1048 | 0 | return s->len_ != 0; |
1049 | 0 | } |
1050 | | |
1051 | 0 | inline double to_float(Str* s) { |
1052 | 0 | assert(s->IsNulTerminated()); |
1053 | 0 | double result = atof(s->data_); |
1054 | 0 | return result; |
1055 | 0 | } |
1056 | | |
1057 | | // e.g. ('a' in 'abc') |
1058 | 8 | inline bool str_contains(Str* haystack, Str* needle) { |
1059 | | // Common case |
1060 | 8 | if (needle->len_ == 1) { |
1061 | 2 | return memchr(haystack->data_, needle->data_[0], haystack->len_); |
1062 | 2 | } |
1063 | | |
1064 | | // General case. TODO: We could use a smarter substring algorithm. |
1065 | 6 | if (needle->len_ > haystack->len_) { |
1066 | 1 | return false; |
1067 | 1 | } |
1068 | | |
1069 | 5 | const char* end = haystack->data_ + haystack->len_; |
1070 | 5 | const char* last_possible = end - needle->len_; |
1071 | 5 | const char* p = haystack->data_; |
1072 | | |
1073 | 11 | while (p <= last_possible) { |
1074 | 10 | if (memcmp(p, needle->data_, needle->len_) == 0) { |
1075 | 4 | return true; |
1076 | 4 | } |
1077 | 6 | p++; |
1078 | 6 | } |
1079 | 1 | return false; |
1080 | 5 | } |
1081 | | |
1082 | | // e.g. [None] * 3 |
1083 | | template <typename T> |
1084 | 2 | List<T>* list_repeat(T item, int times) { |
1085 | 2 | return new List<T>(item, times); |
1086 | 2 | } _Z11list_repeatIP3StrEP4ListIT_ES3_i Line | Count | Source | 1084 | 1 | List<T>* list_repeat(T item, int times) { | 1085 | 1 | return new List<T>(item, times); | 1086 | 1 | } |
_Z11list_repeatIbEP4ListIT_ES1_i Line | Count | Source | 1084 | 1 | List<T>* list_repeat(T item, int times) { | 1085 | 1 | return new List<T>(item, times); | 1086 | 1 | } |
|
1087 | | |
1088 | | // list(L) copies the list |
1089 | | template <typename T> |
1090 | | List<T>* list(List<T>* other) { |
1091 | | auto result = new List<T>(); |
1092 | | for (int i = 0; i < len(other); ++i) { |
1093 | | result->set(i, other->index_(i)); |
1094 | | } |
1095 | | return result; |
1096 | | } |
1097 | | |
1098 | | template <typename T> |
1099 | 8 | bool list_contains(List<T>* haystack, T needle) { |
1100 | 8 | int n = haystack->v_.size(); |
1101 | 21 | for (int i = 0; i < n; ++i) { |
1102 | 17 | if (are_equal(haystack->index_(i), needle)) { |
1103 | 4 | return true; |
1104 | 4 | } |
1105 | 17 | } |
1106 | 4 | return false; |
1107 | 8 | } _Z13list_containsIP3StrEbP4ListIT_ES3_ Line | Count | Source | 1099 | 4 | bool list_contains(List<T>* haystack, T needle) { | 1100 | 4 | int n = haystack->v_.size(); | 1101 | 11 | for (int i = 0; i < n; ++i) { | 1102 | 9 | if (are_equal(haystack->index_(i), needle)) { | 1103 | 2 | return true; | 1104 | 2 | } | 1105 | 9 | } | 1106 | 2 | return false; | 1107 | 4 | } |
_Z13list_containsIiEbP4ListIT_ES1_ Line | Count | Source | 1099 | 2 | bool list_contains(List<T>* haystack, T needle) { | 1100 | 2 | int n = haystack->v_.size(); | 1101 | 5 | for (int i = 0; i < n; ++i) { | 1102 | 4 | if (are_equal(haystack->index_(i), needle)) { | 1103 | 1 | return true; | 1104 | 1 | } | 1105 | 4 | } | 1106 | 1 | return false; | 1107 | 2 | } |
_Z13list_containsIdEbP4ListIT_ES1_ Line | Count | Source | 1099 | 2 | bool list_contains(List<T>* haystack, T needle) { | 1100 | 2 | int n = haystack->v_.size(); | 1101 | 5 | for (int i = 0; i < n; ++i) { | 1102 | 4 | if (are_equal(haystack->index_(i), needle)) { | 1103 | 1 | return true; | 1104 | 1 | } | 1105 | 4 | } | 1106 | 1 | return false; | 1107 | 2 | } |
|
1108 | | |
1109 | | template <typename T> |
1110 | | bool list_contains(List<T>* haystack, T* needle) { |
1111 | | bool result = false; |
1112 | | |
1113 | | if (needle) { |
1114 | | result = list_contains(haystack, *needle); |
1115 | | } |
1116 | | |
1117 | | return result; |
1118 | | } |
1119 | | |
1120 | | template <typename K, typename V> |
1121 | 5 | inline bool dict_contains(Dict<K, V>* haystack, K needle) { |
1122 | 5 | return find_by_key(haystack->items_, needle) != -1; |
1123 | 5 | } _Z13dict_containsIiP3StrEbP4DictIT_T0_ES3_ Line | Count | Source | 1121 | 2 | inline bool dict_contains(Dict<K, V>* haystack, K needle) { | 1122 | 2 | return find_by_key(haystack->items_, needle) != -1; | 1123 | 2 | } |
_Z13dict_containsIP3StriEbP4DictIT_T0_ES3_ Line | Count | Source | 1121 | 3 | inline bool dict_contains(Dict<K, V>* haystack, K needle) { | 1122 | 3 | return find_by_key(haystack->items_, needle) != -1; | 1123 | 3 | } |
|
1124 | | |
1125 | | template <typename V> |
1126 | 1 | List<Str*>* sorted(Dict<Str*, V>* d) { |
1127 | 1 | auto keys = d->keys(); |
1128 | 1 | keys->sort(); |
1129 | 1 | return keys; |
1130 | 1 | } |
1131 | | |
1132 | 8 | inline int int_cmp(int a, int b) { |
1133 | 8 | if (a == b) { |
1134 | 2 | return 0; |
1135 | 2 | } |
1136 | 6 | return a < b ? -1 : 1; |
1137 | 8 | } |
1138 | | |
1139 | | // Used by [[ a > b ]] and so forth |
1140 | 14 | inline int str_cmp(Str* a, Str* b) { |
1141 | 14 | int min = std::min(a->len_, b->len_); |
1142 | 14 | if (min == 0) { |
1143 | 4 | return int_cmp(a->len_, b->len_); |
1144 | 4 | } |
1145 | 10 | int comp = memcmp(a->data_, b->data_, min); |
1146 | 10 | if (comp == 0) { |
1147 | 1 | return int_cmp(a->len_, b->len_); // tiebreaker |
1148 | 1 | } |
1149 | 9 | return comp; |
1150 | 10 | } |
1151 | | |
1152 | | // Hm std::sort() just needs true/false, not 0, 1, 1. |
1153 | 8 | inline bool _cmp(Str* a, Str* b) { |
1154 | 8 | return str_cmp(a, b) < 0; |
1155 | 8 | } |
1156 | | |
1157 | | // specialization for Str only |
1158 | 2 | inline void mysort(std::vector<Str*>* v) { |
1159 | 2 | std::sort(v->begin(), v->end(), _cmp); |
1160 | 2 | } |
1161 | | |
1162 | | // |
1163 | | // Buf is StringIO |
1164 | | // |
1165 | | |
1166 | | namespace mylib { // MyPy artifact |
1167 | | |
1168 | | template <typename V> |
1169 | 3 | inline void dict_remove(Dict<Str*, V>* haystack, Str* needle) { |
1170 | 3 | int pos = find_by_key(haystack->items_, needle); |
1171 | 3 | if (pos == -1) { |
1172 | 0 | return; |
1173 | 0 | } |
1174 | 3 | haystack->items_[pos].first = nullptr; |
1175 | 3 | } _ZN5mylib11dict_removeIiEEvP4DictIP3StrT_ES3_ Line | Count | Source | 1169 | 2 | inline void dict_remove(Dict<Str*, V>* haystack, Str* needle) { | 1170 | 2 | int pos = find_by_key(haystack->items_, needle); | 1171 | 2 | if (pos == -1) { | 1172 | 0 | return; | 1173 | 0 | } | 1174 | 2 | haystack->items_[pos].first = nullptr; | 1175 | 2 | } |
_ZN5mylib11dict_removeIP3StrEEvP4DictIS2_T_ES2_ Line | Count | Source | 1169 | 1 | inline void dict_remove(Dict<Str*, V>* haystack, Str* needle) { | 1170 | 1 | int pos = find_by_key(haystack->items_, needle); | 1171 | 1 | if (pos == -1) { | 1172 | 0 | return; | 1173 | 0 | } | 1174 | 1 | haystack->items_[pos].first = nullptr; | 1175 | 1 | } |
|
1176 | | |
1177 | | // TODO: how to do the int version of this? Do you need an extra bit? |
1178 | | template <typename V> |
1179 | | inline void dict_remove(Dict<int, V>* haystack, int needle) { |
1180 | | NotImplemented(); |
1181 | | } |
1182 | | |
1183 | | // A class for interfacing Str* slices with C functions that expect a NUL |
1184 | | // terminated string. It's meant to be used on the stack, like |
1185 | | // |
1186 | | // void f(Str* pat) { |
1187 | | // Str0 c_pattern(pat); |
1188 | | // int n = strlen(c_pattern.Get()); |
1189 | | // |
1190 | | // // copy of Str* is destroyed |
1191 | | // } |
1192 | | class Str0 { |
1193 | | public: |
1194 | 47 | Str0(Str* s) : s_(s), nul_str_(nullptr) { |
1195 | 47 | } |
1196 | 94 | ~Str0() { |
1197 | 94 | if (nul_str_) { |
1198 | 6 | free(nul_str_); |
1199 | 6 | } |
1200 | 94 | } |
1201 | | |
1202 | 94 | const char* Get() { // caller should not modify this string! |
1203 | 94 | if (s_->IsNulTerminated()) { |
1204 | 88 | return s_->data_; |
1205 | 88 | } else { |
1206 | 6 | nul_str_ = static_cast<char*>(malloc(s_->len_ + 1)); |
1207 | 6 | memcpy(nul_str_, s_->data_, s_->len_); |
1208 | 6 | nul_str_[s_->len_] = '\0'; |
1209 | 6 | return nul_str_; |
1210 | 6 | } |
1211 | 94 | } Line | Count | Source | 1202 | 47 | const char* Get() { // caller should not modify this string! | 1203 | 47 | if (s_->IsNulTerminated()) { | 1204 | 44 | return s_->data_; | 1205 | 44 | } else { | 1206 | 3 | nul_str_ = static_cast<char*>(malloc(s_->len_ + 1)); | 1207 | 3 | memcpy(nul_str_, s_->data_, s_->len_); | 1208 | 3 | nul_str_[s_->len_] = '\0'; | 1209 | 3 | return nul_str_; | 1210 | 3 | } | 1211 | 47 | } |
Line | Count | Source | 1202 | 47 | const char* Get() { // caller should not modify this string! | 1203 | 47 | if (s_->IsNulTerminated()) { | 1204 | 44 | return s_->data_; | 1205 | 44 | } else { | 1206 | 3 | nul_str_ = static_cast<char*>(malloc(s_->len_ + 1)); | 1207 | 3 | memcpy(nul_str_, s_->data_, s_->len_); | 1208 | 3 | nul_str_[s_->len_] = '\0'; | 1209 | 3 | return nul_str_; | 1210 | 3 | } | 1211 | 47 | } |
|
1212 | | |
1213 | | Str* s_; |
1214 | | char* nul_str_; |
1215 | | }; |
1216 | | |
1217 | | Tuple2<Str*, Str*> split_once(Str* s, Str* delim); |
1218 | | |
1219 | | // Emulate GC API so we can reuse bindings |
1220 | | |
1221 | 4 | inline Str* AllocStr(int len) { |
1222 | 4 | char* buf = static_cast<char*>(malloc(len + 1)); |
1223 | 4 | memset(buf, 0, len + 1); |
1224 | 4 | return new Str(buf, len); |
1225 | 4 | } Line | Count | Source | 1221 | 2 | inline Str* AllocStr(int len) { | 1222 | 2 | char* buf = static_cast<char*>(malloc(len + 1)); | 1223 | 2 | memset(buf, 0, len + 1); | 1224 | 2 | return new Str(buf, len); | 1225 | 2 | } |
Line | Count | Source | 1221 | 2 | inline Str* AllocStr(int len) { | 1222 | 2 | char* buf = static_cast<char*>(malloc(len + 1)); | 1223 | 2 | memset(buf, 0, len + 1); | 1224 | 2 | return new Str(buf, len); | 1225 | 2 | } |
|
1226 | | |
1227 | 1 | inline Str* OverAllocatedStr(int len) { |
1228 | | // Here they are identical, but in gc_heap.cc they're different |
1229 | 1 | return AllocStr(len); |
1230 | 1 | } |
1231 | | |
1232 | 4 | inline Str* CopyStr(const char* s, int len) { |
1233 | | // take ownership (but still leaks) |
1234 | 4 | char* buf = static_cast<char*>(malloc(len + 1)); |
1235 | 4 | memcpy(buf, s, len); |
1236 | 4 | buf[len] = '\0'; |
1237 | 4 | return new Str(buf, len); |
1238 | 4 | } Line | Count | Source | 1232 | 2 | inline Str* CopyStr(const char* s, int len) { | 1233 | | // take ownership (but still leaks) | 1234 | 2 | char* buf = static_cast<char*>(malloc(len + 1)); | 1235 | 2 | memcpy(buf, s, len); | 1236 | 2 | buf[len] = '\0'; | 1237 | 2 | return new Str(buf, len); | 1238 | 2 | } |
Line | Count | Source | 1232 | 2 | inline Str* CopyStr(const char* s, int len) { | 1233 | | // take ownership (but still leaks) | 1234 | 2 | char* buf = static_cast<char*>(malloc(len + 1)); | 1235 | 2 | memcpy(buf, s, len); | 1236 | 2 | buf[len] = '\0'; | 1237 | 2 | return new Str(buf, len); | 1238 | 2 | } |
|
1239 | | |
1240 | 1 | inline Str* CopyStr(const char* s) { |
1241 | 1 | return CopyStr(s, strlen(s)); |
1242 | 1 | } |
1243 | | |
1244 | | // emulate gc_heap API for ASDL |
1245 | | |
1246 | | template <typename T> |
1247 | 0 | List<T>* NewList() { |
1248 | 0 | return new List<T>(); |
1249 | 0 | } Unexecuted instantiation: _ZN5mylib7NewListIPN10hnode_asdl5fieldEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN10hnode_asdl7hnode_tEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIP3StrEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIiEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN12runtime_asdl10assign_argEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN12runtime_asdl12part_value_tEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN12runtime_asdl7value_tEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl13compound_wordEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl11word_part_tEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl9command_tEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl6word_tEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl5redirEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl8env_pairEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl11assign_pairEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl6if_armEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl8case_armEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl9name_typeEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl12place_expr_tEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl5paramEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl11type_expr_tEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl7variantEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl12class_item_tEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl11import_nameEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl12UntypedParamEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl10TypedParamEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl5TokenEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl5speckEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl6expr_tEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl13comprehensionEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl20class_literal_term_tEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl4re_tEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl9named_argEEEP4ListIT_Ev Unexecuted instantiation: _ZN5mylib7NewListIPN11syntax_asdl11string_lineEEEP4ListIT_Ev |
1250 | | |
1251 | | template <typename T> |
1252 | | List<T>* NewList(std::initializer_list<T> init) { |
1253 | | return new List<T>(init); |
1254 | | } |
1255 | | |
1256 | | class LineReader { |
1257 | | public: |
1258 | | virtual Str* readline() = 0; |
1259 | 1 | virtual bool isatty() { |
1260 | 1 | return false; |
1261 | 1 | } |
1262 | | |
1263 | 0 | virtual int fileno() { |
1264 | 0 | NotImplemented(); |
1265 | 0 | } |
1266 | | }; |
1267 | | |
1268 | | class BufLineReader : public LineReader { |
1269 | | public: |
1270 | 0 | explicit BufLineReader(Str* s) : s_(s), pos_(s->data_) { |
1271 | 0 | } |
1272 | | virtual Str* readline(); |
1273 | | |
1274 | | private: |
1275 | | Str* s_; |
1276 | | const char* pos_; |
1277 | | |
1278 | | DISALLOW_COPY_AND_ASSIGN(BufLineReader) |
1279 | | }; |
1280 | | |
1281 | | // Wrap a FILE* |
1282 | | class CFileLineReader : public LineReader { |
1283 | | public: |
1284 | 4 | explicit CFileLineReader(FILE* f) : f_(f) { |
1285 | 4 | } |
1286 | | virtual Str* readline(); |
1287 | 1 | virtual int fileno() { |
1288 | 1 | return ::fileno(f_); |
1289 | 1 | } |
1290 | | |
1291 | | private: |
1292 | | FILE* f_; |
1293 | | |
1294 | | DISALLOW_COPY_AND_ASSIGN(CFileLineReader) |
1295 | | }; |
1296 | | |
1297 | | extern LineReader* gStdin; |
1298 | | |
1299 | | inline LineReader* Stdin() { |
1300 | | if (gStdin == nullptr) { |
1301 | | gStdin = new CFileLineReader(stdin); |
1302 | | } |
1303 | | return gStdin; |
1304 | | } |
1305 | | |
1306 | 0 | inline LineReader* open(Str* path) { |
1307 | 0 | Str0 path0(path); |
1308 | 0 | FILE* f = fopen(path0.Get(), "r"); |
1309 | 0 |
|
1310 | 0 | // TODO: Better error checking. IOError? |
1311 | 0 | if (!f) { |
1312 | 0 | throw new AssertionError("file not found"); |
1313 | 0 | } |
1314 | 0 | return new CFileLineReader(f); |
1315 | 0 | } |
1316 | | |
1317 | | class Writer { |
1318 | | public: |
1319 | | virtual void write(Str* s) = 0; |
1320 | | virtual void flush() = 0; |
1321 | | virtual bool isatty() = 0; |
1322 | | }; |
1323 | | |
1324 | | class BufWriter : public Writer { |
1325 | | public: |
1326 | 60 | BufWriter() : data_(nullptr), len_(0) { |
1327 | 60 | } |
1328 | | virtual void write(Str* s) override; |
1329 | 0 | virtual void flush() override { |
1330 | 0 | } |
1331 | 0 | virtual bool isatty() override { |
1332 | 0 | return false; |
1333 | 0 | } |
1334 | | // For cStringIO API |
1335 | 317 | Str* getvalue() { |
1336 | 317 | if (data_) { |
1337 | 317 | Str* ret = new Str(data_, len_); |
1338 | 317 | reset(); // Invalidate this instance |
1339 | 317 | return ret; |
1340 | 317 | } else { |
1341 | | // log('') translates to this |
1342 | | // Strings are immutable so we can do this. |
1343 | 0 | return kEmptyString; |
1344 | 0 | } |
1345 | 317 | } |
1346 | | |
1347 | | // Methods to compile printf format strings to |
1348 | | |
1349 | | // To reuse the global gBuf instance |
1350 | | // problem: '%r' % obj will recursively call asdl/format.py, which has its |
1351 | | // own % operations |
1352 | 610 | void reset() { |
1353 | 610 | data_ = nullptr; // make sure we get a new buffer next time |
1354 | 610 | len_ = 0; |
1355 | 610 | } |
1356 | | |
1357 | | // Note: we do NOT need to instantiate a Str() to append |
1358 | | void write_const(const char* s, int len); |
1359 | | |
1360 | | // strategy: snprintf() based on sizeof(int) |
1361 | | void format_d(int i); |
1362 | | void format_o(int i); |
1363 | | void format_s(Str* s); |
1364 | | void format_r(Str* s); // formats with quotes |
1365 | | |
1366 | | // looks at arbitrary type tags? Is this possible |
1367 | | // Passes "this" to functions generated by ASDL? |
1368 | | void format_r(void* s); |
1369 | | |
1370 | | private: |
1371 | | // Just like a string, except it's mutable |
1372 | | char* data_; |
1373 | | int len_; |
1374 | | }; |
1375 | | |
1376 | | // Wrap a FILE* |
1377 | | class CFileWriter : public Writer { |
1378 | | public: |
1379 | | explicit CFileWriter(FILE* f) : f_(f) { |
1380 | | } |
1381 | | virtual void write(Str* s) override; |
1382 | | virtual void flush() override; |
1383 | | virtual bool isatty() override; |
1384 | | |
1385 | | private: |
1386 | | FILE* f_; |
1387 | | |
1388 | | DISALLOW_COPY_AND_ASSIGN(CFileWriter) |
1389 | | }; |
1390 | | |
1391 | | extern Writer* gStdout; |
1392 | | |
1393 | | inline Writer* Stdout() { |
1394 | | if (gStdout == nullptr) { |
1395 | | gStdout = new CFileWriter(stdout); |
1396 | | } |
1397 | | return gStdout; |
1398 | | } |
1399 | | |
1400 | | extern Writer* gStderr; |
1401 | | |
1402 | 0 | inline Writer* Stderr() { |
1403 | 0 | if (gStderr == nullptr) { |
1404 | 0 | gStderr = new CFileWriter(stderr); |
1405 | 0 | } |
1406 | 0 | return gStderr; |
1407 | 0 | } |
1408 | | |
1409 | 4 | inline Str* hex_lower(int i) { |
1410 | 4 | char* buf = static_cast<char*>(malloc(kIntBufSize)); |
1411 | 4 | int len = snprintf(buf, kIntBufSize, "%x", i); |
1412 | 4 | return new Str(buf, len); |
1413 | 4 | } |
1414 | | |
1415 | 4 | inline Str* hex_upper(int i) { |
1416 | 4 | char* buf = static_cast<char*>(malloc(kIntBufSize)); |
1417 | 4 | int len = snprintf(buf, kIntBufSize, "%X", i); |
1418 | 4 | return new Str(buf, len); |
1419 | 4 | } |
1420 | | |
1421 | 4 | inline Str* octal(int i) { |
1422 | 4 | char* buf = static_cast<char*>(malloc(kIntBufSize)); |
1423 | 4 | int len = snprintf(buf, kIntBufSize, "%o", i); |
1424 | 4 | return new Str(buf, len); |
1425 | 4 | } |
1426 | | |
1427 | | } // namespace mylib |
1428 | | |
1429 | | // |
1430 | | // Formatter for Python's %s |
1431 | | // |
1432 | | |
1433 | | extern mylib::BufWriter gBuf; |
1434 | | |
1435 | | // mycpp doesn't understand dynamic format strings yet |
1436 | 0 | inline Str* dynamic_fmt_dummy() { |
1437 | 0 | return new Str("dynamic_fmt_dummy"); |
1438 | 0 | } |
1439 | | |
1440 | | #endif // MYLIB_H |