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

Unified Diff: src/zone/zone-chunk-list.h

Issue 2449383002: New zone-backed list datastructure to replace ZoneList (Closed)
Patch Set: Added some debug checks Created 4 years, 2 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/v8.gyp ('k') | test/unittests/BUILD.gn » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/zone/zone-chunk-list.h
diff --git a/src/zone/zone-chunk-list.h b/src/zone/zone-chunk-list.h
new file mode 100644
index 0000000000000000000000000000000000000000..6b52c879f3fc16a6fcbb82420e6b9f8279072e8f
--- /dev/null
+++ b/src/zone/zone-chunk-list.h
@@ -0,0 +1,437 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdlib.h>
+
+#include "src/globals.h"
+#include "src/zone/zone.h"
+
+#ifndef V8_SRC_ZONE_ZONE_CHUNK_LIST_H_
+#define V8_SRC_ZONE_ZONE_CHUNK_LIST_H_
+
+namespace v8 {
+namespace internal {
+
+template <typename T>
+class ZoneChunkListIterator;
+template <typename T>
+class ForwardZoneChunkListIterator;
+template <typename T>
+class ReverseZoneChunkListIterator;
+
+// A zone-backed hybrid of a vector and a linked list. Use it if you need a
+// collection that
+// * needs to grow indefinitely,
+// * will mostly grow at the back, but may sometimes grow in front as well
+// (preferrably in batches),
+// * needs to have very low overhead,
+// * offers forward- and backwards-iteration,
+// * offers relatively fast seeking,
+// * offers bidirectional iterators,
+// * can be rewound without freeing the backing store.
+// This list will maintain a doubly-linked list of chunks. When a chunk is
+// filled up, a new one gets appended. New chunks appended at the end will
+// grow in size up to a certain limit to avoid over-allocation and to keep
+// the zone clean.
+template <typename T>
+class ZoneChunkList : public ZoneObject {
+ public:
+ enum class StartMode {
+ // The list will not allocate a starting chunk. Use if you expect your
+ // list to remain empty in many cases.
+ kEmpty = 0,
+ // The list will start with a small initial chunk. Subsequent chunks will
+ // get bigger over time.
+ kSmall = 8,
+ // The list will start with one chunk at maximum size. Use this if you
+ // expect your list to contain many items to avoid growing chunks.
+ kBig = 256
+ };
+
+ explicit ZoneChunkList(Zone* zone, StartMode start_mode = StartMode::kEmpty)
+ : zone_(zone) {
+ if (start_mode != StartMode::kEmpty) {
+ front_ = NewChunk(static_cast<uint32_t>(start_mode));
+ back_ = front_;
+ }
+ }
+
+ size_t size() const;
+
+ T& front() const;
+ T& back() const;
+
+ void push_back(const T& item);
+ void pop_back();
+
+ // Will push a separate chunk to the front of the chunk-list.
+ // Very memory-inefficient. Do only use sparsely! If you have many items to
+ // add in front, consider using 'push_front_many'.
+ void push_front(const T& item);
+ // TODO(heimbuef): Add 'push_front_many'.
+
+ // Cuts the last list elements so at most 'limit' many remain. Does not
+ // free the actual memory, since it is zone allocated.
+ void Rewind(const size_t limit = 0);
+
+ // Quickly scans the list to retrieve the element at the given index. Will
+ // *not* check bounds.
+ ForwardZoneChunkListIterator<T> Find(const size_t index);
+ ForwardZoneChunkListIterator<const T> Find(const size_t index) const;
+ // TODO(heimbuef): Add 'rFind', seeking from the end and returning a
+ // reverse iterator.
+
+ ForwardZoneChunkListIterator<T> begin();
+ ForwardZoneChunkListIterator<T> end();
+ ReverseZoneChunkListIterator<T> rbegin();
+ ReverseZoneChunkListIterator<T> rend();
+ ForwardZoneChunkListIterator<const T> begin() const;
+ ForwardZoneChunkListIterator<const T> end() const;
+ ReverseZoneChunkListIterator<const T> rbegin() const;
+ ReverseZoneChunkListIterator<const T> rend() const;
+
+ private:
+ friend class ZoneChunkListIterator<T>;
+ friend class ForwardZoneChunkListIterator<T>;
+ friend class ReverseZoneChunkListIterator<T>;
+ static const uint32_t kMaxChunkCapacity = 256u;
+
+ STATIC_ASSERT(kMaxChunkCapacity == static_cast<uint32_t>(StartMode::kBig));
+
+ struct Chunk {
+ uint32_t capacity_ = 0;
+ uint32_t position_ = 0;
+ Chunk* next_ = nullptr;
+ Chunk* previous_ = nullptr;
+ T* items() { return reinterpret_cast<T*>(this + 1); }
+ };
+
+ Chunk* NewChunk(const uint32_t capacity) {
+ Chunk* chunk =
+ new (zone_->New(sizeof(Chunk) + capacity * sizeof(T))) Chunk();
+ chunk->capacity_ = capacity;
+ return chunk;
+ }
+
+ struct SeekResult {
+ Chunk* chunk_;
+ uint32_t chunk_index_;
+ };
+
+ // Returns the chunk and relative index of the element at the given global
+ // index. Will skip entire chunks and is therefore faster than iterating.
+ SeekResult SeekIndex(size_t index) const;
+
+ Zone* zone_;
+
+ size_t size_ = 0;
+ Chunk* front_ = nullptr;
+ Chunk* back_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(ZoneChunkList);
+};
+
+template <typename T>
+class ZoneChunkListIterator {
+ public:
+ T& operator*() { return current_->items()[position_]; }
+ bool operator==(const ZoneChunkListIterator& other) {
+ return other.current_ == current_ && other.position_ == position_;
+ }
+ bool operator!=(const ZoneChunkListIterator& other) {
+ return !operator==(other);
+ }
+
+ protected:
+ ZoneChunkListIterator(typename ZoneChunkList<T>::Chunk* current,
+ size_t position)
+ : current_(current), position_(position) {}
+
+ void MoveNext() {
+ ++position_;
+ if (position_ >= current_->capacity_) {
+ current_ = current_->next_;
+ position_ = 0;
+ }
+ }
+
+ void MoveRNext() {
+ if (position_ == 0) {
+ current_ = current_->previous_;
+ position_ = current_ ? current_->capacity_ - 1 : 0;
+ } else {
+ --position_;
+ }
+ }
+
+ typename ZoneChunkList<T>::Chunk* current_;
+ size_t position_;
+};
+
+template <typename T>
+class ForwardZoneChunkListIterator : public ZoneChunkListIterator<T> {
+ using ZoneChunkListIterator<T>::current_;
+ using ZoneChunkListIterator<T>::position_;
+ using ZoneChunkListIterator<T>::MoveNext;
+ using ZoneChunkListIterator<T>::MoveRNext;
+
+ public:
+ ForwardZoneChunkListIterator(typename ZoneChunkList<T>::Chunk* current,
+ size_t position)
+ : ZoneChunkListIterator<T>(current, position) {}
+
+ ForwardZoneChunkListIterator& operator++() {
+ MoveNext();
+ return *this;
+ }
+
+ ForwardZoneChunkListIterator operator++(int) {
+ ForwardZoneChunkListIterator<T> clone(*this);
+ MoveNext();
+ return clone;
+ }
+
+ ForwardZoneChunkListIterator& operator--() {
+ MoveRNext();
+ return *this;
+ }
+
+ ForwardZoneChunkListIterator operator--(int) {
+ ForwardZoneChunkListIterator<T> clone(*this);
+ MoveRNext();
+ return clone;
+ }
+
+ private:
+ friend class ZoneChunkList<T>;
+ static ForwardZoneChunkListIterator<T> Begin(ZoneChunkList<T>* list) {
+ return ForwardZoneChunkListIterator<T>(list->front_, 0);
+ }
+ static ForwardZoneChunkListIterator<T> End(ZoneChunkList<T>* list) {
+ if (list->back_ == nullptr) return Begin(list);
+
+ DCHECK_LE(list->back_->position_, list->back_->capacity_);
+ if (list->back_->position_ == list->back_->capacity_) {
+ return ForwardZoneChunkListIterator<T>(nullptr, 0);
+ }
+
+ return ForwardZoneChunkListIterator<T>(list->back_, list->back_->position_);
+ }
+};
+
+template <typename T>
+class ReverseZoneChunkListIterator : public ZoneChunkListIterator<T> {
+ using ZoneChunkListIterator<T>::current_;
+ using ZoneChunkListIterator<T>::position_;
+ using ZoneChunkListIterator<T>::MoveNext;
+ using ZoneChunkListIterator<T>::MoveRNext;
+
+ public:
+ ReverseZoneChunkListIterator(typename ZoneChunkList<T>::Chunk* current,
+ size_t position)
+ : ZoneChunkListIterator<T>(current, position) {}
+
+ ReverseZoneChunkListIterator& operator++() {
+ MoveRNext();
+ return *this;
+ }
+
+ ReverseZoneChunkListIterator operator++(int) {
+ ReverseZoneChunkListIterator<T> clone(*this);
+ MoveRNext();
+ return clone;
+ }
+
+ ReverseZoneChunkListIterator& operator--() {
+ MoveNext();
+ return *this;
+ }
+
+ ReverseZoneChunkListIterator operator--(int) {
+ ForwardZoneChunkListIterator<T> clone(*this);
+ MoveNext();
+ return clone;
+ }
+
+ private:
+ friend class ZoneChunkList<T>;
+ static ReverseZoneChunkListIterator<T> Begin(ZoneChunkList<T>* list) {
+ if (list->back_ == nullptr) return End(list);
+ if (list->back_->position_ == 0) {
+ if (list->back_->previous_ != nullptr) {
+ return ReverseZoneChunkListIterator<T>(
+ list->back_->previous_, list->back_->previous_->capacity_ - 1);
+ } else {
+ return End(list);
+ }
+ }
+ return ReverseZoneChunkListIterator<T>(list->back_,
+ list->back_->position_ - 1);
+ }
+ static ReverseZoneChunkListIterator<T> End(ZoneChunkList<T>* list) {
+ return ReverseZoneChunkListIterator<T>(nullptr, 0);
+ }
+};
+
+template <typename T>
+size_t ZoneChunkList<T>::size() const {
+ return size_;
+}
+
+template <typename T>
+T& ZoneChunkList<T>::front() const {
+ DCHECK_LT(size_t(0), size());
+ return front_->items()[0];
+}
+
+template <typename T>
+T& ZoneChunkList<T>::back() const {
+ DCHECK_LT(size_t(0), size());
+
+ if (back_->position_ == 0) {
+ return back_->previous_->items()[back_->previous_->position_ - 1];
+ } else {
+ return back_->items()[back_->position_ - 1];
+ }
+}
+
+template <typename T>
+void ZoneChunkList<T>::push_back(const T& item) {
+ if (back_ == nullptr) {
+ front_ = NewChunk(static_cast<uint32_t>(StartMode::kSmall));
+ back_ = front_;
+ }
+
+ DCHECK_LE(back_->position_, back_->capacity_);
+ if (back_->position_ == back_->capacity_) {
+ if (back_->next_ == nullptr) {
+ Chunk* chunk = NewChunk(Min(back_->capacity_ << 1, kMaxChunkCapacity));
+ back_->next_ = chunk;
+ chunk->previous_ = back_;
+ }
+ back_ = back_->next_;
+ }
+ back_->items()[back_->position_] = item;
+ ++back_->position_;
+ ++size_;
+}
+
+template <typename T>
+void ZoneChunkList<T>::pop_back() {
+ DCHECK_LT(size_t(0), size());
+ if (back_->position_ == 0) {
+ back_ = back_->previous_;
+ }
+ --back_->position_;
+}
+
+template <typename T>
+void ZoneChunkList<T>::push_front(const T& item) {
+ Chunk* chunk = NewChunk(1); // Yes, this gets really inefficient.
+ chunk->next_ = front_;
+ if (front_) {
+ front_->previous_ = chunk;
+ } else {
+ back_ = chunk;
+ }
+ front_ = chunk;
+
+ chunk->items()[0] = item;
+ chunk->position_ = 1;
+ ++size_;
+}
+
+template <typename T>
+typename ZoneChunkList<T>::SeekResult ZoneChunkList<T>::SeekIndex(
+ size_t index) const {
+ DCHECK_LT(index, size());
+ Chunk* current = front_;
+ while (index > current->capacity_) {
+ index -= current->capacity_;
+ current = current->next_;
+ }
+ return {current, static_cast<uint32_t>(index)};
+}
+
+template <typename T>
+void ZoneChunkList<T>::Rewind(const size_t limit) {
+ if (limit >= size()) return;
+
+ SeekResult seek_result = SeekIndex(limit);
+ DCHECK_NOT_NULL(seek_result.chunk_);
+
+ // Do a partial rewind of the chunk containing the index.
+ seek_result.chunk_->position_ = seek_result.chunk_index_;
+
+ // Set back_ so iterators will work correctly.
+ back_ = seek_result.chunk_;
+
+ // Do full rewind of all subsequent chunks.
+ for (Chunk* current = seek_result.chunk_->next_; current != nullptr;
+ current = current->next_) {
+ current->position_ = 0;
+ }
+
+ size_ = limit;
+}
+
+template <typename T>
+ForwardZoneChunkListIterator<T> ZoneChunkList<T>::Find(const size_t index) {
+ SeekResult seek_result = SeekIndex(index);
+ return ForwardZoneChunkListIterator<T>(seek_result.chunk_,
+ seek_result.chunk_index_);
+}
+
+template <typename T>
+ForwardZoneChunkListIterator<const T> ZoneChunkList<T>::Find(
+ const size_t index) const {
+ SeekResult seek_result = SeekIndex(index);
+ return ForwardZoneChunkListIterator<const T>(seek_result.chunk_,
+ seek_result.chunk_index_);
+}
+
+template <typename T>
+ForwardZoneChunkListIterator<T> ZoneChunkList<T>::begin() {
+ return ForwardZoneChunkListIterator<T>::Begin(this);
+}
+
+template <typename T>
+ForwardZoneChunkListIterator<T> ZoneChunkList<T>::end() {
+ return ForwardZoneChunkListIterator<T>::End(this);
+}
+
+template <typename T>
+ReverseZoneChunkListIterator<T> ZoneChunkList<T>::rbegin() {
+ return ReverseZoneChunkListIterator<T>::Begin(this);
+}
+
+template <typename T>
+ReverseZoneChunkListIterator<T> ZoneChunkList<T>::rend() {
+ return ReverseZoneChunkListIterator<T>::End(this);
+}
+
+template <typename T>
+ForwardZoneChunkListIterator<const T> ZoneChunkList<T>::begin() const {
+ return ForwardZoneChunkListIterator<const T>::Begin(this);
+}
+
+template <typename T>
+ForwardZoneChunkListIterator<const T> ZoneChunkList<T>::end() const {
+ return ForwardZoneChunkListIterator<const T>::End(this);
+}
+
+template <typename T>
+ReverseZoneChunkListIterator<const T> ZoneChunkList<T>::rbegin() const {
+ return ReverseZoneChunkListIterator<const T>::Begin(this);
+}
+
+template <typename T>
+ReverseZoneChunkListIterator<const T> ZoneChunkList<T>::rend() const {
+ return ReverseZoneChunkListIterator<const T>::End(this);
+}
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_SRC_ZONE_ZONE_CHUNK_LIST_H_
« no previous file with comments | « src/v8.gyp ('k') | test/unittests/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698