/home/uke/oil/mycpp/gc_list.h
Line | Count | Source (jump to first uncovered line) |
1 | | #ifndef MYCPP_GC_LIST_H |
2 | | #define MYCPP_GC_LIST_H |
3 | | |
4 | | #include <string.h> // memcpy |
5 | | |
6 | | #include <algorithm> // sort() is templated |
7 | | |
8 | | #include "mycpp/common.h" // DCHECK |
9 | | #include "mycpp/comparators.h" |
10 | | #include "mycpp/gc_alloc.h" // Alloc |
11 | | #include "mycpp/gc_builtins.h" // ValueError |
12 | | #include "mycpp/gc_slab.h" |
13 | | |
14 | | // GlobalList is layout-compatible with List (unit tests assert this), and it |
15 | | // can be a true C global (incurs zero startup time) |
16 | | |
17 | | template <typename T, int N> |
18 | | class GlobalList { |
19 | | public: |
20 | | int len_; |
21 | | int capacity_; |
22 | | GlobalSlab<T, N>* slab_; |
23 | | }; |
24 | | |
25 | | #define GLOBAL_LIST(name, T, N, array) \ |
26 | | GcGlobal<GlobalSlab<T, N>> _slab_##name = {ObjHeader::Global(TypeTag::Slab), \ |
27 | | {.items_ = array}}; \ |
28 | | GcGlobal<GlobalList<T, N>> _list_##name = { \ |
29 | | ObjHeader::Global(TypeTag::List), \ |
30 | | {.len_ = N, .capacity_ = N, .slab_ = &_slab_##name.obj}}; \ |
31 | | List<T>* name = reinterpret_cast<List<T>*>(&_list_##name.obj); |
32 | | |
33 | | template <typename T> |
34 | | class List { |
35 | | public: |
36 | 377 | List() : len_(0), capacity_(0), slab_(nullptr) { |
37 | 377 | } Line | Count | Source | 36 | 326 | List() : len_(0), capacity_(0), slab_(nullptr) { | 37 | 326 | } |
Line | Count | Source | 36 | 46 | List() : len_(0), capacity_(0), slab_(nullptr) { | 37 | 46 | } |
_ZN4ListIP6Tuple2IiiEEC2Ev Line | Count | Source | 36 | 2 | List() : len_(0), capacity_(0), slab_(nullptr) { | 37 | 2 | } |
Line | Count | Source | 36 | 1 | List() : len_(0), capacity_(0), slab_(nullptr) { | 37 | 1 | } |
Line | Count | Source | 36 | 1 | List() : len_(0), capacity_(0), slab_(nullptr) { | 37 | 1 | } |
Line | Count | Source | 36 | 1 | List() : len_(0), capacity_(0), slab_(nullptr) { | 37 | 1 | } |
|
38 | | |
39 | | // Implements L[i] |
40 | | T at(int i); |
41 | | |
42 | | // returns index of the element |
43 | | int index(T element); |
44 | | |
45 | | // Implements L[i] = item |
46 | | void set(int i, T item); |
47 | | |
48 | | // L[begin:] |
49 | | List* slice(int begin); |
50 | | |
51 | | // L[begin:end] |
52 | | List* slice(int begin, int end); |
53 | | |
54 | | // Should we have a separate API that doesn't return it? |
55 | | // https://stackoverflow.com/questions/12600330/pop-back-return-value |
56 | | T pop(); |
57 | | |
58 | | // Used in osh/word_parse.py to remove from front |
59 | | T pop(int i); |
60 | | |
61 | | // Remove the first occourence of x from the list. |
62 | | void remove(T x); |
63 | | |
64 | | void clear(); |
65 | | |
66 | | // Used in osh/string_ops.py |
67 | | void reverse(); |
68 | | |
69 | | // Templated function |
70 | | void sort(); |
71 | | |
72 | | // Ensure that there's space for at LEAST this many items |
73 | | void reserve(int num_desired); |
74 | | |
75 | | // Append a single element to this list. |
76 | | void append(T item); |
77 | | |
78 | | // Extend this list with multiple elements. |
79 | | void extend(List<T>* other); |
80 | | |
81 | 377 | static constexpr ObjHeader obj_header() { |
82 | 377 | return ObjHeader::ClassFixed(field_mask(), sizeof(List<T>)); |
83 | 377 | } _ZN4ListIiE10obj_headerEv Line | Count | Source | 81 | 326 | static constexpr ObjHeader obj_header() { | 82 | 326 | return ObjHeader::ClassFixed(field_mask(), sizeof(List<T>)); | 83 | 326 | } |
_ZN4ListIP6BigStrE10obj_headerEv Line | Count | Source | 81 | 46 | static constexpr ObjHeader obj_header() { | 82 | 46 | return ObjHeader::ClassFixed(field_mask(), sizeof(List<T>)); | 83 | 46 | } |
_ZN4ListIP6Tuple2IiiEE10obj_headerEv Line | Count | Source | 81 | 2 | static constexpr ObjHeader obj_header() { | 82 | 2 | return ObjHeader::ClassFixed(field_mask(), sizeof(List<T>)); | 83 | 2 | } |
_ZN4ListIbE10obj_headerEv Line | Count | Source | 81 | 1 | static constexpr ObjHeader obj_header() { | 82 | 1 | return ObjHeader::ClassFixed(field_mask(), sizeof(List<T>)); | 83 | 1 | } |
_ZN4ListIPiE10obj_headerEv Line | Count | Source | 81 | 1 | static constexpr ObjHeader obj_header() { | 82 | 1 | return ObjHeader::ClassFixed(field_mask(), sizeof(List<T>)); | 83 | 1 | } |
_ZN4ListIdE10obj_headerEv Line | Count | Source | 81 | 1 | static constexpr ObjHeader obj_header() { | 82 | 1 | return ObjHeader::ClassFixed(field_mask(), sizeof(List<T>)); | 83 | 1 | } |
|
84 | | |
85 | | int len_; // number of entries |
86 | | int capacity_; // max entries before resizing |
87 | | |
88 | | // The container may be resized, so this field isn't in-line. |
89 | | Slab<T>* slab_; |
90 | | |
91 | | // A list has one Slab pointer which we need to follow. |
92 | 378 | static constexpr uint32_t field_mask() { |
93 | 378 | return maskbit(offsetof(List, slab_)); |
94 | 378 | } _ZN4ListIiE10field_maskEv Line | Count | Source | 92 | 327 | static constexpr uint32_t field_mask() { | 93 | 327 | return maskbit(offsetof(List, slab_)); | 94 | 327 | } |
_ZN4ListIP6BigStrE10field_maskEv Line | Count | Source | 92 | 46 | static constexpr uint32_t field_mask() { | 93 | 46 | return maskbit(offsetof(List, slab_)); | 94 | 46 | } |
_ZN4ListIP6Tuple2IiiEE10field_maskEv Line | Count | Source | 92 | 2 | static constexpr uint32_t field_mask() { | 93 | 2 | return maskbit(offsetof(List, slab_)); | 94 | 2 | } |
_ZN4ListIbE10field_maskEv Line | Count | Source | 92 | 1 | static constexpr uint32_t field_mask() { | 93 | 1 | return maskbit(offsetof(List, slab_)); | 94 | 1 | } |
_ZN4ListIPiE10field_maskEv Line | Count | Source | 92 | 1 | static constexpr uint32_t field_mask() { | 93 | 1 | return maskbit(offsetof(List, slab_)); | 94 | 1 | } |
_ZN4ListIdE10field_maskEv Line | Count | Source | 92 | 1 | static constexpr uint32_t field_mask() { | 93 | 1 | return maskbit(offsetof(List, slab_)); | 94 | 1 | } |
|
95 | | |
96 | | DISALLOW_COPY_AND_ASSIGN(List) |
97 | | |
98 | | static_assert(sizeof(ObjHeader) % sizeof(T) == 0, |
99 | | "ObjHeader size should be multiple of item size"); |
100 | | static constexpr int kHeaderFudge = sizeof(ObjHeader) / sizeof(T); |
101 | | |
102 | | #if 0 |
103 | | // 24-byte pool comes from very common List header, and Token |
104 | | static constexpr int kPoolBytes1 = 24 - sizeof(ObjHeader); |
105 | | static_assert(kPoolBytes1 % sizeof(T) == 0, |
106 | | "An integral number of items should fit in first pool"); |
107 | | static constexpr int kNumItems1 = kPoolBytes1 / sizeof(T); |
108 | | #endif |
109 | | |
110 | | // Matches mark_sweep_heap.h |
111 | | static constexpr int kPoolBytes2 = 48 - sizeof(ObjHeader); |
112 | | static_assert(kPoolBytes2 % sizeof(T) == 0, |
113 | | "An integral number of items should fit in second pool"); |
114 | | static constexpr int kNumItems2 = kPoolBytes2 / sizeof(T); |
115 | | |
116 | | #if 0 |
117 | | static constexpr int kMinBytes2 = 128 - sizeof(ObjHeader); |
118 | | static_assert(kMinBytes2 % sizeof(T) == 0, |
119 | | "An integral number of items should fit"); |
120 | | static constexpr int kMinItems2 = kMinBytes2 / sizeof(T); |
121 | | #endif |
122 | | |
123 | | // Given the number of items desired, return the number items we should |
124 | | // reserve room for, according to our growth policy. |
125 | 384 | int HowManyItems(int num_desired) { |
126 | | // Using the 24-byte pool leads to too much GC of tiny slab objects! So |
127 | | // just use the larger 48 byte pool. |
128 | | #if 0 |
129 | | if (num_desired <= kNumItems1) { // use full cell in pool 1 |
130 | | return kNumItems1; |
131 | | } |
132 | | #endif |
133 | 384 | if (num_desired <= kNumItems2) { // use full cell in pool 2 |
134 | 367 | return kNumItems2; |
135 | 367 | } |
136 | | #if 0 |
137 | | if (num_desired <= kMinItems2) { // 48 -> 128, not 48 -> 64 |
138 | | return kMinItems2; |
139 | | } |
140 | | #endif |
141 | | |
142 | | // Make sure the total allocation is a power of 2. TODO: consider using |
143 | | // slightly less than power of 2, to account for malloc() headers, and |
144 | | // reduce fragmentation. |
145 | | // Example: |
146 | | // - ask for 11 integers |
147 | | // - round up 11+2 == 13 up to 16 items |
148 | | // - return 14 items |
149 | | // - 14 integers is 56 bytes, plus 8 byte GC header => 64 byte alloc. |
150 | 17 | return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge; |
151 | 384 | } _ZN4ListIiE12HowManyItemsEi Line | Count | Source | 125 | 334 | int HowManyItems(int num_desired) { | 126 | | // Using the 24-byte pool leads to too much GC of tiny slab objects! So | 127 | | // just use the larger 48 byte pool. | 128 | | #if 0 | 129 | | if (num_desired <= kNumItems1) { // use full cell in pool 1 | 130 | | return kNumItems1; | 131 | | } | 132 | | #endif | 133 | 334 | if (num_desired <= kNumItems2) { // use full cell in pool 2 | 134 | 322 | return kNumItems2; | 135 | 322 | } | 136 | | #if 0 | 137 | | if (num_desired <= kMinItems2) { // 48 -> 128, not 48 -> 64 | 138 | | return kMinItems2; | 139 | | } | 140 | | #endif | 141 | | | 142 | | // Make sure the total allocation is a power of 2. TODO: consider using | 143 | | // slightly less than power of 2, to account for malloc() headers, and | 144 | | // reduce fragmentation. | 145 | | // Example: | 146 | | // - ask for 11 integers | 147 | | // - round up 11+2 == 13 up to 16 items | 148 | | // - return 14 items | 149 | | // - 14 integers is 56 bytes, plus 8 byte GC header => 64 byte alloc. | 150 | 12 | return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge; | 151 | 334 | } |
_ZN4ListIP6BigStrE12HowManyItemsEi Line | Count | Source | 125 | 46 | int HowManyItems(int num_desired) { | 126 | | // Using the 24-byte pool leads to too much GC of tiny slab objects! So | 127 | | // just use the larger 48 byte pool. | 128 | | #if 0 | 129 | | if (num_desired <= kNumItems1) { // use full cell in pool 1 | 130 | | return kNumItems1; | 131 | | } | 132 | | #endif | 133 | 46 | if (num_desired <= kNumItems2) { // use full cell in pool 2 | 134 | 41 | return kNumItems2; | 135 | 41 | } | 136 | | #if 0 | 137 | | if (num_desired <= kMinItems2) { // 48 -> 128, not 48 -> 64 | 138 | | return kMinItems2; | 139 | | } | 140 | | #endif | 141 | | | 142 | | // Make sure the total allocation is a power of 2. TODO: consider using | 143 | | // slightly less than power of 2, to account for malloc() headers, and | 144 | | // reduce fragmentation. | 145 | | // Example: | 146 | | // - ask for 11 integers | 147 | | // - round up 11+2 == 13 up to 16 items | 148 | | // - return 14 items | 149 | | // - 14 integers is 56 bytes, plus 8 byte GC header => 64 byte alloc. | 150 | 5 | return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge; | 151 | 46 | } |
_ZN4ListIP6Tuple2IiiEE12HowManyItemsEi Line | Count | Source | 125 | 2 | int HowManyItems(int num_desired) { | 126 | | // Using the 24-byte pool leads to too much GC of tiny slab objects! So | 127 | | // just use the larger 48 byte pool. | 128 | | #if 0 | 129 | | if (num_desired <= kNumItems1) { // use full cell in pool 1 | 130 | | return kNumItems1; | 131 | | } | 132 | | #endif | 133 | 2 | if (num_desired <= kNumItems2) { // use full cell in pool 2 | 134 | 2 | return kNumItems2; | 135 | 2 | } | 136 | | #if 0 | 137 | | if (num_desired <= kMinItems2) { // 48 -> 128, not 48 -> 64 | 138 | | return kMinItems2; | 139 | | } | 140 | | #endif | 141 | | | 142 | | // Make sure the total allocation is a power of 2. TODO: consider using | 143 | | // slightly less than power of 2, to account for malloc() headers, and | 144 | | // reduce fragmentation. | 145 | | // Example: | 146 | | // - ask for 11 integers | 147 | | // - round up 11+2 == 13 up to 16 items | 148 | | // - return 14 items | 149 | | // - 14 integers is 56 bytes, plus 8 byte GC header => 64 byte alloc. | 150 | 0 | return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge; | 151 | 2 | } |
_ZN4ListIbE12HowManyItemsEi Line | Count | Source | 125 | 1 | int HowManyItems(int num_desired) { | 126 | | // Using the 24-byte pool leads to too much GC of tiny slab objects! So | 127 | | // just use the larger 48 byte pool. | 128 | | #if 0 | 129 | | if (num_desired <= kNumItems1) { // use full cell in pool 1 | 130 | | return kNumItems1; | 131 | | } | 132 | | #endif | 133 | 1 | if (num_desired <= kNumItems2) { // use full cell in pool 2 | 134 | 1 | return kNumItems2; | 135 | 1 | } | 136 | | #if 0 | 137 | | if (num_desired <= kMinItems2) { // 48 -> 128, not 48 -> 64 | 138 | | return kMinItems2; | 139 | | } | 140 | | #endif | 141 | | | 142 | | // Make sure the total allocation is a power of 2. TODO: consider using | 143 | | // slightly less than power of 2, to account for malloc() headers, and | 144 | | // reduce fragmentation. | 145 | | // Example: | 146 | | // - ask for 11 integers | 147 | | // - round up 11+2 == 13 up to 16 items | 148 | | // - return 14 items | 149 | | // - 14 integers is 56 bytes, plus 8 byte GC header => 64 byte alloc. | 150 | 0 | return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge; | 151 | 1 | } |
_ZN4ListIdE12HowManyItemsEi Line | Count | Source | 125 | 1 | int HowManyItems(int num_desired) { | 126 | | // Using the 24-byte pool leads to too much GC of tiny slab objects! So | 127 | | // just use the larger 48 byte pool. | 128 | | #if 0 | 129 | | if (num_desired <= kNumItems1) { // use full cell in pool 1 | 130 | | return kNumItems1; | 131 | | } | 132 | | #endif | 133 | 1 | if (num_desired <= kNumItems2) { // use full cell in pool 2 | 134 | 1 | return kNumItems2; | 135 | 1 | } | 136 | | #if 0 | 137 | | if (num_desired <= kMinItems2) { // 48 -> 128, not 48 -> 64 | 138 | | return kMinItems2; | 139 | | } | 140 | | #endif | 141 | | | 142 | | // Make sure the total allocation is a power of 2. TODO: consider using | 143 | | // slightly less than power of 2, to account for malloc() headers, and | 144 | | // reduce fragmentation. | 145 | | // Example: | 146 | | // - ask for 11 integers | 147 | | // - round up 11+2 == 13 up to 16 items | 148 | | // - return 14 items | 149 | | // - 14 integers is 56 bytes, plus 8 byte GC header => 64 byte alloc. | 150 | 0 | return RoundUp(num_desired + kHeaderFudge) - kHeaderFudge; | 151 | 1 | } |
|
152 | | }; |
153 | | |
154 | | // "Constructors" as free functions since we can't allocate within a |
155 | | // constructor. Allocation may cause garbage collection, which interferes with |
156 | | // placement new. |
157 | | |
158 | | // This is not really necessary, only syntactic sugar. |
159 | | template <typename T> |
160 | 316 | List<T>* NewList() { |
161 | 316 | return Alloc<List<T>>(); |
162 | 316 | } Line | Count | Source | 160 | 309 | List<T>* NewList() { | 161 | 309 | return Alloc<List<T>>(); | 162 | 309 | } |
_Z7NewListIP6BigStrEP4ListIT_Ev Line | Count | Source | 160 | 6 | List<T>* NewList() { | 161 | 6 | return Alloc<List<T>>(); | 162 | 6 | } |
_Z7NewListIPiEP4ListIT_Ev Line | Count | Source | 160 | 1 | List<T>* NewList() { | 161 | 1 | return Alloc<List<T>>(); | 162 | 1 | } |
|
163 | | |
164 | | // Literal ['foo', 'bar'] |
165 | | // This seems to allow better template argument type deduction than a |
166 | | // constructor. |
167 | | template <typename T> |
168 | 38 | List<T>* NewList(std::initializer_list<T> init) { |
169 | 38 | auto self = Alloc<List<T>>(); |
170 | | |
171 | 38 | int n = init.size(); |
172 | 38 | self->reserve(n); |
173 | | |
174 | 38 | int i = 0; |
175 | 69 | for (auto item : init) { |
176 | 69 | self->set(i, item); |
177 | 69 | ++i; |
178 | 69 | } |
179 | 38 | self->len_ = n; |
180 | 38 | return self; |
181 | 38 | } _Z7NewListIiEP4ListIT_ESt16initializer_listIS1_E Line | Count | Source | 168 | 11 | List<T>* NewList(std::initializer_list<T> init) { | 169 | 11 | auto self = Alloc<List<T>>(); | 170 | | | 171 | 11 | int n = init.size(); | 172 | 11 | self->reserve(n); | 173 | | | 174 | 11 | int i = 0; | 175 | 47 | for (auto item : init) { | 176 | 47 | self->set(i, item); | 177 | 47 | ++i; | 178 | 47 | } | 179 | 11 | self->len_ = n; | 180 | 11 | return self; | 181 | 11 | } |
_Z7NewListIP6BigStrEP4ListIT_ESt16initializer_listIS3_E Line | Count | Source | 168 | 26 | List<T>* NewList(std::initializer_list<T> init) { | 169 | 26 | auto self = Alloc<List<T>>(); | 170 | | | 171 | 26 | int n = init.size(); | 172 | 26 | self->reserve(n); | 173 | | | 174 | 26 | int i = 0; | 175 | 26 | for (auto item : init) { | 176 | 19 | self->set(i, item); | 177 | 19 | ++i; | 178 | 19 | } | 179 | 26 | self->len_ = n; | 180 | 26 | return self; | 181 | 26 | } |
_Z7NewListIdEP4ListIT_ESt16initializer_listIS1_E Line | Count | Source | 168 | 1 | List<T>* NewList(std::initializer_list<T> init) { | 169 | 1 | auto self = Alloc<List<T>>(); | 170 | | | 171 | 1 | int n = init.size(); | 172 | 1 | self->reserve(n); | 173 | | | 174 | 1 | int i = 0; | 175 | 3 | for (auto item : init) { | 176 | 3 | self->set(i, item); | 177 | 3 | ++i; | 178 | 3 | } | 179 | 1 | self->len_ = n; | 180 | 1 | return self; | 181 | 1 | } |
|
182 | | |
183 | | // ['foo'] * 3 |
184 | | template <typename T> |
185 | 4 | List<T>* NewList(T item, int times) { |
186 | 4 | auto self = Alloc<List<T>>(); |
187 | | |
188 | 4 | self->reserve(times); |
189 | 4 | self->len_ = times; |
190 | 16 | for (int i = 0; i < times; ++i) { |
191 | 12 | self->set(i, item); |
192 | 12 | } |
193 | 4 | return self; |
194 | 4 | } _Z7NewListIP6BigStrEP4ListIT_ES3_i Line | Count | Source | 185 | 1 | List<T>* NewList(T item, int times) { | 186 | 1 | auto self = Alloc<List<T>>(); | 187 | | | 188 | 1 | self->reserve(times); | 189 | 1 | self->len_ = times; | 190 | 4 | for (int i = 0; i < times; ++i) { | 191 | 3 | self->set(i, item); | 192 | 3 | } | 193 | 1 | return self; | 194 | 1 | } |
_Z7NewListIbEP4ListIT_ES1_i Line | Count | Source | 185 | 1 | List<T>* NewList(T item, int times) { | 186 | 1 | auto self = Alloc<List<T>>(); | 187 | | | 188 | 1 | self->reserve(times); | 189 | 1 | self->len_ = times; | 190 | 4 | for (int i = 0; i < times; ++i) { | 191 | 3 | self->set(i, item); | 192 | 3 | } | 193 | 1 | return self; | 194 | 1 | } |
_Z7NewListIiEP4ListIT_ES1_i Line | Count | Source | 185 | 2 | List<T>* NewList(T item, int times) { | 186 | 2 | auto self = Alloc<List<T>>(); | 187 | | | 188 | 2 | self->reserve(times); | 189 | 2 | self->len_ = times; | 190 | 8 | for (int i = 0; i < times; ++i) { | 191 | 6 | self->set(i, item); | 192 | 6 | } | 193 | 2 | return self; | 194 | 2 | } |
|
195 | | |
196 | | template <typename T> |
197 | 1.46k | void List<T>::append(T item) { |
198 | 1.46k | reserve(len_ + 1); |
199 | 1.46k | slab_->items_[len_] = item; |
200 | 1.46k | ++len_; |
201 | 1.46k | } _ZN4ListIP6BigStrE6appendES1_ Line | Count | Source | 197 | 103 | void List<T>::append(T item) { | 198 | 103 | reserve(len_ + 1); | 199 | 103 | slab_->items_[len_] = item; | 200 | 103 | ++len_; | 201 | 103 | } |
Line | Count | Source | 197 | 1.35k | void List<T>::append(T item) { | 198 | 1.35k | reserve(len_ + 1); | 199 | 1.35k | slab_->items_[len_] = item; | 200 | 1.35k | ++len_; | 201 | 1.35k | } |
_ZN4ListIP6Tuple2IiiEE6appendES2_ Line | Count | Source | 197 | 4 | void List<T>::append(T item) { | 198 | 4 | reserve(len_ + 1); | 199 | 4 | slab_->items_[len_] = item; | 200 | 4 | ++len_; | 201 | 4 | } |
|
202 | | |
203 | | template <typename T> |
204 | 2.06k | int len(const List<T>* L) { |
205 | 2.06k | return L->len_; |
206 | 2.06k | } Line | Count | Source | 204 | 1.97k | int len(const List<T>* L) { | 205 | 1.97k | return L->len_; | 206 | 1.97k | } |
_Z3lenIP6BigStrEiPK4ListIT_E Line | Count | Source | 204 | 83 | int len(const List<T>* L) { | 205 | 83 | return L->len_; | 206 | 83 | } |
_Z3lenIP6Tuple2IiiEEiPK4ListIT_E Line | Count | Source | 204 | 2 | int len(const List<T>* L) { | 205 | 2 | return L->len_; | 206 | 2 | } |
Line | Count | Source | 204 | 1 | int len(const List<T>* L) { | 205 | 1 | return L->len_; | 206 | 1 | } |
Line | Count | Source | 204 | 2 | int len(const List<T>* L) { | 205 | 2 | return L->len_; | 206 | 2 | } |
|
207 | | |
208 | | template <typename T> |
209 | | List<T>* list_repeat(T item, int times); |
210 | | |
211 | | template <typename T> |
212 | | inline bool list_contains(List<T>* haystack, T needle); |
213 | | |
214 | | template <typename K, typename V> |
215 | | class Dict; // forward decl |
216 | | |
217 | | template <typename V> |
218 | | List<BigStr*>* sorted(Dict<BigStr*, V>* d); |
219 | | |
220 | | template <typename T> |
221 | | List<T>* sorted(List<T>* l); |
222 | | |
223 | | // L[begin:] |
224 | | template <typename T> |
225 | 301 | List<T>* List<T>::slice(int begin) { |
226 | 301 | return slice(begin, len_); |
227 | 301 | } |
228 | | |
229 | | // L[begin:end] |
230 | | template <typename T> |
231 | 303 | List<T>* List<T>::slice(int begin, int end) { |
232 | 303 | SLICE_ADJUST(begin, end, len_); |
233 | | |
234 | 303 | DCHECK(0 <= begin && begin <= len_); |
235 | 303 | DCHECK(0 <= end && end <= len_); |
236 | | |
237 | 0 | int new_len = end - begin; |
238 | 303 | DCHECK(0 <= new_len && new_len <= len_); |
239 | | |
240 | 0 | List<T>* result = NewList<T>(); |
241 | 303 | result->reserve(new_len); |
242 | | |
243 | | // Faster than append() in a loop |
244 | 303 | memcpy(result->slab_->items_, slab_->items_ + begin, new_len * sizeof(T)); |
245 | 303 | result->len_ = new_len; |
246 | | |
247 | 303 | return result; |
248 | 303 | } |
249 | | |
250 | | // Ensure that there's space for a number of items |
251 | | template <typename T> |
252 | 1.82k | void List<T>::reserve(int num_desired) { |
253 | | // log("reserve capacity = %d, n = %d", capacity_, n); |
254 | | |
255 | | // Don't do anything if there's already enough space. |
256 | 1.82k | if (capacity_ >= num_desired) { |
257 | 1.43k | return; |
258 | 1.43k | } |
259 | | |
260 | | // Slabs should be a total of 2^N bytes. kCapacityAdjust is the number of |
261 | | // items that the 8 byte header takes up: 1 for List<T*>, and 2 for |
262 | | // List<int>. |
263 | | // |
264 | | // Example: the user reserves space for 3 integers. The minimum number of |
265 | | // items would be 5, which is rounded up to 8. Subtract 2 again, giving 6, |
266 | | // which leads to 8 + 6*4 = 32 byte Slab. |
267 | | |
268 | 384 | capacity_ = HowManyItems(num_desired); |
269 | 384 | auto new_slab = NewSlab<T>(capacity_); |
270 | | |
271 | 384 | if (len_ > 0) { |
272 | | // log("Copying %d bytes", len_ * sizeof(T)); |
273 | 13 | memcpy(new_slab->items_, slab_->items_, len_ * sizeof(T)); |
274 | 13 | } |
275 | 384 | slab_ = new_slab; |
276 | 384 | } Line | Count | Source | 252 | 1.67k | void List<T>::reserve(int num_desired) { | 253 | | // log("reserve capacity = %d, n = %d", capacity_, n); | 254 | | | 255 | | // Don't do anything if there's already enough space. | 256 | 1.67k | if (capacity_ >= num_desired) { | 257 | 1.34k | return; | 258 | 1.34k | } | 259 | | | 260 | | // Slabs should be a total of 2^N bytes. kCapacityAdjust is the number of | 261 | | // items that the 8 byte header takes up: 1 for List<T*>, and 2 for | 262 | | // List<int>. | 263 | | // | 264 | | // Example: the user reserves space for 3 integers. The minimum number of | 265 | | // items would be 5, which is rounded up to 8. Subtract 2 again, giving 6, | 266 | | // which leads to 8 + 6*4 = 32 byte Slab. | 267 | | | 268 | 334 | capacity_ = HowManyItems(num_desired); | 269 | 334 | auto new_slab = NewSlab<T>(capacity_); | 270 | | | 271 | 334 | if (len_ > 0) { | 272 | | // log("Copying %d bytes", len_ * sizeof(T)); | 273 | 9 | memcpy(new_slab->items_, slab_->items_, len_ * sizeof(T)); | 274 | 9 | } | 275 | 334 | slab_ = new_slab; | 276 | 334 | } |
_ZN4ListIP6BigStrE7reserveEi Line | Count | Source | 252 | 137 | void List<T>::reserve(int num_desired) { | 253 | | // log("reserve capacity = %d, n = %d", capacity_, n); | 254 | | | 255 | | // Don't do anything if there's already enough space. | 256 | 137 | if (capacity_ >= num_desired) { | 257 | 91 | return; | 258 | 91 | } | 259 | | | 260 | | // Slabs should be a total of 2^N bytes. kCapacityAdjust is the number of | 261 | | // items that the 8 byte header takes up: 1 for List<T*>, and 2 for | 262 | | // List<int>. | 263 | | // | 264 | | // Example: the user reserves space for 3 integers. The minimum number of | 265 | | // items would be 5, which is rounded up to 8. Subtract 2 again, giving 6, | 266 | | // which leads to 8 + 6*4 = 32 byte Slab. | 267 | | | 268 | 46 | capacity_ = HowManyItems(num_desired); | 269 | 46 | auto new_slab = NewSlab<T>(capacity_); | 270 | | | 271 | 46 | if (len_ > 0) { | 272 | | // log("Copying %d bytes", len_ * sizeof(T)); | 273 | 4 | memcpy(new_slab->items_, slab_->items_, len_ * sizeof(T)); | 274 | 4 | } | 275 | 46 | slab_ = new_slab; | 276 | 46 | } |
_ZN4ListIP6Tuple2IiiEE7reserveEi Line | Count | Source | 252 | 4 | void List<T>::reserve(int num_desired) { | 253 | | // log("reserve capacity = %d, n = %d", capacity_, n); | 254 | | | 255 | | // Don't do anything if there's already enough space. | 256 | 4 | if (capacity_ >= num_desired) { | 257 | 2 | return; | 258 | 2 | } | 259 | | | 260 | | // Slabs should be a total of 2^N bytes. kCapacityAdjust is the number of | 261 | | // items that the 8 byte header takes up: 1 for List<T*>, and 2 for | 262 | | // List<int>. | 263 | | // | 264 | | // Example: the user reserves space for 3 integers. The minimum number of | 265 | | // items would be 5, which is rounded up to 8. Subtract 2 again, giving 6, | 266 | | // which leads to 8 + 6*4 = 32 byte Slab. | 267 | | | 268 | 2 | capacity_ = HowManyItems(num_desired); | 269 | 2 | auto new_slab = NewSlab<T>(capacity_); | 270 | | | 271 | 2 | if (len_ > 0) { | 272 | | // log("Copying %d bytes", len_ * sizeof(T)); | 273 | 0 | memcpy(new_slab->items_, slab_->items_, len_ * sizeof(T)); | 274 | 0 | } | 275 | 2 | slab_ = new_slab; | 276 | 2 | } |
Line | Count | Source | 252 | 1 | void List<T>::reserve(int num_desired) { | 253 | | // log("reserve capacity = %d, n = %d", capacity_, n); | 254 | | | 255 | | // Don't do anything if there's already enough space. | 256 | 1 | if (capacity_ >= num_desired) { | 257 | 0 | return; | 258 | 0 | } | 259 | | | 260 | | // Slabs should be a total of 2^N bytes. kCapacityAdjust is the number of | 261 | | // items that the 8 byte header takes up: 1 for List<T*>, and 2 for | 262 | | // List<int>. | 263 | | // | 264 | | // Example: the user reserves space for 3 integers. The minimum number of | 265 | | // items would be 5, which is rounded up to 8. Subtract 2 again, giving 6, | 266 | | // which leads to 8 + 6*4 = 32 byte Slab. | 267 | | | 268 | 1 | capacity_ = HowManyItems(num_desired); | 269 | 1 | auto new_slab = NewSlab<T>(capacity_); | 270 | | | 271 | 1 | if (len_ > 0) { | 272 | | // log("Copying %d bytes", len_ * sizeof(T)); | 273 | 0 | memcpy(new_slab->items_, slab_->items_, len_ * sizeof(T)); | 274 | 0 | } | 275 | 1 | slab_ = new_slab; | 276 | 1 | } |
Line | Count | Source | 252 | 1 | void List<T>::reserve(int num_desired) { | 253 | | // log("reserve capacity = %d, n = %d", capacity_, n); | 254 | | | 255 | | // Don't do anything if there's already enough space. | 256 | 1 | if (capacity_ >= num_desired) { | 257 | 0 | return; | 258 | 0 | } | 259 | | | 260 | | // Slabs should be a total of 2^N bytes. kCapacityAdjust is the number of | 261 | | // items that the 8 byte header takes up: 1 for List<T*>, and 2 for | 262 | | // List<int>. | 263 | | // | 264 | | // Example: the user reserves space for 3 integers. The minimum number of | 265 | | // items would be 5, which is rounded up to 8. Subtract 2 again, giving 6, | 266 | | // which leads to 8 + 6*4 = 32 byte Slab. | 267 | | | 268 | 1 | capacity_ = HowManyItems(num_desired); | 269 | 1 | auto new_slab = NewSlab<T>(capacity_); | 270 | | | 271 | 1 | if (len_ > 0) { | 272 | | // log("Copying %d bytes", len_ * sizeof(T)); | 273 | 0 | memcpy(new_slab->items_, slab_->items_, len_ * sizeof(T)); | 274 | 0 | } | 275 | 1 | slab_ = new_slab; | 276 | 1 | } |
|
277 | | |
278 | | // Implements L[i] = item |
279 | | template <typename T> |
280 | 104 | void List<T>::set(int i, T item) { |
281 | 104 | if (i < 0) { |
282 | 0 | i = len_ + i; |
283 | 0 | } |
284 | | |
285 | 104 | DCHECK(i >= 0); |
286 | 104 | DCHECK(i < capacity_); |
287 | | |
288 | 0 | slab_->items_[i] = item; |
289 | 104 | } Line | Count | Source | 280 | 70 | void List<T>::set(int i, T item) { | 281 | 70 | if (i < 0) { | 282 | 0 | i = len_ + i; | 283 | 0 | } | 284 | | | 285 | 70 | DCHECK(i >= 0); | 286 | 70 | DCHECK(i < capacity_); | 287 | | | 288 | 0 | slab_->items_[i] = item; | 289 | 70 | } |
_ZN4ListIP6BigStrE3setEiS1_ Line | Count | Source | 280 | 28 | void List<T>::set(int i, T item) { | 281 | 28 | if (i < 0) { | 282 | 0 | i = len_ + i; | 283 | 0 | } | 284 | | | 285 | 28 | DCHECK(i >= 0); | 286 | 28 | DCHECK(i < capacity_); | 287 | | | 288 | 0 | slab_->items_[i] = item; | 289 | 28 | } |
Line | Count | Source | 280 | 3 | void List<T>::set(int i, T item) { | 281 | 3 | if (i < 0) { | 282 | 0 | i = len_ + i; | 283 | 0 | } | 284 | | | 285 | 3 | DCHECK(i >= 0); | 286 | 3 | DCHECK(i < capacity_); | 287 | | | 288 | 0 | slab_->items_[i] = item; | 289 | 3 | } |
Line | Count | Source | 280 | 3 | void List<T>::set(int i, T item) { | 281 | 3 | if (i < 0) { | 282 | 0 | i = len_ + i; | 283 | 0 | } | 284 | | | 285 | 3 | DCHECK(i >= 0); | 286 | 3 | DCHECK(i < capacity_); | 287 | | | 288 | 0 | slab_->items_[i] = item; | 289 | 3 | } |
|
290 | | |
291 | | // Implements L[i] |
292 | | template <typename T> |
293 | 277 | T List<T>::at(int i) { |
294 | 277 | if (i < 0) { |
295 | 0 | int j = len_ + i; |
296 | 0 | if (j >= len_ || j < 0) { |
297 | 0 | throw Alloc<IndexError>(); |
298 | 0 | } |
299 | 0 | return slab_->items_[j]; |
300 | 0 | } |
301 | | |
302 | 277 | if (i >= len_ || i < 0) { |
303 | 0 | throw Alloc<IndexError>(); |
304 | 0 | } |
305 | 277 | return slab_->items_[i]; |
306 | 277 | } Line | Count | Source | 293 | 132 | T List<T>::at(int i) { | 294 | 132 | if (i < 0) { | 295 | 0 | int j = len_ + i; | 296 | 0 | if (j >= len_ || j < 0) { | 297 | 0 | throw Alloc<IndexError>(); | 298 | 0 | } | 299 | 0 | return slab_->items_[j]; | 300 | 0 | } | 301 | | | 302 | 132 | if (i >= len_ || i < 0) { | 303 | 0 | throw Alloc<IndexError>(); | 304 | 0 | } | 305 | 132 | return slab_->items_[i]; | 306 | 132 | } |
Line | Count | Source | 293 | 139 | T List<T>::at(int i) { | 294 | 139 | if (i < 0) { | 295 | 0 | int j = len_ + i; | 296 | 0 | if (j >= len_ || j < 0) { | 297 | 0 | throw Alloc<IndexError>(); | 298 | 0 | } | 299 | 0 | return slab_->items_[j]; | 300 | 0 | } | 301 | | | 302 | 139 | if (i >= len_ || i < 0) { | 303 | 0 | throw Alloc<IndexError>(); | 304 | 0 | } | 305 | 139 | return slab_->items_[i]; | 306 | 139 | } |
Line | Count | Source | 293 | 2 | T List<T>::at(int i) { | 294 | 2 | if (i < 0) { | 295 | 0 | int j = len_ + i; | 296 | 0 | if (j >= len_ || j < 0) { | 297 | 0 | throw Alloc<IndexError>(); | 298 | 0 | } | 299 | 0 | return slab_->items_[j]; | 300 | 0 | } | 301 | | | 302 | 2 | if (i >= len_ || i < 0) { | 303 | 0 | throw Alloc<IndexError>(); | 304 | 0 | } | 305 | 2 | return slab_->items_[i]; | 306 | 2 | } |
Line | Count | Source | 293 | 4 | T List<T>::at(int i) { | 294 | 4 | if (i < 0) { | 295 | 0 | int j = len_ + i; | 296 | 0 | if (j >= len_ || j < 0) { | 297 | 0 | throw Alloc<IndexError>(); | 298 | 0 | } | 299 | 0 | return slab_->items_[j]; | 300 | 0 | } | 301 | | | 302 | 4 | if (i >= len_ || i < 0) { | 303 | 0 | throw Alloc<IndexError>(); | 304 | 0 | } | 305 | 4 | return slab_->items_[i]; | 306 | 4 | } |
|
307 | | |
308 | | // L.index(i) -- Python method |
309 | | template <typename T> |
310 | 4 | int List<T>::index(T value) { |
311 | 4 | int element_count = len(this); |
312 | 9 | for (int i = 0; i < element_count; i++) { |
313 | 8 | if (are_equal(slab_->items_[i], value)) { |
314 | 3 | return i; |
315 | 3 | } |
316 | 8 | } |
317 | 1 | throw Alloc<ValueError>(); |
318 | 4 | } |
319 | | |
320 | | // Should we have a separate API that doesn't return it? |
321 | | // https://stackoverflow.com/questions/12600330/pop-back-return-value |
322 | | template <typename T> |
323 | 2 | T List<T>::pop() { |
324 | 2 | if (len_ == 0) { |
325 | 0 | throw Alloc<IndexError>(); |
326 | 0 | } |
327 | 2 | len_--; |
328 | 2 | T result = slab_->items_[len_]; |
329 | 2 | slab_->items_[len_] = 0; // zero for GC scan |
330 | 2 | return result; |
331 | 2 | } Line | Count | Source | 323 | 1 | T List<T>::pop() { | 324 | 1 | if (len_ == 0) { | 325 | 0 | throw Alloc<IndexError>(); | 326 | 0 | } | 327 | 1 | len_--; | 328 | 1 | T result = slab_->items_[len_]; | 329 | 1 | slab_->items_[len_] = 0; // zero for GC scan | 330 | 1 | return result; | 331 | 1 | } |
Line | Count | Source | 323 | 1 | T List<T>::pop() { | 324 | 1 | if (len_ == 0) { | 325 | 0 | throw Alloc<IndexError>(); | 326 | 0 | } | 327 | 1 | len_--; | 328 | 1 | T result = slab_->items_[len_]; | 329 | 1 | slab_->items_[len_] = 0; // zero for GC scan | 330 | 1 | return result; | 331 | 1 | } |
|
332 | | |
333 | | // Used in osh/word_parse.py to remove from front |
334 | | template <typename T> |
335 | 5 | T List<T>::pop(int i) { |
336 | 5 | if (len_ < i) { |
337 | 0 | throw Alloc<IndexError>(); |
338 | 0 | } |
339 | | |
340 | 5 | T result = at(i); |
341 | 5 | len_--; |
342 | | |
343 | | // Shift everything by one |
344 | 5 | memmove(slab_->items_ + i, slab_->items_ + (i + 1), len_ * sizeof(T)); |
345 | | |
346 | | /* |
347 | | for (int j = 0; j < len_; j++) { |
348 | | slab_->items_[j] = slab_->items_[j+1]; |
349 | | } |
350 | | */ |
351 | | |
352 | 5 | slab_->items_[len_] = 0; // zero for GC scan |
353 | 5 | return result; |
354 | 5 | } |
355 | | |
356 | | template <typename T> |
357 | 3 | void List<T>::remove(T x) { |
358 | 3 | int idx = this->index(x); |
359 | 3 | this->pop(idx); // unused |
360 | 3 | } |
361 | | |
362 | | template <typename T> |
363 | 2 | void List<T>::clear() { |
364 | 2 | if (slab_) { |
365 | 1 | memset(slab_->items_, 0, len_ * sizeof(T)); // zero for GC scan |
366 | 1 | } |
367 | 2 | len_ = 0; |
368 | 2 | } Line | Count | Source | 363 | 1 | void List<T>::clear() { | 364 | 1 | if (slab_) { | 365 | 1 | memset(slab_->items_, 0, len_ * sizeof(T)); // zero for GC scan | 366 | 1 | } | 367 | 1 | len_ = 0; | 368 | 1 | } |
Line | Count | Source | 363 | 1 | void List<T>::clear() { | 364 | 1 | if (slab_) { | 365 | 0 | memset(slab_->items_, 0, len_ * sizeof(T)); // zero for GC scan | 366 | 0 | } | 367 | 1 | len_ = 0; | 368 | 1 | } |
|
369 | | |
370 | | // Used in osh/string_ops.py |
371 | | template <typename T> |
372 | 4 | void List<T>::reverse() { |
373 | 8 | for (int i = 0; i < len_ / 2; ++i) { |
374 | | // log("swapping %d and %d", i, n-i); |
375 | 4 | T tmp = slab_->items_[i]; |
376 | 4 | int j = len_ - 1 - i; |
377 | 4 | slab_->items_[i] = slab_->items_[j]; |
378 | 4 | slab_->items_[j] = tmp; |
379 | 4 | } |
380 | 4 | } |
381 | | |
382 | | // Extend this list with multiple elements. |
383 | | template <typename T> |
384 | 6 | void List<T>::extend(List<T>* other) { |
385 | 6 | int n = other->len_; |
386 | 6 | int new_len = len_ + n; |
387 | 6 | reserve(new_len); |
388 | | |
389 | 24 | for (int i = 0; i < n; ++i) { |
390 | 18 | set(len_ + i, other->slab_->items_[i]); |
391 | 18 | } |
392 | 6 | len_ = new_len; |
393 | 6 | } Line | Count | Source | 384 | 5 | void List<T>::extend(List<T>* other) { | 385 | 5 | int n = other->len_; | 386 | 5 | int new_len = len_ + n; | 387 | 5 | reserve(new_len); | 388 | | | 389 | 20 | for (int i = 0; i < n; ++i) { | 390 | 15 | set(len_ + i, other->slab_->items_[i]); | 391 | 15 | } | 392 | 5 | len_ = new_len; | 393 | 5 | } |
_ZN4ListIP6BigStrE6extendEPS2_ Line | Count | Source | 384 | 1 | void List<T>::extend(List<T>* other) { | 385 | 1 | int n = other->len_; | 386 | 1 | int new_len = len_ + n; | 387 | 1 | reserve(new_len); | 388 | | | 389 | 4 | for (int i = 0; i < n; ++i) { | 390 | 3 | set(len_ + i, other->slab_->items_[i]); | 391 | 3 | } | 392 | 1 | len_ = new_len; | 393 | 1 | } |
|
394 | | |
395 | 17 | inline bool _cmp(BigStr* a, BigStr* b) { |
396 | 17 | return mylib::str_cmp(a, b) < 0; |
397 | 17 | } |
398 | | |
399 | | template <typename T> |
400 | 4 | void List<T>::sort() { |
401 | 4 | std::sort(slab_->items_, slab_->items_ + len_, _cmp); |
402 | 4 | } |
403 | | |
404 | | // TODO: mycpp can just generate the constructor instead? |
405 | | // e.g. [None] * 3 |
406 | | template <typename T> |
407 | 2 | List<T>* list_repeat(T item, int times) { |
408 | 2 | return NewList<T>(item, times); |
409 | 2 | } _Z11list_repeatIP6BigStrEP4ListIT_ES3_i Line | Count | Source | 407 | 1 | List<T>* list_repeat(T item, int times) { | 408 | 1 | return NewList<T>(item, times); | 409 | 1 | } |
_Z11list_repeatIbEP4ListIT_ES1_i Line | Count | Source | 407 | 1 | List<T>* list_repeat(T item, int times) { | 408 | 1 | return NewList<T>(item, times); | 409 | 1 | } |
|
410 | | |
411 | | // e.g. 'a' in ['a', 'b', 'c'] |
412 | | template <typename T> |
413 | 9 | inline bool list_contains(List<T>* haystack, T needle) { |
414 | 9 | int n = len(haystack); |
415 | 22 | for (int i = 0; i < n; ++i) { |
416 | 18 | if (are_equal(haystack->at(i), needle)) { |
417 | 5 | return true; |
418 | 5 | } |
419 | 18 | } |
420 | 4 | return false; |
421 | 9 | } _Z13list_containsIP6BigStrEbP4ListIT_ES3_ Line | Count | Source | 413 | 5 | inline bool list_contains(List<T>* haystack, T needle) { | 414 | 5 | int n = len(haystack); | 415 | 12 | for (int i = 0; i < n; ++i) { | 416 | 10 | if (are_equal(haystack->at(i), needle)) { | 417 | 3 | return true; | 418 | 3 | } | 419 | 10 | } | 420 | 2 | return false; | 421 | 5 | } |
_Z13list_containsIiEbP4ListIT_ES1_ Line | Count | Source | 413 | 2 | inline bool list_contains(List<T>* haystack, T needle) { | 414 | 2 | int n = len(haystack); | 415 | 5 | for (int i = 0; i < n; ++i) { | 416 | 4 | if (are_equal(haystack->at(i), needle)) { | 417 | 1 | return true; | 418 | 1 | } | 419 | 4 | } | 420 | 1 | return false; | 421 | 2 | } |
_Z13list_containsIdEbP4ListIT_ES1_ Line | Count | Source | 413 | 2 | inline bool list_contains(List<T>* haystack, T needle) { | 414 | 2 | int n = len(haystack); | 415 | 5 | for (int i = 0; i < n; ++i) { | 416 | 4 | if (are_equal(haystack->at(i), needle)) { | 417 | 1 | return true; | 418 | 1 | } | 419 | 4 | } | 420 | 1 | return false; | 421 | 2 | } |
|
422 | | |
423 | | template <typename V> |
424 | 1 | List<BigStr*>* sorted(Dict<BigStr*, V>* d) { |
425 | 1 | auto keys = d->keys(); |
426 | 1 | keys->sort(); |
427 | 1 | return keys; |
428 | 1 | } |
429 | | |
430 | | template <typename T> |
431 | 1 | List<T>* sorted(List<T>* l) { |
432 | 1 | auto ret = list(l); |
433 | 1 | ret->sort(); |
434 | 1 | return ret; |
435 | 1 | } |
436 | | |
437 | | // list(L) copies the list |
438 | | template <typename T> |
439 | 3 | List<T>* list(List<T>* other) { |
440 | 3 | auto result = NewList<T>(); |
441 | 3 | result->extend(other); |
442 | 3 | return result; |
443 | 3 | } Line | Count | Source | 439 | 2 | List<T>* list(List<T>* other) { | 440 | 2 | auto result = NewList<T>(); | 441 | 2 | result->extend(other); | 442 | 2 | return result; | 443 | 2 | } |
_Z4listIP6BigStrEP4ListIT_ES5_ Line | Count | Source | 439 | 1 | List<T>* list(List<T>* other) { | 440 | 1 | auto result = NewList<T>(); | 441 | 1 | result->extend(other); | 442 | 1 | return result; | 443 | 1 | } |
|
444 | | |
445 | | template <class T> |
446 | | class ListIter { |
447 | | public: |
448 | 17 | explicit ListIter(List<T>* L) : L_(L), i_(0) { |
449 | | // Cheney only: L_ could be moved during iteration. |
450 | | // gHeap.PushRoot(reinterpret_cast<RawObject**>(&L_)); |
451 | 17 | } _ZN8ListIterIP6Tuple2IiiEEC2EP4ListIS2_E Line | Count | Source | 448 | 2 | explicit ListIter(List<T>* L) : L_(L), i_(0) { | 449 | | // Cheney only: L_ could be moved during iteration. | 450 | | // gHeap.PushRoot(reinterpret_cast<RawObject**>(&L_)); | 451 | 2 | } |
_ZN8ListIterIiEC2EP4ListIiE Line | Count | Source | 448 | 3 | explicit ListIter(List<T>* L) : L_(L), i_(0) { | 449 | | // Cheney only: L_ could be moved during iteration. | 450 | | // gHeap.PushRoot(reinterpret_cast<RawObject**>(&L_)); | 451 | 3 | } |
_ZN8ListIterIP6BigStrEC2EP4ListIS1_E Line | Count | Source | 448 | 12 | explicit ListIter(List<T>* L) : L_(L), i_(0) { | 449 | | // Cheney only: L_ could be moved during iteration. | 450 | | // gHeap.PushRoot(reinterpret_cast<RawObject**>(&L_)); | 451 | 12 | } |
|
452 | | |
453 | 18 | ~ListIter() { |
454 | | // gHeap.PopRoot(); |
455 | 18 | } _ZN8ListIterIP6Tuple2IiiEED2Ev Line | Count | Source | 453 | 2 | ~ListIter() { | 454 | | // gHeap.PopRoot(); | 455 | 2 | } |
Line | Count | Source | 453 | 4 | ~ListIter() { | 454 | | // gHeap.PopRoot(); | 455 | 4 | } |
_ZN8ListIterIP6BigStrED2Ev Line | Count | Source | 453 | 12 | ~ListIter() { | 454 | | // gHeap.PopRoot(); | 455 | 12 | } |
|
456 | 55 | void Next() { |
457 | 55 | i_++; |
458 | 55 | } _ZN8ListIterIP6Tuple2IiiEE4NextEv Line | Count | Source | 456 | 4 | void Next() { | 457 | 4 | i_++; | 458 | 4 | } |
Line | Count | Source | 456 | 16 | void Next() { | 457 | 16 | i_++; | 458 | 16 | } |
_ZN8ListIterIP6BigStrE4NextEv Line | Count | Source | 456 | 35 | void Next() { | 457 | 35 | i_++; | 458 | 35 | } |
|
459 | 71 | bool Done() { |
460 | | // "unsigned size_t was a mistake" |
461 | 71 | return i_ >= static_cast<int>(L_->len_); |
462 | 71 | } _ZN8ListIterIP6Tuple2IiiEE4DoneEv Line | Count | Source | 459 | 6 | bool Done() { | 460 | | // "unsigned size_t was a mistake" | 461 | 6 | return i_ >= static_cast<int>(L_->len_); | 462 | 6 | } |
Line | Count | Source | 459 | 18 | bool Done() { | 460 | | // "unsigned size_t was a mistake" | 461 | 18 | return i_ >= static_cast<int>(L_->len_); | 462 | 18 | } |
_ZN8ListIterIP6BigStrE4DoneEv Line | Count | Source | 459 | 47 | bool Done() { | 460 | | // "unsigned size_t was a mistake" | 461 | 47 | return i_ >= static_cast<int>(L_->len_); | 462 | 47 | } |
|
463 | 59 | T Value() { |
464 | 59 | return L_->slab_->items_[i_]; |
465 | 59 | } _ZN8ListIterIP6Tuple2IiiEE5ValueEv Line | Count | Source | 463 | 8 | T Value() { | 464 | 8 | return L_->slab_->items_[i_]; | 465 | 8 | } |
Line | Count | Source | 463 | 16 | T Value() { | 464 | 16 | return L_->slab_->items_[i_]; | 465 | 16 | } |
_ZN8ListIterIP6BigStrE5ValueEv Line | Count | Source | 463 | 35 | T Value() { | 464 | 35 | return L_->slab_->items_[i_]; | 465 | 35 | } |
|
466 | | T iterNext() { |
467 | | if (Done()) { |
468 | | throw Alloc<StopIteration>(); |
469 | | } |
470 | | T ret = L_->slab_->items_[i_]; |
471 | | Next(); |
472 | | return ret; |
473 | | } |
474 | | |
475 | | // only for use with generators |
476 | 1 | List<T>* GetList() { |
477 | 1 | return L_; |
478 | 1 | } |
479 | | |
480 | | private: |
481 | | List<T>* L_; |
482 | | int i_; |
483 | | }; |
484 | | |
485 | | // list(it) returns the iterator's backing list |
486 | | template <typename T> |
487 | 1 | List<T>* list(ListIter<T> it) { |
488 | 1 | return list(it.GetList()); |
489 | 1 | } |
490 | | |
491 | | // TODO: Does using pointers rather than indices make this more efficient? |
492 | | template <class T> |
493 | | class ReverseListIter { |
494 | | public: |
495 | 1 | explicit ReverseListIter(List<T>* L) : L_(L), i_(L_->len_ - 1) { |
496 | 1 | } |
497 | 3 | void Next() { |
498 | 3 | i_--; |
499 | 3 | } |
500 | 4 | bool Done() { |
501 | 4 | return i_ < 0; |
502 | 4 | } |
503 | 3 | T Value() { |
504 | 3 | return L_->slab_->items_[i_]; |
505 | 3 | } |
506 | | |
507 | | private: |
508 | | List<T>* L_; |
509 | | int i_; |
510 | | }; |
511 | | |
512 | | int max(List<int>* elems); |
513 | | |
514 | | #endif // MYCPP_GC_LIST_H |