Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1215)

Side by Side Diff: src/zone/zone-chunk-list.h

Issue 2449383002: New zone-backed list datastructure to replace ZoneList (Closed)
Patch Set: Changed test to account for the list sizes as well Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stdlib.h>
6
7 #include "src/globals.h"
8 #include "src/zone/zone.h"
9
10 #ifndef V8_SRC_ZONE_ZONE_CHUNK_LIST_H_
11 #define V8_SRC_ZONE_ZONE_CHUNK_LIST_H_
12
13 namespace v8 {
14 namespace internal {
15
16 template <typename T>
17 class ZoneChunkListIterator;
18 template <typename T>
19 class ForwardZoneChunkListIterator;
20 template <typename T>
21 class ReverseZoneChunkListIterator;
22
23 // A zone-backed hybrid of a vector and a linked list. Use it if you need a
24 // collection that
25 // * needs to grow indefinitly,
Jakob Kummerow 2016/10/26 14:45:09 nit: "indefinitely"
26 // * will mostly grow at the back, but may sometimes grow in front as well
27 // (preferrably in batches),
28 // * needs to have very low overhead,
29 // * offers forward- and backwards-iteration,
30 // * offers relatively fast seeking,
31 // * offers bidirectional iterators,
32 // * can be rewound without freeing the backing store.
33 // This list will maintain a doubly-linked list of chunks. When a chunk is
34 // filled up, a new one gets appended. New chunks appended at the end will
35 // grow in size up to a certain limit to avoid over-allocation and to keep
36 // the zone clean.
37 template <typename T>
38 class ZoneChunkList : public ZoneObject {
39 public:
40 enum StartMode {
jochen (gone - plz use gerrit) 2016/10/26 13:24:12 please use an enum class
41 // The list will not allocate a starting chunk. Use if you expect your
42 // list to remain empty in many cases.
43 kEmpty = 0,
44 // The list will start with a small initial chunk. Subsequent chunks will
45 // get bigger over time.
46 kSmall = 8,
47 // The list will start with one chunk at maximum size. Use this if you
48 // expect your list to contain many items to avoid growing chunks.
49 kBig = 256
50 };
51
52 explicit ZoneChunkList(Zone* zone, StartMode start_mode = kEmpty)
53 : zone_(zone) {
54 if (start_mode != kEmpty) {
55 front_ = NewChunk(static_cast<uint32_t>(start_mode));
56 back_ = front_;
57 }
58 }
59
60 size_t size() const;
61
62 T& front() const;
63 T& back() const;
64
65 void push_back(const T& item);
66 void pop_back();
67
68 // Will push a separate chunk to the front of the chunk-list.
69 // Very memory-inefficient. Do only use sparsely! If you have many items to
70 // add in front, consider using 'push_front_many'.
71 void push_front(const T& item);
72 // Todo(heimbuef): Add 'push_front_many'.
Jakob Kummerow 2016/10/26 14:45:09 nit: s/Todo/TODO/
73
74 // Cuts the last list elements so at most 'limit' many remain. Does not
75 // free the actual memory, since it is zone allocated.
76 void Rewind(const size_t limit = 0);
77
78 // Quickly seeks the list to retrieve the element at the given index. Will
Jakob Kummerow 2016/10/26 14:45:09 nit: s/seeks/searches/ (or "scans" or "walks").
79 // *not* check bounds.
80 ForwardZoneChunkListIterator<T> Find(const size_t index);
81 ForwardZoneChunkListIterator<const T> Find(const size_t index) const;
82 // Todo(heimbuef): Add 'rFind', seeking from the end and returning a
Jakob Kummerow 2016/10/26 14:45:10 nit: s/Todo/TODO/
83 // reverse iterator.
84
85 ForwardZoneChunkListIterator<T> begin();
86 ForwardZoneChunkListIterator<T> end();
87 ReverseZoneChunkListIterator<T> rbegin();
88 ReverseZoneChunkListIterator<T> rend();
89 ForwardZoneChunkListIterator<const T> begin() const;
90 ForwardZoneChunkListIterator<const T> end() const;
91 ReverseZoneChunkListIterator<const T> rbegin() const;
92 ReverseZoneChunkListIterator<const T> rend() const;
93
94 private:
95 friend class ZoneChunkListIterator<T>;
96 friend class ForwardZoneChunkListIterator<T>;
97 friend class ReverseZoneChunkListIterator<T>;
98 static const uint32_t kMaxChunkCapacity = 256u;
99
100 STATIC_ASSERT(kMaxChunkCapacity == StartMode::kBig);
101
102 struct Chunk {
103 uint32_t capacity_ = 0;
104 uint32_t position_ = 0;
105 Chunk* next_ = nullptr;
106 Chunk* previous_ = nullptr;
107 T* items() { return reinterpret_cast<T*>(this + 1); }
108 };
109
110 Chunk* NewChunk(const uint32_t capacity) {
111 Chunk* chunk =
112 new (zone_->New(sizeof(Chunk) + capacity * sizeof(T))) Chunk();
113 chunk->capacity_ = capacity;
114 return chunk;
115 }
116
117 struct SeekResult {
118 Chunk* chunk_;
119 uint32_t chunk_index_;
120 };
121
122 // Returns the chunk and relative index of the element at the given global
123 // index. Will skip entire chunks and is therefore faster than iterating.
124 SeekResult SeekIndex(size_t index) const;
125
126 Zone* zone_;
127
128 size_t size_ = 0;
129 Chunk* front_ = nullptr;
130 Chunk* back_ = nullptr;
131 };
jochen (gone - plz use gerrit) 2016/10/26 13:24:12 DISALLOW_COPY_AND_ASSIGN
132
133 template <typename T>
134 class ZoneChunkListIterator {
135 public:
136 T& operator*() { return current_->items()[position_]; }
137 bool operator==(const ZoneChunkListIterator& other) {
138 return other.current_ == current_ && other.position_ == position_;
139 }
140 bool operator!=(const ZoneChunkListIterator& other) {
141 return !operator==(other);
142 }
143
144 protected:
145 ZoneChunkListIterator(typename ZoneChunkList<T>::Chunk* current,
146 size_t position)
147 : current_(current), position_(position) {}
148
149 void MoveNext() {
150 ++position_;
151 if (position_ >= current_->capacity_) {
152 current_ = current_->next_;
153 position_ = 0;
154 }
155 }
156
157 void MoveRNext() {
158 if (position_ == 0) {
159 current_ = current_->previous_;
160 position_ = current_ ? current_->capacity_ - 1 : 0;
161 } else {
162 --position_;
163 }
164 }
165
166 typename ZoneChunkList<T>::Chunk* current_;
167 size_t position_;
168 };
169
170 template <typename T>
171 class ForwardZoneChunkListIterator : public ZoneChunkListIterator<T> {
172 using ZoneChunkListIterator<T>::current_;
173 using ZoneChunkListIterator<T>::position_;
174 using ZoneChunkListIterator<T>::MoveNext;
175 using ZoneChunkListIterator<T>::MoveRNext;
176
177 public:
178 ForwardZoneChunkListIterator(typename ZoneChunkList<T>::Chunk* current,
179 size_t position)
180 : ZoneChunkListIterator<T>(current, position) {}
181
182 ForwardZoneChunkListIterator& operator++() {
183 MoveNext();
184 return *this;
185 }
186
187 ForwardZoneChunkListIterator operator++(int) {
188 ForwardZoneChunkListIterator<T> clone(*this);
189 MoveNext();
190 return clone;
191 }
192
193 ForwardZoneChunkListIterator& operator--() {
194 MoveRNext();
195 return *this;
196 }
197
198 ForwardZoneChunkListIterator operator--(int) {
199 ForwardZoneChunkListIterator<T> clone(*this);
200 MoveRNext();
201 return clone;
202 }
203
204 private:
205 friend class ZoneChunkList<T>;
206 static ForwardZoneChunkListIterator<T> Begin(ZoneChunkList<T>* list) {
207 return ForwardZoneChunkListIterator<T>(list->front_, 0);
208 }
209 static ForwardZoneChunkListIterator<T> End(ZoneChunkList<T>* list) {
210 if (list->back_ == nullptr) return Begin(list);
211
212 if (list->back_->position_ >= list->back_->capacity_) {
Jakob Kummerow 2016/10/26 14:45:09 I don't understand why this condition is necessary
213 return ForwardZoneChunkListIterator<T>(nullptr, 0);
214 }
215
216 return ForwardZoneChunkListIterator<T>(list->back_, list->back_->position_);
217 }
218 };
219
220 template <typename T>
221 class ReverseZoneChunkListIterator : public ZoneChunkListIterator<T> {
222 using ZoneChunkListIterator<T>::current_;
223 using ZoneChunkListIterator<T>::position_;
224 using ZoneChunkListIterator<T>::MoveNext;
225 using ZoneChunkListIterator<T>::MoveRNext;
226
227 public:
228 ReverseZoneChunkListIterator(typename ZoneChunkList<T>::Chunk* current,
229 size_t position)
230 : ZoneChunkListIterator<T>(current, position) {}
231
232 ReverseZoneChunkListIterator& operator++() {
233 MoveRNext();
234 return *this;
235 }
236
237 ReverseZoneChunkListIterator operator++(int) {
238 ReverseZoneChunkListIterator<T> clone(*this);
239 MoveRNext();
240 return clone;
241 }
242
243 ReverseZoneChunkListIterator& operator--() {
244 MoveNext();
245 return *this;
246 }
247
248 ReverseZoneChunkListIterator operator--(int) {
249 ForwardZoneChunkListIterator<T> clone(*this);
250 MoveNext();
251 return clone;
252 }
253
254 private:
255 friend class ZoneChunkList<T>;
256 static ReverseZoneChunkListIterator<T> Begin(ZoneChunkList<T>* list) {
257 if (list->back_ == nullptr) return End(list);
258 if (list->back_->position_ == 0) {
259 if (list->back_->previous_ != nullptr) {
260 return ReverseZoneChunkListIterator<T>(
261 list->back_->previous_, list->back_->previous_->capacity_ - 1);
262 } else {
263 return End(list);
264 }
265 }
266 return ReverseZoneChunkListIterator<T>(list->back_,
267 list->back_->position_ - 1);
268 }
269 static ReverseZoneChunkListIterator<T> End(ZoneChunkList<T>* list) {
270 return ReverseZoneChunkListIterator<T>(nullptr, 0);
271 }
272 };
273
274 template <typename T>
275 size_t ZoneChunkList<T>::size() const {
276 return size_;
277 }
278
279 template <typename T>
280 T& ZoneChunkList<T>::front() const {
281 DCHECK_LE(0, size());
Jakob Kummerow 2016/10/26 14:45:09 This check is useless, every size_t is >= 0. Did y
282 return front_->items()[0];
283 }
284
285 template <typename T>
286 T& ZoneChunkList<T>::back() const {
287 DCHECK_LE(0, size());
Jakob Kummerow 2016/10/26 14:45:09 This check is useless, every size_t is >= 0. Did y
288 return back_->items()[back_->position_ - 1];
Jakob Kummerow 2016/10/26 14:45:09 This is missing a check for back_->position_ == 0.
289 }
290
291 template <typename T>
292 void ZoneChunkList<T>::push_back(const T& item) {
293 if (back_ == nullptr) {
294 front_ = NewChunk(kSmall);
295 back_ = front_;
296 }
297
298 if (back_->position_ >= back_->capacity_) {
Jakob Kummerow 2016/10/26 14:45:09 nit: ">" can't happen (or can it?); just check if
299 if (back_->next_ == nullptr) {
300 Chunk* chunk = NewChunk(Min(back_->capacity_ << 1, kMaxChunkCapacity));
301 back_->next_ = chunk;
302 chunk->previous_ = back_;
303 }
304 back_ = back_->next_;
305 }
306 back_->items()[back_->position_] = item;
307 ++back_->position_;
308 ++size_;
309 }
310
311 template <typename T>
312 void ZoneChunkList<T>::pop_back() {
313 DCHECK_LE(0, size());
Jakob Kummerow 2016/10/26 14:45:09 This check is useless, every size_t is >= 0. Did y
314 if (back_->position_ == 0) {
315 back_ = back_->previous_;
316 }
317 --back_->position_;
318 }
319
320 template <typename T>
321 void ZoneChunkList<T>::push_front(const T& item) {
322 Chunk* chunk = NewChunk(1); // Yes, this gets really inefficient.
323 chunk->next_ = front_;
324 if (front_)
325 front_->previous_ = chunk;
Jakob Kummerow 2016/10/26 14:45:09 nit: {} please, and for the else-branch too
326 else
327 back_ = chunk;
328 front_ = chunk;
329
330 chunk->items()[0] = item;
331 chunk->position_ = 1;
332 ++size_;
333 }
334
335 template <typename T>
336 typename ZoneChunkList<T>::SeekResult ZoneChunkList<T>::SeekIndex(
337 size_t index) const {
338 DCHECK_LE(0, size());
Jakob Kummerow 2016/10/26 14:45:09 This check is useless, every size_t is >= 0. Did y
339 Chunk* current = front_;
340 while (index > current->capacity_) {
341 index -= current->capacity_;
342 current = current->next_;
343 }
344 SeekResult result;
Jakob Kummerow 2016/10/26 14:45:09 simpler: SeekResult result = { current, static_cas
345 result.chunk_ = current;
346 result.chunk_index_ = static_cast<uint32_t>(index);
347 return result;
348 }
349
350 template <typename T>
351 void ZoneChunkList<T>::Rewind(const size_t limit) {
352 if (limit >= size()) return;
353
354 SeekResult seek_result = SeekIndex(limit);
355
356 if (seek_result.chunk_ == nullptr) return;
Jakob Kummerow 2016/10/26 14:45:09 Can this happen?
357
358 // Do a partial rewind of the chunk containing the index.
359 seek_result.chunk_->position_ = seek_result.chunk_index_;
360
361 // Set back_ so iterators will work correctly
Jakob Kummerow 2016/10/26 14:45:09 nit: trailing full stop.
362 back_ = seek_result.chunk_;
363
364 // Do full rewind of all subsequent chunks.
365 for (Chunk* current = seek_result.chunk_->next_; current != nullptr;
366 current = current->next_) {
367 current->position_ = 0;
368 }
369
370 size_ = limit;
371 }
372
373 template <typename T>
374 ForwardZoneChunkListIterator<T> ZoneChunkList<T>::Find(const size_t index) {
375 SeekResult seek_result = SeekIndex(index);
376 return ForwardZoneChunkListIterator<T>(seek_result.chunk_,
377 seek_result.chunk_index_);
378 }
379
380 template <typename T>
381 ForwardZoneChunkListIterator<const T> ZoneChunkList<T>::Find(
382 const size_t index) const {
383 SeekResult seek_result = SeekIndex(index);
384 return ForwardZoneChunkListIterator<const T>(seek_result.chunk_,
385 seek_result.chunk_index_);
386 }
387
388 template <typename T>
389 ForwardZoneChunkListIterator<T> ZoneChunkList<T>::begin() {
390 return ForwardZoneChunkListIterator<T>::Begin(this);
391 }
392
393 template <typename T>
394 ForwardZoneChunkListIterator<T> ZoneChunkList<T>::end() {
395 return ForwardZoneChunkListIterator<T>::End(this);
396 }
397
398 template <typename T>
399 ReverseZoneChunkListIterator<T> ZoneChunkList<T>::rbegin() {
400 return ReverseZoneChunkListIterator<T>::Begin(this);
401 }
402
403 template <typename T>
404 ReverseZoneChunkListIterator<T> ZoneChunkList<T>::rend() {
405 return ReverseZoneChunkListIterator<T>::End(this);
406 }
407
408 template <typename T>
409 ForwardZoneChunkListIterator<const T> ZoneChunkList<T>::begin() const {
410 return ForwardZoneChunkListIterator<const T>::Begin(this);
411 }
412
413 template <typename T>
414 ForwardZoneChunkListIterator<const T> ZoneChunkList<T>::end() const {
415 return ForwardZoneChunkListIterator<const T>::End(this);
416 }
417
418 template <typename T>
419 ReverseZoneChunkListIterator<const T> ZoneChunkList<T>::rbegin() const {
420 return ReverseZoneChunkListIterator<const T>::Begin(this);
421 }
422
423 template <typename T>
424 ReverseZoneChunkListIterator<const T> ZoneChunkList<T>::rend() const {
425 return ReverseZoneChunkListIterator<const T>::End(this);
426 }
427
428 } // namespace internal
429 } // namespace v8
430
431 #endif // V8_SRC_ZONE_ZONE_CHUNK_LIST_H_
OLDNEW
« no previous file with comments | « src/v8.gyp ('k') | test/unittests/BUILD.gn » ('j') | test/unittests/unittests.gyp » ('J')

Powered by Google App Engine
This is Rietveld 408576698