/home/andy/git/oilshell/oil/mycpp/gc_list.h
Line | Count | Source (jump to first uncovered line) |
1 | | #ifndef LIST_TYPES_H |
2 | | #define LIST_TYPES_H |
3 | | |
4 | | #include <algorithm> // sort() is templated |
5 | | |
6 | | #include "mycpp/comparators.h" |
7 | | |
8 | | class ValueError; |
9 | | |
10 | | // Type that is layout-compatible with List (unit tests assert this). Two |
11 | | // purposes: |
12 | | // - To make globals of "plain old data" at compile-time, not at startup time. |
13 | | // This can't be done with subclasses of Obj. |
14 | | // - To avoid invalid-offsetof warnings when computing GC masks. |
15 | | |
16 | | template <typename T, int N> |
17 | | class GlobalList { |
18 | | public: |
19 | | OBJ_HEADER() |
20 | | int len_; |
21 | | int capacity_; |
22 | | GlobalSlab<T, N>* slab_; |
23 | | }; |
24 | | |
25 | | // A list has one Slab pointer which we need to follow. |
26 | 508 | constexpr uint16_t maskof_List() { |
27 | 508 | return maskbit(offsetof(GlobalList<int COMMA 1>, slab_)); |
28 | 508 | } |
29 | | |
30 | | template <typename T> |
31 | | class List : public Obj { |
32 | | // TODO: Move methods that don't allocate or resize: out of gc_heap? |
33 | | // - allocate: append(), extend() |
34 | | // - resize: pop(), clear() |
35 | | // - neither: reverse(), sort() -- these are more like functions. Except |
36 | | // sort() is a templated method that depends on type param T. |
37 | | // - neither: index(), slice() |
38 | | |
39 | | // 8 / 4 = 2 items, or 8 / 8 = 1 item |
40 | | static const int kCapacityAdjust = kSlabHeaderSize / sizeof(T); |
41 | | static_assert(kSlabHeaderSize % sizeof(T) == 0, |
42 | | "Slab header size should be multiple of item size"); |
43 | | |
44 | | public: |
45 | 508 | List() : Obj(Tag::FixedSize, maskof_List(), sizeof(List<T>)) { |
46 | | // Ensured by heap zeroing. It's never directly on the stack. |
47 | 508 | assert(len_ == 0); |
48 | 0 | assert(capacity_ == 0); |
49 | 0 | assert(slab_ == nullptr); |
50 | 508 | } Line | Count | Source | 45 | 102 | List() : Obj(Tag::FixedSize, maskof_List(), sizeof(List<T>)) { | 46 | | // Ensured by heap zeroing. It's never directly on the stack. | 47 | 102 | assert(len_ == 0); | 48 | 0 | assert(capacity_ == 0); | 49 | 0 | assert(slab_ == nullptr); | 50 | 102 | } |
Line | Count | Source | 45 | 330 | List() : Obj(Tag::FixedSize, maskof_List(), sizeof(List<T>)) { | 46 | | // Ensured by heap zeroing. It's never directly on the stack. | 47 | 330 | assert(len_ == 0); | 48 | 0 | assert(capacity_ == 0); | 49 | 0 | assert(slab_ == nullptr); | 50 | 330 | } |
Line | Count | Source | 45 | 3 | List() : Obj(Tag::FixedSize, maskof_List(), sizeof(List<T>)) { | 46 | | // Ensured by heap zeroing. It's never directly on the stack. | 47 | 3 | assert(len_ == 0); | 48 | 0 | assert(capacity_ == 0); | 49 | 0 | assert(slab_ == nullptr); | 50 | 3 | } |
Line | Count | Source | 45 | 2 | List() : Obj(Tag::FixedSize, maskof_List(), sizeof(List<T>)) { | 46 | | // Ensured by heap zeroing. It's never directly on the stack. | 47 | 2 | assert(len_ == 0); | 48 | 0 | assert(capacity_ == 0); | 49 | 0 | assert(slab_ == nullptr); | 50 | 2 | } |
_ZN4ListIP6Tuple2IP3StriEEC2Ev Line | Count | Source | 45 | 1 | List() : Obj(Tag::FixedSize, maskof_List(), sizeof(List<T>)) { | 46 | | // Ensured by heap zeroing. It's never directly on the stack. | 47 | 1 | assert(len_ == 0); | 48 | 0 | assert(capacity_ == 0); | 49 | 0 | assert(slab_ == nullptr); | 50 | 1 | } |
_ZN4ListIP6Tuple2IiP3StrEEC2Ev Line | Count | Source | 45 | 2 | List() : Obj(Tag::FixedSize, maskof_List(), sizeof(List<T>)) { | 46 | | // Ensured by heap zeroing. It's never directly on the stack. | 47 | 2 | assert(len_ == 0); | 48 | 0 | assert(capacity_ == 0); | 49 | 0 | assert(slab_ == nullptr); | 50 | 2 | } |
_ZN4ListIPN10hnode_asdl5fieldEEC2Ev Line | Count | Source | 45 | 34 | List() : Obj(Tag::FixedSize, maskof_List(), sizeof(List<T>)) { | 46 | | // Ensured by heap zeroing. It's never directly on the stack. | 47 | 34 | assert(len_ == 0); | 48 | 0 | assert(capacity_ == 0); | 49 | 0 | assert(slab_ == nullptr); | 50 | 34 | } |
_ZN4ListIPN10hnode_asdl7hnode_tEEC2Ev Line | Count | Source | 45 | 34 | List() : Obj(Tag::FixedSize, maskof_List(), sizeof(List<T>)) { | 46 | | // Ensured by heap zeroing. It's never directly on the stack. | 47 | 34 | assert(len_ == 0); | 48 | 0 | assert(capacity_ == 0); | 49 | 0 | assert(slab_ == nullptr); | 50 | 34 | } |
|
51 | | |
52 | | // Implements L[i] |
53 | | T index_(int i); |
54 | | |
55 | | // returns index of the element |
56 | | int index(T element); |
57 | | |
58 | | // Implements L[i] = item |
59 | | // Note: Unlike Dict::set(), we don't need to specialize List::set() on T for |
60 | | // StackRoots because it doesn't allocate. |
61 | | void set(int i, T item); |
62 | | |
63 | | // L[begin:] |
64 | | List* slice(int begin); |
65 | | |
66 | | // L[begin:end] |
67 | | // TODO: Can this be optimized? |
68 | | List* slice(int begin, int end); |
69 | | |
70 | | // Should we have a separate API that doesn't return it? |
71 | | // https://stackoverflow.com/questions/12600330/pop-back-return-value |
72 | | T pop(); |
73 | | |
74 | | // Used in osh/word_parse.py to remove from front |
75 | | // TODO: Don't accept an arbitrary index? |
76 | | T pop(int i); |
77 | | |
78 | | void clear(); |
79 | | |
80 | | // Used in osh/string_ops.py |
81 | | void reverse(); |
82 | | |
83 | | // Templated function |
84 | | void sort(); |
85 | | |
86 | | // Ensure that there's space for a number of items |
87 | | void reserve(int n); |
88 | | |
89 | | // Append a single element to this list. Must be specialized List<int> vs |
90 | | // List<Str*>. |
91 | | // |
92 | | // NOTE(Jesse): The 'must be a specialized List<int> vs List<Str*>' part of |
93 | | // the comment above is correct, however the entirety of the codebase |
94 | | // completely ignores it. See @template_specialization_append_pointer for |
95 | | // more details and the solution. |
96 | | // |
97 | | void append(T item); |
98 | | |
99 | | // Extend this list with multiple elements. |
100 | | void extend(List<T>* other); |
101 | | |
102 | | int len_; // number of entries |
103 | | int capacity_; // max entries before resizing |
104 | | |
105 | | // The container may be resized, so this field isn't in-line. |
106 | | Slab<T>* slab_; |
107 | | |
108 | | DISALLOW_COPY_AND_ASSIGN(List) |
109 | | }; |
110 | | |
111 | | // "Constructors" as free functions since we can't allocate within a |
112 | | // constructor. Allocation may cause garbage collection, which interferes with |
113 | | // placement new. |
114 | | |
115 | | template <typename T> |
116 | 324 | List<T>* NewList() { |
117 | 324 | return Alloc<List<T>>(); |
118 | 324 | } Line | Count | Source | 116 | 307 | List<T>* NewList() { | 117 | 307 | return Alloc<List<T>>(); | 118 | 307 | } |
_Z7NewListIP3StrEP4ListIT_Ev Line | Count | Source | 116 | 17 | List<T>* NewList() { | 117 | 17 | return Alloc<List<T>>(); | 118 | 17 | } |
Unexecuted instantiation: _Z7NewListIPN10hnode_asdl5fieldEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN10hnode_asdl7hnode_tEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN12runtime_asdl10assign_argEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN12runtime_asdl12part_value_tEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN12runtime_asdl7value_tEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl13compound_wordEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl11word_part_tEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl9command_tEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl6word_tEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl5redirEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl8env_pairEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl11assign_pairEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl6if_armEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl8case_armEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl9name_typeEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl12place_expr_tEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl5paramEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl11type_expr_tEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl7variantEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl12class_item_tEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl11import_nameEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl12UntypedParamEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl10TypedParamEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl5TokenEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl5speckEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl6expr_tEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl13comprehensionEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl20class_literal_term_tEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl17char_class_term_tEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl4re_tEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl9named_argEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIPN11syntax_asdl11string_lineEEP4ListIT_Ev Unexecuted instantiation: _Z7NewListIP6Tuple2IiP3StrEEP4ListIT_Ev |
119 | | |
120 | | // Literal ['foo', 'bar'] |
121 | | template <typename T> |
122 | 48 | List<T>* NewList(std::initializer_list<T> init) { |
123 | 48 | auto self = Alloc<List<T>>(); |
124 | 48 | StackRoots _roots({&self}); |
125 | | |
126 | 48 | int n = init.size(); |
127 | 48 | self->reserve(n); |
128 | | |
129 | 48 | int i = 0; |
130 | 107 | for (auto item : init) { |
131 | 107 | self->set(i, item); |
132 | 107 | ++i; |
133 | 107 | } |
134 | 48 | self->len_ = n; |
135 | 48 | return self; |
136 | 48 | } _Z7NewListIP3StrEP4ListIT_ESt16initializer_listIS3_E Line | Count | Source | 122 | 27 | List<T>* NewList(std::initializer_list<T> init) { | 123 | 27 | auto self = Alloc<List<T>>(); | 124 | 27 | StackRoots _roots({&self}); | 125 | | | 126 | 27 | int n = init.size(); | 127 | 27 | self->reserve(n); | 128 | | | 129 | 27 | int i = 0; | 130 | 45 | for (auto item : init) { | 131 | 45 | self->set(i, item); | 132 | 45 | ++i; | 133 | 45 | } | 134 | 27 | self->len_ = n; | 135 | 27 | return self; | 136 | 27 | } |
_Z7NewListIiEP4ListIT_ESt16initializer_listIS1_E Line | Count | Source | 122 | 16 | List<T>* NewList(std::initializer_list<T> init) { | 123 | 16 | auto self = Alloc<List<T>>(); | 124 | 16 | StackRoots _roots({&self}); | 125 | | | 126 | 16 | int n = init.size(); | 127 | 16 | self->reserve(n); | 128 | | | 129 | 16 | int i = 0; | 130 | 50 | for (auto item : init) { | 131 | 50 | self->set(i, item); | 132 | 50 | ++i; | 133 | 50 | } | 134 | 16 | self->len_ = n; | 135 | 16 | return self; | 136 | 16 | } |
_Z7NewListIdEP4ListIT_ESt16initializer_listIS1_E Line | Count | Source | 122 | 2 | List<T>* NewList(std::initializer_list<T> init) { | 123 | 2 | auto self = Alloc<List<T>>(); | 124 | 2 | StackRoots _roots({&self}); | 125 | | | 126 | 2 | int n = init.size(); | 127 | 2 | self->reserve(n); | 128 | | | 129 | 2 | int i = 0; | 130 | 6 | for (auto item : init) { | 131 | 6 | self->set(i, item); | 132 | 6 | ++i; | 133 | 6 | } | 134 | 2 | self->len_ = n; | 135 | 2 | return self; | 136 | 2 | } |
_Z7NewListIP6Tuple2IP3StriEEP4ListIT_ESt16initializer_listIS6_E Line | Count | Source | 122 | 1 | List<T>* NewList(std::initializer_list<T> init) { | 123 | 1 | auto self = Alloc<List<T>>(); | 124 | 1 | StackRoots _roots({&self}); | 125 | | | 126 | 1 | int n = init.size(); | 127 | 1 | self->reserve(n); | 128 | | | 129 | 1 | int i = 0; | 130 | 2 | for (auto item : init) { | 131 | 2 | self->set(i, item); | 132 | 2 | ++i; | 133 | 2 | } | 134 | 1 | self->len_ = n; | 135 | 1 | return self; | 136 | 1 | } |
_Z7NewListIP6Tuple2IiP3StrEEP4ListIT_ESt16initializer_listIS6_E Line | Count | Source | 122 | 1 | List<T>* NewList(std::initializer_list<T> init) { | 123 | 1 | auto self = Alloc<List<T>>(); | 124 | 1 | StackRoots _roots({&self}); | 125 | | | 126 | 1 | int n = init.size(); | 127 | 1 | self->reserve(n); | 128 | | | 129 | 1 | int i = 0; | 130 | 2 | for (auto item : init) { | 131 | 2 | self->set(i, item); | 132 | 2 | ++i; | 133 | 2 | } | 134 | 1 | self->len_ = n; | 135 | 1 | return self; | 136 | 1 | } |
_Z7NewListIbEP4ListIT_ESt16initializer_listIS1_E Line | Count | Source | 122 | 1 | List<T>* NewList(std::initializer_list<T> init) { | 123 | 1 | auto self = Alloc<List<T>>(); | 124 | 1 | StackRoots _roots({&self}); | 125 | | | 126 | 1 | int n = init.size(); | 127 | 1 | self->reserve(n); | 128 | | | 129 | 1 | int i = 0; | 130 | 2 | for (auto item : init) { | 131 | 2 | self->set(i, item); | 132 | 2 | ++i; | 133 | 2 | } | 134 | 1 | self->len_ = n; | 135 | 1 | return self; | 136 | 1 | } |
|
137 | | |
138 | | // ['foo'] * 3 |
139 | | template <typename T> |
140 | 7 | List<T>* NewList(T item, int times) { |
141 | 7 | auto self = Alloc<List<T>>(); |
142 | 7 | StackRoots _roots({&self}); |
143 | | |
144 | 7 | self->reserve(times); |
145 | 7 | self->len_ = times; |
146 | 28 | for (int i = 0; i < times; ++i) { |
147 | 21 | self->set(i, item); |
148 | 21 | } |
149 | 7 | return self; |
150 | 7 | } _Z7NewListIP3StrEP4ListIT_ES3_i Line | Count | Source | 140 | 3 | List<T>* NewList(T item, int times) { | 141 | 3 | auto self = Alloc<List<T>>(); | 142 | 3 | StackRoots _roots({&self}); | 143 | | | 144 | 3 | self->reserve(times); | 145 | 3 | self->len_ = times; | 146 | 12 | for (int i = 0; i < times; ++i) { | 147 | 9 | self->set(i, item); | 148 | 9 | } | 149 | 3 | return self; | 150 | 3 | } |
_Z7NewListIbEP4ListIT_ES1_i Line | Count | Source | 140 | 2 | List<T>* NewList(T item, int times) { | 141 | 2 | auto self = Alloc<List<T>>(); | 142 | 2 | StackRoots _roots({&self}); | 143 | | | 144 | 2 | self->reserve(times); | 145 | 2 | self->len_ = times; | 146 | 8 | for (int i = 0; i < times; ++i) { | 147 | 6 | self->set(i, item); | 148 | 6 | } | 149 | 2 | return self; | 150 | 2 | } |
_Z7NewListIiEP4ListIT_ES1_i Line | Count | Source | 140 | 2 | List<T>* NewList(T item, int times) { | 141 | 2 | auto self = Alloc<List<T>>(); | 142 | 2 | StackRoots _roots({&self}); | 143 | | | 144 | 2 | self->reserve(times); | 145 | 2 | self->len_ = times; | 146 | 8 | for (int i = 0; i < times; ++i) { | 147 | 6 | self->set(i, item); | 148 | 6 | } | 149 | 2 | return self; | 150 | 2 | } |
|
151 | | |
152 | | // e.g. List<int> |
153 | | template <typename T> |
154 | 2.52k | void list_append(List<T>* self, T item) { |
155 | 2.52k | StackRoots _roots({&self}); |
156 | | |
157 | 2.52k | self->reserve(self->len_ + 1); |
158 | 2.52k | self->set(self->len_, item); |
159 | 2.52k | ++self->len_; |
160 | 2.52k | } |
161 | | |
162 | | // e.g. List<Str*> |
163 | | template <typename T> |
164 | 318 | void list_append(List<T*>* self, T* item) { |
165 | 318 | StackRoots _roots({&self, &item}); |
166 | | |
167 | 318 | self->reserve(self->len_ + 1); |
168 | 318 | self->set(self->len_, item); |
169 | 318 | ++self->len_; |
170 | 318 | } _Z11list_appendI3StrEvP4ListIPT_ES3_ Line | Count | Source | 164 | 257 | void list_append(List<T*>* self, T* item) { | 165 | 257 | StackRoots _roots({&self, &item}); | 166 | | | 167 | 257 | self->reserve(self->len_ + 1); | 168 | 257 | self->set(self->len_, item); | 169 | 257 | ++self->len_; | 170 | 257 | } |
Unexecuted instantiation: _Z11list_appendI6Tuple2IP3StriEEvP4ListIPT_ES6_ _Z11list_appendIN10hnode_asdl5fieldEEvP4ListIPT_ES4_ Line | Count | Source | 164 | 60 | void list_append(List<T*>* self, T* item) { | 165 | 60 | StackRoots _roots({&self, &item}); | 166 | | | 167 | 60 | self->reserve(self->len_ + 1); | 168 | 60 | self->set(self->len_, item); | 169 | 60 | ++self->len_; | 170 | 60 | } |
_Z11list_appendI6Tuple2IiP3StrEEvP4ListIPT_ES6_ Line | Count | Source | 164 | 1 | void list_append(List<T*>* self, T* item) { | 165 | 1 | StackRoots _roots({&self, &item}); | 166 | | | 167 | 1 | self->reserve(self->len_ + 1); | 168 | 1 | self->set(self->len_, item); | 169 | 1 | ++self->len_; | 170 | 1 | } |
|
171 | | |
172 | | template <typename T> |
173 | 2.84k | void List<T>::append(T item) { |
174 | 2.84k | list_append(this, item); |
175 | 2.84k | } Line | Count | Source | 173 | 2.52k | void List<T>::append(T item) { | 174 | 2.52k | list_append(this, item); | 175 | 2.52k | } |
_ZN4ListIP3StrE6appendES1_ Line | Count | Source | 173 | 257 | void List<T>::append(T item) { | 174 | 257 | list_append(this, item); | 175 | 257 | } |
Unexecuted instantiation: _ZN4ListIP6Tuple2IP3StriEE6appendES4_ _ZN4ListIPN10hnode_asdl5fieldEE6appendES2_ Line | Count | Source | 173 | 60 | void List<T>::append(T item) { | 174 | 60 | list_append(this, item); | 175 | 60 | } |
_ZN4ListIP6Tuple2IiP3StrEE6appendES4_ Line | Count | Source | 173 | 1 | void List<T>::append(T item) { | 174 | 1 | list_append(this, item); | 175 | 1 | } |
|
176 | | |
177 | | template <typename T> |
178 | 2.09k | int len(const List<T>* L) { |
179 | 2.09k | return L->len_; |
180 | 2.09k | } Line | Count | Source | 178 | 1.95k | int len(const List<T>* L) { | 179 | 1.95k | return L->len_; | 180 | 1.95k | } |
Line | Count | Source | 178 | 2 | int len(const List<T>* L) { | 179 | 2 | return L->len_; | 180 | 2 | } |
Line | Count | Source | 178 | 4 | int len(const List<T>* L) { | 179 | 4 | return L->len_; | 180 | 4 | } |
_Z3lenIP3StrEiPK4ListIT_E Line | Count | Source | 178 | 140 | int len(const List<T>* L) { | 179 | 140 | return L->len_; | 180 | 140 | } |
_Z3lenIP6Tuple2IiP3StrEEiPK4ListIT_E Line | Count | Source | 178 | 1 | int len(const List<T>* L) { | 179 | 1 | return L->len_; | 180 | 1 | } |
|
181 | | |
182 | | template <typename T> |
183 | | List<T>* list_repeat(T item, int times); |
184 | | |
185 | | template <typename T> |
186 | | inline bool list_contains(List<T>* haystack, T needle); |
187 | | |
188 | 18 | inline int int_cmp(int a, int b) { |
189 | 18 | if (a == b) { |
190 | 4 | return 0; |
191 | 4 | } |
192 | 14 | return a < b ? -1 : 1; |
193 | 18 | } |
194 | | |
195 | | inline int str_cmp(Str* a, Str* b); |
196 | | inline bool _cmp(Str* a, Str* b); |
197 | | |
198 | | // NOTE(Jesse): Move to gc_dict_impl once I get there |
199 | | template <typename K, typename V> |
200 | | class Dict; |
201 | | |
202 | | template <typename V> |
203 | | List<Str*>* sorted(Dict<Str*, V>* d); |
204 | | |
205 | | /* template <typename T> */ |
206 | | /* void List<T>::sort(); */ |
207 | | |
208 | | // L[begin:] |
209 | | template <typename T> |
210 | 305 | List<T>* List<T>::slice(int begin) { |
211 | 305 | if (begin < 0) { |
212 | 0 | begin = len_ + begin; |
213 | 0 | } |
214 | | |
215 | 305 | assert(begin >= 0); |
216 | | |
217 | 0 | auto self = this; |
218 | 305 | List<T>* result = nullptr; |
219 | 305 | StackRoots _roots({&self, &result}); |
220 | | |
221 | 305 | result = NewList<T>(); |
222 | | |
223 | 1.51k | for (int i = begin; i < self->len_; i++) { |
224 | 1.21k | result->append(self->slab_->items_[i]); |
225 | 1.21k | } |
226 | | |
227 | 305 | return result; |
228 | 305 | } Line | Count | Source | 210 | 302 | List<T>* List<T>::slice(int begin) { | 211 | 302 | if (begin < 0) { | 212 | 0 | begin = len_ + begin; | 213 | 0 | } | 214 | | | 215 | 302 | assert(begin >= 0); | 216 | | | 217 | 0 | auto self = this; | 218 | 302 | List<T>* result = nullptr; | 219 | 302 | StackRoots _roots({&self, &result}); | 220 | | | 221 | 302 | result = NewList<T>(); | 222 | | | 223 | 1.50k | for (int i = begin; i < self->len_; i++) { | 224 | 1.20k | result->append(self->slab_->items_[i]); | 225 | 1.20k | } | 226 | | | 227 | 302 | return result; | 228 | 302 | } |
Line | Count | Source | 210 | 3 | List<T>* List<T>::slice(int begin) { | 211 | 3 | if (begin < 0) { | 212 | 0 | begin = len_ + begin; | 213 | 0 | } | 214 | | | 215 | 3 | assert(begin >= 0); | 216 | | | 217 | 0 | auto self = this; | 218 | 3 | List<T>* result = nullptr; | 219 | 3 | StackRoots _roots({&self, &result}); | 220 | | | 221 | 3 | result = NewList<T>(); | 222 | | | 223 | 9 | for (int i = begin; i < self->len_; i++) { | 224 | 6 | result->append(self->slab_->items_[i]); | 225 | 6 | } | 226 | | | 227 | 3 | return result; | 228 | 3 | } |
|
229 | | |
230 | | // L[begin:end] |
231 | | // TODO: Can this be optimized? |
232 | | template <typename T> |
233 | 2 | List<T>* List<T>::slice(int begin, int end) { |
234 | 2 | if (begin < 0) { |
235 | 1 | begin = len_ + begin; |
236 | 1 | } |
237 | 2 | if (end < 0) { |
238 | 2 | end = len_ + end; |
239 | 2 | } |
240 | | |
241 | 2 | assert(end <= len_); |
242 | 0 | assert(begin >= 0); |
243 | 0 | assert(end >= 0); |
244 | | |
245 | 0 | auto self = this; |
246 | 2 | List<T>* result = nullptr; |
247 | 2 | StackRoots _roots({&self, &result}); |
248 | | |
249 | 2 | result = NewList<T>(); |
250 | 6 | for (int i = begin; i < end; i++) { |
251 | 4 | result->append(self->slab_->items_[i]); |
252 | 4 | } |
253 | | |
254 | 2 | return result; |
255 | 2 | } |
256 | | |
257 | | // Ensure that there's space for a number of items |
258 | | template <typename T> |
259 | 2.90k | void List<T>::reserve(int n) { |
260 | | // log("reserve capacity = %d, n = %d", capacity_, n); |
261 | 2.90k | auto self = this; |
262 | 2.90k | StackRoots _roots({&self}); |
263 | | |
264 | | // Don't do anything if there's already enough space. |
265 | 2.90k | if (self->capacity_ >= n) return; |
266 | | |
267 | | // Example: The user asks for space for 7 integers. Account for the |
268 | | // header, and say we need 9 to determine the obj length. 9 is |
269 | | // rounded up to 16, for a 64-byte obj. Then we actually have space |
270 | | // for 14 items. |
271 | 479 | self->capacity_ = RoundUp(n + kCapacityAdjust) - kCapacityAdjust; |
272 | 479 | auto new_slab = NewSlab<T>(self->capacity_); |
273 | | |
274 | 479 | if (self->len_ > 0) { |
275 | | // log("Copying %d bytes", len_ * sizeof(T)); |
276 | 13 | memcpy(new_slab->items_, self->slab_->items_, self->len_ * sizeof(T)); |
277 | 13 | } |
278 | 479 | self->slab_ = new_slab; |
279 | 479 | } _ZN4ListIP3StrE7reserveEi Line | Count | Source | 259 | 287 | void List<T>::reserve(int n) { | 260 | | // log("reserve capacity = %d, n = %d", capacity_, n); | 261 | 287 | auto self = this; | 262 | 287 | StackRoots _roots({&self}); | 263 | | | 264 | | // Don't do anything if there's already enough space. | 265 | 287 | if (self->capacity_ >= n) return; | 266 | | | 267 | | // Example: The user asks for space for 7 integers. Account for the | 268 | | // header, and say we need 9 to determine the obj length. 9 is | 269 | | // rounded up to 16, for a 64-byte obj. Then we actually have space | 270 | | // for 14 items. | 271 | 101 | self->capacity_ = RoundUp(n + kCapacityAdjust) - kCapacityAdjust; | 272 | 101 | auto new_slab = NewSlab<T>(self->capacity_); | 273 | | | 274 | 101 | if (self->len_ > 0) { | 275 | | // log("Copying %d bytes", len_ * sizeof(T)); | 276 | 5 | memcpy(new_slab->items_, self->slab_->items_, self->len_ * sizeof(T)); | 277 | 5 | } | 278 | 101 | self->slab_ = new_slab; | 279 | 101 | } |
Line | Count | Source | 259 | 2.54k | void List<T>::reserve(int n) { | 260 | | // log("reserve capacity = %d, n = %d", capacity_, n); | 261 | 2.54k | auto self = this; | 262 | 2.54k | StackRoots _roots({&self}); | 263 | | | 264 | | // Don't do anything if there's already enough space. | 265 | 2.54k | if (self->capacity_ >= n) return; | 266 | | | 267 | | // Example: The user asks for space for 7 integers. Account for the | 268 | | // header, and say we need 9 to determine the obj length. 9 is | 269 | | // rounded up to 16, for a 64-byte obj. Then we actually have space | 270 | | // for 14 items. | 271 | 336 | self->capacity_ = RoundUp(n + kCapacityAdjust) - kCapacityAdjust; | 272 | 336 | auto new_slab = NewSlab<T>(self->capacity_); | 273 | | | 274 | 336 | if (self->len_ > 0) { | 275 | | // log("Copying %d bytes", len_ * sizeof(T)); | 276 | 8 | memcpy(new_slab->items_, self->slab_->items_, self->len_ * sizeof(T)); | 277 | 8 | } | 278 | 336 | self->slab_ = new_slab; | 279 | 336 | } |
Line | Count | Source | 259 | 3 | void List<T>::reserve(int n) { | 260 | | // log("reserve capacity = %d, n = %d", capacity_, n); | 261 | 3 | auto self = this; | 262 | 3 | StackRoots _roots({&self}); | 263 | | | 264 | | // Don't do anything if there's already enough space. | 265 | 3 | if (self->capacity_ >= n) return; | 266 | | | 267 | | // Example: The user asks for space for 7 integers. Account for the | 268 | | // header, and say we need 9 to determine the obj length. 9 is | 269 | | // rounded up to 16, for a 64-byte obj. Then we actually have space | 270 | | // for 14 items. | 271 | 3 | self->capacity_ = RoundUp(n + kCapacityAdjust) - kCapacityAdjust; | 272 | 3 | auto new_slab = NewSlab<T>(self->capacity_); | 273 | | | 274 | 3 | if (self->len_ > 0) { | 275 | | // log("Copying %d bytes", len_ * sizeof(T)); | 276 | 0 | memcpy(new_slab->items_, self->slab_->items_, self->len_ * sizeof(T)); | 277 | 0 | } | 278 | 3 | self->slab_ = new_slab; | 279 | 3 | } |
Line | Count | Source | 259 | 2 | void List<T>::reserve(int n) { | 260 | | // log("reserve capacity = %d, n = %d", capacity_, n); | 261 | 2 | auto self = this; | 262 | 2 | StackRoots _roots({&self}); | 263 | | | 264 | | // Don't do anything if there's already enough space. | 265 | 2 | if (self->capacity_ >= n) return; | 266 | | | 267 | | // Example: The user asks for space for 7 integers. Account for the | 268 | | // header, and say we need 9 to determine the obj length. 9 is | 269 | | // rounded up to 16, for a 64-byte obj. Then we actually have space | 270 | | // for 14 items. | 271 | 2 | self->capacity_ = RoundUp(n + kCapacityAdjust) - kCapacityAdjust; | 272 | 2 | auto new_slab = NewSlab<T>(self->capacity_); | 273 | | | 274 | 2 | if (self->len_ > 0) { | 275 | | // log("Copying %d bytes", len_ * sizeof(T)); | 276 | 0 | memcpy(new_slab->items_, self->slab_->items_, self->len_ * sizeof(T)); | 277 | 0 | } | 278 | 2 | self->slab_ = new_slab; | 279 | 2 | } |
_ZN4ListIP6Tuple2IP3StriEE7reserveEi Line | Count | Source | 259 | 1 | void List<T>::reserve(int n) { | 260 | | // log("reserve capacity = %d, n = %d", capacity_, n); | 261 | 1 | auto self = this; | 262 | 1 | StackRoots _roots({&self}); | 263 | | | 264 | | // Don't do anything if there's already enough space. | 265 | 1 | if (self->capacity_ >= n) return; | 266 | | | 267 | | // Example: The user asks for space for 7 integers. Account for the | 268 | | // header, and say we need 9 to determine the obj length. 9 is | 269 | | // rounded up to 16, for a 64-byte obj. Then we actually have space | 270 | | // for 14 items. | 271 | 1 | self->capacity_ = RoundUp(n + kCapacityAdjust) - kCapacityAdjust; | 272 | 1 | auto new_slab = NewSlab<T>(self->capacity_); | 273 | | | 274 | 1 | if (self->len_ > 0) { | 275 | | // log("Copying %d bytes", len_ * sizeof(T)); | 276 | 0 | memcpy(new_slab->items_, self->slab_->items_, self->len_ * sizeof(T)); | 277 | 0 | } | 278 | 1 | self->slab_ = new_slab; | 279 | 1 | } |
_ZN4ListIP6Tuple2IiP3StrEE7reserveEi Line | Count | Source | 259 | 2 | void List<T>::reserve(int n) { | 260 | | // log("reserve capacity = %d, n = %d", capacity_, n); | 261 | 2 | auto self = this; | 262 | 2 | StackRoots _roots({&self}); | 263 | | | 264 | | // Don't do anything if there's already enough space. | 265 | 2 | if (self->capacity_ >= n) return; | 266 | | | 267 | | // Example: The user asks for space for 7 integers. Account for the | 268 | | // header, and say we need 9 to determine the obj length. 9 is | 269 | | // rounded up to 16, for a 64-byte obj. Then we actually have space | 270 | | // for 14 items. | 271 | 2 | self->capacity_ = RoundUp(n + kCapacityAdjust) - kCapacityAdjust; | 272 | 2 | auto new_slab = NewSlab<T>(self->capacity_); | 273 | | | 274 | 2 | if (self->len_ > 0) { | 275 | | // log("Copying %d bytes", len_ * sizeof(T)); | 276 | 0 | memcpy(new_slab->items_, self->slab_->items_, self->len_ * sizeof(T)); | 277 | 0 | } | 278 | 2 | self->slab_ = new_slab; | 279 | 2 | } |
_ZN4ListIPN10hnode_asdl5fieldEE7reserveEi Line | Count | Source | 259 | 60 | void List<T>::reserve(int n) { | 260 | | // log("reserve capacity = %d, n = %d", capacity_, n); | 261 | 60 | auto self = this; | 262 | 60 | StackRoots _roots({&self}); | 263 | | | 264 | | // Don't do anything if there's already enough space. | 265 | 60 | if (self->capacity_ >= n) return; | 266 | | | 267 | | // Example: The user asks for space for 7 integers. Account for the | 268 | | // header, and say we need 9 to determine the obj length. 9 is | 269 | | // rounded up to 16, for a 64-byte obj. Then we actually have space | 270 | | // for 14 items. | 271 | 34 | self->capacity_ = RoundUp(n + kCapacityAdjust) - kCapacityAdjust; | 272 | 34 | auto new_slab = NewSlab<T>(self->capacity_); | 273 | | | 274 | 34 | if (self->len_ > 0) { | 275 | | // log("Copying %d bytes", len_ * sizeof(T)); | 276 | 0 | memcpy(new_slab->items_, self->slab_->items_, self->len_ * sizeof(T)); | 277 | 0 | } | 278 | 34 | self->slab_ = new_slab; | 279 | 34 | } |
|
280 | | |
281 | | // Implements L[i] = item |
282 | | // Note: Unlike Dict::set(), we don't need to specialize List::set() on T for |
283 | | // StackRoots because it doesn't allocate. |
284 | | template <typename T> |
285 | 2.98k | void List<T>::set(int i, T item) { |
286 | 2.98k | if (i < 0) { |
287 | 0 | i = len_ + i; |
288 | 0 | } |
289 | | |
290 | 2.98k | assert(i >= 0); |
291 | 0 | assert(i < capacity_); |
292 | | |
293 | 0 | slab_->items_[i] = item; |
294 | 2.98k | } Line | Count | Source | 285 | 314 | void List<T>::set(int i, T item) { | 286 | 314 | if (i < 0) { | 287 | 0 | i = len_ + i; | 288 | 0 | } | 289 | | | 290 | 314 | assert(i >= 0); | 291 | 0 | assert(i < capacity_); | 292 | | | 293 | 0 | slab_->items_[i] = item; | 294 | 314 | } |
Line | Count | Source | 285 | 2.59k | void List<T>::set(int i, T item) { | 286 | 2.59k | if (i < 0) { | 287 | 0 | i = len_ + i; | 288 | 0 | } | 289 | | | 290 | 2.59k | assert(i >= 0); | 291 | 0 | assert(i < capacity_); | 292 | | | 293 | 0 | slab_->items_[i] = item; | 294 | 2.59k | } |
Line | Count | Source | 285 | 8 | void List<T>::set(int i, T item) { | 286 | 8 | if (i < 0) { | 287 | 0 | i = len_ + i; | 288 | 0 | } | 289 | | | 290 | 8 | assert(i >= 0); | 291 | 0 | assert(i < capacity_); | 292 | | | 293 | 0 | slab_->items_[i] = item; | 294 | 8 | } |
Line | Count | Source | 285 | 6 | void List<T>::set(int i, T item) { | 286 | 6 | if (i < 0) { | 287 | 0 | i = len_ + i; | 288 | 0 | } | 289 | | | 290 | 6 | assert(i >= 0); | 291 | 0 | assert(i < capacity_); | 292 | | | 293 | 0 | slab_->items_[i] = item; | 294 | 6 | } |
_ZN4ListIP6Tuple2IP3StriEE3setEiS4_ Line | Count | Source | 285 | 2 | void List<T>::set(int i, T item) { | 286 | 2 | if (i < 0) { | 287 | 0 | i = len_ + i; | 288 | 0 | } | 289 | | | 290 | 2 | assert(i >= 0); | 291 | 0 | assert(i < capacity_); | 292 | | | 293 | 0 | slab_->items_[i] = item; | 294 | 2 | } |
_ZN4ListIP6Tuple2IiP3StrEE3setEiS4_ Line | Count | Source | 285 | 3 | void List<T>::set(int i, T item) { | 286 | 3 | if (i < 0) { | 287 | 0 | i = len_ + i; | 288 | 0 | } | 289 | | | 290 | 3 | assert(i >= 0); | 291 | 0 | assert(i < capacity_); | 292 | | | 293 | 0 | slab_->items_[i] = item; | 294 | 3 | } |
_ZN4ListIPN10hnode_asdl5fieldEE3setEiS2_ Line | Count | Source | 285 | 60 | void List<T>::set(int i, T item) { | 286 | 60 | if (i < 0) { | 287 | 0 | i = len_ + i; | 288 | 0 | } | 289 | | | 290 | 60 | assert(i >= 0); | 291 | 0 | assert(i < capacity_); | 292 | | | 293 | 0 | slab_->items_[i] = item; | 294 | 60 | } |
|
295 | | |
296 | | // Implements L[i] |
297 | | template <typename T> |
298 | 593 | T List<T>::index_(int i) { |
299 | 593 | if (i < 0) { |
300 | 4 | int j = len_ + i; |
301 | 4 | assert(j < len_); |
302 | 0 | assert(j >= 0); |
303 | 0 | return slab_->items_[j]; |
304 | 4 | } |
305 | | |
306 | 589 | assert(i < len_); |
307 | 0 | assert(i >= 0); |
308 | 0 | return slab_->items_[i]; |
309 | 593 | } Line | Count | Source | 298 | 72 | T List<T>::index_(int i) { | 299 | 72 | if (i < 0) { | 300 | 1 | int j = len_ + i; | 301 | 1 | assert(j < len_); | 302 | 0 | assert(j >= 0); | 303 | 0 | return slab_->items_[j]; | 304 | 1 | } | 305 | | | 306 | 71 | assert(i < len_); | 307 | 0 | assert(i >= 0); | 308 | 0 | return slab_->items_[i]; | 309 | 72 | } |
Line | Count | Source | 298 | 4 | T List<T>::index_(int i) { | 299 | 4 | if (i < 0) { | 300 | 0 | int j = len_ + i; | 301 | 0 | assert(j < len_); | 302 | 0 | assert(j >= 0); | 303 | 0 | return slab_->items_[j]; | 304 | 0 | } | 305 | | | 306 | 4 | assert(i < len_); | 307 | 0 | assert(i >= 0); | 308 | 0 | return slab_->items_[i]; | 309 | 4 | } |
Line | Count | Source | 298 | 8 | T List<T>::index_(int i) { | 299 | 8 | if (i < 0) { | 300 | 0 | int j = len_ + i; | 301 | 0 | assert(j < len_); | 302 | 0 | assert(j >= 0); | 303 | 0 | return slab_->items_[j]; | 304 | 0 | } | 305 | | | 306 | 8 | assert(i < len_); | 307 | 0 | assert(i >= 0); | 308 | 0 | return slab_->items_[i]; | 309 | 8 | } |
Line | Count | Source | 298 | 509 | T List<T>::index_(int i) { | 299 | 509 | if (i < 0) { | 300 | 3 | int j = len_ + i; | 301 | 3 | assert(j < len_); | 302 | 0 | assert(j >= 0); | 303 | 0 | return slab_->items_[j]; | 304 | 3 | } | 305 | | | 306 | 506 | assert(i < len_); | 307 | 0 | assert(i >= 0); | 308 | 0 | return slab_->items_[i]; | 309 | 509 | } |
|
310 | | |
311 | | // L.index(i) -- Python method |
312 | | template <typename T> |
313 | | int List<T>::index(T value) { |
314 | | int element_count = len(this); |
315 | | for (int i = 0; i < element_count; i++) { |
316 | | if (are_equal(slab_->items_[i], value)) { |
317 | | return i; |
318 | | } |
319 | | } |
320 | | throw Alloc<ValueError>(); |
321 | | } |
322 | | |
323 | | // Should we have a separate API that doesn't return it? |
324 | | // https://stackoverflow.com/questions/12600330/pop-back-return-value |
325 | | template <typename T> |
326 | 5 | T List<T>::pop() { |
327 | 5 | assert(len_ > 0); |
328 | 0 | len_--; |
329 | 5 | T result = slab_->items_[len_]; |
330 | 5 | slab_->items_[len_] = 0; // zero for GC scan |
331 | 5 | return result; |
332 | 5 | } Line | Count | Source | 326 | 1 | T List<T>::pop() { | 327 | 1 | assert(len_ > 0); | 328 | 0 | len_--; | 329 | 1 | T result = slab_->items_[len_]; | 330 | 1 | slab_->items_[len_] = 0; // zero for GC scan | 331 | 1 | return result; | 332 | 1 | } |
Line | Count | Source | 326 | 4 | T List<T>::pop() { | 327 | 4 | assert(len_ > 0); | 328 | 0 | len_--; | 329 | 4 | T result = slab_->items_[len_]; | 330 | 4 | slab_->items_[len_] = 0; // zero for GC scan | 331 | 4 | return result; | 332 | 4 | } |
|
333 | | |
334 | | // Used in osh/word_parse.py to remove from front |
335 | | // TODO: Don't accept an arbitrary index? |
336 | | // |
337 | | // NOTE(Jesse): This operation is typically called 'shift' I think |
338 | | template <typename T> |
339 | 2 | T List<T>::pop(int i) { |
340 | 2 | assert(len_ > 0); |
341 | 0 | assert(i == 0); // only support popping the first item |
342 | | |
343 | 0 | T result = index_(0); |
344 | 2 | len_--; |
345 | | |
346 | | // Shift everything by one |
347 | 2 | memmove(slab_->items_, slab_->items_ + 1, len_ * sizeof(T)); |
348 | | |
349 | | /* |
350 | | for (int j = 0; j < len_; j++) { |
351 | | slab_->items_[j] = slab_->items_[j+1]; |
352 | | } |
353 | | */ |
354 | | |
355 | 2 | slab_->items_[len_] = 0; // zero for GC scan |
356 | 2 | return result; |
357 | 2 | } |
358 | | |
359 | | template <typename T> |
360 | 3 | void List<T>::clear() { |
361 | 3 | memset(slab_->items_, 0, len_ * sizeof(T)); // zero for GC scan |
362 | 3 | len_ = 0; |
363 | 3 | } Line | Count | Source | 360 | 2 | void List<T>::clear() { | 361 | 2 | memset(slab_->items_, 0, len_ * sizeof(T)); // zero for GC scan | 362 | 2 | len_ = 0; | 363 | 2 | } |
Line | Count | Source | 360 | 1 | void List<T>::clear() { | 361 | 1 | memset(slab_->items_, 0, len_ * sizeof(T)); // zero for GC scan | 362 | 1 | len_ = 0; | 363 | 1 | } |
|
364 | | |
365 | | // Used in osh/string_ops.py |
366 | | template <typename T> |
367 | 4 | void List<T>::reverse() { |
368 | 8 | for (int i = 0; i < len_ / 2; ++i) { |
369 | | // log("swapping %d and %d", i, n-i); |
370 | 4 | T tmp = slab_->items_[i]; |
371 | 4 | int j = len_ - 1 - i; |
372 | 4 | slab_->items_[i] = slab_->items_[j]; |
373 | 4 | slab_->items_[j] = tmp; |
374 | 4 | } |
375 | 4 | } Line | Count | Source | 367 | 4 | void List<T>::reverse() { | 368 | 8 | for (int i = 0; i < len_ / 2; ++i) { | 369 | | // log("swapping %d and %d", i, n-i); | 370 | 4 | T tmp = slab_->items_[i]; | 371 | 4 | int j = len_ - 1 - i; | 372 | 4 | slab_->items_[i] = slab_->items_[j]; | 373 | 4 | slab_->items_[j] = tmp; | 374 | 4 | } | 375 | 4 | } |
Unexecuted instantiation: _ZN4ListIP3StrE7reverseEv |
376 | | |
377 | | // Extend this list with multiple elements. |
378 | | template <typename T> |
379 | 3 | void List<T>::extend(List<T>* other) { |
380 | 3 | auto self = this; |
381 | 3 | StackRoots _roots({&self, &other}); |
382 | | |
383 | 3 | int n = other->len_; |
384 | 3 | int new_len = self->len_ + n; |
385 | 3 | self->reserve(new_len); |
386 | | |
387 | 12 | for (int i = 0; i < n; ++i) { |
388 | 9 | self->set(self->len_ + i, other->slab_->items_[i]); |
389 | 9 | } |
390 | 3 | self->len_ = new_len; |
391 | 3 | } Line | Count | Source | 379 | 3 | void List<T>::extend(List<T>* other) { | 380 | 3 | auto self = this; | 381 | 3 | StackRoots _roots({&self, &other}); | 382 | | | 383 | 3 | int n = other->len_; | 384 | 3 | int new_len = self->len_ + n; | 385 | 3 | self->reserve(new_len); | 386 | | | 387 | 12 | for (int i = 0; i < n; ++i) { | 388 | 9 | self->set(self->len_ + i, other->slab_->items_[i]); | 389 | 9 | } | 390 | 3 | self->len_ = new_len; | 391 | 3 | } |
Unexecuted instantiation: _ZN4ListIP3StrE6extendEPS2_ |
392 | | |
393 | | // NOTE(Jesse): It's highly sus that we have str_equals and str_cmp.. |
394 | | // shouldn't we write one in terms of the other? |
395 | | // |
396 | | // @duplicate_string_compare_code |
397 | | // |
398 | | // Used by [[ a > b ]] and so forth |
399 | 25 | inline int str_cmp(Str* a, Str* b) { |
400 | 25 | int len_a = len(a); |
401 | 25 | int len_b = len(b); |
402 | | |
403 | 25 | int min = std::min(len_a, len_b); |
404 | 25 | if (min == 0) { |
405 | 8 | return int_cmp(len_a, len_b); |
406 | 8 | } |
407 | 17 | int comp = memcmp(a->data_, b->data_, min); |
408 | 17 | if (comp == 0) { |
409 | 4 | return int_cmp(len_a, len_b); // tiebreaker |
410 | 4 | } |
411 | 13 | return comp; |
412 | 17 | } |
413 | | |
414 | 13 | inline bool _cmp(Str* a, Str* b) { |
415 | 13 | return str_cmp(a, b) < 0; |
416 | 13 | } |
417 | | |
418 | | template <typename T> |
419 | 3 | void List<T>::sort() { |
420 | 3 | std::sort(slab_->items_, slab_->items_ + len_, _cmp); |
421 | 3 | } |
422 | | |
423 | | /* template <typename T> */ |
424 | | /* int len(const List<T>* L) { */ |
425 | | /* return L->len_; */ |
426 | | /* } */ |
427 | | |
428 | | // TODO: mycpp can just generate the constructor instead? |
429 | | // e.g. [None] * 3 |
430 | | template <typename T> |
431 | 5 | List<T>* list_repeat(T item, int times) { |
432 | 5 | return NewList<T>(item, times); |
433 | 5 | } _Z11list_repeatIP3StrEP4ListIT_ES3_i Line | Count | Source | 431 | 3 | List<T>* list_repeat(T item, int times) { | 432 | 3 | return NewList<T>(item, times); | 433 | 3 | } |
_Z11list_repeatIbEP4ListIT_ES1_i Line | Count | Source | 431 | 2 | List<T>* list_repeat(T item, int times) { | 432 | 2 | return NewList<T>(item, times); | 433 | 2 | } |
|
434 | | |
435 | | #if 0 |
436 | | template <typename T> |
437 | | List<T>* NewList() { |
438 | | return Alloc<List<T>>(); |
439 | | } |
440 | | |
441 | | // Literal ['foo', 'bar'] |
442 | | template <typename T> |
443 | | List<T>* NewList(std::initializer_list<T> init) { |
444 | | auto self = Alloc<List<T>>(); |
445 | | StackRoots _roots({&self}); |
446 | | |
447 | | int n = init.size(); |
448 | | self->reserve(n); |
449 | | |
450 | | int i = 0; |
451 | | for (auto item : init) { |
452 | | self->set(i, item); |
453 | | ++i; |
454 | | } |
455 | | self->len_ = n; |
456 | | return self; |
457 | | } |
458 | | |
459 | | // ['foo'] * 3 |
460 | | template <typename T> |
461 | | List<T>* NewList(T item, int times) { |
462 | | auto self = Alloc<List<T>>(); |
463 | | StackRoots _roots({&self}); |
464 | | |
465 | | self->reserve(times); |
466 | | self->len_ = times; |
467 | | for (int i = 0; i < times; ++i) { |
468 | | self->set(i, item); |
469 | | } |
470 | | return self; |
471 | | } |
472 | | #endif |
473 | | |
474 | | // e.g. 'a' in ['a', 'b', 'c'] |
475 | | template <typename T> |
476 | 19 | inline bool list_contains(List<T>* haystack, T needle) { |
477 | | // StackRoots _roots({&haystack, &needle}); // doesn't allocate |
478 | | |
479 | 19 | int n = len(haystack); |
480 | 43 | for (int i = 0; i < n; ++i) { |
481 | 35 | if (are_equal(haystack->index_(i), needle)) { |
482 | 11 | return true; |
483 | 11 | } |
484 | 35 | } |
485 | 8 | return false; |
486 | 19 | } _Z13list_containsIP3StrEbP4ListIT_ES3_ Line | Count | Source | 476 | 9 | inline bool list_contains(List<T>* haystack, T needle) { | 477 | | // StackRoots _roots({&haystack, &needle}); // doesn't allocate | 478 | | | 479 | 9 | int n = len(haystack); | 480 | 20 | for (int i = 0; i < n; ++i) { | 481 | 16 | if (are_equal(haystack->index_(i), needle)) { | 482 | 5 | return true; | 483 | 5 | } | 484 | 16 | } | 485 | 4 | return false; | 486 | 9 | } |
_Z13list_containsIiEbP4ListIT_ES1_ Line | Count | Source | 476 | 6 | inline bool list_contains(List<T>* haystack, T needle) { | 477 | | // StackRoots _roots({&haystack, &needle}); // doesn't allocate | 478 | | | 479 | 6 | int n = len(haystack); | 480 | 13 | for (int i = 0; i < n; ++i) { | 481 | 11 | if (are_equal(haystack->index_(i), needle)) { | 482 | 4 | return true; | 483 | 4 | } | 484 | 11 | } | 485 | 2 | return false; | 486 | 6 | } |
_Z13list_containsIdEbP4ListIT_ES1_ Line | Count | Source | 476 | 4 | inline bool list_contains(List<T>* haystack, T needle) { | 477 | | // StackRoots _roots({&haystack, &needle}); // doesn't allocate | 478 | | | 479 | 4 | int n = len(haystack); | 480 | 10 | for (int i = 0; i < n; ++i) { | 481 | 8 | if (are_equal(haystack->index_(i), needle)) { | 482 | 2 | return true; | 483 | 2 | } | 484 | 8 | } | 485 | 2 | return false; | 486 | 4 | } |
|
487 | | |
488 | | // NOTE(Jesse): Move to gc_dict_impl once I get there |
489 | | template <typename K, typename V> |
490 | | class Dict; |
491 | | |
492 | | template <typename V> |
493 | 1 | List<Str*>* sorted(Dict<Str*, V>* d) { |
494 | 1 | auto keys = d->keys(); |
495 | 1 | keys->sort(); |
496 | 1 | return keys; |
497 | 1 | } |
498 | | |
499 | | // list(L) copies the list |
500 | | template <typename T> |
501 | | List<T>* list(List<T>* other) { |
502 | | auto result = NewList<T>(); |
503 | | for (int i = 0; i < len(other); ++i) { |
504 | | result->set(i, other->index_(i)); |
505 | | } |
506 | | return result; |
507 | | } |
508 | | |
509 | | #define GLOBAL_LIST(T, N, name, array) \ |
510 | | GlobalSlab<T, N> _slab_##name = {Tag::Global, 0, kZeroMask, kNoObjLen, \ |
511 | | array}; \ |
512 | | GlobalList<T, N> _list_##name = {Tag::Global, 0, kZeroMask, kNoObjLen, \ |
513 | | N, N, &_slab_##name}; \ |
514 | | List<T>* name = reinterpret_cast<List<T>*>(&_list_##name); |
515 | | |
516 | | template <class T> |
517 | | class ListIter { |
518 | | public: |
519 | 112 | explicit ListIter(List<T>* L) : L_(L), i_(0) { |
520 | | // We need this because ListIter is directly on the stack, and L_ could be |
521 | | // moved during iteration. |
522 | 112 | gHeap.PushRoot(reinterpret_cast<Obj**>(&L_)); |
523 | 112 | } _ZN8ListIterIiEC2EP4ListIiE Line | Count | Source | 519 | 6 | explicit ListIter(List<T>* L) : L_(L), i_(0) { | 520 | | // We need this because ListIter is directly on the stack, and L_ could be | 521 | | // moved during iteration. | 522 | 6 | gHeap.PushRoot(reinterpret_cast<Obj**>(&L_)); | 523 | 6 | } |
_ZN8ListIterIP3StrEC2EP4ListIS1_E Line | Count | Source | 519 | 23 | explicit ListIter(List<T>* L) : L_(L), i_(0) { | 520 | | // We need this because ListIter is directly on the stack, and L_ could be | 521 | | // moved during iteration. | 522 | 23 | gHeap.PushRoot(reinterpret_cast<Obj**>(&L_)); | 523 | 23 | } |
_ZN8ListIterIP6Tuple2IP3StriEEC2EP4ListIS4_E Line | Count | Source | 519 | 1 | explicit ListIter(List<T>* L) : L_(L), i_(0) { | 520 | | // We need this because ListIter is directly on the stack, and L_ could be | 521 | | // moved during iteration. | 522 | 1 | gHeap.PushRoot(reinterpret_cast<Obj**>(&L_)); | 523 | 1 | } |
_ZN8ListIterIP6Tuple2IiP3StrEEC2EP4ListIS4_E Line | Count | Source | 519 | 2 | explicit ListIter(List<T>* L) : L_(L), i_(0) { | 520 | | // We need this because ListIter is directly on the stack, and L_ could be | 521 | | // moved during iteration. | 522 | 2 | gHeap.PushRoot(reinterpret_cast<Obj**>(&L_)); | 523 | 2 | } |
Unexecuted instantiation: _ZN8ListIterIPN10hnode_asdl7hnode_tEEC2EP4ListIS2_E _ZN8ListIterIPN10hnode_asdl5fieldEEC2EP4ListIS2_E Line | Count | Source | 519 | 79 | explicit ListIter(List<T>* L) : L_(L), i_(0) { | 520 | | // We need this because ListIter is directly on the stack, and L_ could be | 521 | | // moved during iteration. | 522 | 79 | gHeap.PushRoot(reinterpret_cast<Obj**>(&L_)); | 523 | 79 | } |
_ZN8ListIterIbEC2EP4ListIbE Line | Count | Source | 519 | 1 | explicit ListIter(List<T>* L) : L_(L), i_(0) { | 520 | | // We need this because ListIter is directly on the stack, and L_ could be | 521 | | // moved during iteration. | 522 | 1 | gHeap.PushRoot(reinterpret_cast<Obj**>(&L_)); | 523 | 1 | } |
|
524 | 112 | ~ListIter() { |
525 | 112 | gHeap.PopRoot(); |
526 | 112 | } Line | Count | Source | 524 | 6 | ~ListIter() { | 525 | 6 | gHeap.PopRoot(); | 526 | 6 | } |
Line | Count | Source | 524 | 23 | ~ListIter() { | 525 | 23 | gHeap.PopRoot(); | 526 | 23 | } |
_ZN8ListIterIP6Tuple2IP3StriEED2Ev Line | Count | Source | 524 | 1 | ~ListIter() { | 525 | 1 | gHeap.PopRoot(); | 526 | 1 | } |
_ZN8ListIterIP6Tuple2IiP3StrEED2Ev Line | Count | Source | 524 | 2 | ~ListIter() { | 525 | 2 | gHeap.PopRoot(); | 526 | 2 | } |
Unexecuted instantiation: _ZN8ListIterIPN10hnode_asdl7hnode_tEED2Ev _ZN8ListIterIPN10hnode_asdl5fieldEED2Ev Line | Count | Source | 524 | 79 | ~ListIter() { | 525 | 79 | gHeap.PopRoot(); | 526 | 79 | } |
Line | Count | Source | 524 | 1 | ~ListIter() { | 525 | 1 | gHeap.PopRoot(); | 526 | 1 | } |
|
527 | 242 | void Next() { |
528 | 242 | i_++; |
529 | 242 | } Line | Count | Source | 527 | 19 | void Next() { | 528 | 19 | i_++; | 529 | 19 | } |
_ZN8ListIterIP3StrE4NextEv Line | Count | Source | 527 | 97 | void Next() { | 528 | 97 | i_++; | 529 | 97 | } |
_ZN8ListIterIP6Tuple2IP3StriEE4NextEv Line | Count | Source | 527 | 2 | void Next() { | 528 | 2 | i_++; | 529 | 2 | } |
_ZN8ListIterIP6Tuple2IiP3StrEE4NextEv Line | Count | Source | 527 | 4 | void Next() { | 528 | 4 | i_++; | 529 | 4 | } |
Unexecuted instantiation: _ZN8ListIterIPN10hnode_asdl7hnode_tEE4NextEv _ZN8ListIterIPN10hnode_asdl5fieldEE4NextEv Line | Count | Source | 527 | 118 | void Next() { | 528 | 118 | i_++; | 529 | 118 | } |
Line | Count | Source | 527 | 2 | void Next() { | 528 | 2 | i_++; | 529 | 2 | } |
|
530 | 354 | bool Done() { |
531 | | // "unsigned size_t was a mistake" |
532 | 354 | return i_ >= static_cast<int>(L_->len_); |
533 | 354 | } Line | Count | Source | 530 | 25 | bool Done() { | 531 | | // "unsigned size_t was a mistake" | 532 | 25 | return i_ >= static_cast<int>(L_->len_); | 533 | 25 | } |
_ZN8ListIterIP3StrE4DoneEv Line | Count | Source | 530 | 120 | bool Done() { | 531 | | // "unsigned size_t was a mistake" | 532 | 120 | return i_ >= static_cast<int>(L_->len_); | 533 | 120 | } |
_ZN8ListIterIP6Tuple2IP3StriEE4DoneEv Line | Count | Source | 530 | 3 | bool Done() { | 531 | | // "unsigned size_t was a mistake" | 532 | 3 | return i_ >= static_cast<int>(L_->len_); | 533 | 3 | } |
_ZN8ListIterIP6Tuple2IiP3StrEE4DoneEv Line | Count | Source | 530 | 6 | bool Done() { | 531 | | // "unsigned size_t was a mistake" | 532 | 6 | return i_ >= static_cast<int>(L_->len_); | 533 | 6 | } |
Unexecuted instantiation: _ZN8ListIterIPN10hnode_asdl7hnode_tEE4DoneEv _ZN8ListIterIPN10hnode_asdl5fieldEE4DoneEv Line | Count | Source | 530 | 197 | bool Done() { | 531 | | // "unsigned size_t was a mistake" | 532 | 197 | return i_ >= static_cast<int>(L_->len_); | 533 | 197 | } |
Line | Count | Source | 530 | 3 | bool Done() { | 531 | | // "unsigned size_t was a mistake" | 532 | 3 | return i_ >= static_cast<int>(L_->len_); | 533 | 3 | } |
|
534 | 266 | T Value() { |
535 | 266 | return L_->slab_->items_[i_]; |
536 | 266 | } Line | Count | Source | 534 | 19 | T Value() { | 535 | 19 | return L_->slab_->items_[i_]; | 536 | 19 | } |
_ZN8ListIterIP3StrE5ValueEv Line | Count | Source | 534 | 98 | T Value() { | 535 | 98 | return L_->slab_->items_[i_]; | 536 | 98 | } |
_ZN8ListIterIP6Tuple2IP3StriEE5ValueEv Line | Count | Source | 534 | 2 | T Value() { | 535 | 2 | return L_->slab_->items_[i_]; | 536 | 2 | } |
_ZN8ListIterIP6Tuple2IiP3StrEE5ValueEv Line | Count | Source | 534 | 4 | T Value() { | 535 | 4 | return L_->slab_->items_[i_]; | 536 | 4 | } |
Unexecuted instantiation: _ZN8ListIterIPN10hnode_asdl7hnode_tEE5ValueEv _ZN8ListIterIPN10hnode_asdl5fieldEE5ValueEv Line | Count | Source | 534 | 141 | T Value() { | 535 | 141 | return L_->slab_->items_[i_]; | 536 | 141 | } |
Line | Count | Source | 534 | 2 | T Value() { | 535 | 2 | return L_->slab_->items_[i_]; | 536 | 2 | } |
|
537 | | |
538 | | private: |
539 | | List<T>* L_; |
540 | | int i_; |
541 | | }; |
542 | | |
543 | | // TODO: Does using pointers rather than indices make this more efficient? |
544 | | template <class T> |
545 | | class ReverseListIter { |
546 | | public: |
547 | 4 | explicit ReverseListIter(List<T>* L) : L_(L), i_(L_->len_ - 1) { |
548 | 4 | } _ZN15ReverseListIterIiEC2EP4ListIiE Line | Count | Source | 547 | 2 | explicit ReverseListIter(List<T>* L) : L_(L), i_(L_->len_ - 1) { | 548 | 2 | } |
_ZN15ReverseListIterIP3StrEC2EP4ListIS1_E Line | Count | Source | 547 | 1 | explicit ReverseListIter(List<T>* L) : L_(L), i_(L_->len_ - 1) { | 548 | 1 | } |
_ZN15ReverseListIterIP6Tuple2IiP3StrEEC2EP4ListIS4_E Line | Count | Source | 547 | 1 | explicit ReverseListIter(List<T>* L) : L_(L), i_(L_->len_ - 1) { | 548 | 1 | } |
|
549 | 10 | void Next() { |
550 | 10 | i_--; |
551 | 10 | } _ZN15ReverseListIterIiE4NextEv Line | Count | Source | 549 | 6 | void Next() { | 550 | 6 | i_--; | 551 | 6 | } |
_ZN15ReverseListIterIP3StrE4NextEv Line | Count | Source | 549 | 2 | void Next() { | 550 | 2 | i_--; | 551 | 2 | } |
_ZN15ReverseListIterIP6Tuple2IiP3StrEE4NextEv Line | Count | Source | 549 | 2 | void Next() { | 550 | 2 | i_--; | 551 | 2 | } |
|
552 | 14 | bool Done() { |
553 | 14 | return i_ < 0; |
554 | 14 | } _ZN15ReverseListIterIiE4DoneEv Line | Count | Source | 552 | 8 | bool Done() { | 553 | 8 | return i_ < 0; | 554 | 8 | } |
_ZN15ReverseListIterIP3StrE4DoneEv Line | Count | Source | 552 | 3 | bool Done() { | 553 | 3 | return i_ < 0; | 554 | 3 | } |
_ZN15ReverseListIterIP6Tuple2IiP3StrEE4DoneEv Line | Count | Source | 552 | 3 | bool Done() { | 553 | 3 | return i_ < 0; | 554 | 3 | } |
|
555 | 10 | T Value() { |
556 | 10 | return L_->slab_->items_[i_]; |
557 | 10 | } _ZN15ReverseListIterIiE5ValueEv Line | Count | Source | 555 | 6 | T Value() { | 556 | 6 | return L_->slab_->items_[i_]; | 557 | 6 | } |
_ZN15ReverseListIterIP3StrE5ValueEv Line | Count | Source | 555 | 2 | T Value() { | 556 | 2 | return L_->slab_->items_[i_]; | 557 | 2 | } |
_ZN15ReverseListIterIP6Tuple2IiP3StrEE5ValueEv Line | Count | Source | 555 | 2 | T Value() { | 556 | 2 | return L_->slab_->items_[i_]; | 557 | 2 | } |
|
558 | | |
559 | | private: |
560 | | List<T>* L_; |
561 | | int i_; |
562 | | }; |
563 | | |
564 | | #endif // LIST_TYPES_H |