| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cc/base/contiguous_container.h" | 5 #include "cc/base/contiguous_container.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| 11 namespace cc { | 11 namespace cc { |
| 12 | 12 |
| 13 namespace { |
| 14 |
| 13 // Default number of max-sized elements to allocate space for, if there is no | 15 // Default number of max-sized elements to allocate space for, if there is no |
| 14 // initial buffer. | 16 // initial buffer. |
| 15 static const unsigned kDefaultInitialBufferSize = 32; | 17 const unsigned kDefaultInitialBufferSize = 32; |
| 18 |
| 19 inline char* AlignAddress(char* address, size_t alignment) { |
| 20 char* aligned = reinterpret_cast<char*>( |
| 21 alignment * |
| 22 ((reinterpret_cast<size_t>(address) + alignment - 1) / alignment)); |
| 23 DCHECK(reinterpret_cast<size_t>(aligned) % alignment == 0); |
| 24 DCHECK(aligned >= address); |
| 25 DCHECK(aligned < address + alignment); |
| 26 return aligned; |
| 27 } |
| 28 |
| 29 } // namespace |
| 16 | 30 |
| 17 class ContiguousContainerBase::Buffer { | 31 class ContiguousContainerBase::Buffer { |
| 18 public: | 32 public: |
| 19 explicit Buffer(size_t buffer_size) | 33 explicit Buffer(size_t buffer_size) |
| 20 : data_(new char[buffer_size]), end_(begin()), capacity_(buffer_size) {} | 34 : data_(new char[buffer_size]), end_(begin()), capacity_(buffer_size) {} |
| 21 | 35 |
| 22 ~Buffer() {} | 36 ~Buffer() {} |
| 23 | 37 |
| 24 size_t Capacity() const { return capacity_; } | 38 size_t Capacity() const { return capacity_; } |
| 25 size_t UsedCapacity() const { return end_ - begin(); } | 39 size_t UsedCapacity() const { return end_ - begin(); } |
| 26 size_t UnusedCapacity() const { return Capacity() - UsedCapacity(); } | 40 size_t UnusedCapacity() const { return Capacity() - UsedCapacity(); } |
| 27 bool empty() const { return UsedCapacity() == 0; } | 41 bool empty() const { return UsedCapacity() == 0; } |
| 28 | 42 |
| 29 void* Allocate(size_t object_size) { | 43 void* Allocate(size_t object_size, size_t alignment) { |
| 30 DCHECK_GE(UnusedCapacity(), object_size); | 44 char* aligned_address = AlignAddress(end_, alignment); |
| 31 void* result = end_; | 45 if (aligned_address - begin() + object_size > Capacity()) |
| 32 end_ += object_size; | 46 return nullptr; |
| 33 return result; | 47 if (empty()) |
| 48 first_object_ = aligned_address; |
| 49 end_ = aligned_address + object_size; |
| 50 return aligned_address; |
| 34 } | 51 } |
| 35 | 52 |
| 36 void DeallocateLastObject(void* object) { | 53 void DeallocateLastObject(void* object) { |
| 37 DCHECK_LE(begin(), object); | 54 DCHECK_LE(begin(), object); |
| 38 DCHECK_LT(object, end_); | 55 DCHECK_LT(object, end_); |
| 39 end_ = static_cast<char*>(object); | 56 end_ = static_cast<char*>(object); |
| 57 if (end_ == first_object_) { |
| 58 // We have deallocated the first object in this buffer. Reset en_ so that |
| 59 // empty() can return correct value. |
| 60 end_ = begin(); |
| 61 } |
| 62 // Otherwise we may leave a gap between the end of the previous object |
| 63 // (which we don't know) and end_ because of alignment of the deallocated |
| 64 // object. |
| 40 } | 65 } |
| 41 | 66 |
| 42 private: | 67 private: |
| 43 char* begin() { return &data_[0]; } | 68 char* begin() { return &data_[0]; } |
| 44 const char* begin() const { return &data_[0]; } | 69 const char* begin() const { return &data_[0]; } |
| 45 | 70 |
| 46 // begin() <= end_ <= begin() + capacity_ | 71 // begin() <= first_object_ <= end_ <= begin() + capacity_ |
| 47 std::unique_ptr<char[]> data_; | 72 std::unique_ptr<char[]> data_; |
| 73 // Because of alignment, the first object may be allocated after begin(). |
| 74 char* first_object_; |
| 48 char* end_; | 75 char* end_; |
| 49 size_t capacity_; | 76 size_t capacity_; |
| 50 }; | 77 }; |
| 51 | 78 |
| 52 ContiguousContainerBase::ContiguousContainerBase(size_t max_object_size) | 79 ContiguousContainerBase::ContiguousContainerBase(size_t max_object_size) |
| 53 : end_index_(0), max_object_size_(max_object_size) {} | 80 : end_index_(0), max_object_size_(max_object_size) {} |
| 54 | 81 |
| 55 ContiguousContainerBase::ContiguousContainerBase(size_t max_object_size, | 82 ContiguousContainerBase::ContiguousContainerBase(size_t max_object_size, |
| 56 size_t initial_size_bytes) | 83 size_t initial_size_bytes) |
| 57 : ContiguousContainerBase(max_object_size) { | 84 : ContiguousContainerBase(max_object_size) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 73 for (const auto& buffer : buffers_) | 100 for (const auto& buffer : buffers_) |
| 74 used_capacity += buffer->UsedCapacity(); | 101 used_capacity += buffer->UsedCapacity(); |
| 75 return used_capacity; | 102 return used_capacity; |
| 76 } | 103 } |
| 77 | 104 |
| 78 size_t ContiguousContainerBase::MemoryUsageInBytes() const { | 105 size_t ContiguousContainerBase::MemoryUsageInBytes() const { |
| 79 return sizeof(*this) + GetCapacityInBytes() + | 106 return sizeof(*this) + GetCapacityInBytes() + |
| 80 elements_.capacity() * sizeof(elements_[0]); | 107 elements_.capacity() * sizeof(elements_[0]); |
| 81 } | 108 } |
| 82 | 109 |
| 83 void* ContiguousContainerBase::Allocate(size_t object_size) { | 110 void* ContiguousContainerBase::Allocate(size_t object_size, size_t alignment) { |
| 84 DCHECK_LE(object_size, max_object_size_); | 111 DCHECK_LE(object_size, max_object_size_); |
| 85 | 112 |
| 86 Buffer* buffer_for_alloc = nullptr; | 113 void* element = buffers_.empty() ? nullptr : buffers_[end_index_]->Allocate( |
| 87 if (!buffers_.empty()) { | 114 object_size, alignment); |
| 88 Buffer* end_buffer = buffers_[end_index_].get(); | 115 if (!element) { |
| 89 if (end_buffer->UnusedCapacity() >= object_size) | 116 Buffer* buffer_for_alloc; |
| 90 buffer_for_alloc = end_buffer; | 117 if (end_index_ + 1 < buffers_.size()) { |
| 91 else if (end_index_ + 1 < buffers_.size()) | |
| 92 buffer_for_alloc = buffers_[++end_index_].get(); | 118 buffer_for_alloc = buffers_[++end_index_].get(); |
| 119 } else { |
| 120 size_t new_buffer_size = |
| 121 buffers_.empty() ? kDefaultInitialBufferSize * max_object_size_ |
| 122 : 2 * buffers_.back()->Capacity(); |
| 123 buffer_for_alloc = AllocateNewBufferForNextAllocation(new_buffer_size); |
| 124 } |
| 125 element = buffer_for_alloc->Allocate(object_size, alignment); |
| 126 DCHECK(element); |
| 93 } | 127 } |
| 94 | |
| 95 if (!buffer_for_alloc) { | |
| 96 size_t new_buffer_size = buffers_.empty() | |
| 97 ? kDefaultInitialBufferSize * max_object_size_ | |
| 98 : 2 * buffers_.back()->Capacity(); | |
| 99 buffer_for_alloc = AllocateNewBufferForNextAllocation(new_buffer_size); | |
| 100 } | |
| 101 | |
| 102 void* element = buffer_for_alloc->Allocate(object_size); | |
| 103 elements_.push_back(element); | 128 elements_.push_back(element); |
| 104 return element; | 129 return element; |
| 105 } | 130 } |
| 106 | 131 |
| 107 void ContiguousContainerBase::RemoveLast() { | 132 void ContiguousContainerBase::RemoveLast() { |
| 108 void* object = elements_.back(); | 133 void* object = elements_.back(); |
| 109 elements_.pop_back(); | 134 elements_.pop_back(); |
| 110 | 135 |
| 111 Buffer* end_buffer = buffers_[end_index_].get(); | 136 Buffer* end_buffer = buffers_[end_index_].get(); |
| 112 end_buffer->DeallocateLastObject(object); | 137 end_buffer->DeallocateLastObject(object); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 137 size_t buffer_size) { | 162 size_t buffer_size) { |
| 138 DCHECK(buffers_.empty() || end_index_ == buffers_.size() - 1); | 163 DCHECK(buffers_.empty() || end_index_ == buffers_.size() - 1); |
| 139 std::unique_ptr<Buffer> new_buffer(new Buffer(buffer_size)); | 164 std::unique_ptr<Buffer> new_buffer(new Buffer(buffer_size)); |
| 140 Buffer* buffer_to_return = new_buffer.get(); | 165 Buffer* buffer_to_return = new_buffer.get(); |
| 141 buffers_.push_back(std::move(new_buffer)); | 166 buffers_.push_back(std::move(new_buffer)); |
| 142 end_index_ = buffers_.size() - 1; | 167 end_index_ = buffers_.size() - 1; |
| 143 return buffer_to_return; | 168 return buffer_to_return; |
| 144 } | 169 } |
| 145 | 170 |
| 146 } // namespace cc | 171 } // namespace cc |
| OLD | NEW |