Commit 3bcc3dfc authored by weiliangc's avatar weiliangc Committed by Commit bot

Revert of Class for allocating a chunk of memory for RenderPass (patchset #31...

Revert of Class for allocating a chunk of memory for RenderPass (patchset #31 id:660001 of https://codereview.chromium.org/400463002/)

Reason for revert:
Broke cc_unittest for Linux ASan bot

Original issue's description:
> Class for allocating a chunk of memory for RenderPass
>
> For DrawQuads and SharedQuadState, RenderPass used allocate them one by
> one whenever needed. This new class helps RenderPass manages allocation
> and iteration of those two types. This container allocates a chunk of
> memory at one time and hands out raw pointers. It also provides iterator
> and reverse iterators for going through its contents.
>
> Unittest for ListContainer makes sure the raw pointers it hands out are
> valid and iterator has same behavior as vector iterators.
>
> Follows 398533002, and 404563005.
>
> BUG=344962
>
> Committed: https://crrev.com/6ae8c50c839a8c0d8fb399578256c754ed3ce39a
> Cr-Commit-Position: refs/heads/master@{#296100}

TBR=danakj@chromium.org,jamesr@chromium.org
NOTREECHECKS=true
NOTRY=true
BUG=344962

Review URL: https://codereview.chromium.org/595733002

Cr-Commit-Position: refs/heads/master@{#296119}
parent e07573d4
...@@ -292,8 +292,6 @@ component("cc") { ...@@ -292,8 +292,6 @@ component("cc") {
"quads/io_surface_draw_quad.cc", "quads/io_surface_draw_quad.cc",
"quads/io_surface_draw_quad.h", "quads/io_surface_draw_quad.h",
"quads/largest_draw_quad.h", "quads/largest_draw_quad.h",
"quads/list_container.cc",
"quads/list_container.h",
"quads/picture_draw_quad.cc", "quads/picture_draw_quad.cc",
"quads/picture_draw_quad.h", "quads/picture_draw_quad.h",
"quads/render_pass.cc", "quads/render_pass.cc",
...@@ -718,7 +716,6 @@ test("cc_unittests") { ...@@ -718,7 +716,6 @@ test("cc_unittests") {
"output/shader_unittest.cc", "output/shader_unittest.cc",
"output/software_renderer_unittest.cc", "output/software_renderer_unittest.cc",
"quads/draw_quad_unittest.cc", "quads/draw_quad_unittest.cc",
"quads/list_container_unittest.cc",
"quads/render_pass_unittest.cc", "quads/render_pass_unittest.cc",
"resources/layer_quad_unittest.cc", "resources/layer_quad_unittest.cc",
"resources/picture_layer_tiling_set_unittest.cc", "resources/picture_layer_tiling_set_unittest.cc",
......
...@@ -320,8 +320,6 @@ ...@@ -320,8 +320,6 @@
'quads/io_surface_draw_quad.cc', 'quads/io_surface_draw_quad.cc',
'quads/io_surface_draw_quad.h', 'quads/io_surface_draw_quad.h',
'quads/largest_draw_quad.h', 'quads/largest_draw_quad.h',
'quads/list_container.cc',
'quads/list_container.h',
'quads/picture_draw_quad.cc', 'quads/picture_draw_quad.cc',
'quads/picture_draw_quad.h', 'quads/picture_draw_quad.h',
'quads/render_pass.cc', 'quads/render_pass.cc',
......
...@@ -71,7 +71,6 @@ ...@@ -71,7 +71,6 @@
'output/software_renderer_unittest.cc', 'output/software_renderer_unittest.cc',
'quads/draw_polygon_unittest.cc', 'quads/draw_polygon_unittest.cc',
'quads/draw_quad_unittest.cc', 'quads/draw_quad_unittest.cc',
'quads/list_container_unittest.cc',
'quads/render_pass_unittest.cc', 'quads/render_pass_unittest.cc',
'resources/layer_quad_unittest.cc', 'resources/layer_quad_unittest.cc',
'resources/picture_layer_tiling_set_unittest.cc', 'resources/picture_layer_tiling_set_unittest.cc',
......
// 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 <algorithm>
#include <vector>
#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 <typename BaseElementType>
class ListContainer<BaseElementType>::ListContainerCharAllocator {
public:
// ListContainerCharAllocator::InnerList
/////////////////////////////////////////////
// This class holds the raw memory chunk, as well as information about its
// size and availability.
struct InnerList {
scoped_ptr<char> 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; }
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) {
DCHECK_NE(0u, element_count);
AllocateNewList(element_count);
}
~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<InnerList>::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<InnerList> 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 = make_scoped_ptr(new char[list->capacity * list->step]);
}
size_t NumAvailableElementsInLastList() const {
return last_list_->NumElementsAvailable();
}
private:
ScopedPtrVector<InnerList> storage_;
const size_t element_size_;
size_t size_;
size_t list_count_;
InnerList* last_list_;
DISALLOW_COPY_AND_ASSIGN(ListContainerCharAllocator);
};
// PositionInListContainerCharAllocator
//////////////////////////////////////////////////////
template <typename BaseElementType>
ListContainer<BaseElementType>::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 <typename BaseElementType>
ListContainer<BaseElementType>::PositionInListContainerCharAllocator::
PositionInListContainerCharAllocator(
typename ListContainer<BaseElementType>::ListContainerCharAllocator*
container,
size_t vector_ind,
char* item_iter)
: ptr_to_container(container),
vector_index(vector_ind),
item_iterator(item_iter) {
}
template <typename BaseElementType>
bool ListContainer<BaseElementType>::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 <typename BaseElementType>
bool ListContainer<BaseElementType>::PositionInListContainerCharAllocator::
operator!=(const typename ListContainer<
BaseElementType>::PositionInListContainerCharAllocator& other) const {
return !(*this == other);
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::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 BaseElementType>
typename ListContainer<BaseElementType>::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 <typename BaseElementType>
ListContainer<BaseElementType>::ListContainer(size_t max_size_for_derived_class)
: data_(new ListContainerCharAllocator(max_size_for_derived_class)) {
}
template <typename BaseElementType>
ListContainer<BaseElementType>::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 <typename BaseElementType>
ListContainer<BaseElementType>::ListContainer()
: data_(new ListContainerCharAllocator(sizeof(BaseElementType))) {
}
template <typename BaseElementType>
ListContainer<BaseElementType>::~ListContainer() {
for (Iterator i = begin(); i != end(); ++i) {
i->~BaseElementType();
}
}
template <typename BaseElementType>
void ListContainer<BaseElementType>::EraseAndInvalidateAllPointers(
typename ListContainer<BaseElementType>::Iterator position) {
BaseElementType* item = &*position;
item->~BaseElementType();
data_->Erase(position);
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ConstReverseIterator
ListContainer<BaseElementType>::rbegin() const {
if (data_->IsEmpty())
return ConstReverseIterator(data_.get(), 0, NULL);
size_t last_id = data_->list_count() - 1;
return ConstReverseIterator(
data_.get(), last_id, data_->InnerListById(last_id)->LastElement());
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ConstReverseIterator
ListContainer<BaseElementType>::rend() const {
return ConstReverseIterator(data_.get(), 0, NULL);
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ReverseIterator
ListContainer<BaseElementType>::rbegin() {
if (data_->IsEmpty())
return ReverseIterator(data_.get(), 0, NULL);
size_t last_id = data_->list_count() - 1;
return ReverseIterator(
data_.get(), last_id, data_->InnerListById(last_id)->LastElement());
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ReverseIterator
ListContainer<BaseElementType>::rend() {
return ReverseIterator(data_.get(), 0, NULL);
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ConstIterator
ListContainer<BaseElementType>::begin() const {
if (data_->IsEmpty())
return ConstIterator(data_.get(), 0, NULL);
return ConstIterator(data_.get(), 0, data_->InnerListById(0)->Begin());
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ConstIterator
ListContainer<BaseElementType>::end() const {
if (data_->IsEmpty())
return ConstIterator(data_.get(), 0, NULL);
size_t last_id = data_->list_count() - 1;
return ConstIterator(data_.get(), last_id, NULL);
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::Iterator
ListContainer<BaseElementType>::begin() {
if (data_->IsEmpty())
return Iterator(data_.get(), 0, NULL);
return Iterator(data_.get(), 0, data_->InnerListById(0)->Begin());
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::Iterator
ListContainer<BaseElementType>::end() {
if (data_->IsEmpty())
return Iterator(data_.get(), 0, NULL);
size_t last_id = data_->list_count() - 1;
return Iterator(data_.get(), last_id, NULL);
}
template <typename BaseElementType>
BaseElementType* ListContainer<BaseElementType>::front() {
Iterator iter = begin();
return &*iter;
}
template <typename BaseElementType>
BaseElementType* ListContainer<BaseElementType>::back() {
ReverseIterator iter = rbegin();
return &*iter;
}
template <typename BaseElementType>
const BaseElementType* ListContainer<BaseElementType>::front() const {
ConstIterator iter = begin();
return &*iter;
}
template <typename BaseElementType>
const BaseElementType* ListContainer<BaseElementType>::back() const {
ConstReverseIterator iter = rbegin();
return &*iter;
}
template <typename BaseElementType>
BaseElementType* ListContainer<BaseElementType>::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<BaseElementType*>(result);
}
template <typename BaseElementType>
size_t ListContainer<BaseElementType>::size() const {
return data_->size();
}
template <typename BaseElementType>
bool ListContainer<BaseElementType>::empty() const {
return data_->IsEmpty();
}
template <typename BaseElementType>
void ListContainer<BaseElementType>::clear() {
for (Iterator i = begin(); i != end(); ++i) {
i->~BaseElementType();
}
data_->Clear();
}
template <typename BaseElementType>
size_t ListContainer<
BaseElementType>::AvailableSizeWithoutAnotherAllocationForTesting() const {
return data_->NumAvailableElementsInLastList();
}
// ListContainer::Iterator
/////////////////////////////////////////////////
template <typename BaseElementType>
ListContainer<BaseElementType>::Iterator::Iterator(
ListContainerCharAllocator* container,
size_t vector_ind,
char* item_iter)
: PositionInListContainerCharAllocator(container, vector_ind, item_iter) {
}
template <typename BaseElementType>
ListContainer<BaseElementType>::Iterator::~Iterator() {
}
template <typename BaseElementType>
BaseElementType* ListContainer<BaseElementType>::Iterator::operator->() const {
return reinterpret_cast<BaseElementType*>(this->item_iterator);
}
template <typename BaseElementType>
BaseElementType& ListContainer<BaseElementType>::Iterator::operator*() const {
return *(reinterpret_cast<BaseElementType*>(this->item_iterator));
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::Iterator
ListContainer<BaseElementType>::Iterator::
operator++(int unused_post_increment) {
Iterator tmp = *this;
operator++();
return tmp;
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::Iterator
ListContainer<BaseElementType>::Iterator::
operator++() {
this->Increment();
return *this;
}
// ListContainer::ConstIterator
/////////////////////////////////////////////////
template <typename BaseElementType>
ListContainer<BaseElementType>::ConstIterator::ConstIterator(
const typename ListContainer<BaseElementType>::Iterator& other)
: PositionInListContainerCharAllocator(other) {
}
template <typename BaseElementType>
ListContainer<BaseElementType>::ConstIterator::ConstIterator(
ListContainerCharAllocator* container,
size_t vector_ind,
char* item_iter)
: PositionInListContainerCharAllocator(container, vector_ind, item_iter) {
}
template <typename BaseElementType>
ListContainer<BaseElementType>::ConstIterator::~ConstIterator() {
}
template <typename BaseElementType>
const BaseElementType* ListContainer<BaseElementType>::ConstIterator::
operator->() const {
return reinterpret_cast<const BaseElementType*>(this->item_iterator);
}
template <typename BaseElementType>
const BaseElementType& ListContainer<BaseElementType>::ConstIterator::
operator*() const {
return *(reinterpret_cast<const BaseElementType*>(this->item_iterator));
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ConstIterator
ListContainer<BaseElementType>::ConstIterator::
operator++(int unused_post_increment) {
ConstIterator tmp = *this;
operator++();
return tmp;
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ConstIterator
ListContainer<BaseElementType>::ConstIterator::
operator++() {
this->Increment();
return *this;
}
// ListContainer::ReverseIterator
/////////////////////////////////////////////////
template <typename BaseElementType>
ListContainer<BaseElementType>::ReverseIterator::ReverseIterator(
ListContainerCharAllocator* container,
size_t vector_ind,
char* item_iter)
: PositionInListContainerCharAllocator(container, vector_ind, item_iter) {
}
template <typename BaseElementType>
ListContainer<BaseElementType>::ReverseIterator::~ReverseIterator() {
}
template <typename BaseElementType>
BaseElementType* ListContainer<BaseElementType>::ReverseIterator::operator->()
const {
return reinterpret_cast<BaseElementType*>(this->item_iterator);
}
template <typename BaseElementType>
BaseElementType& ListContainer<BaseElementType>::ReverseIterator::operator*()
const {
return *(reinterpret_cast<BaseElementType*>(this->item_iterator));
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ReverseIterator
ListContainer<BaseElementType>::ReverseIterator::
operator++(int unused_post_increment) {
ReverseIterator tmp = *this;
operator++();
return tmp;
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ReverseIterator
ListContainer<BaseElementType>::ReverseIterator::
operator++() {
this->ReverseIncrement();
return *this;
}
// ListContainer::ConstReverseIterator
/////////////////////////////////////////////////
template <typename BaseElementType>
ListContainer<BaseElementType>::ConstReverseIterator::ConstReverseIterator(
const typename ListContainer<BaseElementType>::ReverseIterator& other)
: PositionInListContainerCharAllocator(other) {
}
template <typename BaseElementType>
ListContainer<BaseElementType>::ConstReverseIterator::ConstReverseIterator(
ListContainerCharAllocator* container,
size_t vector_ind,
char* item_iter)
: PositionInListContainerCharAllocator(container, vector_ind, item_iter) {
}
template <typename BaseElementType>
ListContainer<BaseElementType>::ConstReverseIterator::~ConstReverseIterator() {
}
template <typename BaseElementType>
const BaseElementType* ListContainer<BaseElementType>::ConstReverseIterator::
operator->() const {
return reinterpret_cast<const BaseElementType*>(this->item_iterator);
}
template <typename BaseElementType>
const BaseElementType& ListContainer<BaseElementType>::ConstReverseIterator::
operator*() const {
return *(reinterpret_cast<const BaseElementType*>(this->item_iterator));
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ConstReverseIterator
ListContainer<BaseElementType>::ConstReverseIterator::
operator++(int unused_post_increment) {
ConstReverseIterator tmp = *this;
operator++();
return tmp;
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ConstReverseIterator
ListContainer<BaseElementType>::ConstReverseIterator::
operator++() {
this->ReverseIncrement();
return *this;
}
template class ListContainer<SharedQuadState>;
template class ListContainer<DrawQuad>;
} // namespace cc
// 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.
#ifndef CC_QUADS_LIST_CONTAINER_H_
#define CC_QUADS_LIST_CONTAINER_H_
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
namespace cc {
class SharedQuadState;
class DrawQuad;
// This class is a container type that handles allocating contiguous memory for
// new elements and traversing through elements with either iterator or reverse
// iterator. Since this container hands out raw pointers of its elements, it is
// very important that this container never reallocate its memory so those raw
// pointer will continue to be valid. This class is used to contain
// SharedQuadState or DrawQuad. Since the size of each DrawQuad varies, to hold
// DrawQuads, the allocations size of each element in this class is
// kLargestDrawQuad while BaseElementType is DrawQuad.
template <class BaseElementType>
class CC_EXPORT ListContainer {
public:
// BaseElementType is the type of raw pointers this class hands out; however,
// its derived classes might require different memory sizes.
// max_size_for_derived_class the largest memory size required for all the
// derived classes to use for allocation.
explicit ListContainer(size_t max_size_for_derived_class);
// This constructor omits input variable for max_size_for_derived_class. This
// is used when there is no derived classes from BaseElementType we need to
// worry about, and allocation size is just sizeof(BaseElementType).
ListContainer();
// This constructor reserves the requested memory up front so only a single
// allocation is needed.
ListContainer(size_t max_size_for_derived_class,
size_t num_of_elements_to_reserve_for);
~ListContainer();
// 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 CC_EXPORT ListContainerCharAllocator;
// This class points to a certain position inside memory of
// ListContainerCharAllocator. It is a base class for ListContainer iterators.
struct CC_EXPORT PositionInListContainerCharAllocator {
ListContainerCharAllocator* ptr_to_container;
size_t vector_index;
char* item_iterator;
PositionInListContainerCharAllocator(
const PositionInListContainerCharAllocator& other);
PositionInListContainerCharAllocator(ListContainerCharAllocator* container,
size_t vector_ind,
char* item_iter);
bool operator==(const PositionInListContainerCharAllocator& other) const;
bool operator!=(const PositionInListContainerCharAllocator& other) const;
PositionInListContainerCharAllocator Increment();
PositionInListContainerCharAllocator ReverseIncrement();
};
// Iterator classes that can be used to access data.
/////////////////////////////////////////////////////////////////
class CC_EXPORT Iterator : public PositionInListContainerCharAllocator {
// This class is only defined to forward iterate through
// ListContainerCharAllocator.
public:
Iterator(ListContainerCharAllocator* container,
size_t vector_ind,
char* item_iter);
~Iterator();
BaseElementType* operator->() const;
BaseElementType& operator*() const;
Iterator operator++(int unused_post_increment);
Iterator operator++();
};
class CC_EXPORT ConstIterator : public PositionInListContainerCharAllocator {
// This class is only defined to forward iterate through
// ListContainerCharAllocator.
public:
ConstIterator(ListContainerCharAllocator* container,
size_t vector_ind,
char* item_iter);
ConstIterator(const Iterator& other); // NOLINT
~ConstIterator();
const BaseElementType* operator->() const;
const BaseElementType& operator*() const;
ConstIterator operator++(int unused_post_increment);
ConstIterator operator++();
};
class CC_EXPORT ReverseIterator
: public PositionInListContainerCharAllocator {
// This class is only defined to reverse iterate through
// ListContainerCharAllocator.
public:
ReverseIterator(ListContainerCharAllocator* container,
size_t vector_ind,
char* item_iter);
~ReverseIterator();
BaseElementType* operator->() const;
BaseElementType& operator*() const;
ReverseIterator operator++(int unused_post_increment);
ReverseIterator operator++();
};
class CC_EXPORT ConstReverseIterator
: public PositionInListContainerCharAllocator {
// This class is only defined to reverse iterate through
// ListContainerCharAllocator.
public:
ConstReverseIterator(ListContainerCharAllocator* container,
size_t vector_ind,
char* item_iter);
ConstReverseIterator(const ReverseIterator& other); // NOLINT
~ConstReverseIterator();
const BaseElementType* operator->() const;
const BaseElementType& operator*() const;
ConstReverseIterator operator++(int unused_post_increment);
ConstReverseIterator operator++();
};
// When called, all raw pointers that have been handed out are no longer
// valid. Use with caution.
// This function does not deallocate memory.
void EraseAndInvalidateAllPointers(Iterator position);
ConstReverseIterator rbegin() const;
ConstReverseIterator rend() const;
ReverseIterator rbegin();
ReverseIterator rend();
ConstIterator begin() const;
ConstIterator end() const;
Iterator begin();
Iterator end();
BaseElementType* front();
BaseElementType* back();
const BaseElementType* front() const;
const BaseElementType* back() const;
// Take in derived element type and construct it at location generated by
// Allocate().
template <typename DerivedElementType>
DerivedElementType* AllocateAndConstruct() {
DerivedElementType* result =
new (Allocate(sizeof(DerivedElementType))) DerivedElementType;
return result;
}
size_t size() const;
bool empty() const;
void clear();
size_t AvailableSizeWithoutAnotherAllocationForTesting() const;
private:
// Hands out memory location for an element at the end of data structure.
BaseElementType* Allocate(size_t size_of_actual_element_in_bytes);
scoped_ptr<ListContainerCharAllocator> data_;
DISALLOW_COPY_AND_ASSIGN(ListContainer);
};
#if !defined(COMPILER_MSVC)
extern template class ListContainer<SharedQuadState>;
extern template class ListContainer<DrawQuad>;
#endif
} // namespace cc
#endif // CC_QUADS_LIST_CONTAINER_H_
// 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 <vector>
#include "cc/quads/draw_quad.h"
#include "cc/quads/largest_draw_quad.h"
#include "cc/quads/render_pass_draw_quad.h"
#include "cc/quads/shared_quad_state.h"
#include "cc/quads/stream_video_draw_quad.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
namespace {
int kMagicNumberToUseForDrawQuadOne = 42;
int kMagicNumberToUseForDrawQuadTwo = 314;
bool isConstSharedQuadStatePointer(const SharedQuadState* ptr) {
return true;
}
bool isConstSharedQuadStatePointer(SharedQuadState* ptr) {
return false;
}
class SimpleDrawQuad : public DrawQuad {
public:
virtual ~SimpleDrawQuad() {}
virtual void IterateResources(
const ResourceIteratorCallback& callback) OVERRIDE {}
void set_value(int val) { value = val; }
int get_value() { return value; }
virtual void ExtendValue(base::debug::TracedValue* value) const OVERRIDE {}
private:
int value;
};
class SimpleDrawQuadConstructMagicNumberOne : public SimpleDrawQuad {
public:
SimpleDrawQuadConstructMagicNumberOne() : SimpleDrawQuad() {
set_value(kMagicNumberToUseForDrawQuadOne);
}
};
class SimpleDrawQuadConstructMagicNumberTwo : public SimpleDrawQuad {
public:
SimpleDrawQuadConstructMagicNumberTwo() : SimpleDrawQuad() {
set_value(kMagicNumberToUseForDrawQuadTwo);
}
};
class MockDrawQuad : public DrawQuad {
public:
virtual ~MockDrawQuad() { Destruct(); }
virtual void IterateResources(
const ResourceIteratorCallback& callback) OVERRIDE {}
virtual void ExtendValue(base::debug::TracedValue* value) const OVERRIDE {}
MOCK_METHOD0(Destruct, void());
};
TEST(ListContainerTest, ConstructorCalledInAllocateAndConstruct) {
ListContainer<DrawQuad> list(sizeof(kLargestDrawQuad));
size_t size = 2;
SimpleDrawQuadConstructMagicNumberOne* dq_1 =
list.AllocateAndConstruct<SimpleDrawQuadConstructMagicNumberOne>();
SimpleDrawQuadConstructMagicNumberTwo* dq_2 =
list.AllocateAndConstruct<SimpleDrawQuadConstructMagicNumberTwo>();
EXPECT_EQ(size, list.size());
EXPECT_EQ(dq_1, list.front());
EXPECT_EQ(dq_2, list.back());
EXPECT_EQ(kMagicNumberToUseForDrawQuadOne, dq_1->get_value());
EXPECT_EQ(kMagicNumberToUseForDrawQuadTwo, dq_2->get_value());
}
TEST(ListContainerTest, DestructorCalled) {
ListContainer<DrawQuad> list(sizeof(kLargestDrawQuad));
size_t size = 1;
MockDrawQuad* dq_1 = list.AllocateAndConstruct<MockDrawQuad>();
EXPECT_CALL(*dq_1, Destruct());
EXPECT_EQ(size, list.size());
EXPECT_EQ(dq_1, list.front());
}
TEST(ListContainerTest, DestructorCalledOnceWhenClear) {
ListContainer<DrawQuad> list(sizeof(kLargestDrawQuad));
size_t size = 1;
MockDrawQuad* dq_1 = list.AllocateAndConstruct<MockDrawQuad>();
EXPECT_EQ(size, list.size());
EXPECT_EQ(dq_1, list.front());
// Make sure destructor is called once during clear, and won't be called
// again.
testing::MockFunction<void()> separator;
{
testing::InSequence s;
EXPECT_CALL(*dq_1, Destruct());
EXPECT_CALL(separator, Call());
EXPECT_CALL(*dq_1, Destruct()).Times(0);
}
list.clear();
separator.Call();
}
TEST(ListContainerTest, DestructorCalledOnceWhenErase) {
ListContainer<DrawQuad> list(sizeof(kLargestDrawQuad));
size_t size = 1;
MockDrawQuad* dq_1 = list.AllocateAndConstruct<MockDrawQuad>();
EXPECT_EQ(size, list.size());
EXPECT_EQ(dq_1, list.front());
// Make sure destructor is called once during clear, and won't be called
// again.
testing::MockFunction<void()> separator;
{
testing::InSequence s;
EXPECT_CALL(*dq_1, Destruct());
EXPECT_CALL(separator, Call());
EXPECT_CALL(*dq_1, Destruct()).Times(0);
}
list.EraseAndInvalidateAllPointers(list.begin());
separator.Call();
}
TEST(ListContainerTest, SimpleInsertionSharedQuadState) {
ListContainer<SharedQuadState> list;
size_t size = 3;
SharedQuadState* sqs_1 = list.AllocateAndConstruct<SharedQuadState>();
list.AllocateAndConstruct<SharedQuadState>();
SharedQuadState* sqs_3 = list.AllocateAndConstruct<SharedQuadState>();
EXPECT_EQ(size, list.size());
EXPECT_EQ(sqs_1, list.front());
EXPECT_EQ(sqs_3, list.back());
}
TEST(ListContainerTest, SimpleInsertionAndClearSharedQuadState) {
ListContainer<SharedQuadState> list;
EXPECT_TRUE(list.empty());
EXPECT_EQ(0u, list.size());
size_t size = 3;
SharedQuadState* sqs_1 = list.AllocateAndConstruct<SharedQuadState>();
list.AllocateAndConstruct<SharedQuadState>();
SharedQuadState* sqs_3 = list.AllocateAndConstruct<SharedQuadState>();
EXPECT_EQ(size, list.size());
EXPECT_EQ(sqs_1, list.front());
EXPECT_EQ(sqs_3, list.back());
EXPECT_FALSE(list.empty());
list.clear();
EXPECT_TRUE(list.empty());
EXPECT_EQ(0u, list.size());
}
TEST(ListContainerTest, SimpleInsertionClearAndInsertAgainSharedQuadState) {
ListContainer<SharedQuadState> list;
EXPECT_TRUE(list.empty());
EXPECT_EQ(0u, list.size());
size_t size = 2;
SharedQuadState* sqs_front = list.AllocateAndConstruct<SharedQuadState>();
SharedQuadState* sqs_back = list.AllocateAndConstruct<SharedQuadState>();
EXPECT_EQ(size, list.size());
EXPECT_EQ(sqs_front, list.front());
EXPECT_EQ(sqs_back, list.back());
EXPECT_FALSE(list.empty());
list.clear();
EXPECT_TRUE(list.empty());
EXPECT_EQ(0u, list.size());
size = 3;
sqs_front = list.AllocateAndConstruct<SharedQuadState>();
list.AllocateAndConstruct<SharedQuadState>();
sqs_back = list.AllocateAndConstruct<SharedQuadState>();
EXPECT_EQ(size, list.size());
EXPECT_EQ(sqs_front, list.front());
EXPECT_EQ(sqs_back, list.back());
EXPECT_FALSE(list.empty());
}
// This test is used to test when there is more than one allocation needed
// for, ListContainer can still perform like normal vector.
TEST(ListContainerTest,
SimpleInsertionTriggerMoreThanOneAllocationSharedQuadState) {
ListContainer<SharedQuadState> list(sizeof(SharedQuadState), 2);
std::vector<SharedQuadState*> sqs_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
sqs_list.push_back(list.AllocateAndConstruct<SharedQuadState>());
}
EXPECT_EQ(size, list.size());
ListContainer<SharedQuadState>::Iterator iter = list.begin();
for (std::vector<SharedQuadState*>::const_iterator sqs_iter =
sqs_list.begin();
sqs_iter != sqs_list.end();
++sqs_iter) {
EXPECT_EQ(*sqs_iter, &*iter);
++iter;
}
}
TEST(ListContainerTest,
CorrectAllocationSizeForMoreThanOneAllocationSharedQuadState) {
// Constructor sets the allocation size to 2. Every time ListContainer needs
// to allocate again, it doubles allocation size. In this test, 10 elements is
// needed, thus ListContainerShould allocate spaces 2, 4 and 8 elements.
ListContainer<SharedQuadState> list(sizeof(SharedQuadState), 2);
std::vector<SharedQuadState*> sqs_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
// Before asking for a new element, space available without another
// allocation follows.
switch (i) {
case 2:
case 6:
EXPECT_EQ(0u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
case 1:
case 5:
EXPECT_EQ(1u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
case 0:
case 4:
EXPECT_EQ(2u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
case 3:
EXPECT_EQ(3u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
case 9:
EXPECT_EQ(5u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
case 8:
EXPECT_EQ(6u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
case 7:
EXPECT_EQ(7u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
default:
break;
}
sqs_list.push_back(list.AllocateAndConstruct<SharedQuadState>());
// After asking for a new element, space available without another
// allocation follows.
switch (i) {
case 1:
case 5:
EXPECT_EQ(0u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
case 0:
case 4:
EXPECT_EQ(1u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
case 3:
EXPECT_EQ(2u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
case 2:
EXPECT_EQ(3u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
case 9:
EXPECT_EQ(4u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
case 8:
EXPECT_EQ(5u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
case 7:
EXPECT_EQ(6u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
case 6:
EXPECT_EQ(7u, list.AvailableSizeWithoutAnotherAllocationForTesting());
break;
default:
break;
}
}
EXPECT_EQ(size, list.size());
ListContainer<SharedQuadState>::Iterator iter = list.begin();
for (std::vector<SharedQuadState*>::const_iterator sqs_iter =
sqs_list.begin();
sqs_iter != sqs_list.end();
++sqs_iter) {
EXPECT_EQ(*sqs_iter, &*iter);
++iter;
}
}
TEST(ListContainerTest, SimpleIterationSharedQuadState) {
ListContainer<SharedQuadState> list;
std::vector<SharedQuadState*> sqs_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
sqs_list.push_back(list.AllocateAndConstruct<SharedQuadState>());
}
EXPECT_EQ(size, list.size());
size_t num_iters_in_list = 0;
{
std::vector<SharedQuadState*>::const_iterator sqs_iter = sqs_list.begin();
for (ListContainer<SharedQuadState>::Iterator iter = list.begin();
iter != list.end();
++iter) {
EXPECT_EQ(*sqs_iter, &*iter);
++num_iters_in_list;
++sqs_iter;
}
}
size_t num_iters_in_vector = 0;
{
ListContainer<SharedQuadState>::Iterator iter = list.begin();
for (std::vector<SharedQuadState*>::const_iterator sqs_iter =
sqs_list.begin();
sqs_iter != sqs_list.end();
++sqs_iter) {
EXPECT_EQ(*sqs_iter, &*iter);
++num_iters_in_vector;
++iter;
}
}
EXPECT_EQ(num_iters_in_vector, num_iters_in_list);
}
TEST(ListContainerTest, SimpleConstIteratorIterationSharedQuadState) {
ListContainer<SharedQuadState> list;
std::vector<const SharedQuadState*> sqs_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
sqs_list.push_back(list.AllocateAndConstruct<SharedQuadState>());
}
EXPECT_EQ(size, list.size());
{
std::vector<const SharedQuadState*>::const_iterator sqs_iter =
sqs_list.begin();
for (ListContainer<SharedQuadState>::ConstIterator iter = list.begin();
iter != list.end();
++iter) {
EXPECT_TRUE(isConstSharedQuadStatePointer(&*iter));
EXPECT_EQ(*sqs_iter, &*iter);
++sqs_iter;
}
}
{
std::vector<const SharedQuadState*>::const_iterator sqs_iter =
sqs_list.begin();
for (ListContainer<SharedQuadState>::Iterator iter = list.begin();
iter != list.end();
++iter) {
EXPECT_FALSE(isConstSharedQuadStatePointer(&*iter));
EXPECT_EQ(*sqs_iter, &*iter);
++sqs_iter;
}
}
{
ListContainer<SharedQuadState>::ConstIterator iter = list.begin();
for (std::vector<const SharedQuadState*>::const_iterator sqs_iter =
sqs_list.begin();
sqs_iter != sqs_list.end();
++sqs_iter) {
EXPECT_EQ(*sqs_iter, &*iter);
++iter;
}
}
}
TEST(ListContainerTest, SimpleReverseInsertionSharedQuadState) {
ListContainer<SharedQuadState> list;
std::vector<SharedQuadState*> sqs_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
sqs_list.push_back(list.AllocateAndConstruct<SharedQuadState>());
}
EXPECT_EQ(size, list.size());
{
std::vector<SharedQuadState*>::const_reverse_iterator sqs_iter =
sqs_list.rbegin();
for (ListContainer<SharedQuadState>::ReverseIterator iter = list.rbegin();
iter != list.rend();
++iter) {
EXPECT_EQ(*sqs_iter, &(*iter));
++sqs_iter;
}
}
{
ListContainer<SharedQuadState>::ReverseIterator iter = list.rbegin();
for (std::vector<SharedQuadState*>::reverse_iterator sqs_iter =
sqs_list.rbegin();
sqs_iter != sqs_list.rend();
++sqs_iter) {
EXPECT_EQ(*sqs_iter, &(*iter));
++iter;
}
}
}
TEST(ListContainerTest, SimpleDeletion) {
ListContainer<DrawQuad> list(sizeof(kLargestDrawQuad));
std::vector<SimpleDrawQuad*> sdq_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
sdq_list.push_back(list.AllocateAndConstruct<SimpleDrawQuad>());
sdq_list.back()->set_value(i);
}
EXPECT_EQ(size, list.size());
list.EraseAndInvalidateAllPointers(list.begin());
--size;
EXPECT_EQ(size, list.size());
int i = 1;
for (ListContainer<DrawQuad>::Iterator iter = list.begin();
iter != list.end();
++iter) {
EXPECT_EQ(i, static_cast<SimpleDrawQuad*>(&*iter)->get_value());
++i;
}
}
TEST(ListContainerTest, SimpleIterationAndManipulation) {
ListContainer<DrawQuad> list(sizeof(kLargestDrawQuad));
std::vector<SimpleDrawQuad*> sdq_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
SimpleDrawQuad* simple_dq = list.AllocateAndConstruct<SimpleDrawQuad>();
sdq_list.push_back(simple_dq);
}
EXPECT_EQ(size, list.size());
ListContainer<DrawQuad>::Iterator iter = list.begin();
for (int i = 0; i < 10; ++i) {
static_cast<SimpleDrawQuad*>(&*iter)->set_value(i);
++iter;
}
int i = 0;
for (std::vector<SimpleDrawQuad*>::const_iterator sdq_iter = sdq_list.begin();
sdq_iter < sdq_list.end();
++sdq_iter) {
EXPECT_EQ(i, (*sdq_iter)->get_value());
++i;
}
}
} // namespace
} // namespace cc
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment