Commit 6ae8c50c authored by weiliangc's avatar weiliangc Committed by Commit bot

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

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

Cr-Commit-Position: refs/heads/master@{#296100}
parent 7f437453
......@@ -292,6 +292,8 @@ component("cc") {
"quads/io_surface_draw_quad.cc",
"quads/io_surface_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.h",
"quads/render_pass.cc",
......@@ -716,6 +718,7 @@ test("cc_unittests") {
"output/shader_unittest.cc",
"output/software_renderer_unittest.cc",
"quads/draw_quad_unittest.cc",
"quads/list_container_unittest.cc",
"quads/render_pass_unittest.cc",
"resources/layer_quad_unittest.cc",
"resources/picture_layer_tiling_set_unittest.cc",
......
......@@ -320,6 +320,8 @@
'quads/io_surface_draw_quad.cc',
'quads/io_surface_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.h',
'quads/render_pass.cc',
......
......@@ -71,6 +71,7 @@
'output/software_renderer_unittest.cc',
'quads/draw_polygon_unittest.cc',
'quads/draw_quad_unittest.cc',
'quads/list_container_unittest.cc',
'quads/render_pass_unittest.cc',
'resources/layer_quad_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