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.
4
5 #include "cc/quads/list_container.h"
6
7 #include <algorithm>
8 #include <vector>
9
10 #include "cc/base/scoped_ptr_vector.h"
11 #include "cc/quads/draw_quad.h"
12 #include "cc/quads/shared_quad_state.h"
13
14 namespace {
15 const size_t kDefaultNumElementTypesToReserve = 32;
16 } // namespace
17
18 namespace cc {
19
20 // ListContainerCharAllocator
21 ////////////////////////////////////////////////////
22 // This class deals only with char* and void*. It does allocation and passing
23 // out raw pointers, as well as memory deallocation when being destroyed.
24 template <typename BaseElementType>
25 class ListContainer<BaseElementType>::ListContainerCharAllocator {
26 public:
27 // ListContainerCharAllocator::InnerList
28 /////////////////////////////////////////////
29 // This class holds the raw memory chunk, as well as information about its
30 // size and availability.
31 struct InnerList {
32 scoped_ptr<char[]> data;
33 // The number of elements in total the memory can hold. The difference
34 // between capacity and size is the how many more elements this list can
35 // hold.
36 size_t capacity;
37 // The number of elements have been put into this list.
38 size_t size;
39 // The size of each element is in bytes. This is used to move from between
40 // elements' memory locations.
41 size_t step;
42
InnerListcc::ListContainer::ListContainerCharAllocator::InnerList43 InnerList() : capacity(0), size(0), step(0) {}
44
Erasecc::ListContainer::ListContainerCharAllocator::InnerList45 void Erase(char* position) {
46 // Confident that destructor is called by caller of this function. Since
47 // ListContainerCharAllocator does not handle construction after
48 // allocation, it doesn't handle desctrution before deallocation.
49 DCHECK_LE(position, LastElement());
50 DCHECK_GE(position, Begin());
51 char* start = position + step;
52 std::copy(start, End(), position);
53
54 --size;
55 // Decrease capacity to avoid creating not full not last InnerList.
56 --capacity;
57 }
58
IsFullcc::ListContainer::ListContainerCharAllocator::InnerList59 bool IsFull() { return capacity == size; }
NumElementsAvailablecc::ListContainer::ListContainerCharAllocator::InnerList60 size_t NumElementsAvailable() const { return capacity - size; }
61
AddElementcc::ListContainer::ListContainerCharAllocator::InnerList62 void* AddElement() {
63 DCHECK_LT(size, capacity);
64 ++size;
65 return LastElement();
66 }
67
Begincc::ListContainer::ListContainerCharAllocator::InnerList68 char* Begin() const { return data.get(); }
Endcc::ListContainer::ListContainerCharAllocator::InnerList69 char* End() const { return data.get() + size * step; }
LastElementcc::ListContainer::ListContainerCharAllocator::InnerList70 char* LastElement() const { return data.get() + (size - 1) * step; }
ElementAtcc::ListContainer::ListContainerCharAllocator::InnerList71 char* ElementAt(size_t index) const { return data.get() + index * step; }
72
73 private:
74 DISALLOW_COPY_AND_ASSIGN(InnerList);
75 };
76
ListContainerCharAllocator(size_t element_size)77 explicit ListContainerCharAllocator(size_t element_size)
78 : element_size_(element_size),
79 size_(0),
80 list_count_(0),
81 last_list_(NULL) {
82 AllocateNewList(kDefaultNumElementTypesToReserve);
83 }
84
ListContainerCharAllocator(size_t element_size,size_t element_count)85 ListContainerCharAllocator(size_t element_size, size_t element_count)
86 : element_size_(element_size),
87 size_(0),
88 list_count_(0),
89 last_list_(NULL) {
90 DCHECK_NE(0u, element_count);
91 AllocateNewList(element_count);
92 }
93
~ListContainerCharAllocator()94 ~ListContainerCharAllocator() {}
95
Allocate()96 void* Allocate() {
97 if (last_list_->IsFull())
98 AllocateNewList(last_list_->capacity * 2);
99
100 ++size_;
101 return last_list_->AddElement();
102 }
103
element_size() const104 size_t element_size() const { return element_size_; }
list_count() const105 size_t list_count() const { return list_count_; }
size() const106 size_t size() const { return size_; }
IsEmpty() const107 bool IsEmpty() const { return size() == 0; }
108
Capacity() const109 size_t Capacity() const {
110 size_t capacity_sum = 0;
111 for (typename ScopedPtrVector<InnerList>::const_iterator iter =
112 storage_.begin();
113 iter != storage_.end();
114 ++iter) {
115 capacity_sum += (*iter)->capacity;
116 }
117 return capacity_sum;
118 }
119
Clear()120 void Clear() {
121 size_t initial_allocation_size = storage_.front()->capacity;
122 storage_.clear();
123 list_count_ = 0;
124 last_list_ = NULL;
125 size_ = 0;
126 AllocateNewList(initial_allocation_size);
127 }
128
Erase(PositionInListContainerCharAllocator position)129 void Erase(PositionInListContainerCharAllocator position) {
130 DCHECK_EQ(this, position.ptr_to_container);
131 storage_[position.vector_index]->Erase(position.item_iterator);
132 // TODO(weiliangc): Free the InnerList if it is empty.
133 --size_;
134 }
135
InnerListById(size_t id) const136 InnerList* InnerListById(size_t id) const {
137 DCHECK_LT(id, list_count_);
138 return storage_[id];
139 }
140
AllocateNewList(size_t list_size)141 void AllocateNewList(size_t list_size) {
142 ++list_count_;
143 scoped_ptr<InnerList> new_list(new InnerList);
144 storage_.push_back(new_list.Pass());
145 last_list_ = storage_.back();
146 InnerList* list = last_list_;
147 list->capacity = list_size;
148 list->size = 0;
149 list->step = element_size_;
150 list->data.reset(new char[list->capacity * list->step]);
151 }
152
NumAvailableElementsInLastList() const153 size_t NumAvailableElementsInLastList() const {
154 return last_list_->NumElementsAvailable();
155 }
156
157 private:
158 ScopedPtrVector<InnerList> storage_;
159 const size_t element_size_;
160 size_t size_;
161 size_t list_count_;
162 InnerList* last_list_;
163
164 DISALLOW_COPY_AND_ASSIGN(ListContainerCharAllocator);
165 };
166
167 // PositionInListContainerCharAllocator
168 //////////////////////////////////////////////////////
169 template <typename BaseElementType>
170 ListContainer<BaseElementType>::PositionInListContainerCharAllocator::
PositionInListContainerCharAllocator(const typename ListContainer<BaseElementType>::PositionInListContainerCharAllocator & other)171 PositionInListContainerCharAllocator(const typename ListContainer<
172 BaseElementType>::PositionInListContainerCharAllocator& other)
173 : ptr_to_container(other.ptr_to_container),
174 vector_index(other.vector_index),
175 item_iterator(other.item_iterator) {
176 }
177
178 template <typename BaseElementType>
179 ListContainer<BaseElementType>::PositionInListContainerCharAllocator::
PositionInListContainerCharAllocator(typename ListContainer<BaseElementType>::ListContainerCharAllocator * container,size_t vector_ind,char * item_iter)180 PositionInListContainerCharAllocator(
181 typename ListContainer<BaseElementType>::ListContainerCharAllocator*
182 container,
183 size_t vector_ind,
184 char* item_iter)
185 : ptr_to_container(container),
186 vector_index(vector_ind),
187 item_iterator(item_iter) {
188 }
189
190 template <typename BaseElementType>
191 bool ListContainer<BaseElementType>::PositionInListContainerCharAllocator::
operator ==(const typename ListContainer<BaseElementType>::PositionInListContainerCharAllocator & other) const192 operator==(const typename ListContainer<
193 BaseElementType>::PositionInListContainerCharAllocator& other) const {
194 DCHECK_EQ(ptr_to_container, other.ptr_to_container);
195 return vector_index == other.vector_index &&
196 item_iterator == other.item_iterator;
197 }
198
199 template <typename BaseElementType>
200 bool ListContainer<BaseElementType>::PositionInListContainerCharAllocator::
operator !=(const typename ListContainer<BaseElementType>::PositionInListContainerCharAllocator & other) const201 operator!=(const typename ListContainer<
202 BaseElementType>::PositionInListContainerCharAllocator& other) const {
203 return !(*this == other);
204 }
205
206 template <typename BaseElementType>
207 typename ListContainer<BaseElementType>::PositionInListContainerCharAllocator
208 ListContainer<
Increment()209 BaseElementType>::PositionInListContainerCharAllocator::Increment() {
210 typename ListContainerCharAllocator::InnerList* list =
211 ptr_to_container->InnerListById(vector_index);
212 if (item_iterator == list->LastElement()) {
213 if (vector_index < ptr_to_container->list_count() - 1) {
214 ++vector_index;
215 item_iterator = ptr_to_container->InnerListById(vector_index)->Begin();
216 } else {
217 item_iterator = NULL;
218 }
219 } else {
220 item_iterator += list->step;
221 }
222 return *this;
223 }
224
225 template <typename BaseElementType>
226 typename ListContainer<BaseElementType>::PositionInListContainerCharAllocator
227 ListContainer<
ReverseIncrement()228 BaseElementType>::PositionInListContainerCharAllocator::ReverseIncrement() {
229 typename ListContainerCharAllocator::InnerList* list =
230 ptr_to_container->InnerListById(vector_index);
231 if (item_iterator == list->Begin()) {
232 if (vector_index > 0) {
233 --vector_index;
234 item_iterator =
235 ptr_to_container->InnerListById(vector_index)->LastElement();
236 } else {
237 item_iterator = NULL;
238 }
239 } else {
240 item_iterator -= list->step;
241 }
242 return *this;
243 }
244
245 // ListContainer
246 ////////////////////////////////////////////
247 template <typename BaseElementType>
ListContainer(size_t max_size_for_derived_class)248 ListContainer<BaseElementType>::ListContainer(size_t max_size_for_derived_class)
249 : data_(new ListContainerCharAllocator(max_size_for_derived_class)) {
250 }
251
252 template <typename BaseElementType>
ListContainer(size_t max_size_for_derived_class,size_t num_of_elements_to_reserve_for)253 ListContainer<BaseElementType>::ListContainer(
254 size_t max_size_for_derived_class,
255 size_t num_of_elements_to_reserve_for)
256 : data_(new ListContainerCharAllocator(max_size_for_derived_class,
257 num_of_elements_to_reserve_for)) {
258 }
259
260 template <typename BaseElementType>
ListContainer()261 ListContainer<BaseElementType>::ListContainer()
262 : data_(new ListContainerCharAllocator(sizeof(BaseElementType))) {
263 }
264
265 template <typename BaseElementType>
~ListContainer()266 ListContainer<BaseElementType>::~ListContainer() {
267 for (Iterator i = begin(); i != end(); ++i) {
268 i->~BaseElementType();
269 }
270 }
271
272 template <typename BaseElementType>
EraseAndInvalidateAllPointers(typename ListContainer<BaseElementType>::Iterator position)273 void ListContainer<BaseElementType>::EraseAndInvalidateAllPointers(
274 typename ListContainer<BaseElementType>::Iterator position) {
275 BaseElementType* item = &*position;
276 item->~BaseElementType();
277 data_->Erase(position);
278 }
279
280 template <typename BaseElementType>
281 typename ListContainer<BaseElementType>::ConstReverseIterator
rbegin() const282 ListContainer<BaseElementType>::rbegin() const {
283 if (data_->IsEmpty())
284 return ConstReverseIterator(data_.get(), 0, NULL);
285
286 size_t last_id = data_->list_count() - 1;
287 return ConstReverseIterator(
288 data_.get(), last_id, data_->InnerListById(last_id)->LastElement());
289 }
290
291 template <typename BaseElementType>
292 typename ListContainer<BaseElementType>::ConstReverseIterator
rend() const293 ListContainer<BaseElementType>::rend() const {
294 return ConstReverseIterator(data_.get(), 0, NULL);
295 }
296
297 template <typename BaseElementType>
298 typename ListContainer<BaseElementType>::ReverseIterator
rbegin()299 ListContainer<BaseElementType>::rbegin() {
300 if (data_->IsEmpty())
301 return ReverseIterator(data_.get(), 0, NULL);
302
303 size_t last_id = data_->list_count() - 1;
304 return ReverseIterator(
305 data_.get(), last_id, data_->InnerListById(last_id)->LastElement());
306 }
307
308 template <typename BaseElementType>
309 typename ListContainer<BaseElementType>::ReverseIterator
rend()310 ListContainer<BaseElementType>::rend() {
311 return ReverseIterator(data_.get(), 0, NULL);
312 }
313
314 template <typename BaseElementType>
315 typename ListContainer<BaseElementType>::ConstIterator
begin() const316 ListContainer<BaseElementType>::begin() const {
317 if (data_->IsEmpty())
318 return ConstIterator(data_.get(), 0, NULL);
319
320 return ConstIterator(data_.get(), 0, data_->InnerListById(0)->Begin());
321 }
322
323 template <typename BaseElementType>
324 typename ListContainer<BaseElementType>::ConstIterator
end() const325 ListContainer<BaseElementType>::end() const {
326 if (data_->IsEmpty())
327 return ConstIterator(data_.get(), 0, NULL);
328
329 size_t last_id = data_->list_count() - 1;
330 return ConstIterator(data_.get(), last_id, NULL);
331 }
332
333 template <typename BaseElementType>
334 typename ListContainer<BaseElementType>::Iterator
begin()335 ListContainer<BaseElementType>::begin() {
336 if (data_->IsEmpty())
337 return Iterator(data_.get(), 0, NULL);
338
339 return Iterator(data_.get(), 0, data_->InnerListById(0)->Begin());
340 }
341
342 template <typename BaseElementType>
343 typename ListContainer<BaseElementType>::Iterator
end()344 ListContainer<BaseElementType>::end() {
345 if (data_->IsEmpty())
346 return Iterator(data_.get(), 0, NULL);
347
348 size_t last_id = data_->list_count() - 1;
349 return Iterator(data_.get(), last_id, NULL);
350 }
351
352 template <typename BaseElementType>
front()353 BaseElementType* ListContainer<BaseElementType>::front() {
354 Iterator iter = begin();
355 return &*iter;
356 }
357
358 template <typename BaseElementType>
back()359 BaseElementType* ListContainer<BaseElementType>::back() {
360 ReverseIterator iter = rbegin();
361 return &*iter;
362 }
363
364 template <typename BaseElementType>
front() const365 const BaseElementType* ListContainer<BaseElementType>::front() const {
366 ConstIterator iter = begin();
367 return &*iter;
368 }
369
370 template <typename BaseElementType>
back() const371 const BaseElementType* ListContainer<BaseElementType>::back() const {
372 ConstReverseIterator iter = rbegin();
373 return &*iter;
374 }
375
376 template <typename BaseElementType>
ElementAt(size_t index) const377 const BaseElementType* ListContainer<BaseElementType>::ElementAt(
378 size_t index) const {
379 DCHECK_LT(index, size());
380 size_t list_index;
381 for (list_index = 0; list_index < data_->list_count(); ++list_index) {
382 size_t current_size = data_->InnerListById(list_index)->size;
383 if (index < current_size)
384 break;
385 index -= current_size;
386 }
387 return &*ConstIterator(data_.get(),
388 list_index,
389 data_->InnerListById(list_index)->ElementAt(index));
390 }
391
392 template <typename BaseElementType>
ElementAt(size_t index)393 BaseElementType* ListContainer<BaseElementType>::ElementAt(size_t index) {
394 DCHECK_LT(index, size());
395 size_t list_index;
396 for (list_index = 0; list_index < data_->list_count(); ++list_index) {
397 size_t current_size = data_->InnerListById(list_index)->size;
398 if (index < current_size)
399 break;
400 index -= current_size;
401 }
402 return &*Iterator(data_.get(),
403 list_index,
404 data_->InnerListById(list_index)->ElementAt(index));
405 }
406
407 template <typename BaseElementType>
Allocate(size_t size_of_actual_element_in_bytes)408 BaseElementType* ListContainer<BaseElementType>::Allocate(
409 size_t size_of_actual_element_in_bytes) {
410 DCHECK_LE(size_of_actual_element_in_bytes, data_->element_size());
411 void* result = data_->Allocate();
412 return static_cast<BaseElementType*>(result);
413 }
414
415 template <typename BaseElementType>
size() const416 size_t ListContainer<BaseElementType>::size() const {
417 return data_->size();
418 }
419
420 template <typename BaseElementType>
empty() const421 bool ListContainer<BaseElementType>::empty() const {
422 return data_->IsEmpty();
423 }
424
425 template <typename BaseElementType>
clear()426 void ListContainer<BaseElementType>::clear() {
427 for (Iterator i = begin(); i != end(); ++i) {
428 i->~BaseElementType();
429 }
430 data_->Clear();
431 }
432
433 template <typename BaseElementType>
434 size_t ListContainer<
AvailableSizeWithoutAnotherAllocationForTesting() const435 BaseElementType>::AvailableSizeWithoutAnotherAllocationForTesting() const {
436 return data_->NumAvailableElementsInLastList();
437 }
438
439 // ListContainer::Iterator
440 /////////////////////////////////////////////////
441 template <typename BaseElementType>
Iterator(ListContainerCharAllocator * container,size_t vector_ind,char * item_iter)442 ListContainer<BaseElementType>::Iterator::Iterator(
443 ListContainerCharAllocator* container,
444 size_t vector_ind,
445 char* item_iter)
446 : PositionInListContainerCharAllocator(container, vector_ind, item_iter) {
447 }
448
449 template <typename BaseElementType>
~Iterator()450 ListContainer<BaseElementType>::Iterator::~Iterator() {
451 }
452
453 template <typename BaseElementType>
operator ->() const454 BaseElementType* ListContainer<BaseElementType>::Iterator::operator->() const {
455 return reinterpret_cast<BaseElementType*>(this->item_iterator);
456 }
457
458 template <typename BaseElementType>
operator *() const459 BaseElementType& ListContainer<BaseElementType>::Iterator::operator*() const {
460 return *(reinterpret_cast<BaseElementType*>(this->item_iterator));
461 }
462
463 template <typename BaseElementType>
464 typename ListContainer<BaseElementType>::Iterator
465 ListContainer<BaseElementType>::Iterator::
operator ++(int unused_post_increment)466 operator++(int unused_post_increment) {
467 Iterator tmp = *this;
468 operator++();
469 return tmp;
470 }
471
472 template <typename BaseElementType>
473 typename ListContainer<BaseElementType>::Iterator
474 ListContainer<BaseElementType>::Iterator::
operator ++()475 operator++() {
476 this->Increment();
477 return *this;
478 }
479
480 // ListContainer::ConstIterator
481 /////////////////////////////////////////////////
482 template <typename BaseElementType>
ConstIterator(const typename ListContainer<BaseElementType>::Iterator & other)483 ListContainer<BaseElementType>::ConstIterator::ConstIterator(
484 const typename ListContainer<BaseElementType>::Iterator& other)
485 : PositionInListContainerCharAllocator(other) {
486 }
487
488 template <typename BaseElementType>
ConstIterator(ListContainerCharAllocator * container,size_t vector_ind,char * item_iter)489 ListContainer<BaseElementType>::ConstIterator::ConstIterator(
490 ListContainerCharAllocator* container,
491 size_t vector_ind,
492 char* item_iter)
493 : PositionInListContainerCharAllocator(container, vector_ind, item_iter) {
494 }
495
496 template <typename BaseElementType>
~ConstIterator()497 ListContainer<BaseElementType>::ConstIterator::~ConstIterator() {
498 }
499
500 template <typename BaseElementType>
501 const BaseElementType* ListContainer<BaseElementType>::ConstIterator::
operator ->() const502 operator->() const {
503 return reinterpret_cast<const BaseElementType*>(this->item_iterator);
504 }
505
506 template <typename BaseElementType>
507 const BaseElementType& ListContainer<BaseElementType>::ConstIterator::
operator *() const508 operator*() const {
509 return *(reinterpret_cast<const BaseElementType*>(this->item_iterator));
510 }
511
512 template <typename BaseElementType>
513 typename ListContainer<BaseElementType>::ConstIterator
514 ListContainer<BaseElementType>::ConstIterator::
operator ++(int unused_post_increment)515 operator++(int unused_post_increment) {
516 ConstIterator tmp = *this;
517 operator++();
518 return tmp;
519 }
520
521 template <typename BaseElementType>
522 typename ListContainer<BaseElementType>::ConstIterator
523 ListContainer<BaseElementType>::ConstIterator::
operator ++()524 operator++() {
525 this->Increment();
526 return *this;
527 }
528
529 // ListContainer::ReverseIterator
530 /////////////////////////////////////////////////
531 template <typename BaseElementType>
ReverseIterator(ListContainerCharAllocator * container,size_t vector_ind,char * item_iter)532 ListContainer<BaseElementType>::ReverseIterator::ReverseIterator(
533 ListContainerCharAllocator* container,
534 size_t vector_ind,
535 char* item_iter)
536 : PositionInListContainerCharAllocator(container, vector_ind, item_iter) {
537 }
538
539 template <typename BaseElementType>
~ReverseIterator()540 ListContainer<BaseElementType>::ReverseIterator::~ReverseIterator() {
541 }
542
543 template <typename BaseElementType>
operator ->() const544 BaseElementType* ListContainer<BaseElementType>::ReverseIterator::operator->()
545 const {
546 return reinterpret_cast<BaseElementType*>(this->item_iterator);
547 }
548
549 template <typename BaseElementType>
operator *() const550 BaseElementType& ListContainer<BaseElementType>::ReverseIterator::operator*()
551 const {
552 return *(reinterpret_cast<BaseElementType*>(this->item_iterator));
553 }
554
555 template <typename BaseElementType>
556 typename ListContainer<BaseElementType>::ReverseIterator
557 ListContainer<BaseElementType>::ReverseIterator::
operator ++(int unused_post_increment)558 operator++(int unused_post_increment) {
559 ReverseIterator tmp = *this;
560 operator++();
561 return tmp;
562 }
563
564 template <typename BaseElementType>
565 typename ListContainer<BaseElementType>::ReverseIterator
566 ListContainer<BaseElementType>::ReverseIterator::
operator ++()567 operator++() {
568 this->ReverseIncrement();
569 return *this;
570 }
571
572 // ListContainer::ConstReverseIterator
573 /////////////////////////////////////////////////
574 template <typename BaseElementType>
ConstReverseIterator(const typename ListContainer<BaseElementType>::ReverseIterator & other)575 ListContainer<BaseElementType>::ConstReverseIterator::ConstReverseIterator(
576 const typename ListContainer<BaseElementType>::ReverseIterator& other)
577 : PositionInListContainerCharAllocator(other) {
578 }
579
580 template <typename BaseElementType>
ConstReverseIterator(ListContainerCharAllocator * container,size_t vector_ind,char * item_iter)581 ListContainer<BaseElementType>::ConstReverseIterator::ConstReverseIterator(
582 ListContainerCharAllocator* container,
583 size_t vector_ind,
584 char* item_iter)
585 : PositionInListContainerCharAllocator(container, vector_ind, item_iter) {
586 }
587
588 template <typename BaseElementType>
~ConstReverseIterator()589 ListContainer<BaseElementType>::ConstReverseIterator::~ConstReverseIterator() {
590 }
591
592 template <typename BaseElementType>
593 const BaseElementType* ListContainer<BaseElementType>::ConstReverseIterator::
operator ->() const594 operator->() const {
595 return reinterpret_cast<const BaseElementType*>(this->item_iterator);
596 }
597
598 template <typename BaseElementType>
599 const BaseElementType& ListContainer<BaseElementType>::ConstReverseIterator::
operator *() const600 operator*() const {
601 return *(reinterpret_cast<const BaseElementType*>(this->item_iterator));
602 }
603
604 template <typename BaseElementType>
605 typename ListContainer<BaseElementType>::ConstReverseIterator
606 ListContainer<BaseElementType>::ConstReverseIterator::
operator ++(int unused_post_increment)607 operator++(int unused_post_increment) {
608 ConstReverseIterator tmp = *this;
609 operator++();
610 return tmp;
611 }
612
613 template <typename BaseElementType>
614 typename ListContainer<BaseElementType>::ConstReverseIterator
615 ListContainer<BaseElementType>::ConstReverseIterator::
operator ++()616 operator++() {
617 this->ReverseIncrement();
618 return *this;
619 }
620
621 template class ListContainer<SharedQuadState>;
622 template class ListContainer<DrawQuad>;
623
624 } // namespace cc
625