1*4882a593SmuzhiyunFrom da832c778d013f4217e2d704c27c1d2e19a9364c Mon Sep 17 00:00:00 2001
2*4882a593SmuzhiyunFrom: Khem Raj <raj.khem@gmail.com>
3*4882a593SmuzhiyunDate: Thu, 2 Jan 2020 17:13:55 -0800
4*4882a593SmuzhiyunSubject: [PATCH] chromium: Move CharAllocator definition to a header file
5*4882a593Smuzhiyun
6*4882a593SmuzhiyunFixes
7*4882a593Smuzhiyunerror: invalid application of 'sizeof' to an incomplete type 'cc::ListContainerHelper::CharAllocator'
8*4882a593Smuzhiyun
9*4882a593SmuzhiyunUpstream-Status: Pending
10*4882a593SmuzhiyunSigned-off-by: Khem Raj <raj.khem@gmail.com>
11*4882a593Smuzhiyun---
12*4882a593Smuzhiyun chromium/cc/base/list_container_helper.cc | 251 ---------------------
13*4882a593Smuzhiyun chromium/cc/base/list_container_helper.h  | 255 ++++++++++++++++++++++
14*4882a593Smuzhiyun 2 files changed, 255 insertions(+), 251 deletions(-)
15*4882a593Smuzhiyun
16*4882a593Smuzhiyundiff --git a/chromium/cc/base/list_container_helper.cc b/chromium/cc/base/list_container_helper.cc
17*4882a593Smuzhiyunindex 7b594b4a458..9dae1c360c4 100644
18*4882a593Smuzhiyun--- a/chromium/cc/base/list_container_helper.cc
19*4882a593Smuzhiyun+++ b/chromium/cc/base/list_container_helper.cc
20*4882a593Smuzhiyun@@ -13,259 +13,8 @@
21*4882a593Smuzhiyun #include "base/check_op.h"
22*4882a593Smuzhiyun #include "base/memory/aligned_memory.h"
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun-namespace {
25*4882a593Smuzhiyun-const size_t kDefaultNumElementTypesToReserve = 32;
26*4882a593Smuzhiyun-}  // namespace
27*4882a593Smuzhiyun-
28*4882a593Smuzhiyun namespace cc {
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun-// CharAllocator
31*4882a593Smuzhiyun-////////////////////////////////////////////////////
32*4882a593Smuzhiyun-// This class deals only with char* and void*. It does allocation and passing
33*4882a593Smuzhiyun-// out raw pointers, as well as memory deallocation when being destroyed.
34*4882a593Smuzhiyun-class ListContainerHelper::CharAllocator {
35*4882a593Smuzhiyun- public:
36*4882a593Smuzhiyun-  // CharAllocator::InnerList
37*4882a593Smuzhiyun-  /////////////////////////////////////////////
38*4882a593Smuzhiyun-  // This class holds the raw memory chunk, as well as information about its
39*4882a593Smuzhiyun-  // size and availability.
40*4882a593Smuzhiyun-  struct InnerList {
41*4882a593Smuzhiyun-    InnerList(const InnerList&) = delete;
42*4882a593Smuzhiyun-    InnerList& operator=(const InnerList&) = delete;
43*4882a593Smuzhiyun-
44*4882a593Smuzhiyun-    std::unique_ptr<char[], base::AlignedFreeDeleter> data;
45*4882a593Smuzhiyun-    // The number of elements in total the memory can hold. The difference
46*4882a593Smuzhiyun-    // between capacity and size is the how many more elements this list can
47*4882a593Smuzhiyun-    // hold.
48*4882a593Smuzhiyun-    size_t capacity;
49*4882a593Smuzhiyun-    // The number of elements have been put into this list.
50*4882a593Smuzhiyun-    size_t size;
51*4882a593Smuzhiyun-    // The size of each element is in bytes. This is used to move from between
52*4882a593Smuzhiyun-    // elements' memory locations.
53*4882a593Smuzhiyun-    size_t step;
54*4882a593Smuzhiyun-
55*4882a593Smuzhiyun-    InnerList() : capacity(0), size(0), step(0) {}
56*4882a593Smuzhiyun-
57*4882a593Smuzhiyun-    void Erase(char* position) {
58*4882a593Smuzhiyun-      // Confident that destructor is called by caller of this function. Since
59*4882a593Smuzhiyun-      // CharAllocator does not handle construction after
60*4882a593Smuzhiyun-      // allocation, it doesn't handle desctrution before deallocation.
61*4882a593Smuzhiyun-      DCHECK_LE(position, LastElement());
62*4882a593Smuzhiyun-      DCHECK_GE(position, Begin());
63*4882a593Smuzhiyun-      char* start = position + step;
64*4882a593Smuzhiyun-      std::copy(start, End(), position);
65*4882a593Smuzhiyun-
66*4882a593Smuzhiyun-      --size;
67*4882a593Smuzhiyun-      // Decrease capacity to avoid creating not full not last InnerList.
68*4882a593Smuzhiyun-      --capacity;
69*4882a593Smuzhiyun-    }
70*4882a593Smuzhiyun-
71*4882a593Smuzhiyun-    void InsertBefore(size_t alignment, char** position, size_t count) {
72*4882a593Smuzhiyun-      DCHECK_LE(*position, LastElement() + step);
73*4882a593Smuzhiyun-      DCHECK_GE(*position, Begin());
74*4882a593Smuzhiyun-
75*4882a593Smuzhiyun-      // Adjust the size and capacity
76*4882a593Smuzhiyun-      size_t old_size = size;
77*4882a593Smuzhiyun-      size += count;
78*4882a593Smuzhiyun-      capacity = size;
79*4882a593Smuzhiyun-
80*4882a593Smuzhiyun-      // Allocate the new data and update the iterator's pointer.
81*4882a593Smuzhiyun-      std::unique_ptr<char[], base::AlignedFreeDeleter> new_data(
82*4882a593Smuzhiyun-          static_cast<char*>(base::AlignedAlloc(size * step, alignment)));
83*4882a593Smuzhiyun-      size_t position_offset = *position - Begin();
84*4882a593Smuzhiyun-      *position = new_data.get() + position_offset;
85*4882a593Smuzhiyun-
86*4882a593Smuzhiyun-      // Copy the data before the inserted segment
87*4882a593Smuzhiyun-      memcpy(new_data.get(), data.get(), position_offset);
88*4882a593Smuzhiyun-      // Copy the data after the inserted segment.
89*4882a593Smuzhiyun-      memcpy(new_data.get() + position_offset + count * step,
90*4882a593Smuzhiyun-             data.get() + position_offset, old_size * step - position_offset);
91*4882a593Smuzhiyun-      data = std::move(new_data);
92*4882a593Smuzhiyun-    }
93*4882a593Smuzhiyun-
94*4882a593Smuzhiyun-    bool IsEmpty() const { return !size; }
95*4882a593Smuzhiyun-    bool IsFull() { return capacity == size; }
96*4882a593Smuzhiyun-    size_t NumElementsAvailable() const { return capacity - size; }
97*4882a593Smuzhiyun-
98*4882a593Smuzhiyun-    void* AddElement() {
99*4882a593Smuzhiyun-      DCHECK_LT(size, capacity);
100*4882a593Smuzhiyun-      ++size;
101*4882a593Smuzhiyun-      return LastElement();
102*4882a593Smuzhiyun-    }
103*4882a593Smuzhiyun-
104*4882a593Smuzhiyun-    void RemoveLast() {
105*4882a593Smuzhiyun-      DCHECK(!IsEmpty());
106*4882a593Smuzhiyun-      --size;
107*4882a593Smuzhiyun-    }
108*4882a593Smuzhiyun-
109*4882a593Smuzhiyun-    char* Begin() const { return data.get(); }
110*4882a593Smuzhiyun-    char* End() const { return data.get() + size * step; }
111*4882a593Smuzhiyun-    char* LastElement() const { return data.get() + (size - 1) * step; }
112*4882a593Smuzhiyun-    char* ElementAt(size_t index) const { return data.get() + index * step; }
113*4882a593Smuzhiyun-  };
114*4882a593Smuzhiyun-
115*4882a593Smuzhiyun-  CharAllocator(size_t alignment, size_t element_size, size_t element_count)
116*4882a593Smuzhiyun-      // base::AlignedAlloc does not accept alignment less than sizeof(void*).
117*4882a593Smuzhiyun-      : alignment_(std::max(sizeof(void*), alignment)),
118*4882a593Smuzhiyun-        element_size_(element_size),
119*4882a593Smuzhiyun-        size_(0),
120*4882a593Smuzhiyun-        last_list_index_(0),
121*4882a593Smuzhiyun-        last_list_(nullptr) {
122*4882a593Smuzhiyun-    // If this fails, then alignment of elements after the first could be wrong,
123*4882a593Smuzhiyun-    // and we need to pad sizes to fix that.
124*4882a593Smuzhiyun-    DCHECK_EQ(element_size % alignment, 0u);
125*4882a593Smuzhiyun-    AllocateNewList(element_count > 0 ? element_count
126*4882a593Smuzhiyun-                                      : kDefaultNumElementTypesToReserve);
127*4882a593Smuzhiyun-    last_list_ = storage_[last_list_index_].get();
128*4882a593Smuzhiyun-  }
129*4882a593Smuzhiyun-
130*4882a593Smuzhiyun-  CharAllocator(const CharAllocator&) = delete;
131*4882a593Smuzhiyun-  ~CharAllocator() = default;
132*4882a593Smuzhiyun-
133*4882a593Smuzhiyun-  CharAllocator& operator=(const CharAllocator&) = delete;
134*4882a593Smuzhiyun-
135*4882a593Smuzhiyun-  void* Allocate() {
136*4882a593Smuzhiyun-    if (last_list_->IsFull()) {
137*4882a593Smuzhiyun-      // Only allocate a new list if there isn't a spare one still there from
138*4882a593Smuzhiyun-      // previous usage.
139*4882a593Smuzhiyun-      if (last_list_index_ + 1 >= storage_.size())
140*4882a593Smuzhiyun-        AllocateNewList(last_list_->capacity * 2);
141*4882a593Smuzhiyun-
142*4882a593Smuzhiyun-      ++last_list_index_;
143*4882a593Smuzhiyun-      last_list_ = storage_[last_list_index_].get();
144*4882a593Smuzhiyun-    }
145*4882a593Smuzhiyun-
146*4882a593Smuzhiyun-    ++size_;
147*4882a593Smuzhiyun-    return last_list_->AddElement();
148*4882a593Smuzhiyun-  }
149*4882a593Smuzhiyun-
150*4882a593Smuzhiyun-  size_t alignment() const { return alignment_; }
151*4882a593Smuzhiyun-  size_t element_size() const { return element_size_; }
152*4882a593Smuzhiyun-  size_t list_count() const { return storage_.size(); }
153*4882a593Smuzhiyun-  size_t size() const { return size_; }
154*4882a593Smuzhiyun-  bool IsEmpty() const { return size() == 0; }
155*4882a593Smuzhiyun-
156*4882a593Smuzhiyun-  size_t Capacity() const {
157*4882a593Smuzhiyun-    size_t capacity_sum = 0;
158*4882a593Smuzhiyun-    for (const auto& inner_list : storage_)
159*4882a593Smuzhiyun-      capacity_sum += inner_list->capacity;
160*4882a593Smuzhiyun-    return capacity_sum;
161*4882a593Smuzhiyun-  }
162*4882a593Smuzhiyun-
163*4882a593Smuzhiyun-  void Clear() {
164*4882a593Smuzhiyun-    // Remove all except for the first InnerList.
165*4882a593Smuzhiyun-    DCHECK(!storage_.empty());
166*4882a593Smuzhiyun-    storage_.erase(storage_.begin() + 1, storage_.end());
167*4882a593Smuzhiyun-    last_list_index_ = 0;
168*4882a593Smuzhiyun-    last_list_ = storage_[0].get();
169*4882a593Smuzhiyun-    last_list_->size = 0;
170*4882a593Smuzhiyun-    size_ = 0;
171*4882a593Smuzhiyun-  }
172*4882a593Smuzhiyun-
173*4882a593Smuzhiyun-  void RemoveLast() {
174*4882a593Smuzhiyun-    DCHECK(!IsEmpty());
175*4882a593Smuzhiyun-    last_list_->RemoveLast();
176*4882a593Smuzhiyun-    if (last_list_->IsEmpty() && last_list_index_ > 0) {
177*4882a593Smuzhiyun-      --last_list_index_;
178*4882a593Smuzhiyun-      last_list_ = storage_[last_list_index_].get();
179*4882a593Smuzhiyun-
180*4882a593Smuzhiyun-      // If there are now two empty inner lists, free one of them.
181*4882a593Smuzhiyun-      if (last_list_index_ + 2 < storage_.size())
182*4882a593Smuzhiyun-        storage_.pop_back();
183*4882a593Smuzhiyun-    }
184*4882a593Smuzhiyun-    --size_;
185*4882a593Smuzhiyun-  }
186*4882a593Smuzhiyun-
187*4882a593Smuzhiyun-  void Erase(PositionInCharAllocator* position) {
188*4882a593Smuzhiyun-    DCHECK_EQ(this, position->ptr_to_container);
189*4882a593Smuzhiyun-
190*4882a593Smuzhiyun-    // Update |position| to point to the element after the erased element.
191*4882a593Smuzhiyun-    InnerList* list = storage_[position->vector_index].get();
192*4882a593Smuzhiyun-    char* item_iterator = position->item_iterator;
193*4882a593Smuzhiyun-    if (item_iterator == list->LastElement())
194*4882a593Smuzhiyun-      position->Increment();
195*4882a593Smuzhiyun-
196*4882a593Smuzhiyun-    list->Erase(item_iterator);
197*4882a593Smuzhiyun-    // TODO(weiliangc): Free the InnerList if it is empty.
198*4882a593Smuzhiyun-    --size_;
199*4882a593Smuzhiyun-  }
200*4882a593Smuzhiyun-
201*4882a593Smuzhiyun-  void InsertBefore(ListContainerHelper::Iterator* position, size_t count) {
202*4882a593Smuzhiyun-    if (!count)
203*4882a593Smuzhiyun-      return;
204*4882a593Smuzhiyun-
205*4882a593Smuzhiyun-    // If |position| is End(), then append |count| elements at the end. This
206*4882a593Smuzhiyun-    // will happen to not invalidate any iterators or memory.
207*4882a593Smuzhiyun-    if (!position->item_iterator) {
208*4882a593Smuzhiyun-      // Set |position| to be the first inserted element.
209*4882a593Smuzhiyun-      Allocate();
210*4882a593Smuzhiyun-      position->vector_index = storage_.size() - 1;
211*4882a593Smuzhiyun-      position->item_iterator = storage_[position->vector_index]->LastElement();
212*4882a593Smuzhiyun-      // Allocate the rest.
213*4882a593Smuzhiyun-      for (size_t i = 1; i < count; ++i)
214*4882a593Smuzhiyun-        Allocate();
215*4882a593Smuzhiyun-    } else {
216*4882a593Smuzhiyun-      storage_[position->vector_index]->InsertBefore(
217*4882a593Smuzhiyun-          alignment_, &position->item_iterator, count);
218*4882a593Smuzhiyun-      size_ += count;
219*4882a593Smuzhiyun-    }
220*4882a593Smuzhiyun-  }
221*4882a593Smuzhiyun-
222*4882a593Smuzhiyun-  InnerList* InnerListById(size_t id) const {
223*4882a593Smuzhiyun-    DCHECK_LT(id, storage_.size());
224*4882a593Smuzhiyun-    return storage_[id].get();
225*4882a593Smuzhiyun-  }
226*4882a593Smuzhiyun-
227*4882a593Smuzhiyun-  size_t FirstInnerListId() const {
228*4882a593Smuzhiyun-    // |size_| > 0 means that at least one vector in |storage_| will be
229*4882a593Smuzhiyun-    // non-empty.
230*4882a593Smuzhiyun-    DCHECK_GT(size_, 0u);
231*4882a593Smuzhiyun-    size_t id = 0;
232*4882a593Smuzhiyun-    while (storage_[id]->size == 0)
233*4882a593Smuzhiyun-      ++id;
234*4882a593Smuzhiyun-    return id;
235*4882a593Smuzhiyun-  }
236*4882a593Smuzhiyun-
237*4882a593Smuzhiyun-  size_t LastInnerListId() const {
238*4882a593Smuzhiyun-    // |size_| > 0 means that at least one vector in |storage_| will be
239*4882a593Smuzhiyun-    // non-empty.
240*4882a593Smuzhiyun-    DCHECK_GT(size_, 0u);
241*4882a593Smuzhiyun-    size_t id = storage_.size() - 1;
242*4882a593Smuzhiyun-    while (storage_[id]->size == 0)
243*4882a593Smuzhiyun-      --id;
244*4882a593Smuzhiyun-    return id;
245*4882a593Smuzhiyun-  }
246*4882a593Smuzhiyun-
247*4882a593Smuzhiyun-  size_t NumAvailableElementsInLastList() const {
248*4882a593Smuzhiyun-    return last_list_->NumElementsAvailable();
249*4882a593Smuzhiyun-  }
250*4882a593Smuzhiyun-
251*4882a593Smuzhiyun- private:
252*4882a593Smuzhiyun-  void AllocateNewList(size_t list_size) {
253*4882a593Smuzhiyun-    std::unique_ptr<InnerList> new_list(new InnerList);
254*4882a593Smuzhiyun-    new_list->capacity = list_size;
255*4882a593Smuzhiyun-    new_list->size = 0;
256*4882a593Smuzhiyun-    new_list->step = element_size_;
257*4882a593Smuzhiyun-    new_list->data.reset(static_cast<char*>(
258*4882a593Smuzhiyun-        base::AlignedAlloc(list_size * element_size_, alignment_)));
259*4882a593Smuzhiyun-    storage_.push_back(std::move(new_list));
260*4882a593Smuzhiyun-  }
261*4882a593Smuzhiyun-
262*4882a593Smuzhiyun-  std::vector<std::unique_ptr<InnerList>> storage_;
263*4882a593Smuzhiyun-  const size_t alignment_;
264*4882a593Smuzhiyun-  const size_t element_size_;
265*4882a593Smuzhiyun-
266*4882a593Smuzhiyun-  // The number of elements in the list.
267*4882a593Smuzhiyun-  size_t size_;
268*4882a593Smuzhiyun-
269*4882a593Smuzhiyun-  // The index of the last list to have had elements added to it, or the only
270*4882a593Smuzhiyun-  // list if the container has not had elements added since being cleared.
271*4882a593Smuzhiyun-  size_t last_list_index_;
272*4882a593Smuzhiyun-
273*4882a593Smuzhiyun-  // This is equivalent to |storage_[last_list_index_]|.
274*4882a593Smuzhiyun-  InnerList* last_list_;
275*4882a593Smuzhiyun-};
276*4882a593Smuzhiyun-
277*4882a593Smuzhiyun // PositionInCharAllocator
278*4882a593Smuzhiyun //////////////////////////////////////////////////////
279*4882a593Smuzhiyun ListContainerHelper::PositionInCharAllocator::PositionInCharAllocator(
280*4882a593Smuzhiyundiff --git a/chromium/cc/base/list_container_helper.h b/chromium/cc/base/list_container_helper.h
281*4882a593Smuzhiyunindex 31658bc8486..9e65013cbdb 100644
282*4882a593Smuzhiyun--- a/chromium/cc/base/list_container_helper.h
283*4882a593Smuzhiyun+++ b/chromium/cc/base/list_container_helper.h
284*4882a593Smuzhiyun@@ -8,9 +8,17 @@
285*4882a593Smuzhiyun #include <stddef.h>
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun #include <memory>
288*4882a593Smuzhiyun+#include <algorithm>
289*4882a593Smuzhiyun+#include <vector>
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun+#include "base/logging.h"
292*4882a593Smuzhiyun+#include "base/memory/aligned_memory.h"
293*4882a593Smuzhiyun #include "cc/base/base_export.h"
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun+namespace {
296*4882a593Smuzhiyun+const size_t kDefaultNumElementTypesToReserve = 32;
297*4882a593Smuzhiyun+}  // namespace
298*4882a593Smuzhiyun+
299*4882a593Smuzhiyun namespace cc {
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun // Helper class for ListContainer non-templated logic. All methods are private,
302*4882a593Smuzhiyun@@ -174,6 +182,253 @@ class CC_BASE_EXPORT ListContainerHelper final {
303*4882a593Smuzhiyun   std::unique_ptr<CharAllocator> data_;
304*4882a593Smuzhiyun };
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun+// CharAllocator
307*4882a593Smuzhiyun+////////////////////////////////////////////////////
308*4882a593Smuzhiyun+// This class deals only with char* and void*. It does allocation and passing
309*4882a593Smuzhiyun+// out raw pointers, as well as memory deallocation when being destroyed.
310*4882a593Smuzhiyun+class ListContainerHelper::CharAllocator {
311*4882a593Smuzhiyun+ public:
312*4882a593Smuzhiyun+  // CharAllocator::InnerList
313*4882a593Smuzhiyun+  /////////////////////////////////////////////
314*4882a593Smuzhiyun+  // This class holds the raw memory chunk, as well as information about its
315*4882a593Smuzhiyun+  // size and availability.
316*4882a593Smuzhiyun+  struct InnerList {
317*4882a593Smuzhiyun+    InnerList(const InnerList&) = delete;
318*4882a593Smuzhiyun+    InnerList& operator=(const InnerList&) = delete;
319*4882a593Smuzhiyun+
320*4882a593Smuzhiyun+    std::unique_ptr<char[], base::AlignedFreeDeleter> data;
321*4882a593Smuzhiyun+    // The number of elements in total the memory can hold. The difference
322*4882a593Smuzhiyun+    // between capacity and size is the how many more elements this list can
323*4882a593Smuzhiyun+    // hold.
324*4882a593Smuzhiyun+    size_t capacity;
325*4882a593Smuzhiyun+    // The number of elements have been put into this list.
326*4882a593Smuzhiyun+    size_t size;
327*4882a593Smuzhiyun+    // The size of each element is in bytes. This is used to move from between
328*4882a593Smuzhiyun+    // elements' memory locations.
329*4882a593Smuzhiyun+    size_t step;
330*4882a593Smuzhiyun+
331*4882a593Smuzhiyun+    InnerList() : capacity(0), size(0), step(0) {}
332*4882a593Smuzhiyun+
333*4882a593Smuzhiyun+    void Erase(char* position) {
334*4882a593Smuzhiyun+      // Confident that destructor is called by caller of this function. Since
335*4882a593Smuzhiyun+      // CharAllocator does not handle construction after
336*4882a593Smuzhiyun+      // allocation, it doesn't handle desctrution before deallocation.
337*4882a593Smuzhiyun+      DCHECK_LE(position, LastElement());
338*4882a593Smuzhiyun+      DCHECK_GE(position, Begin());
339*4882a593Smuzhiyun+      char* start = position + step;
340*4882a593Smuzhiyun+      std::copy(start, End(), position);
341*4882a593Smuzhiyun+
342*4882a593Smuzhiyun+      --size;
343*4882a593Smuzhiyun+      // Decrease capacity to avoid creating not full not last InnerList.
344*4882a593Smuzhiyun+      --capacity;
345*4882a593Smuzhiyun+    }
346*4882a593Smuzhiyun+
347*4882a593Smuzhiyun+    void InsertBefore(size_t alignment, char** position, size_t count) {
348*4882a593Smuzhiyun+      DCHECK_LE(*position, LastElement() + step);
349*4882a593Smuzhiyun+      DCHECK_GE(*position, Begin());
350*4882a593Smuzhiyun+
351*4882a593Smuzhiyun+      // Adjust the size and capacity
352*4882a593Smuzhiyun+      size_t old_size = size;
353*4882a593Smuzhiyun+      size += count;
354*4882a593Smuzhiyun+      capacity = size;
355*4882a593Smuzhiyun+
356*4882a593Smuzhiyun+      // Allocate the new data and update the iterator's pointer.
357*4882a593Smuzhiyun+      std::unique_ptr<char[], base::AlignedFreeDeleter> new_data(
358*4882a593Smuzhiyun+          static_cast<char*>(base::AlignedAlloc(size * step, alignment)));
359*4882a593Smuzhiyun+      size_t position_offset = *position - Begin();
360*4882a593Smuzhiyun+      *position = new_data.get() + position_offset;
361*4882a593Smuzhiyun+
362*4882a593Smuzhiyun+      // Copy the data before the inserted segment
363*4882a593Smuzhiyun+      memcpy(new_data.get(), data.get(), position_offset);
364*4882a593Smuzhiyun+      // Copy the data after the inserted segment.
365*4882a593Smuzhiyun+      memcpy(new_data.get() + position_offset + count * step,
366*4882a593Smuzhiyun+             data.get() + position_offset, old_size * step - position_offset);
367*4882a593Smuzhiyun+      data = std::move(new_data);
368*4882a593Smuzhiyun+    }
369*4882a593Smuzhiyun+
370*4882a593Smuzhiyun+    bool IsEmpty() const { return !size; }
371*4882a593Smuzhiyun+    bool IsFull() { return capacity == size; }
372*4882a593Smuzhiyun+    size_t NumElementsAvailable() const { return capacity - size; }
373*4882a593Smuzhiyun+
374*4882a593Smuzhiyun+    void* AddElement() {
375*4882a593Smuzhiyun+      DCHECK_LT(size, capacity);
376*4882a593Smuzhiyun+      ++size;
377*4882a593Smuzhiyun+      return LastElement();
378*4882a593Smuzhiyun+    }
379*4882a593Smuzhiyun+
380*4882a593Smuzhiyun+    void RemoveLast() {
381*4882a593Smuzhiyun+      DCHECK(!IsEmpty());
382*4882a593Smuzhiyun+      --size;
383*4882a593Smuzhiyun+    }
384*4882a593Smuzhiyun+
385*4882a593Smuzhiyun+    char* Begin() const { return data.get(); }
386*4882a593Smuzhiyun+    char* End() const { return data.get() + size * step; }
387*4882a593Smuzhiyun+    char* LastElement() const { return data.get() + (size - 1) * step; }
388*4882a593Smuzhiyun+    char* ElementAt(size_t index) const { return data.get() + index * step; }
389*4882a593Smuzhiyun+  };
390*4882a593Smuzhiyun+
391*4882a593Smuzhiyun+  CharAllocator(size_t alignment, size_t element_size, size_t element_count)
392*4882a593Smuzhiyun+      // base::AlignedAlloc does not accept alignment less than sizeof(void*).
393*4882a593Smuzhiyun+      : alignment_(std::max(sizeof(void*), alignment)),
394*4882a593Smuzhiyun+        element_size_(element_size),
395*4882a593Smuzhiyun+        size_(0),
396*4882a593Smuzhiyun+        last_list_index_(0),
397*4882a593Smuzhiyun+        last_list_(nullptr) {
398*4882a593Smuzhiyun+    // If this fails, then alignment of elements after the first could be wrong,
399*4882a593Smuzhiyun+    // and we need to pad sizes to fix that.
400*4882a593Smuzhiyun+    DCHECK_EQ(element_size % alignment, 0u);
401*4882a593Smuzhiyun+    AllocateNewList(element_count > 0 ? element_count
402*4882a593Smuzhiyun+                                      : kDefaultNumElementTypesToReserve);
403*4882a593Smuzhiyun+    last_list_ = storage_[last_list_index_].get();
404*4882a593Smuzhiyun+  }
405*4882a593Smuzhiyun+
406*4882a593Smuzhiyun+  CharAllocator(const CharAllocator&) = delete;
407*4882a593Smuzhiyun+  ~CharAllocator() = default;
408*4882a593Smuzhiyun+
409*4882a593Smuzhiyun+  CharAllocator& operator=(const CharAllocator&) = delete;
410*4882a593Smuzhiyun+
411*4882a593Smuzhiyun+  void* Allocate() {
412*4882a593Smuzhiyun+    if (last_list_->IsFull()) {
413*4882a593Smuzhiyun+      // Only allocate a new list if there isn't a spare one still there from
414*4882a593Smuzhiyun+      // previous usage.
415*4882a593Smuzhiyun+      if (last_list_index_ + 1 >= storage_.size())
416*4882a593Smuzhiyun+        AllocateNewList(last_list_->capacity * 2);
417*4882a593Smuzhiyun+
418*4882a593Smuzhiyun+      ++last_list_index_;
419*4882a593Smuzhiyun+      last_list_ = storage_[last_list_index_].get();
420*4882a593Smuzhiyun+    }
421*4882a593Smuzhiyun+
422*4882a593Smuzhiyun+    ++size_;
423*4882a593Smuzhiyun+    return last_list_->AddElement();
424*4882a593Smuzhiyun+  }
425*4882a593Smuzhiyun+
426*4882a593Smuzhiyun+  size_t alignment() const { return alignment_; }
427*4882a593Smuzhiyun+  size_t element_size() const { return element_size_; }
428*4882a593Smuzhiyun+  size_t list_count() const { return storage_.size(); }
429*4882a593Smuzhiyun+  size_t size() const { return size_; }
430*4882a593Smuzhiyun+  bool IsEmpty() const { return size() == 0; }
431*4882a593Smuzhiyun+
432*4882a593Smuzhiyun+  size_t Capacity() const {
433*4882a593Smuzhiyun+    size_t capacity_sum = 0;
434*4882a593Smuzhiyun+    for (const auto& inner_list : storage_)
435*4882a593Smuzhiyun+      capacity_sum += inner_list->capacity;
436*4882a593Smuzhiyun+    return capacity_sum;
437*4882a593Smuzhiyun+  }
438*4882a593Smuzhiyun+
439*4882a593Smuzhiyun+  void Clear() {
440*4882a593Smuzhiyun+    // Remove all except for the first InnerList.
441*4882a593Smuzhiyun+    DCHECK(!storage_.empty());
442*4882a593Smuzhiyun+    storage_.erase(storage_.begin() + 1, storage_.end());
443*4882a593Smuzhiyun+    last_list_index_ = 0;
444*4882a593Smuzhiyun+    last_list_ = storage_[0].get();
445*4882a593Smuzhiyun+    last_list_->size = 0;
446*4882a593Smuzhiyun+    size_ = 0;
447*4882a593Smuzhiyun+  }
448*4882a593Smuzhiyun+
449*4882a593Smuzhiyun+  void RemoveLast() {
450*4882a593Smuzhiyun+    DCHECK(!IsEmpty());
451*4882a593Smuzhiyun+    last_list_->RemoveLast();
452*4882a593Smuzhiyun+    if (last_list_->IsEmpty() && last_list_index_ > 0) {
453*4882a593Smuzhiyun+      --last_list_index_;
454*4882a593Smuzhiyun+      last_list_ = storage_[last_list_index_].get();
455*4882a593Smuzhiyun+
456*4882a593Smuzhiyun+      // If there are now two empty inner lists, free one of them.
457*4882a593Smuzhiyun+      if (last_list_index_ + 2 < storage_.size())
458*4882a593Smuzhiyun+        storage_.pop_back();
459*4882a593Smuzhiyun+    }
460*4882a593Smuzhiyun+    --size_;
461*4882a593Smuzhiyun+  }
462*4882a593Smuzhiyun+
463*4882a593Smuzhiyun+  void Erase(PositionInCharAllocator* position) {
464*4882a593Smuzhiyun+    DCHECK_EQ(this, position->ptr_to_container);
465*4882a593Smuzhiyun+
466*4882a593Smuzhiyun+    // Update |position| to point to the element after the erased element.
467*4882a593Smuzhiyun+    InnerList* list = storage_[position->vector_index].get();
468*4882a593Smuzhiyun+    char* item_iterator = position->item_iterator;
469*4882a593Smuzhiyun+    if (item_iterator == list->LastElement())
470*4882a593Smuzhiyun+      position->Increment();
471*4882a593Smuzhiyun+
472*4882a593Smuzhiyun+    list->Erase(item_iterator);
473*4882a593Smuzhiyun+    // TODO(weiliangc): Free the InnerList if it is empty.
474*4882a593Smuzhiyun+    --size_;
475*4882a593Smuzhiyun+  }
476*4882a593Smuzhiyun+
477*4882a593Smuzhiyun+  void InsertBefore(ListContainerHelper::Iterator* position, size_t count) {
478*4882a593Smuzhiyun+    if (!count)
479*4882a593Smuzhiyun+      return;
480*4882a593Smuzhiyun+
481*4882a593Smuzhiyun+    // If |position| is End(), then append |count| elements at the end. This
482*4882a593Smuzhiyun+    // will happen to not invalidate any iterators or memory.
483*4882a593Smuzhiyun+    if (!position->item_iterator) {
484*4882a593Smuzhiyun+      // Set |position| to be the first inserted element.
485*4882a593Smuzhiyun+      Allocate();
486*4882a593Smuzhiyun+      position->vector_index = storage_.size() - 1;
487*4882a593Smuzhiyun+      position->item_iterator = storage_[position->vector_index]->LastElement();
488*4882a593Smuzhiyun+      // Allocate the rest.
489*4882a593Smuzhiyun+      for (size_t i = 1; i < count; ++i)
490*4882a593Smuzhiyun+        Allocate();
491*4882a593Smuzhiyun+    } else {
492*4882a593Smuzhiyun+      storage_[position->vector_index]->InsertBefore(
493*4882a593Smuzhiyun+          alignment_, &position->item_iterator, count);
494*4882a593Smuzhiyun+      size_ += count;
495*4882a593Smuzhiyun+    }
496*4882a593Smuzhiyun+  }
497*4882a593Smuzhiyun+
498*4882a593Smuzhiyun+  InnerList* InnerListById(size_t id) const {
499*4882a593Smuzhiyun+    DCHECK_LT(id, storage_.size());
500*4882a593Smuzhiyun+    return storage_[id].get();
501*4882a593Smuzhiyun+  }
502*4882a593Smuzhiyun+
503*4882a593Smuzhiyun+  size_t FirstInnerListId() const {
504*4882a593Smuzhiyun+    // |size_| > 0 means that at least one vector in |storage_| will be
505*4882a593Smuzhiyun+    // non-empty.
506*4882a593Smuzhiyun+    DCHECK_GT(size_, 0u);
507*4882a593Smuzhiyun+    size_t id = 0;
508*4882a593Smuzhiyun+    while (storage_[id]->size == 0)
509*4882a593Smuzhiyun+      ++id;
510*4882a593Smuzhiyun+    return id;
511*4882a593Smuzhiyun+  }
512*4882a593Smuzhiyun+
513*4882a593Smuzhiyun+  size_t LastInnerListId() const {
514*4882a593Smuzhiyun+    // |size_| > 0 means that at least one vector in |storage_| will be
515*4882a593Smuzhiyun+    // non-empty.
516*4882a593Smuzhiyun+    DCHECK_GT(size_, 0u);
517*4882a593Smuzhiyun+    size_t id = storage_.size() - 1;
518*4882a593Smuzhiyun+    while (storage_[id]->size == 0)
519*4882a593Smuzhiyun+      --id;
520*4882a593Smuzhiyun+    return id;
521*4882a593Smuzhiyun+  }
522*4882a593Smuzhiyun+
523*4882a593Smuzhiyun+  size_t NumAvailableElementsInLastList() const {
524*4882a593Smuzhiyun+    return last_list_->NumElementsAvailable();
525*4882a593Smuzhiyun+  }
526*4882a593Smuzhiyun+
527*4882a593Smuzhiyun+ private:
528*4882a593Smuzhiyun+  void AllocateNewList(size_t list_size) {
529*4882a593Smuzhiyun+    std::unique_ptr<InnerList> new_list(new InnerList);
530*4882a593Smuzhiyun+    new_list->capacity = list_size;
531*4882a593Smuzhiyun+    new_list->size = 0;
532*4882a593Smuzhiyun+    new_list->step = element_size_;
533*4882a593Smuzhiyun+    new_list->data.reset(static_cast<char*>(
534*4882a593Smuzhiyun+        base::AlignedAlloc(list_size * element_size_, alignment_)));
535*4882a593Smuzhiyun+    storage_.push_back(std::move(new_list));
536*4882a593Smuzhiyun+  }
537*4882a593Smuzhiyun+
538*4882a593Smuzhiyun+  std::vector<std::unique_ptr<InnerList>> storage_;
539*4882a593Smuzhiyun+  const size_t alignment_;
540*4882a593Smuzhiyun+  const size_t element_size_;
541*4882a593Smuzhiyun+
542*4882a593Smuzhiyun+  // The number of elements in the list.
543*4882a593Smuzhiyun+  size_t size_;
544*4882a593Smuzhiyun+
545*4882a593Smuzhiyun+  // The index of the last list to have had elements added to it, or the only
546*4882a593Smuzhiyun+  // list if the container has not had elements added since being cleared.
547*4882a593Smuzhiyun+  size_t last_list_index_;
548*4882a593Smuzhiyun+
549*4882a593Smuzhiyun+  // This is equivalent to |storage_[last_list_index_]|.
550*4882a593Smuzhiyun+  InnerList* last_list_;
551*4882a593Smuzhiyun+};
552*4882a593Smuzhiyun+
553*4882a593Smuzhiyun }  // namespace cc
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun #endif  // CC_BASE_LIST_CONTAINER_HELPER_H_
556