1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/base/list_container.h"
10 #include "cc/base/scoped_ptr_vector.h"
13 const size_t kDefaultNumElementTypesToReserve
= 32;
18 // ListContainerCharAllocator
19 ////////////////////////////////////////////////////
20 // This class deals only with char* and void*. It does allocation and passing
21 // out raw pointers, as well as memory deallocation when being destroyed.
22 class ListContainerBase::ListContainerCharAllocator
{
24 // ListContainerCharAllocator::InnerList
25 /////////////////////////////////////////////
26 // This class holds the raw memory chunk, as well as information about its
27 // size and availability.
29 scoped_ptr
<char[]> data
;
30 // The number of elements in total the memory can hold. The difference
31 // between capacity and size is the how many more elements this list can
34 // The number of elements have been put into this list.
36 // The size of each element is in bytes. This is used to move from between
37 // elements' memory locations.
40 InnerList() : capacity(0), size(0), step(0) {}
42 void Erase(char* position
) {
43 // Confident that destructor is called by caller of this function. Since
44 // ListContainerCharAllocator does not handle construction after
45 // allocation, it doesn't handle desctrution before deallocation.
46 DCHECK_LE(position
, LastElement());
47 DCHECK_GE(position
, Begin());
48 char* start
= position
+ step
;
49 std::copy(start
, End(), position
);
52 // Decrease capacity to avoid creating not full not last InnerList.
56 bool IsFull() { return capacity
== size
; }
57 size_t NumElementsAvailable() const { return capacity
- size
; }
60 DCHECK_LT(size
, capacity
);
65 char* Begin() const { return data
.get(); }
66 char* End() const { return data
.get() + size
* step
; }
67 char* LastElement() const { return data
.get() + (size
- 1) * step
; }
68 char* ElementAt(size_t index
) const { return data
.get() + index
* step
; }
71 DISALLOW_COPY_AND_ASSIGN(InnerList
);
74 explicit ListContainerCharAllocator(size_t element_size
)
75 : element_size_(element_size
),
79 AllocateNewList(kDefaultNumElementTypesToReserve
);
82 ListContainerCharAllocator(size_t element_size
, size_t element_count
)
83 : element_size_(element_size
),
87 AllocateNewList(element_count
> 0 ? element_count
88 : kDefaultNumElementTypesToReserve
);
91 ~ListContainerCharAllocator() {}
94 if (last_list_
->IsFull())
95 AllocateNewList(last_list_
->capacity
* 2);
98 return last_list_
->AddElement();
101 size_t element_size() const { return element_size_
; }
102 size_t list_count() const { return list_count_
; }
103 size_t size() const { return size_
; }
104 bool IsEmpty() const { return size() == 0; }
106 size_t Capacity() const {
107 size_t capacity_sum
= 0;
108 for (ScopedPtrVector
<InnerList
>::const_iterator iter
= storage_
.begin();
109 iter
!= storage_
.end(); ++iter
) {
110 capacity_sum
+= (*iter
)->capacity
;
116 size_t initial_allocation_size
= storage_
.front()->capacity
;
121 AllocateNewList(initial_allocation_size
);
124 void Erase(PositionInListContainerCharAllocator position
) {
125 DCHECK_EQ(this, position
.ptr_to_container
);
126 storage_
[position
.vector_index
]->Erase(position
.item_iterator
);
127 // TODO(weiliangc): Free the InnerList if it is empty.
131 InnerList
* InnerListById(size_t id
) const {
132 DCHECK_LT(id
, list_count_
);
136 size_t FirstInnerListId() const {
137 // |size_| > 0 means that at least one vector in |storage_| will be
139 DCHECK_GT(size_
, 0u);
141 while (storage_
[id
]->size
== 0)
146 size_t LastInnerListId() const {
147 // |size_| > 0 means that at least one vector in |storage_| will be
149 DCHECK_GT(size_
, 0u);
150 size_t id
= list_count_
- 1;
151 while (storage_
[id
]->size
== 0)
156 void AllocateNewList(size_t list_size
) {
158 scoped_ptr
<InnerList
> new_list(new InnerList
);
159 storage_
.push_back(new_list
.Pass());
160 last_list_
= storage_
.back();
161 InnerList
* list
= last_list_
;
162 list
->capacity
= list_size
;
164 list
->step
= element_size_
;
165 list
->data
.reset(new char[list
->capacity
* list
->step
]);
168 size_t NumAvailableElementsInLastList() const {
169 return last_list_
->NumElementsAvailable();
173 ScopedPtrVector
<InnerList
> storage_
;
174 const size_t element_size_
;
177 InnerList
* last_list_
;
179 DISALLOW_COPY_AND_ASSIGN(ListContainerCharAllocator
);
182 // PositionInListContainerCharAllocator
183 //////////////////////////////////////////////////////
184 ListContainerBase::PositionInListContainerCharAllocator::
185 PositionInListContainerCharAllocator(
186 const ListContainerBase::PositionInListContainerCharAllocator
& other
)
187 : ptr_to_container(other
.ptr_to_container
),
188 vector_index(other
.vector_index
),
189 item_iterator(other
.item_iterator
) {
192 ListContainerBase::PositionInListContainerCharAllocator::
193 PositionInListContainerCharAllocator(
194 ListContainerBase::ListContainerCharAllocator
* container
,
197 : ptr_to_container(container
),
198 vector_index(vector_ind
),
199 item_iterator(item_iter
) {
202 bool ListContainerBase::PositionInListContainerCharAllocator::operator==(
203 const ListContainerBase::PositionInListContainerCharAllocator
& other
)
205 DCHECK_EQ(ptr_to_container
, other
.ptr_to_container
);
206 return vector_index
== other
.vector_index
&&
207 item_iterator
== other
.item_iterator
;
210 bool ListContainerBase::PositionInListContainerCharAllocator::operator!=(
211 const ListContainerBase::PositionInListContainerCharAllocator
& other
)
213 return !(*this == other
);
216 ListContainerBase::PositionInListContainerCharAllocator
217 ListContainerBase::PositionInListContainerCharAllocator::Increment() {
218 ListContainerCharAllocator::InnerList
* list
=
219 ptr_to_container
->InnerListById(vector_index
);
220 if (item_iterator
== list
->LastElement()) {
222 while (vector_index
< ptr_to_container
->list_count()) {
223 if (ptr_to_container
->InnerListById(vector_index
)->size
!= 0)
227 if (vector_index
< ptr_to_container
->list_count())
228 item_iterator
= ptr_to_container
->InnerListById(vector_index
)->Begin();
230 item_iterator
= NULL
;
232 item_iterator
+= list
->step
;
237 ListContainerBase::PositionInListContainerCharAllocator
238 ListContainerBase::PositionInListContainerCharAllocator::ReverseIncrement() {
239 ListContainerCharAllocator::InnerList
* list
=
240 ptr_to_container
->InnerListById(vector_index
);
241 if (item_iterator
== list
->Begin()) {
243 // Since |vector_index| is unsigned, we compare < list_count() instead of
244 // comparing >= 0, as the variable will wrap around when it goes out of
246 while (vector_index
< ptr_to_container
->list_count()) {
247 if (ptr_to_container
->InnerListById(vector_index
)->size
!= 0)
251 if (vector_index
< ptr_to_container
->list_count()) {
253 ptr_to_container
->InnerListById(vector_index
)->LastElement();
255 item_iterator
= NULL
;
258 item_iterator
-= list
->step
;
264 ////////////////////////////////////////////
265 ListContainerBase::ListContainerBase(size_t max_size_for_derived_class
)
266 : data_(new ListContainerCharAllocator(max_size_for_derived_class
)) {
269 ListContainerBase::ListContainerBase(size_t max_size_for_derived_class
,
270 size_t num_of_elements_to_reserve_for
)
271 : data_(new ListContainerCharAllocator(max_size_for_derived_class
,
272 num_of_elements_to_reserve_for
)) {
275 ListContainerBase::~ListContainerBase() {
278 void ListContainerBase::EraseAndInvalidateAllPointers(
279 ListContainerBase::Iterator position
) {
280 data_
->Erase(position
);
283 ListContainerBase::ConstReverseIterator
ListContainerBase::crbegin() const {
284 if (data_
->IsEmpty())
287 size_t id
= data_
->LastInnerListId();
288 return ConstReverseIterator(data_
.get(), id
,
289 data_
->InnerListById(id
)->LastElement(), 0);
292 ListContainerBase::ConstReverseIterator
ListContainerBase::crend() const {
293 return ConstReverseIterator(data_
.get(), static_cast<size_t>(-1), NULL
,
297 ListContainerBase::ReverseIterator
ListContainerBase::rbegin() {
298 if (data_
->IsEmpty())
301 size_t id
= data_
->LastInnerListId();
302 return ReverseIterator(data_
.get(), id
,
303 data_
->InnerListById(id
)->LastElement(), 0);
306 ListContainerBase::ReverseIterator
ListContainerBase::rend() {
307 return ReverseIterator(data_
.get(), static_cast<size_t>(-1), NULL
, size());
310 ListContainerBase::ConstIterator
ListContainerBase::cbegin() const {
311 if (data_
->IsEmpty())
314 size_t id
= data_
->FirstInnerListId();
315 return ConstIterator(data_
.get(), id
, data_
->InnerListById(id
)->Begin(), 0);
318 ListContainerBase::ConstIterator
ListContainerBase::cend() const {
319 if (data_
->IsEmpty())
320 return ConstIterator(data_
.get(), 0, NULL
, size());
322 size_t id
= data_
->list_count();
323 return ConstIterator(data_
.get(), id
, NULL
, size());
326 ListContainerBase::Iterator
ListContainerBase::begin() {
327 if (data_
->IsEmpty())
330 size_t id
= data_
->FirstInnerListId();
331 return Iterator(data_
.get(), id
, data_
->InnerListById(id
)->Begin(), 0);
334 ListContainerBase::Iterator
ListContainerBase::end() {
335 if (data_
->IsEmpty())
336 return Iterator(data_
.get(), 0, NULL
, size());
338 size_t id
= data_
->list_count();
339 return Iterator(data_
.get(), id
, NULL
, size());
342 ListContainerBase::ConstIterator
ListContainerBase::IteratorAt(
343 size_t index
) const {
344 DCHECK_LT(index
, size());
345 size_t original_index
= index
;
347 for (list_index
= 0; list_index
< data_
->list_count(); ++list_index
) {
348 size_t current_size
= data_
->InnerListById(list_index
)->size
;
349 if (index
< current_size
)
351 index
-= current_size
;
353 return ConstIterator(data_
.get(), list_index
,
354 data_
->InnerListById(list_index
)->ElementAt(index
),
358 ListContainerBase::Iterator
ListContainerBase::IteratorAt(size_t index
) {
359 DCHECK_LT(index
, size());
360 size_t original_index
= index
;
362 for (list_index
= 0; list_index
< data_
->list_count(); ++list_index
) {
363 size_t current_size
= data_
->InnerListById(list_index
)->size
;
364 if (index
< current_size
)
366 index
-= current_size
;
368 return Iterator(data_
.get(), list_index
,
369 data_
->InnerListById(list_index
)->ElementAt(index
),
373 void* ListContainerBase::Allocate(size_t size_of_actual_element_in_bytes
) {
374 DCHECK_LE(size_of_actual_element_in_bytes
, data_
->element_size());
375 return data_
->Allocate();
378 size_t ListContainerBase::size() const {
379 return data_
->size();
382 bool ListContainerBase::empty() const {
383 return data_
->IsEmpty();
386 void ListContainerBase::clear() {
390 size_t ListContainerBase::AvailableSizeWithoutAnotherAllocationForTesting()
392 return data_
->NumAvailableElementsInLastList();
395 // ListContainerBase::Iterator
396 /////////////////////////////////////////////////
397 ListContainerBase::Iterator::Iterator(ListContainerCharAllocator
* container
,
401 : PositionInListContainerCharAllocator(container
, vector_ind
, item_iter
),
405 ListContainerBase::Iterator::~Iterator() {
408 size_t ListContainerBase::Iterator::index() const {
412 // ListContainerBase::ConstIterator
413 /////////////////////////////////////////////////
414 ListContainerBase::ConstIterator::ConstIterator(
415 const ListContainerBase::Iterator
& other
)
416 : PositionInListContainerCharAllocator(other
), index_(other
.index()) {
419 ListContainerBase::ConstIterator::ConstIterator(
420 ListContainerCharAllocator
* container
,
424 : PositionInListContainerCharAllocator(container
, vector_ind
, item_iter
),
428 ListContainerBase::ConstIterator::~ConstIterator() {
431 size_t ListContainerBase::ConstIterator::index() const {
435 // ListContainerBase::ReverseIterator
436 /////////////////////////////////////////////////
437 ListContainerBase::ReverseIterator::ReverseIterator(
438 ListContainerCharAllocator
* container
,
442 : PositionInListContainerCharAllocator(container
, vector_ind
, item_iter
),
446 ListContainerBase::ReverseIterator::~ReverseIterator() {
449 size_t ListContainerBase::ReverseIterator::index() const {
453 // ListContainerBase::ConstReverseIterator
454 /////////////////////////////////////////////////
455 ListContainerBase::ConstReverseIterator::ConstReverseIterator(
456 const ListContainerBase::ReverseIterator
& other
)
457 : PositionInListContainerCharAllocator(other
), index_(other
.index()) {
460 ListContainerBase::ConstReverseIterator::ConstReverseIterator(
461 ListContainerCharAllocator
* container
,
465 : PositionInListContainerCharAllocator(container
, vector_ind
, item_iter
),
469 ListContainerBase::ConstReverseIterator::~ConstReverseIterator() {
472 size_t ListContainerBase::ConstReverseIterator::index() const {