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