mycpp

Coverage Report

Created: 2025-05-15 02:52

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