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 void InsertBefore(char** position
, size_t count
) {
57 DCHECK_LE(*position
, LastElement() + step
);
58 DCHECK_GE(*position
, Begin());
60 // Adjust the size and capacity
61 size_t old_size
= size
;
65 // Allocate the new data and update the iterator's pointer.
66 scoped_ptr
<char[]> new_data(new char[size
* step
]);
67 size_t position_offset
= *position
- Begin();
68 *position
= new_data
.get() + position_offset
;
70 // Copy the data before the inserted segment
71 memcpy(new_data
.get(), data
.get(), position_offset
);
72 // Copy the data after the inserted segment.
73 memcpy(new_data
.get() + position_offset
+ count
* step
,
74 data
.get() + position_offset
, old_size
* step
- position_offset
);
78 bool IsEmpty() const { return !size
; }
79 bool IsFull() { return capacity
== size
; }
80 size_t NumElementsAvailable() const { return capacity
- size
; }
83 DCHECK_LT(size
, capacity
);
93 char* Begin() const { return data
.get(); }
94 char* End() const { return data
.get() + size
* step
; }
95 char* LastElement() const { return data
.get() + (size
- 1) * step
; }
96 char* ElementAt(size_t index
) const { return data
.get() + index
* step
; }
99 DISALLOW_COPY_AND_ASSIGN(InnerList
);
102 explicit ListContainerCharAllocator(size_t element_size
)
103 : element_size_(element_size
),
107 AllocateNewList(kDefaultNumElementTypesToReserve
);
108 last_list_
= storage_
[last_list_index_
];
111 ListContainerCharAllocator(size_t element_size
, size_t element_count
)
112 : element_size_(element_size
),
116 AllocateNewList(element_count
> 0 ? element_count
117 : kDefaultNumElementTypesToReserve
);
118 last_list_
= storage_
[last_list_index_
];
121 ~ListContainerCharAllocator() {}
124 if (last_list_
->IsFull()) {
125 // Only allocate a new list if there isn't a spare one still there from
127 if (last_list_index_
+ 1 >= storage_
.size())
128 AllocateNewList(last_list_
->capacity
* 2);
131 last_list_
= storage_
[last_list_index_
];
135 return last_list_
->AddElement();
138 size_t element_size() const { return element_size_
; }
139 size_t list_count() const { return storage_
.size(); }
140 size_t size() const { return size_
; }
141 bool IsEmpty() const { return size() == 0; }
143 size_t Capacity() const {
144 size_t capacity_sum
= 0;
145 for (const auto& inner_list
: storage_
)
146 capacity_sum
+= inner_list
->capacity
;
151 // Remove all except for the first InnerList.
152 DCHECK(!storage_
.empty());
153 storage_
.erase(storage_
.begin() + 1, storage_
.end());
154 last_list_index_
= 0;
155 last_list_
= storage_
[0];
156 last_list_
->size
= 0;
162 last_list_
->RemoveLast();
163 if (last_list_
->IsEmpty() && last_list_index_
> 0) {
165 last_list_
= storage_
[last_list_index_
];
167 // If there are now two empty inner lists, free one of them.
168 if (last_list_index_
+ 2 < storage_
.size())
174 void Erase(PositionInListContainerCharAllocator
* position
) {
175 DCHECK_EQ(this, position
->ptr_to_container
);
177 // Update |position| to point to the element after the erased element.
178 InnerList
* list
= storage_
[position
->vector_index
];
179 char* item_iterator
= position
->item_iterator
;
180 if (item_iterator
== list
->LastElement())
181 position
->Increment();
183 list
->Erase(item_iterator
);
184 // TODO(weiliangc): Free the InnerList if it is empty.
188 void InsertBefore(ListContainerBase::Iterator
* position
, size_t count
) {
192 // If |position| is End(), then append |count| elements at the end. This
193 // will happen to not invalidate any iterators or memory.
194 if (!position
->item_iterator
) {
195 // Set |position| to be the first inserted element.
197 position
->vector_index
= storage_
.size() - 1;
198 position
->item_iterator
= storage_
[position
->vector_index
]->LastElement();
199 // Allocate the rest.
200 for (size_t i
= 1; i
< count
; ++i
)
203 storage_
[position
->vector_index
]->InsertBefore(&position
->item_iterator
,
209 InnerList
* InnerListById(size_t id
) const {
210 DCHECK_LT(id
, storage_
.size());
214 size_t FirstInnerListId() const {
215 // |size_| > 0 means that at least one vector in |storage_| will be
217 DCHECK_GT(size_
, 0u);
219 while (storage_
[id
]->size
== 0)
224 size_t LastInnerListId() const {
225 // |size_| > 0 means that at least one vector in |storage_| will be
227 DCHECK_GT(size_
, 0u);
228 size_t id
= storage_
.size() - 1;
229 while (storage_
[id
]->size
== 0)
234 size_t NumAvailableElementsInLastList() const {
235 return last_list_
->NumElementsAvailable();
239 void AllocateNewList(size_t list_size
) {
240 scoped_ptr
<InnerList
> new_list(new InnerList
);
241 new_list
->capacity
= list_size
;
243 new_list
->step
= element_size_
;
244 new_list
->data
.reset(new char[list_size
* element_size_
]);
245 storage_
.push_back(new_list
.Pass());
248 ScopedPtrVector
<InnerList
> storage_
;
249 const size_t element_size_
;
251 // The number of elements in the list.
254 // The index of the last list to have had elements added to it, or the only
255 // list if the container has not had elements added since being cleared.
256 size_t last_list_index_
;
258 // This is equivalent to |storage_[last_list_index_]|.
259 InnerList
* last_list_
;
261 DISALLOW_COPY_AND_ASSIGN(ListContainerCharAllocator
);
264 // PositionInListContainerCharAllocator
265 //////////////////////////////////////////////////////
266 ListContainerBase::PositionInListContainerCharAllocator::
267 PositionInListContainerCharAllocator(
268 const ListContainerBase::PositionInListContainerCharAllocator
& other
)
269 : ptr_to_container(other
.ptr_to_container
),
270 vector_index(other
.vector_index
),
271 item_iterator(other
.item_iterator
) {
274 ListContainerBase::PositionInListContainerCharAllocator::
275 PositionInListContainerCharAllocator(
276 ListContainerBase::ListContainerCharAllocator
* container
,
279 : ptr_to_container(container
),
280 vector_index(vector_ind
),
281 item_iterator(item_iter
) {
284 bool ListContainerBase::PositionInListContainerCharAllocator::operator==(
285 const ListContainerBase::PositionInListContainerCharAllocator
& other
)
287 DCHECK_EQ(ptr_to_container
, other
.ptr_to_container
);
288 return vector_index
== other
.vector_index
&&
289 item_iterator
== other
.item_iterator
;
292 bool ListContainerBase::PositionInListContainerCharAllocator::operator!=(
293 const ListContainerBase::PositionInListContainerCharAllocator
& other
)
295 return !(*this == other
);
298 ListContainerBase::PositionInListContainerCharAllocator
299 ListContainerBase::PositionInListContainerCharAllocator::Increment() {
300 ListContainerCharAllocator::InnerList
* list
=
301 ptr_to_container
->InnerListById(vector_index
);
302 if (item_iterator
== list
->LastElement()) {
304 while (vector_index
< ptr_to_container
->list_count()) {
305 if (ptr_to_container
->InnerListById(vector_index
)->size
!= 0)
309 if (vector_index
< ptr_to_container
->list_count())
310 item_iterator
= ptr_to_container
->InnerListById(vector_index
)->Begin();
312 item_iterator
= NULL
;
314 item_iterator
+= list
->step
;
319 ListContainerBase::PositionInListContainerCharAllocator
320 ListContainerBase::PositionInListContainerCharAllocator::ReverseIncrement() {
321 ListContainerCharAllocator::InnerList
* list
=
322 ptr_to_container
->InnerListById(vector_index
);
323 if (item_iterator
== list
->Begin()) {
325 // Since |vector_index| is unsigned, we compare < list_count() instead of
326 // comparing >= 0, as the variable will wrap around when it goes out of
328 while (vector_index
< ptr_to_container
->list_count()) {
329 if (ptr_to_container
->InnerListById(vector_index
)->size
!= 0)
333 if (vector_index
< ptr_to_container
->list_count()) {
335 ptr_to_container
->InnerListById(vector_index
)->LastElement();
337 item_iterator
= NULL
;
340 item_iterator
-= list
->step
;
346 ////////////////////////////////////////////
347 ListContainerBase::ListContainerBase(size_t max_size_for_derived_class
)
348 : data_(new ListContainerCharAllocator(max_size_for_derived_class
)) {
351 ListContainerBase::ListContainerBase(size_t max_size_for_derived_class
,
352 size_t num_of_elements_to_reserve_for
)
353 : data_(new ListContainerCharAllocator(max_size_for_derived_class
,
354 num_of_elements_to_reserve_for
)) {
357 ListContainerBase::~ListContainerBase() {
360 void ListContainerBase::RemoveLast() {
364 void ListContainerBase::EraseAndInvalidateAllPointers(
365 ListContainerBase::Iterator
* position
) {
366 data_
->Erase(position
);
369 void ListContainerBase::InsertBeforeAndInvalidateAllPointers(
370 ListContainerBase::Iterator
* position
,
372 data_
->InsertBefore(position
, count
);
375 ListContainerBase::ConstReverseIterator
ListContainerBase::crbegin() const {
376 if (data_
->IsEmpty())
379 size_t id
= data_
->LastInnerListId();
380 return ConstReverseIterator(data_
.get(), id
,
381 data_
->InnerListById(id
)->LastElement(), 0);
384 ListContainerBase::ConstReverseIterator
ListContainerBase::crend() const {
385 return ConstReverseIterator(data_
.get(), static_cast<size_t>(-1), NULL
,
389 ListContainerBase::ReverseIterator
ListContainerBase::rbegin() {
390 if (data_
->IsEmpty())
393 size_t id
= data_
->LastInnerListId();
394 return ReverseIterator(data_
.get(), id
,
395 data_
->InnerListById(id
)->LastElement(), 0);
398 ListContainerBase::ReverseIterator
ListContainerBase::rend() {
399 return ReverseIterator(data_
.get(), static_cast<size_t>(-1), NULL
, size());
402 ListContainerBase::ConstIterator
ListContainerBase::cbegin() const {
403 if (data_
->IsEmpty())
406 size_t id
= data_
->FirstInnerListId();
407 return ConstIterator(data_
.get(), id
, data_
->InnerListById(id
)->Begin(), 0);
410 ListContainerBase::ConstIterator
ListContainerBase::cend() const {
411 if (data_
->IsEmpty())
412 return ConstIterator(data_
.get(), 0, NULL
, size());
414 size_t id
= data_
->list_count();
415 return ConstIterator(data_
.get(), id
, NULL
, size());
418 ListContainerBase::Iterator
ListContainerBase::begin() {
419 if (data_
->IsEmpty())
422 size_t id
= data_
->FirstInnerListId();
423 return Iterator(data_
.get(), id
, data_
->InnerListById(id
)->Begin(), 0);
426 ListContainerBase::Iterator
ListContainerBase::end() {
427 if (data_
->IsEmpty())
428 return Iterator(data_
.get(), 0, NULL
, size());
430 size_t id
= data_
->list_count();
431 return Iterator(data_
.get(), id
, NULL
, size());
434 ListContainerBase::ConstIterator
ListContainerBase::IteratorAt(
435 size_t index
) const {
436 DCHECK_LT(index
, size());
437 size_t original_index
= index
;
439 for (list_index
= 0; list_index
< data_
->list_count(); ++list_index
) {
440 size_t current_size
= data_
->InnerListById(list_index
)->size
;
441 if (index
< current_size
)
443 index
-= current_size
;
445 return ConstIterator(data_
.get(), list_index
,
446 data_
->InnerListById(list_index
)->ElementAt(index
),
450 ListContainerBase::Iterator
ListContainerBase::IteratorAt(size_t index
) {
451 DCHECK_LT(index
, size());
452 size_t original_index
= index
;
454 for (list_index
= 0; list_index
< data_
->list_count(); ++list_index
) {
455 size_t current_size
= data_
->InnerListById(list_index
)->size
;
456 if (index
< current_size
)
458 index
-= current_size
;
460 return Iterator(data_
.get(), list_index
,
461 data_
->InnerListById(list_index
)->ElementAt(index
),
465 void* ListContainerBase::Allocate(size_t size_of_actual_element_in_bytes
) {
466 DCHECK_LE(size_of_actual_element_in_bytes
, data_
->element_size());
467 return data_
->Allocate();
470 size_t ListContainerBase::size() const {
471 return data_
->size();
474 bool ListContainerBase::empty() const {
475 return data_
->IsEmpty();
478 size_t ListContainerBase::MaxSizeForDerivedClass() const {
479 return data_
->element_size();
482 size_t ListContainerBase::GetCapacityInBytes() const {
483 return data_
->Capacity() * data_
->element_size();
486 void ListContainerBase::clear() {
490 size_t ListContainerBase::AvailableSizeWithoutAnotherAllocationForTesting()
492 return data_
->NumAvailableElementsInLastList();
495 // ListContainerBase::Iterator
496 /////////////////////////////////////////////////
497 ListContainerBase::Iterator::Iterator(ListContainerCharAllocator
* container
,
501 : PositionInListContainerCharAllocator(container
, vector_ind
, item_iter
),
505 ListContainerBase::Iterator::~Iterator() {
508 size_t ListContainerBase::Iterator::index() const {
512 // ListContainerBase::ConstIterator
513 /////////////////////////////////////////////////
514 ListContainerBase::ConstIterator::ConstIterator(
515 const ListContainerBase::Iterator
& other
)
516 : PositionInListContainerCharAllocator(other
), index_(other
.index()) {
519 ListContainerBase::ConstIterator::ConstIterator(
520 ListContainerCharAllocator
* container
,
524 : PositionInListContainerCharAllocator(container
, vector_ind
, item_iter
),
528 ListContainerBase::ConstIterator::~ConstIterator() {
531 size_t ListContainerBase::ConstIterator::index() const {
535 // ListContainerBase::ReverseIterator
536 /////////////////////////////////////////////////
537 ListContainerBase::ReverseIterator::ReverseIterator(
538 ListContainerCharAllocator
* container
,
542 : PositionInListContainerCharAllocator(container
, vector_ind
, item_iter
),
546 ListContainerBase::ReverseIterator::~ReverseIterator() {
549 size_t ListContainerBase::ReverseIterator::index() const {
553 // ListContainerBase::ConstReverseIterator
554 /////////////////////////////////////////////////
555 ListContainerBase::ConstReverseIterator::ConstReverseIterator(
556 const ListContainerBase::ReverseIterator
& other
)
557 : PositionInListContainerCharAllocator(other
), index_(other
.index()) {
560 ListContainerBase::ConstReverseIterator::ConstReverseIterator(
561 ListContainerCharAllocator
* container
,
565 : PositionInListContainerCharAllocator(container
, vector_ind
, item_iter
),
569 ListContainerBase::ConstReverseIterator::~ConstReverseIterator() {
572 size_t ListContainerBase::ConstReverseIterator::index() const {