// Copyright 2014 The Chromium 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 "cc/quads/list_container.h" #include #include #include "cc/base/scoped_ptr_vector.h" #include "cc/quads/draw_quad.h" #include "cc/quads/shared_quad_state.h" namespace { const size_t kDefaultNumElementTypesToReserve = 32; } // namespace namespace cc { // ListContainerCharAllocator //////////////////////////////////////////////////// // This class deals only with char* and void*. It does allocation and passing // out raw pointers, as well as memory deallocation when being destroyed. template class ListContainer::ListContainerCharAllocator { public: // ListContainerCharAllocator::InnerList ///////////////////////////////////////////// // This class holds the raw memory chunk, as well as information about its // size and availability. struct InnerList { scoped_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 // ListContainerCharAllocator 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; } bool IsFull() { return capacity == size; } size_t NumElementsAvailable() const { return capacity - size; } void* AddElement() { DCHECK_LT(size, capacity); ++size; return LastElement(); } 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; } private: DISALLOW_COPY_AND_ASSIGN(InnerList); }; explicit ListContainerCharAllocator(size_t element_size) : element_size_(element_size), size_(0), list_count_(0), last_list_(NULL) { AllocateNewList(kDefaultNumElementTypesToReserve); } ListContainerCharAllocator(size_t element_size, size_t element_count) : element_size_(element_size), size_(0), list_count_(0), last_list_(NULL) { AllocateNewList(element_count > 0 ? element_count : kDefaultNumElementTypesToReserve); } ~ListContainerCharAllocator() {} void* Allocate() { if (last_list_->IsFull()) AllocateNewList(last_list_->capacity * 2); ++size_; return last_list_->AddElement(); } size_t element_size() const { return element_size_; } size_t list_count() const { return list_count_; } size_t size() const { return size_; } bool IsEmpty() const { return size() == 0; } size_t Capacity() const { size_t capacity_sum = 0; for (typename ScopedPtrVector::const_iterator iter = storage_.begin(); iter != storage_.end(); ++iter) { capacity_sum += (*iter)->capacity; } return capacity_sum; } void Clear() { size_t initial_allocation_size = storage_.front()->capacity; storage_.clear(); list_count_ = 0; last_list_ = NULL; size_ = 0; AllocateNewList(initial_allocation_size); } void Erase(PositionInListContainerCharAllocator position) { DCHECK_EQ(this, position.ptr_to_container); storage_[position.vector_index]->Erase(position.item_iterator); // TODO(weiliangc): Free the InnerList if it is empty. --size_; } InnerList* InnerListById(size_t id) const { DCHECK_LT(id, list_count_); return storage_[id]; } void AllocateNewList(size_t list_size) { ++list_count_; scoped_ptr new_list(new InnerList); storage_.push_back(new_list.Pass()); last_list_ = storage_.back(); InnerList* list = last_list_; list->capacity = list_size; list->size = 0; list->step = element_size_; list->data.reset(new char[list->capacity * list->step]); } size_t NumAvailableElementsInLastList() const { return last_list_->NumElementsAvailable(); } private: ScopedPtrVector storage_; const size_t element_size_; size_t size_; size_t list_count_; InnerList* last_list_; DISALLOW_COPY_AND_ASSIGN(ListContainerCharAllocator); }; // PositionInListContainerCharAllocator ////////////////////////////////////////////////////// template ListContainer::PositionInListContainerCharAllocator:: PositionInListContainerCharAllocator(const typename ListContainer< BaseElementType>::PositionInListContainerCharAllocator& other) : ptr_to_container(other.ptr_to_container), vector_index(other.vector_index), item_iterator(other.item_iterator) { } template ListContainer::PositionInListContainerCharAllocator:: PositionInListContainerCharAllocator( typename ListContainer::ListContainerCharAllocator* container, size_t vector_ind, char* item_iter) : ptr_to_container(container), vector_index(vector_ind), item_iterator(item_iter) { } template bool ListContainer::PositionInListContainerCharAllocator:: operator==(const typename ListContainer< BaseElementType>::PositionInListContainerCharAllocator& other) const { DCHECK_EQ(ptr_to_container, other.ptr_to_container); return vector_index == other.vector_index && item_iterator == other.item_iterator; } template bool ListContainer::PositionInListContainerCharAllocator:: operator!=(const typename ListContainer< BaseElementType>::PositionInListContainerCharAllocator& other) const { return !(*this == other); } template typename ListContainer::PositionInListContainerCharAllocator ListContainer< BaseElementType>::PositionInListContainerCharAllocator::Increment() { typename ListContainerCharAllocator::InnerList* list = ptr_to_container->InnerListById(vector_index); if (item_iterator == list->LastElement()) { if (vector_index < ptr_to_container->list_count() - 1) { ++vector_index; item_iterator = ptr_to_container->InnerListById(vector_index)->Begin(); } else { item_iterator = NULL; } } else { item_iterator += list->step; } return *this; } template typename ListContainer::PositionInListContainerCharAllocator ListContainer< BaseElementType>::PositionInListContainerCharAllocator::ReverseIncrement() { typename ListContainerCharAllocator::InnerList* list = ptr_to_container->InnerListById(vector_index); if (item_iterator == list->Begin()) { if (vector_index > 0) { --vector_index; item_iterator = ptr_to_container->InnerListById(vector_index)->LastElement(); } else { item_iterator = NULL; } } else { item_iterator -= list->step; } return *this; } // ListContainer //////////////////////////////////////////// template ListContainer::ListContainer(size_t max_size_for_derived_class) : data_(new ListContainerCharAllocator(max_size_for_derived_class)) { } template ListContainer::ListContainer( size_t max_size_for_derived_class, size_t num_of_elements_to_reserve_for) : data_(new ListContainerCharAllocator(max_size_for_derived_class, num_of_elements_to_reserve_for)) { } template ListContainer::ListContainer() : data_(new ListContainerCharAllocator(sizeof(BaseElementType))) { } template ListContainer::~ListContainer() { for (Iterator i = begin(); i != end(); ++i) { i->~BaseElementType(); } } template void ListContainer::EraseAndInvalidateAllPointers( typename ListContainer::Iterator position) { BaseElementType* item = *position; item->~BaseElementType(); data_->Erase(position); } template typename ListContainer::ConstReverseIterator ListContainer::crbegin() const { if (data_->IsEmpty()) return ConstReverseIterator(data_.get(), 0, NULL, 0); size_t last_id = data_->list_count() - 1; return ConstReverseIterator( data_.get(), last_id, data_->InnerListById(last_id)->LastElement(), 0); } template typename ListContainer::ConstReverseIterator ListContainer::crend() const { return ConstReverseIterator(data_.get(), 0, NULL, size()); } template typename ListContainer::ConstReverseIterator ListContainer::rbegin() const { return crbegin(); } template typename ListContainer::ConstReverseIterator ListContainer::rend() const { return crend(); } template typename ListContainer::ReverseIterator ListContainer::rbegin() { if (data_->IsEmpty()) return ReverseIterator(data_.get(), 0, NULL, 0); size_t last_id = data_->list_count() - 1; return ReverseIterator( data_.get(), last_id, data_->InnerListById(last_id)->LastElement(), 0); } template typename ListContainer::ReverseIterator ListContainer::rend() { return ReverseIterator(data_.get(), 0, NULL, size()); } template typename ListContainer::ConstIterator ListContainer::cbegin() const { if (data_->IsEmpty()) return ConstIterator(data_.get(), 0, NULL, 0); return ConstIterator(data_.get(), 0, data_->InnerListById(0)->Begin(), 0); } template typename ListContainer::ConstIterator ListContainer::cend() const { if (data_->IsEmpty()) return ConstIterator(data_.get(), 0, NULL, size()); size_t last_id = data_->list_count() - 1; return ConstIterator(data_.get(), last_id, NULL, size()); } template typename ListContainer::ConstIterator ListContainer::begin() const { return cbegin(); } template typename ListContainer::ConstIterator ListContainer::end() const { return cend(); } template typename ListContainer::Iterator ListContainer::begin() { if (data_->IsEmpty()) return Iterator(data_.get(), 0, NULL, 0); return Iterator(data_.get(), 0, data_->InnerListById(0)->Begin(), 0); } template typename ListContainer::Iterator ListContainer::end() { if (data_->IsEmpty()) return Iterator(data_.get(), 0, NULL, size()); size_t last_id = data_->list_count() - 1; return Iterator(data_.get(), last_id, NULL, size()); } template BaseElementType* ListContainer::front() { Iterator iter = begin(); return *iter; } template BaseElementType* ListContainer::back() { ReverseIterator iter = rbegin(); return *iter; } template const BaseElementType* ListContainer::front() const { ConstIterator iter = begin(); return *iter; } template const BaseElementType* ListContainer::back() const { ConstReverseIterator iter = rbegin(); return *iter; } template const BaseElementType* ListContainer::ElementAt( size_t index) const { DCHECK_LT(index, size()); size_t original_index = index; size_t list_index; for (list_index = 0; list_index < data_->list_count(); ++list_index) { size_t current_size = data_->InnerListById(list_index)->size; if (index < current_size) break; index -= current_size; } return *ConstIterator(data_.get(), list_index, data_->InnerListById(list_index)->ElementAt(index), original_index); } template BaseElementType* ListContainer::ElementAt(size_t index) { DCHECK_LT(index, size()); size_t original_index = index; size_t list_index; for (list_index = 0; list_index < data_->list_count(); ++list_index) { size_t current_size = data_->InnerListById(list_index)->size; if (index < current_size) break; index -= current_size; } return *Iterator(data_.get(), list_index, data_->InnerListById(list_index)->ElementAt(index), original_index); } template BaseElementType* ListContainer::Allocate( size_t size_of_actual_element_in_bytes) { DCHECK_LE(size_of_actual_element_in_bytes, data_->element_size()); void* result = data_->Allocate(); return static_cast(result); } template size_t ListContainer::size() const { return data_->size(); } template bool ListContainer::empty() const { return data_->IsEmpty(); } template void ListContainer::clear() { for (Iterator i = begin(); i != end(); ++i) { i->~BaseElementType(); } data_->Clear(); } template size_t ListContainer< BaseElementType>::AvailableSizeWithoutAnotherAllocationForTesting() const { return data_->NumAvailableElementsInLastList(); } // ListContainer::Iterator ///////////////////////////////////////////////// template ListContainer::Iterator::Iterator( ListContainerCharAllocator* container, size_t vector_ind, char* item_iter, size_t index) : PositionInListContainerCharAllocator(container, vector_ind, item_iter), index_(index) { } template ListContainer::Iterator::~Iterator() { } template BaseElementType* ListContainer::Iterator::operator->() const { return reinterpret_cast(this->item_iterator); } template BaseElementType* ListContainer::Iterator::operator*() const { return reinterpret_cast(this->item_iterator); } template typename ListContainer::Iterator ListContainer::Iterator:: operator++(int unused_post_increment) { Iterator tmp = *this; operator++(); return tmp; } template typename ListContainer::Iterator& ListContainer::Iterator:: operator++() { this->Increment(); ++index_; return *this; } template size_t ListContainer::Iterator::index() const { return index_; } // ListContainer::ConstIterator ///////////////////////////////////////////////// template ListContainer::ConstIterator::ConstIterator( const typename ListContainer::Iterator& other) : PositionInListContainerCharAllocator(other), index_(other.index()) { } template ListContainer::ConstIterator::ConstIterator( ListContainerCharAllocator* container, size_t vector_ind, char* item_iter, size_t index) : PositionInListContainerCharAllocator(container, vector_ind, item_iter), index_(index) { } template ListContainer::ConstIterator::~ConstIterator() { } template const BaseElementType* ListContainer::ConstIterator:: operator->() const { return reinterpret_cast(this->item_iterator); } template const BaseElementType* ListContainer::ConstIterator:: operator*() const { return reinterpret_cast(this->item_iterator); } template typename ListContainer::ConstIterator ListContainer::ConstIterator:: operator++(int unused_post_increment) { ConstIterator tmp = *this; operator++(); return tmp; } template typename ListContainer::ConstIterator& ListContainer::ConstIterator:: operator++() { this->Increment(); ++index_; return *this; } template size_t ListContainer::ConstIterator::index() const { return index_; } // ListContainer::ReverseIterator ///////////////////////////////////////////////// template ListContainer::ReverseIterator::ReverseIterator( ListContainerCharAllocator* container, size_t vector_ind, char* item_iter, size_t index) : PositionInListContainerCharAllocator(container, vector_ind, item_iter), index_(index) { } template ListContainer::ReverseIterator::~ReverseIterator() { } template BaseElementType* ListContainer::ReverseIterator::operator->() const { return reinterpret_cast(this->item_iterator); } template BaseElementType* ListContainer::ReverseIterator::operator*() const { return reinterpret_cast(this->item_iterator); } template typename ListContainer::ReverseIterator ListContainer::ReverseIterator:: operator++(int unused_post_increment) { ReverseIterator tmp = *this; operator++(); return tmp; } template typename ListContainer::ReverseIterator& ListContainer::ReverseIterator:: operator++() { this->ReverseIncrement(); ++index_; return *this; } template size_t ListContainer::ReverseIterator::index() const { return index_; } // ListContainer::ConstReverseIterator ///////////////////////////////////////////////// template ListContainer::ConstReverseIterator::ConstReverseIterator( const typename ListContainer::ReverseIterator& other) : PositionInListContainerCharAllocator(other), index_(other.index()) { } template ListContainer::ConstReverseIterator::ConstReverseIterator( ListContainerCharAllocator* container, size_t vector_ind, char* item_iter, size_t index) : PositionInListContainerCharAllocator(container, vector_ind, item_iter), index_(index) { } template ListContainer::ConstReverseIterator::~ConstReverseIterator() { } template const BaseElementType* ListContainer::ConstReverseIterator:: operator->() const { return reinterpret_cast(this->item_iterator); } template const BaseElementType* ListContainer::ConstReverseIterator:: operator*() const { return reinterpret_cast(this->item_iterator); } template typename ListContainer::ConstReverseIterator ListContainer::ConstReverseIterator:: operator++(int unused_post_increment) { ConstReverseIterator tmp = *this; operator++(); return tmp; } template typename ListContainer::ConstReverseIterator& ListContainer::ConstReverseIterator:: operator++() { this->ReverseIncrement(); ++index_; return *this; } template size_t ListContainer::ConstReverseIterator::index() const { return index_; } template class ListContainer; template class ListContainer; } // namespace cc