| 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 #ifndef ContiguousContainer_h | 5 #ifndef ContiguousContainer_h |
| 6 #define ContiguousContainer_h | 6 #define ContiguousContainer_h |
| 7 | 7 |
| 8 #include "platform/PlatformExport.h" | 8 #include "platform/PlatformExport.h" |
| 9 #include "wtf/Alignment.h" | 9 #include "wtf/Alignment.h" |
| 10 #include "wtf/Allocator.h" | 10 #include "wtf/Allocator.h" |
| 11 #include "wtf/Compiler.h" | 11 #include "wtf/Compiler.h" |
| 12 #include "wtf/Noncopyable.h" | 12 #include "wtf/Noncopyable.h" |
| 13 #include "wtf/TypeTraits.h" | 13 #include "wtf/TypeTraits.h" |
| 14 #include "wtf/Vector.h" | 14 #include "wtf/Vector.h" |
| 15 #include <cstddef> | 15 #include <cstddef> |
| 16 #include <iterator> | 16 #include <iterator> |
| 17 #include <memory> | 17 #include <memory> |
| 18 #include <utility> | 18 #include <utility> |
| 19 | 19 |
| 20 namespace blink { | 20 namespace blink { |
| 21 | 21 |
| 22 namespace internal { |
| 23 template <size_t input> struct Log2 { }; |
| 24 template<> struct Log2<1> { |
| 25 static const unsigned value = 0; |
| 26 }; |
| 27 template<> struct Log2<2> { |
| 28 static const unsigned value = 1; |
| 29 }; |
| 30 template<> struct Log2<4> { |
| 31 static const unsigned value = 2; |
| 32 }; |
| 33 template<> struct Log2<8> { |
| 34 static const unsigned value = 3; |
| 35 }; |
| 36 template<> struct Log2<16> { |
| 37 static const unsigned value = 4; |
| 38 }; |
| 39 } |
| 40 |
| 41 template<typename T> |
| 42 unsigned log2Alignment() { return internal::Log2<WTF_ALIGN_OF(T)>::value; } |
| 43 |
| 22 // ContiguousContainer is a container which stores a list of heterogeneous | 44 // ContiguousContainer is a container which stores a list of heterogeneous |
| 23 // objects (in particular, of varying sizes), packed next to one another in | 45 // objects (in particular, of varying sizes), packed next to one another in |
| 24 // memory. Objects are never relocated, so it is safe to store pointers to them | 46 // memory. Objects are never relocated, so it is safe to store pointers to them |
| 25 // for the lifetime of the container (unless the object is removed). | 47 // for the lifetime of the container (unless the object is removed). |
| 26 // | 48 // |
| 27 // Memory is allocated in a series of buffers (with exponential growth). When an | 49 // Memory is allocated in a series of buffers (with exponential growth). When an |
| 28 // object is allocated, it is given only the space it requires (possibly with | 50 // object is allocated, it is given only the space it requires (possibly with |
| 29 // enough padding to preserve alignment), rather than the maximum possible size. | 51 // enough padding to preserve alignment), rather than the maximum possible size. |
| 30 // This allows small and large objects to coexist without wasting much space. | 52 // This allows small and large objects to coexist without wasting much space. |
| 31 // | 53 // |
| (...skipping 16 matching lines...) Expand all Loading... |
| 48 ContiguousContainerBase& operator=(ContiguousContainerBase&&); | 70 ContiguousContainerBase& operator=(ContiguousContainerBase&&); |
| 49 | 71 |
| 50 size_t size() const { return m_elements.size(); } | 72 size_t size() const { return m_elements.size(); } |
| 51 bool isEmpty() const { return !size(); } | 73 bool isEmpty() const { return !size(); } |
| 52 size_t capacityInBytes() const; | 74 size_t capacityInBytes() const; |
| 53 size_t usedCapacityInBytes() const; | 75 size_t usedCapacityInBytes() const; |
| 54 size_t memoryUsageInBytes() const; | 76 size_t memoryUsageInBytes() const; |
| 55 | 77 |
| 56 // These do not invoke constructors or destructors. | 78 // These do not invoke constructors or destructors. |
| 57 void reserveInitialCapacity(size_t, const char* typeName); | 79 void reserveInitialCapacity(size_t, const char* typeName); |
| 58 void* allocate(size_t objectSize, const char* typeName); | 80 void* allocate(size_t objectSize, unsigned log2Alignment, const char* typeNa
me); |
| 59 void removeLast(); | 81 void removeLast(); |
| 60 void clear(); | 82 void clear(); |
| 61 void swap(ContiguousContainerBase&); | 83 void swap(ContiguousContainerBase&); |
| 62 | 84 |
| 63 Vector<void*> m_elements; | 85 Vector<void*> m_elements; |
| 64 | 86 |
| 65 private: | 87 private: |
| 66 class Buffer; | 88 class Buffer; |
| 67 | 89 |
| 68 Buffer* allocateNewBufferForNextAllocation(size_t, const char* typeName); | 90 Buffer* allocateNewBufferForNextAllocation(size_t, const char* typeName); |
| 69 | 91 |
| 70 Vector<std::unique_ptr<Buffer>> m_buffers; | 92 Vector<std::unique_ptr<Buffer>> m_buffers; |
| 71 unsigned m_endIndex; | 93 unsigned m_endIndex; |
| 72 size_t m_maxObjectSize; | 94 size_t m_maxObjectSize; |
| 73 }; | 95 }; |
| 74 | 96 |
| 75 // For most cases, no alignment stricter than pointer alignment is required. If | 97 template <class BaseElementType> |
| 76 // one of the derived classes has stronger alignment requirements (and the | |
| 77 // static_assert fires), set alignment to the LCM of the derived class | |
| 78 // alignments. For small structs without pointers, it may be possible to reduce | |
| 79 // alignment for tighter packing. | |
| 80 | |
| 81 template <class BaseElementType, unsigned alignment = sizeof(void*)> | |
| 82 class ContiguousContainer : public ContiguousContainerBase { | 98 class ContiguousContainer : public ContiguousContainerBase { |
| 83 private: | 99 private: |
| 84 // Declares itself as a forward iterator, but also supports a few more | 100 // Declares itself as a forward iterator, but also supports a few more |
| 85 // things. The whole random access iterator interface is a bit much. | 101 // things. The whole random access iterator interface is a bit much. |
| 86 template <typename BaseIterator, typename ValueType> | 102 template <typename BaseIterator, typename ValueType> |
| 87 class IteratorWrapper : public std::iterator<std::forward_iterator_tag, Valu
eType> { | 103 class IteratorWrapper : public std::iterator<std::forward_iterator_tag, Valu
eType> { |
| 88 DISALLOW_NEW(); | 104 DISALLOW_NEW(); |
| 89 public: | 105 public: |
| 90 IteratorWrapper() {} | 106 IteratorWrapper() {} |
| 91 bool operator==(const IteratorWrapper& other) const { return m_it == oth
er.m_it; } | 107 bool operator==(const IteratorWrapper& other) const { return m_it == oth
er.m_it; } |
| 92 bool operator!=(const IteratorWrapper& other) const { return m_it != oth
er.m_it; } | 108 bool operator!=(const IteratorWrapper& other) const { return m_it != oth
er.m_it; } |
| 93 ValueType& operator*() const { return *static_cast<ValueType*>(*m_it); } | 109 ValueType& operator*() const { return *static_cast<ValueType*>(*m_it); } |
| 94 ValueType* operator->() const { return &operator*(); } | 110 ValueType* operator->() const { return &operator*(); } |
| 95 IteratorWrapper operator+(std::ptrdiff_t n) const { return IteratorWrapp
er(m_it + n); } | 111 IteratorWrapper operator+(std::ptrdiff_t n) const { return IteratorWrapp
er(m_it + n); } |
| 96 IteratorWrapper operator++(int) { IteratorWrapper tmp = *this; ++m_it; r
eturn tmp; } | 112 IteratorWrapper operator++(int) { IteratorWrapper tmp = *this; ++m_it; r
eturn tmp; } |
| 97 std::ptrdiff_t operator-(const IteratorWrapper& other) const { return m_
it - other.m_it; } | 113 std::ptrdiff_t operator-(const IteratorWrapper& other) const { return m_
it - other.m_it; } |
| 98 IteratorWrapper& operator++() { ++m_it; return *this; } | 114 IteratorWrapper& operator++() { ++m_it; return *this; } |
| 99 private: | 115 private: |
| 100 explicit IteratorWrapper(const BaseIterator& it) : m_it(it) {} | 116 explicit IteratorWrapper(const BaseIterator& it) : m_it(it) {} |
| 101 BaseIterator m_it; | 117 BaseIterator m_it; |
| 102 friend class ContiguousContainer; | 118 friend class ContiguousContainer; |
| 103 }; | 119 }; |
| 104 | 120 |
| 105 public: | 121 public: |
| 106 using iterator = IteratorWrapper<Vector<void*>::iterator, BaseElementType>; | 122 using iterator = IteratorWrapper<Vector<void*>::iterator, BaseElementType>; |
| 107 using const_iterator = IteratorWrapper<Vector<void*>::const_iterator, const
BaseElementType>; | 123 using const_iterator = IteratorWrapper<Vector<void*>::const_iterator, const
BaseElementType>; |
| 108 using reverse_iterator = IteratorWrapper<Vector<void*>::reverse_iterator, Ba
seElementType>; | 124 using reverse_iterator = IteratorWrapper<Vector<void*>::reverse_iterator, Ba
seElementType>; |
| 109 using const_reverse_iterator = IteratorWrapper<Vector<void*>::const_reverse_
iterator, const BaseElementType>; | 125 using const_reverse_iterator = IteratorWrapper<Vector<void*>::const_reverse_
iterator, const BaseElementType>; |
| 110 | 126 |
| 111 explicit ContiguousContainer(size_t maxObjectSize) : ContiguousContainerBase
(align(maxObjectSize)) {} | 127 explicit ContiguousContainer(size_t maxObjectSize) : ContiguousContainerBase
(maxObjectSize) {} |
| 112 | 128 |
| 113 ContiguousContainer(size_t maxObjectSize, size_t initialSizeBytes) | 129 ContiguousContainer(size_t maxObjectSize, size_t initialSizeBytes) |
| 114 : ContiguousContainer(maxObjectSize) | 130 : ContiguousContainer(maxObjectSize) |
| 115 { | 131 { |
| 116 reserveInitialCapacity(std::max(maxObjectSize, initialSizeBytes), WTF_HE
AP_PROFILER_TYPE_NAME(BaseElementType)); | 132 reserveInitialCapacity(std::max(maxObjectSize, initialSizeBytes), WTF_HE
AP_PROFILER_TYPE_NAME(BaseElementType)); |
| 117 } | 133 } |
| 118 | 134 |
| 119 ContiguousContainer(ContiguousContainer&& source) | 135 ContiguousContainer(ContiguousContainer&& source) |
| 120 : ContiguousContainerBase(std::move(source)) {} | 136 : ContiguousContainerBase(std::move(source)) {} |
| 121 | 137 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 157 BaseElementType& last() { return *rbegin(); } | 173 BaseElementType& last() { return *rbegin(); } |
| 158 const BaseElementType& last() const { return *rbegin(); } | 174 const BaseElementType& last() const { return *rbegin(); } |
| 159 BaseElementType& operator[](size_t index) { return *(begin() + index); } | 175 BaseElementType& operator[](size_t index) { return *(begin() + index); } |
| 160 const BaseElementType& operator[](size_t index) const { return *(begin() + i
ndex); } | 176 const BaseElementType& operator[](size_t index) const { return *(begin() + i
ndex); } |
| 161 | 177 |
| 162 template <class DerivedElementType, typename... Args> | 178 template <class DerivedElementType, typename... Args> |
| 163 DerivedElementType& allocateAndConstruct(Args&&... args) | 179 DerivedElementType& allocateAndConstruct(Args&&... args) |
| 164 { | 180 { |
| 165 static_assert(WTF::IsSubclass<DerivedElementType, BaseElementType>::valu
e, | 181 static_assert(WTF::IsSubclass<DerivedElementType, BaseElementType>::valu
e, |
| 166 "Must use subclass of BaseElementType."); | 182 "Must use subclass of BaseElementType."); |
| 167 static_assert(alignment % WTF_ALIGN_OF(DerivedElementType) == 0, | 183 return *new (allocate(sizeof(DerivedElementType), log2Alignment<DerivedE
lementType>())) |
| 168 "Derived type requires stronger alignment."); | 184 DerivedElementType(std::forward<Args>(args)...); |
| 169 size_t allocSize = align(sizeof(DerivedElementType)); | |
| 170 return *new (allocate(allocSize)) DerivedElementType(std::forward<Args>(
args)...); | |
| 171 } | 185 } |
| 172 | 186 |
| 173 void removeLast() | 187 void removeLast() |
| 174 { | 188 { |
| 175 ASSERT(!isEmpty()); | 189 ASSERT(!isEmpty()); |
| 176 last().~BaseElementType(); | 190 last().~BaseElementType(); |
| 177 ContiguousContainerBase::removeLast(); | 191 ContiguousContainerBase::removeLast(); |
| 178 } | 192 } |
| 179 | 193 |
| 180 void clear() | 194 void clear() |
| 181 { | 195 { |
| 182 for (auto& element : *this) { | 196 for (auto& element : *this) { |
| 183 (void)element; // MSVC incorrectly reports this variable as unused. | 197 (void)element; // MSVC incorrectly reports this variable as unused. |
| 184 element.~BaseElementType(); | 198 element.~BaseElementType(); |
| 185 } | 199 } |
| 186 ContiguousContainerBase::clear(); | 200 ContiguousContainerBase::clear(); |
| 187 } | 201 } |
| 188 | 202 |
| 189 void swap(ContiguousContainer& other) { ContiguousContainerBase::swap(other)
; } | 203 void swap(ContiguousContainer& other) { ContiguousContainerBase::swap(other)
; } |
| 190 | 204 |
| 191 // Appends a new element using memcpy, then default-constructs a base | 205 // Appends a new element using memcpy, then default-constructs a base |
| 192 // element in its place. Use with care. | 206 // element in its place. Use with care. |
| 193 BaseElementType& appendByMoving(BaseElementType& item, size_t size) | 207 BaseElementType& appendByMoving(BaseElementType& item, size_t size, unsigned
log2Alignment) |
| 194 { | 208 { |
| 195 ASSERT(size >= sizeof(BaseElementType)); | 209 ASSERT(size >= sizeof(BaseElementType)); |
| 196 void* newItem = allocate(size); | 210 void* newItem = allocate(size, log2Alignment); |
| 197 memcpy(newItem, static_cast<void*>(&item), size); | 211 memcpy(newItem, static_cast<void*>(&item), size); |
| 198 new (&item) BaseElementType; | 212 new (&item) BaseElementType; |
| 199 return *static_cast<BaseElementType*>(newItem); | 213 return *static_cast<BaseElementType*>(newItem); |
| 200 } | 214 } |
| 201 | 215 |
| 202 private: | 216 private: |
| 203 void* allocate(size_t objectSize) | 217 FRIEND_TEST_ALL_PREFIXES(ContiguousContainerTest, Alignment); |
| 218 |
| 219 void* allocate(size_t objectSize, size_t log2Alignment) |
| 204 { | 220 { |
| 205 return ContiguousContainerBase::allocate(objectSize, WTF_HEAP_PROFILER_T
YPE_NAME(BaseElementType)); | 221 return ContiguousContainerBase::allocate(objectSize, log2Alignment, WTF_
HEAP_PROFILER_TYPE_NAME(BaseElementType)); |
| 206 } | |
| 207 | |
| 208 static size_t align(size_t size) | |
| 209 { | |
| 210 size_t alignedSize = alignment * ((size + alignment - 1) / alignment); | |
| 211 ASSERT(alignedSize % alignment == 0); | |
| 212 ASSERT(alignedSize >= size); | |
| 213 ASSERT(alignedSize < size + alignment); | |
| 214 return alignedSize; | |
| 215 } | 222 } |
| 216 }; | 223 }; |
| 217 | 224 |
| 218 } // namespace blink | 225 } // namespace blink |
| 219 | 226 |
| 220 #endif // ContiguousContainer_h | 227 #endif // ContiguousContainer_h |
| OLD | NEW |