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 IsEmpty() const { return !size
; }
57 bool IsFull() { return capacity
== size
; }
58 size_t NumElementsAvailable() const { return capacity
- size
; }
61 DCHECK_LT(size
, capacity
);
71 char* Begin() const { return data
.get(); }
72 char* End() const { return data
.get() + size
* step
; }
73 char* LastElement() const { return data
.get() + (size
- 1) * step
; }
74 char* ElementAt(size_t index
) const { return data
.get() + index
* step
; }
77 DISALLOW_COPY_AND_ASSIGN(InnerList
);
80 explicit ListContainerCharAllocator(size_t element_size
)
81 : element_size_(element_size
),
85 AllocateNewList(kDefaultNumElementTypesToReserve
);
86 last_list_
= storage_
[last_list_index_
];
89 ListContainerCharAllocator(size_t element_size
, size_t element_count
)
90 : element_size_(element_size
),
94 AllocateNewList(element_count
> 0 ? element_count
95 : kDefaultNumElementTypesToReserve
);
96 last_list_
= storage_
[last_list_index_
];
99 ~ListContainerCharAllocator() {}
102 if (last_list_
->IsFull()) {
103 // Only allocate a new list if there isn't a spare one still there from
105 if (last_list_index_
+ 1 >= storage_
.size())
106 AllocateNewList(last_list_
->capacity
* 2);
109 last_list_
= storage_
[last_list_index_
];
113 return last_list_
->AddElement();
116 size_t element_size() const { return element_size_
; }
117 size_t list_count() const { return storage_
.size(); }
118 size_t size() const { return size_
; }
119 bool IsEmpty() const { return size() == 0; }
121 size_t Capacity() const {
122 size_t capacity_sum
= 0;
123 for (const auto& inner_list
: storage_
)
124 capacity_sum
+= inner_list
->capacity
;
129 // Remove all except for the first InnerList.
130 DCHECK(!storage_
.empty());
131 storage_
.erase(storage_
.begin() + 1, storage_
.end());
132 last_list_index_
= 0;
133 last_list_
= storage_
[0];
134 last_list_
->size
= 0;
140 last_list_
->RemoveLast();
141 if (last_list_
->IsEmpty() && last_list_index_
> 0) {
143 last_list_
= storage_
[last_list_index_
];
145 // If there are now two empty inner lists, free one of them.
146 if (last_list_index_
+ 2 < storage_
.size())
152 void Erase(PositionInListContainerCharAllocator position
) {
153 DCHECK_EQ(this, position
.ptr_to_container
);
154 storage_
[position
.vector_index
]->Erase(position
.item_iterator
);
155 // TODO(weiliangc): Free the InnerList if it is empty.
159 InnerList
* InnerListById(size_t id
) const {
160 DCHECK_LT(id
, storage_
.size());
164 size_t FirstInnerListId() const {
165 // |size_| > 0 means that at least one vector in |storage_| will be
167 DCHECK_GT(size_
, 0u);
169 while (storage_
[id
]->size
== 0)
174 size_t LastInnerListId() const {
175 // |size_| > 0 means that at least one vector in |storage_| will be
177 DCHECK_GT(size_
, 0u);
178 size_t id
= storage_
.size() - 1;
179 while (storage_
[id
]->size
== 0)
184 size_t NumAvailableElementsInLastList() const {
185 return last_list_
->NumElementsAvailable();
189 void AllocateNewList(size_t list_size
) {
190 scoped_ptr
<InnerList
> new_list(new InnerList
);
191 new_list
->capacity
= list_size
;
193 new_list
->step
= element_size_
;
194 new_list
->data
.reset(new char[list_size
* element_size_
]);
195 storage_
.push_back(new_list
.Pass());
198 ScopedPtrVector
<InnerList
> storage_
;
199 const size_t element_size_
;
201 // The number of elements in the list.
204 // The index of the last list to have had elements added to it, or the only
205 // list if the container has not had elements added since being cleared.
206 size_t last_list_index_
;
208 // This is equivalent to |storage_[last_list_index_]|.
209 InnerList
* last_list_
;
211 DISALLOW_COPY_AND_ASSIGN(ListContainerCharAllocator
);
214 // PositionInListContainerCharAllocator
215 //////////////////////////////////////////////////////
216 ListContainerBase::PositionInListContainerCharAllocator::
217 PositionInListContainerCharAllocator(
218 const ListContainerBase::PositionInListContainerCharAllocator
& other
)
219 : ptr_to_container(other
.ptr_to_container
),
220 vector_index(other
.vector_index
),
221 item_iterator(other
.item_iterator
) {
224 ListContainerBase::PositionInListContainerCharAllocator::
225 PositionInListContainerCharAllocator(
226 ListContainerBase::ListContainerCharAllocator
* container
,
229 : ptr_to_container(container
),
230 vector_index(vector_ind
),
231 item_iterator(item_iter
) {
234 bool ListContainerBase::PositionInListContainerCharAllocator::operator==(
235 const ListContainerBase::PositionInListContainerCharAllocator
& other
)
237 DCHECK_EQ(ptr_to_container
, other
.ptr_to_container
);
238 return vector_index
== other
.vector_index
&&
239 item_iterator
== other
.item_iterator
;
242 bool ListContainerBase::PositionInListContainerCharAllocator::operator!=(
243 const ListContainerBase::PositionInListContainerCharAllocator
& other
)
245 return !(*this == other
);
248 ListContainerBase::PositionInListContainerCharAllocator
249 ListContainerBase::PositionInListContainerCharAllocator::Increment() {
250 ListContainerCharAllocator::InnerList
* list
=
251 ptr_to_container
->InnerListById(vector_index
);
252 if (item_iterator
== list
->LastElement()) {
254 while (vector_index
< ptr_to_container
->list_count()) {
255 if (ptr_to_container
->InnerListById(vector_index
)->size
!= 0)
259 if (vector_index
< ptr_to_container
->list_count())
260 item_iterator
= ptr_to_container
->InnerListById(vector_index
)->Begin();
262 item_iterator
= NULL
;
264 item_iterator
+= list
->step
;
269 ListContainerBase::PositionInListContainerCharAllocator
270 ListContainerBase::PositionInListContainerCharAllocator::ReverseIncrement() {
271 ListContainerCharAllocator::InnerList
* list
=
272 ptr_to_container
->InnerListById(vector_index
);
273 if (item_iterator
== list
->Begin()) {
275 // Since |vector_index| is unsigned, we compare < list_count() instead of
276 // comparing >= 0, as the variable will wrap around when it goes out of
278 while (vector_index
< ptr_to_container
->list_count()) {
279 if (ptr_to_container
->InnerListById(vector_index
)->size
!= 0)
283 if (vector_index
< ptr_to_container
->list_count()) {
285 ptr_to_container
->InnerListById(vector_index
)->LastElement();
287 item_iterator
= NULL
;
290 item_iterator
-= list
->step
;
296 ////////////////////////////////////////////
297 ListContainerBase::ListContainerBase(size_t max_size_for_derived_class
)
298 : data_(new ListContainerCharAllocator(max_size_for_derived_class
)) {
301 ListContainerBase::ListContainerBase(size_t max_size_for_derived_class
,
302 size_t num_of_elements_to_reserve_for
)
303 : data_(new ListContainerCharAllocator(max_size_for_derived_class
,
304 num_of_elements_to_reserve_for
)) {
307 ListContainerBase::~ListContainerBase() {
310 void ListContainerBase::RemoveLast() {
314 void ListContainerBase::EraseAndInvalidateAllPointers(
315 ListContainerBase::Iterator position
) {
316 data_
->Erase(position
);
319 ListContainerBase::ConstReverseIterator
ListContainerBase::crbegin() const {
320 if (data_
->IsEmpty())
323 size_t id
= data_
->LastInnerListId();
324 return ConstReverseIterator(data_
.get(), id
,
325 data_
->InnerListById(id
)->LastElement(), 0);
328 ListContainerBase::ConstReverseIterator
ListContainerBase::crend() const {
329 return ConstReverseIterator(data_
.get(), static_cast<size_t>(-1), NULL
,
333 ListContainerBase::ReverseIterator
ListContainerBase::rbegin() {
334 if (data_
->IsEmpty())
337 size_t id
= data_
->LastInnerListId();
338 return ReverseIterator(data_
.get(), id
,
339 data_
->InnerListById(id
)->LastElement(), 0);
342 ListContainerBase::ReverseIterator
ListContainerBase::rend() {
343 return ReverseIterator(data_
.get(), static_cast<size_t>(-1), NULL
, size());
346 ListContainerBase::ConstIterator
ListContainerBase::cbegin() const {
347 if (data_
->IsEmpty())
350 size_t id
= data_
->FirstInnerListId();
351 return ConstIterator(data_
.get(), id
, data_
->InnerListById(id
)->Begin(), 0);
354 ListContainerBase::ConstIterator
ListContainerBase::cend() const {
355 if (data_
->IsEmpty())
356 return ConstIterator(data_
.get(), 0, NULL
, size());
358 size_t id
= data_
->list_count();
359 return ConstIterator(data_
.get(), id
, NULL
, size());
362 ListContainerBase::Iterator
ListContainerBase::begin() {
363 if (data_
->IsEmpty())
366 size_t id
= data_
->FirstInnerListId();
367 return Iterator(data_
.get(), id
, data_
->InnerListById(id
)->Begin(), 0);
370 ListContainerBase::Iterator
ListContainerBase::end() {
371 if (data_
->IsEmpty())
372 return Iterator(data_
.get(), 0, NULL
, size());
374 size_t id
= data_
->list_count();
375 return Iterator(data_
.get(), id
, NULL
, size());
378 ListContainerBase::ConstIterator
ListContainerBase::IteratorAt(
379 size_t index
) const {
380 DCHECK_LT(index
, size());
381 size_t original_index
= index
;
383 for (list_index
= 0; list_index
< data_
->list_count(); ++list_index
) {
384 size_t current_size
= data_
->InnerListById(list_index
)->size
;
385 if (index
< current_size
)
387 index
-= current_size
;
389 return ConstIterator(data_
.get(), list_index
,
390 data_
->InnerListById(list_index
)->ElementAt(index
),
394 ListContainerBase::Iterator
ListContainerBase::IteratorAt(size_t index
) {
395 DCHECK_LT(index
, size());
396 size_t original_index
= index
;
398 for (list_index
= 0; list_index
< data_
->list_count(); ++list_index
) {
399 size_t current_size
= data_
->InnerListById(list_index
)->size
;
400 if (index
< current_size
)
402 index
-= current_size
;
404 return Iterator(data_
.get(), list_index
,
405 data_
->InnerListById(list_index
)->ElementAt(index
),
409 void* ListContainerBase::Allocate(size_t size_of_actual_element_in_bytes
) {
410 DCHECK_LE(size_of_actual_element_in_bytes
, data_
->element_size());
411 return data_
->Allocate();
414 size_t ListContainerBase::size() const {
415 return data_
->size();
418 bool ListContainerBase::empty() const {
419 return data_
->IsEmpty();
422 size_t ListContainerBase::MaxSizeForDerivedClass() const {
423 return data_
->element_size();
426 size_t ListContainerBase::GetCapacityInBytes() const {
427 return data_
->Capacity() * data_
->element_size();
430 void ListContainerBase::clear() {
434 size_t ListContainerBase::AvailableSizeWithoutAnotherAllocationForTesting()
436 return data_
->NumAvailableElementsInLastList();
439 // ListContainerBase::Iterator
440 /////////////////////////////////////////////////
441 ListContainerBase::Iterator::Iterator(ListContainerCharAllocator
* container
,
445 : PositionInListContainerCharAllocator(container
, vector_ind
, item_iter
),
449 ListContainerBase::Iterator::~Iterator() {
452 size_t ListContainerBase::Iterator::index() const {
456 // ListContainerBase::ConstIterator
457 /////////////////////////////////////////////////
458 ListContainerBase::ConstIterator::ConstIterator(
459 const ListContainerBase::Iterator
& other
)
460 : PositionInListContainerCharAllocator(other
), index_(other
.index()) {
463 ListContainerBase::ConstIterator::ConstIterator(
464 ListContainerCharAllocator
* container
,
468 : PositionInListContainerCharAllocator(container
, vector_ind
, item_iter
),
472 ListContainerBase::ConstIterator::~ConstIterator() {
475 size_t ListContainerBase::ConstIterator::index() const {
479 // ListContainerBase::ReverseIterator
480 /////////////////////////////////////////////////
481 ListContainerBase::ReverseIterator::ReverseIterator(
482 ListContainerCharAllocator
* container
,
486 : PositionInListContainerCharAllocator(container
, vector_ind
, item_iter
),
490 ListContainerBase::ReverseIterator::~ReverseIterator() {
493 size_t ListContainerBase::ReverseIterator::index() const {
497 // ListContainerBase::ConstReverseIterator
498 /////////////////////////////////////////////////
499 ListContainerBase::ConstReverseIterator::ConstReverseIterator(
500 const ListContainerBase::ReverseIterator
& other
)
501 : PositionInListContainerCharAllocator(other
), index_(other
.index()) {
504 ListContainerBase::ConstReverseIterator::ConstReverseIterator(
505 ListContainerCharAllocator
* container
,
509 : PositionInListContainerCharAllocator(container
, vector_ind
, item_iter
),
513 ListContainerBase::ConstReverseIterator::~ConstReverseIterator() {
516 size_t ListContainerBase::ConstReverseIterator::index() const {