From b30936d56615107fa518d313d9961fcd0c5930af Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Thu, 2 Jan 2020 17:13:55 -0800 Subject: [PATCH] chromium: Move CharAllocator definition to a header file Fixes error: invalid application of 'sizeof' to an incomplete type 'cc::ListContainerHelper::CharAllocator' Signed-off-by: Khem Raj --- chromium/cc/base/list_container_helper.cc | 251 --------------------- chromium/cc/base/list_container_helper.h | 255 ++++++++++++++++++++++ 2 files changed, 255 insertions(+), 251 deletions(-) diff --git a/chromium/cc/base/list_container_helper.cc b/chromium/cc/base/list_container_helper.cc index 3a4c0b6a2f9..89df57a7b8e 100644 --- a/chromium/cc/base/list_container_helper.cc +++ b/chromium/cc/base/list_container_helper.cc @@ -12,259 +12,8 @@ #include "base/logging.h" #include "base/memory/aligned_memory.h" -namespace { -const size_t kDefaultNumElementTypesToReserve = 32; -} // namespace - namespace cc { -// CharAllocator -//////////////////////////////////////////////////// -// This class deals only with char* and void*. It does allocation and passing -// out raw pointers, as well as memory deallocation when being destroyed. -class ListContainerHelper::CharAllocator { - public: - // CharAllocator::InnerList - ///////////////////////////////////////////// - // This class holds the raw memory chunk, as well as information about its - // size and availability. - struct InnerList { - InnerList(const InnerList&) = delete; - InnerList& operator=(const InnerList&) = delete; - - std::unique_ptr data; - // The number of elements in total the memory can hold. The difference - // between capacity and size is the how many more elements this list can - // hold. - size_t capacity; - // The number of elements have been put into this list. - size_t size; - // The size of each element is in bytes. This is used to move from between - // elements' memory locations. - size_t step; - - InnerList() : capacity(0), size(0), step(0) {} - - void Erase(char* position) { - // Confident that destructor is called by caller of this function. Since - // CharAllocator does not handle construction after - // allocation, it doesn't handle desctrution before deallocation. - DCHECK_LE(position, LastElement()); - DCHECK_GE(position, Begin()); - char* start = position + step; - std::copy(start, End(), position); - - --size; - // Decrease capacity to avoid creating not full not last InnerList. - --capacity; - } - - void InsertBefore(size_t alignment, char** position, size_t count) { - DCHECK_LE(*position, LastElement() + step); - DCHECK_GE(*position, Begin()); - - // Adjust the size and capacity - size_t old_size = size; - size += count; - capacity = size; - - // Allocate the new data and update the iterator's pointer. - std::unique_ptr new_data( - static_cast(base::AlignedAlloc(size * step, alignment))); - size_t position_offset = *position - Begin(); - *position = new_data.get() + position_offset; - - // Copy the data before the inserted segment - memcpy(new_data.get(), data.get(), position_offset); - // Copy the data after the inserted segment. - memcpy(new_data.get() + position_offset + count * step, - data.get() + position_offset, old_size * step - position_offset); - data = std::move(new_data); - } - - bool IsEmpty() const { return !size; } - bool IsFull() { return capacity == size; } - size_t NumElementsAvailable() const { return capacity - size; } - - void* AddElement() { - DCHECK_LT(size, capacity); - ++size; - return LastElement(); - } - - void RemoveLast() { - DCHECK(!IsEmpty()); - --size; - } - - char* Begin() const { return data.get(); } - char* End() const { return data.get() + size * step; } - char* LastElement() const { return data.get() + (size - 1) * step; } - char* ElementAt(size_t index) const { return data.get() + index * step; } - }; - - CharAllocator(size_t alignment, size_t element_size, size_t element_count) - // base::AlignedAlloc does not accept alignment less than sizeof(void*). - : alignment_(std::max(sizeof(void*), alignment)), - element_size_(element_size), - size_(0), - last_list_index_(0), - last_list_(nullptr) { - // If this fails, then alignment of elements after the first could be wrong, - // and we need to pad sizes to fix that. - DCHECK_EQ(element_size % alignment, 0u); - AllocateNewList(element_count > 0 ? element_count - : kDefaultNumElementTypesToReserve); - last_list_ = storage_[last_list_index_].get(); - } - - CharAllocator(const CharAllocator&) = delete; - ~CharAllocator() = default; - - CharAllocator& operator=(const CharAllocator&) = delete; - - void* Allocate() { - if (last_list_->IsFull()) { - // Only allocate a new list if there isn't a spare one still there from - // previous usage. - if (last_list_index_ + 1 >= storage_.size()) - AllocateNewList(last_list_->capacity * 2); - - ++last_list_index_; - last_list_ = storage_[last_list_index_].get(); - } - - ++size_; - return last_list_->AddElement(); - } - - size_t alignment() const { return alignment_; } - size_t element_size() const { return element_size_; } - size_t list_count() const { return storage_.size(); } - size_t size() const { return size_; } - bool IsEmpty() const { return size() == 0; } - - size_t Capacity() const { - size_t capacity_sum = 0; - for (const auto& inner_list : storage_) - capacity_sum += inner_list->capacity; - return capacity_sum; - } - - void Clear() { - // Remove all except for the first InnerList. - DCHECK(!storage_.empty()); - storage_.erase(storage_.begin() + 1, storage_.end()); - last_list_index_ = 0; - last_list_ = storage_[0].get(); - last_list_->size = 0; - size_ = 0; - } - - void RemoveLast() { - DCHECK(!IsEmpty()); - last_list_->RemoveLast(); - if (last_list_->IsEmpty() && last_list_index_ > 0) { - --last_list_index_; - last_list_ = storage_[last_list_index_].get(); - - // If there are now two empty inner lists, free one of them. - if (last_list_index_ + 2 < storage_.size()) - storage_.pop_back(); - } - --size_; - } - - void Erase(PositionInCharAllocator* position) { - DCHECK_EQ(this, position->ptr_to_container); - - // Update |position| to point to the element after the erased element. - InnerList* list = storage_[position->vector_index].get(); - char* item_iterator = position->item_iterator; - if (item_iterator == list->LastElement()) - position->Increment(); - - list->Erase(item_iterator); - // TODO(weiliangc): Free the InnerList if it is empty. - --size_; - } - - void InsertBefore(ListContainerHelper::Iterator* position, size_t count) { - if (!count) - return; - - // If |position| is End(), then append |count| elements at the end. This - // will happen to not invalidate any iterators or memory. - if (!position->item_iterator) { - // Set |position| to be the first inserted element. - Allocate(); - position->vector_index = storage_.size() - 1; - position->item_iterator = storage_[position->vector_index]->LastElement(); - // Allocate the rest. - for (size_t i = 1; i < count; ++i) - Allocate(); - } else { - storage_[position->vector_index]->InsertBefore( - alignment_, &position->item_iterator, count); - size_ += count; - } - } - - InnerList* InnerListById(size_t id) const { - DCHECK_LT(id, storage_.size()); - return storage_[id].get(); - } - - size_t FirstInnerListId() const { - // |size_| > 0 means that at least one vector in |storage_| will be - // non-empty. - DCHECK_GT(size_, 0u); - size_t id = 0; - while (storage_[id]->size == 0) - ++id; - return id; - } - - size_t LastInnerListId() const { - // |size_| > 0 means that at least one vector in |storage_| will be - // non-empty. - DCHECK_GT(size_, 0u); - size_t id = storage_.size() - 1; - while (storage_[id]->size == 0) - --id; - return id; - } - - size_t NumAvailableElementsInLastList() const { - return last_list_->NumElementsAvailable(); - } - - private: - void AllocateNewList(size_t list_size) { - std::unique_ptr new_list(new InnerList); - new_list->capacity = list_size; - new_list->size = 0; - new_list->step = element_size_; - new_list->data.reset(static_cast( - base::AlignedAlloc(list_size * element_size_, alignment_))); - storage_.push_back(std::move(new_list)); - } - - std::vector> storage_; - const size_t alignment_; - const size_t element_size_; - - // The number of elements in the list. - size_t size_; - - // The index of the last list to have had elements added to it, or the only - // list if the container has not had elements added since being cleared. - size_t last_list_index_; - - // This is equivalent to |storage_[last_list_index_]|. - InnerList* last_list_; -}; - // PositionInCharAllocator ////////////////////////////////////////////////////// ListContainerHelper::PositionInCharAllocator::PositionInCharAllocator( diff --git a/chromium/cc/base/list_container_helper.h b/chromium/cc/base/list_container_helper.h index 31658bc8486..9e65013cbdb 100644 --- a/chromium/cc/base/list_container_helper.h +++ b/chromium/cc/base/list_container_helper.h @@ -8,9 +8,17 @@ #include #include +#include +#include +#include "base/logging.h" +#include "base/memory/aligned_memory.h" #include "cc/base/base_export.h" +namespace { +const size_t kDefaultNumElementTypesToReserve = 32; +} // namespace + namespace cc { // Helper class for ListContainer non-templated logic. All methods are private, @@ -174,6 +182,253 @@ class CC_BASE_EXPORT ListContainerHelper final { std::unique_ptr data_; }; +// CharAllocator +//////////////////////////////////////////////////// +// This class deals only with char* and void*. It does allocation and passing +// out raw pointers, as well as memory deallocation when being destroyed. +class ListContainerHelper::CharAllocator { + public: + // CharAllocator::InnerList + ///////////////////////////////////////////// + // This class holds the raw memory chunk, as well as information about its + // size and availability. + struct InnerList { + InnerList(const InnerList&) = delete; + InnerList& operator=(const InnerList&) = delete; + + std::unique_ptr data; + // The number of elements in total the memory can hold. The difference + // between capacity and size is the how many more elements this list can + // hold. + size_t capacity; + // The number of elements have been put into this list. + size_t size; + // The size of each element is in bytes. This is used to move from between + // elements' memory locations. + size_t step; + + InnerList() : capacity(0), size(0), step(0) {} + + void Erase(char* position) { + // Confident that destructor is called by caller of this function. Since + // CharAllocator does not handle construction after + // allocation, it doesn't handle desctrution before deallocation. + DCHECK_LE(position, LastElement()); + DCHECK_GE(position, Begin()); + char* start = position + step; + std::copy(start, End(), position); + + --size; + // Decrease capacity to avoid creating not full not last InnerList. + --capacity; + } + + void InsertBefore(size_t alignment, char** position, size_t count) { + DCHECK_LE(*position, LastElement() + step); + DCHECK_GE(*position, Begin()); + + // Adjust the size and capacity + size_t old_size = size; + size += count; + capacity = size; + + // Allocate the new data and update the iterator's pointer. + std::unique_ptr new_data( + static_cast(base::AlignedAlloc(size * step, alignment))); + size_t position_offset = *position - Begin(); + *position = new_data.get() + position_offset; + + // Copy the data before the inserted segment + memcpy(new_data.get(), data.get(), position_offset); + // Copy the data after the inserted segment. + memcpy(new_data.get() + position_offset + count * step, + data.get() + position_offset, old_size * step - position_offset); + data = std::move(new_data); + } + + bool IsEmpty() const { return !size; } + bool IsFull() { return capacity == size; } + size_t NumElementsAvailable() const { return capacity - size; } + + void* AddElement() { + DCHECK_LT(size, capacity); + ++size; + return LastElement(); + } + + void RemoveLast() { + DCHECK(!IsEmpty()); + --size; + } + + char* Begin() const { return data.get(); } + char* End() const { return data.get() + size * step; } + char* LastElement() const { return data.get() + (size - 1) * step; } + char* ElementAt(size_t index) const { return data.get() + index * step; } + }; + + CharAllocator(size_t alignment, size_t element_size, size_t element_count) + // base::AlignedAlloc does not accept alignment less than sizeof(void*). + : alignment_(std::max(sizeof(void*), alignment)), + element_size_(element_size), + size_(0), + last_list_index_(0), + last_list_(nullptr) { + // If this fails, then alignment of elements after the first could be wrong, + // and we need to pad sizes to fix that. + DCHECK_EQ(element_size % alignment, 0u); + AllocateNewList(element_count > 0 ? element_count + : kDefaultNumElementTypesToReserve); + last_list_ = storage_[last_list_index_].get(); + } + + CharAllocator(const CharAllocator&) = delete; + ~CharAllocator() = default; + + CharAllocator& operator=(const CharAllocator&) = delete; + + void* Allocate() { + if (last_list_->IsFull()) { + // Only allocate a new list if there isn't a spare one still there from + // previous usage. + if (last_list_index_ + 1 >= storage_.size()) + AllocateNewList(last_list_->capacity * 2); + + ++last_list_index_; + last_list_ = storage_[last_list_index_].get(); + } + + ++size_; + return last_list_->AddElement(); + } + + size_t alignment() const { return alignment_; } + size_t element_size() const { return element_size_; } + size_t list_count() const { return storage_.size(); } + size_t size() const { return size_; } + bool IsEmpty() const { return size() == 0; } + + size_t Capacity() const { + size_t capacity_sum = 0; + for (const auto& inner_list : storage_) + capacity_sum += inner_list->capacity; + return capacity_sum; + } + + void Clear() { + // Remove all except for the first InnerList. + DCHECK(!storage_.empty()); + storage_.erase(storage_.begin() + 1, storage_.end()); + last_list_index_ = 0; + last_list_ = storage_[0].get(); + last_list_->size = 0; + size_ = 0; + } + + void RemoveLast() { + DCHECK(!IsEmpty()); + last_list_->RemoveLast(); + if (last_list_->IsEmpty() && last_list_index_ > 0) { + --last_list_index_; + last_list_ = storage_[last_list_index_].get(); + + // If there are now two empty inner lists, free one of them. + if (last_list_index_ + 2 < storage_.size()) + storage_.pop_back(); + } + --size_; + } + + void Erase(PositionInCharAllocator* position) { + DCHECK_EQ(this, position->ptr_to_container); + + // Update |position| to point to the element after the erased element. + InnerList* list = storage_[position->vector_index].get(); + char* item_iterator = position->item_iterator; + if (item_iterator == list->LastElement()) + position->Increment(); + + list->Erase(item_iterator); + // TODO(weiliangc): Free the InnerList if it is empty. + --size_; + } + + void InsertBefore(ListContainerHelper::Iterator* position, size_t count) { + if (!count) + return; + + // If |position| is End(), then append |count| elements at the end. This + // will happen to not invalidate any iterators or memory. + if (!position->item_iterator) { + // Set |position| to be the first inserted element. + Allocate(); + position->vector_index = storage_.size() - 1; + position->item_iterator = storage_[position->vector_index]->LastElement(); + // Allocate the rest. + for (size_t i = 1; i < count; ++i) + Allocate(); + } else { + storage_[position->vector_index]->InsertBefore( + alignment_, &position->item_iterator, count); + size_ += count; + } + } + + InnerList* InnerListById(size_t id) const { + DCHECK_LT(id, storage_.size()); + return storage_[id].get(); + } + + size_t FirstInnerListId() const { + // |size_| > 0 means that at least one vector in |storage_| will be + // non-empty. + DCHECK_GT(size_, 0u); + size_t id = 0; + while (storage_[id]->size == 0) + ++id; + return id; + } + + size_t LastInnerListId() const { + // |size_| > 0 means that at least one vector in |storage_| will be + // non-empty. + DCHECK_GT(size_, 0u); + size_t id = storage_.size() - 1; + while (storage_[id]->size == 0) + --id; + return id; + } + + size_t NumAvailableElementsInLastList() const { + return last_list_->NumElementsAvailable(); + } + + private: + void AllocateNewList(size_t list_size) { + std::unique_ptr new_list(new InnerList); + new_list->capacity = list_size; + new_list->size = 0; + new_list->step = element_size_; + new_list->data.reset(static_cast( + base::AlignedAlloc(list_size * element_size_, alignment_))); + storage_.push_back(std::move(new_list)); + } + + std::vector> storage_; + const size_t alignment_; + const size_t element_size_; + + // The number of elements in the list. + size_t size_; + + // The index of the last list to have had elements added to it, or the only + // list if the container has not had elements added since being cleared. + size_t last_list_index_; + + // This is equivalent to |storage_[last_list_index_]|. + InnerList* last_list_; +}; + } // namespace cc #endif // CC_BASE_LIST_CONTAINER_HELPER_H_