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