1 #ifndef _DEPOOLARRAY_HPP
2 #define _DEPOOLARRAY_HPP
3 /*-------------------------------------------------------------------------
4 * drawElements C++ Base Library
5 * -----------------------------
7 * Copyright 2014 The Android Open Source Project
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 * \brief Array template backed by memory pool.
24 *//*--------------------------------------------------------------------*/
27 #include "deMemPool.hpp"
35 //! Self-test for PoolArray
36 void PoolArray_selfTest (void);
38 template<typename T, deUint32 Alignment>
39 class PoolArrayConstIterator;
41 template<typename T, deUint32 Alignment>
42 class PoolArrayIterator;
44 /*--------------------------------------------------------------------*//*!
45 * \brief Array template backed by memory pool
47 * \note Memory in PoolArray is not contiguous so pointer arithmetic
48 * to access next element(s) doesn't work.
49 * \todo [2013-02-11 pyry] Make elements per page template argument.
50 *//*--------------------------------------------------------------------*/
51 template<typename T, deUint32 Alignment = (sizeof(T) > sizeof(void*) ? (deUint32)sizeof(void*) : (deUint32)sizeof(T))>
55 typedef PoolArrayIterator<T, Alignment> Iterator;
56 typedef PoolArrayConstIterator<T, Alignment> ConstIterator;
58 typedef Iterator iterator;
59 typedef ConstIterator const_iterator;
61 explicit PoolArray (MemPool* pool);
62 PoolArray (MemPool* pool, const PoolArray<T, Alignment>& other);
67 void reserve (deUintptr capacity);
68 void resize (deUintptr size);
69 void resize (deUintptr size, const T& value);
71 deUintptr size (void) const { return m_numElements; }
72 bool empty (void) const { return m_numElements == 0;}
74 void pushBack (const T& value);
77 const T& at (deIntptr ndx) const { return *getPtr(ndx); }
78 T& at (deIntptr ndx) { return *getPtr(ndx); }
80 const T& operator[] (deIntptr ndx) const { return at(ndx); }
81 T& operator[] (deIntptr ndx) { return at(ndx); }
83 Iterator begin (void) { return Iterator(this, 0); }
84 Iterator end (void) { return Iterator(this, (deIntptr)m_numElements); }
86 ConstIterator begin (void) const { return ConstIterator(this, 0); }
87 ConstIterator end (void) const { return ConstIterator(this, (deIntptr)m_numElements); }
89 const T& front (void) const { return at(0); }
90 T& front (void) { return at(0); }
92 const T& back (void) const { return at(m_numElements-1); }
93 T& back (void) { return at(m_numElements-1); }
98 ELEMENTS_PER_PAGE_LOG2 = 4 //!< 16 elements per page.
101 PoolArray (const PoolArray<T, Alignment>& other); // \note Default copy ctor is not allowed, use PoolArray(pool, copy) instead.
103 T* getPtr (deIntptr ndx) const;
107 deUintptr m_numElements; //!< Number of elements in the array.
108 deUintptr m_capacity; //!< Number of allocated elements in the array.
110 deUintptr m_pageTableCapacity; //!< Size of the page table.
111 void** m_pageTable; //!< Pointer to the page table.
114 template<typename T, deUint32 Alignment>
115 class PoolArrayIteratorBase
118 PoolArrayIteratorBase (deUintptr ndx) : m_ndx(ndx) {}
119 ~PoolArrayIteratorBase (void) {}
121 deIntptr getNdx (void) const throw() { return m_ndx; }
127 template<typename T, deUint32 Alignment>
128 class PoolArrayConstIterator : public PoolArrayIteratorBase<T, Alignment>
131 PoolArrayConstIterator (void);
132 PoolArrayConstIterator (const PoolArray<T, Alignment>* array, deIntptr ndx);
133 PoolArrayConstIterator (const PoolArrayIterator<T, Alignment>& iterator);
134 ~PoolArrayConstIterator (void);
136 // \note Default assignment and copy-constructor are auto-generated.
138 const PoolArray<T, Alignment>* getArray (void) const throw() { return m_array; }
140 // De-reference operators.
141 const T* operator-> (void) const throw() { return &(*m_array)[this->m_ndx]; }
142 const T& operator* (void) const throw() { return (*m_array)[this->m_ndx]; }
143 const T& operator[] (deUintptr offs) const throw() { return (*m_array)[this->m_ndx+offs]; }
145 // Pre-increment and decrement.
146 PoolArrayConstIterator<T, Alignment>& operator++ (void) { this->m_ndx += 1; return *this; }
147 PoolArrayConstIterator<T, Alignment>& operator-- (void) { this->m_ndx -= 1; return *this; }
149 // Post-increment and decrement.
150 PoolArrayConstIterator<T, Alignment> operator++ (int) { PoolArrayConstIterator<T, Alignment> copy(*this); this->m_ndx +=1; return copy; }
151 PoolArrayConstIterator<T, Alignment> operator-- (int) { PoolArrayConstIterator<T, Alignment> copy(*this); this->m_ndx -=1; return copy; }
153 // Compound assignment.
154 PoolArrayConstIterator<T, Alignment>& operator+= (deIntptr offs) { this->m_ndx += offs; return *this; }
155 PoolArrayConstIterator<T, Alignment>& operator-= (deIntptr offs) { this->m_ndx -= offs; return *this; }
157 // Assignment from non-const.
158 PoolArrayConstIterator<T, Alignment>& operator= (const PoolArrayIterator<T, Alignment>& iter);
161 const PoolArray<T, Alignment>* m_array;
164 template<typename T, deUint32 Alignment>
165 class PoolArrayIterator : public PoolArrayIteratorBase<T, Alignment>
168 PoolArrayIterator (void);
169 PoolArrayIterator (PoolArray<T, Alignment>* array, deIntptr ndx);
170 ~PoolArrayIterator (void);
172 // \note Default assignment and copy-constructor are auto-generated.
174 PoolArray<T, Alignment>* getArray (void) const throw() { return m_array; }
176 // De-reference operators.
177 T* operator-> (void) const throw() { return &(*m_array)[this->m_ndx]; }
178 T& operator* (void) const throw() { return (*m_array)[this->m_ndx]; }
179 T& operator[] (deUintptr offs) const throw() { return (*m_array)[this->m_ndx+offs]; }
181 // Pre-increment and decrement.
182 PoolArrayIterator<T, Alignment>& operator++ (void) { this->m_ndx += 1; return *this; }
183 PoolArrayIterator<T, Alignment>& operator-- (void) { this->m_ndx -= 1; return *this; }
185 // Post-increment and decrement.
186 PoolArrayIterator<T, Alignment> operator++ (int) { PoolArrayIterator<T, Alignment> copy(*this); this->m_ndx +=1; return copy; }
187 PoolArrayIterator<T, Alignment> operator-- (int) { PoolArrayIterator<T, Alignment> copy(*this); this->m_ndx -=1; return copy; }
189 // Compound assignment.
190 PoolArrayIterator<T, Alignment>& operator+= (deIntptr offs) { this->m_ndx += offs; return *this; }
191 PoolArrayIterator<T, Alignment>& operator-= (deIntptr offs) { this->m_ndx -= offs; return *this; }
194 PoolArray<T, Alignment>* m_array;
197 // Initializer helper for array.
199 struct PoolArrayElement
201 static void constructDefault (void* ptr) { new (ptr) T(); } //!< Called for non-initialized memory.
202 static void constructCopy (void* ptr, const T& val) { new (ptr) T(val); } //!< Called for non-initialized memory when initial value is provided.
203 static void destruct (T* ptr) { ptr->~T(); } //!< Called when element is destructed.
206 // Specialization for basic types.
207 #define DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(TYPE) \
208 template<> struct PoolArrayElement<TYPE> { \
209 static void constructDefault (void*) {} \
210 static void constructCopy (void* ptr, TYPE val) { *(TYPE*)ptr = val; } \
211 static void destruct (TYPE*) {} \
214 DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deUint8);
215 DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deUint16);
216 DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deUint32);
217 DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deUint64);
218 DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deInt8);
219 DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deInt16);
220 DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deInt32);
221 DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deInt64);
223 // PoolArray<T> implementation.
225 template<typename T, deUint32 Alignment>
226 PoolArray<T, Alignment>::PoolArray (MemPool* pool)
230 , m_pageTableCapacity (0)
233 DE_ASSERT(deIsPowerOfTwo32(Alignment));
236 template<typename T, deUint32 Alignment>
237 PoolArray<T, Alignment>::~PoolArray (void)
239 // Clear resets values to T()
243 template<typename T, deUint32 Alignment>
244 inline void PoolArray<T, Alignment>::clear (void)
249 template<typename T, deUint32 Alignment>
250 inline void PoolArray<T, Alignment>::resize (deUintptr newSize)
252 if (newSize < m_numElements)
254 // Destruct elements that are no longer active.
255 for (deUintptr ndx = newSize; ndx < m_numElements; ndx++)
256 PoolArrayElement<T>::destruct(getPtr(ndx));
258 m_numElements = newSize;
260 else if (newSize > m_numElements)
262 deUintptr prevSize = m_numElements;
265 m_numElements = newSize;
267 // Fill new elements with default values
268 for (deUintptr ndx = prevSize; ndx < m_numElements; ndx++)
269 PoolArrayElement<T>::constructDefault(getPtr(ndx));
273 template<typename T, deUint32 Alignment>
274 inline void PoolArray<T, Alignment>::resize (deUintptr newSize, const T& value)
276 if (newSize < m_numElements)
277 resize(newSize); // value is not used
278 else if (newSize > m_numElements)
280 deUintptr prevSize = m_numElements;
283 m_numElements = newSize;
285 // Fill new elements with copies of value
286 for (deUintptr ndx = prevSize; ndx < m_numElements; ndx++)
287 PoolArrayElement<T>::constructCopy(getPtr(ndx), value);
291 template<typename T, deUint32 Alignment>
292 inline void PoolArray<T, Alignment>::reserve (deUintptr capacity)
294 if (capacity >= m_capacity)
296 void* oldPageTable = DE_NULL;
297 deUintptr oldPageTableSize = 0;
299 deUintptr newCapacity = (deUintptr)deAlignPtr((void*)capacity, 1 << ELEMENTS_PER_PAGE_LOG2);
300 deUintptr reqPageTableCapacity = newCapacity >> ELEMENTS_PER_PAGE_LOG2;
302 if (m_pageTableCapacity < reqPageTableCapacity)
304 deUintptr newPageTableCapacity = max(2*m_pageTableCapacity, reqPageTableCapacity);
305 void** newPageTable = (void**)m_pool->alloc(newPageTableCapacity * sizeof(void*));
308 for (i = 0; i < m_pageTableCapacity; i++)
309 newPageTable[i] = m_pageTable[i];
311 for (; i < newPageTableCapacity; i++)
312 newPageTable[i] = DE_NULL;
314 // Grab information about old page table for recycling purposes.
315 oldPageTable = m_pageTable;
316 oldPageTableSize = m_pageTableCapacity * sizeof(T*);
318 m_pageTable = newPageTable;
319 m_pageTableCapacity = newPageTableCapacity;
322 // Allocate new pages.
324 deUintptr elementSize = (deUintptr)deAlignPtr((void*)(deUintptr)sizeof(T), Alignment);
325 deUintptr pageAllocSize = elementSize << ELEMENTS_PER_PAGE_LOG2;
326 deUintptr pageTableNdx = m_capacity >> ELEMENTS_PER_PAGE_LOG2;
328 // Allocate new pages from recycled old page table.
331 void* newPage = deAlignPtr(oldPageTable, Alignment);
332 deUintptr alignPadding = (deUintptr)newPage - (deUintptr)oldPageTable;
334 if (oldPageTableSize < pageAllocSize+alignPadding)
335 break; // No free space for alloc + alignment.
337 DE_ASSERT(m_pageTableCapacity > pageTableNdx);
338 DE_ASSERT(!m_pageTable[pageTableNdx]);
339 m_pageTable[pageTableNdx++] = newPage;
341 oldPageTable = (void*)((deUint8*)newPage + pageAllocSize);
342 oldPageTableSize -= pageAllocSize+alignPadding;
345 // Allocate the rest of the needed pages from the pool.
346 for (; pageTableNdx < reqPageTableCapacity; pageTableNdx++)
348 DE_ASSERT(!m_pageTable[pageTableNdx]);
349 m_pageTable[pageTableNdx] = m_pool->alignedAlloc(pageAllocSize, Alignment);
352 m_capacity = pageTableNdx << ELEMENTS_PER_PAGE_LOG2;
353 DE_ASSERT(m_capacity >= newCapacity);
358 template<typename T, deUint32 Alignment>
359 inline void PoolArray<T, Alignment>::pushBack (const T& value)
362 at(size()-1) = value;
365 template<typename T, deUint32 Alignment>
366 inline T PoolArray<T, Alignment>::popBack (void)
368 T val = at(size()-1);
373 template<typename T, deUint32 Alignment>
374 inline T* PoolArray<T, Alignment>::getPtr (deIntptr ndx) const
376 DE_ASSERT(inBounds<deIntptr>(ndx, 0, (deIntptr)m_numElements));
377 deUintptr pageNdx = ((deUintptr)ndx >> ELEMENTS_PER_PAGE_LOG2);
378 deUintptr subNdx = (deUintptr)ndx & ((1 << ELEMENTS_PER_PAGE_LOG2) - 1);
379 deUintptr elemSize = (deUintptr)deAlignPtr((void*)(deUintptr)sizeof(T), Alignment);
380 T* ptr = (T*)((deUint8*)m_pageTable[pageNdx] + (subNdx*elemSize));
381 DE_ASSERT(deIsAlignedPtr(ptr, Alignment));
385 // PoolArrayIteratorBase implementation
387 template<typename T, deUint32 Alignment>
388 inline bool operator== (const PoolArrayIteratorBase<T, Alignment>& a, const PoolArrayIteratorBase<T, Alignment>& b)
390 // \todo [2013-02-08 pyry] Compare array ptr.
391 return a.getNdx() == b.getNdx();
394 template<typename T, deUint32 Alignment>
395 inline bool operator!= (const PoolArrayIteratorBase<T, Alignment>& a, const PoolArrayIteratorBase<T, Alignment>& b)
397 // \todo [2013-02-08 pyry] Compare array ptr.
398 return a.getNdx() != b.getNdx();
401 template<typename T, deUint32 Alignment>
402 inline bool operator< (const PoolArrayIteratorBase<T, Alignment>& a, const PoolArrayIteratorBase<T, Alignment>& b)
404 return a.getNdx() < b.getNdx();
407 template<typename T, deUint32 Alignment>
408 inline bool operator> (const PoolArrayIteratorBase<T, Alignment>& a, const PoolArrayIteratorBase<T, Alignment>& b)
410 return a.getNdx() > b.getNdx();
413 template<typename T, deUint32 Alignment>
414 inline bool operator<= (const PoolArrayIteratorBase<T, Alignment>& a, const PoolArrayIteratorBase<T, Alignment>& b)
416 return a.getNdx() <= b.getNdx();
419 template<typename T, deUint32 Alignment>
420 inline bool operator>= (const PoolArrayIteratorBase<T, Alignment>& a, const PoolArrayIteratorBase<T, Alignment>& b)
422 return a.getNdx() >= b.getNdx();
425 // PoolArrayConstIterator<T> implementation
427 template<typename T, deUint32 Alignment>
428 inline PoolArrayConstIterator<T, Alignment>::PoolArrayConstIterator (void)
429 : PoolArrayIteratorBase<T, Alignment> (0)
434 template<typename T, deUint32 Alignment>
435 inline PoolArrayConstIterator<T, Alignment>::PoolArrayConstIterator (const PoolArray<T, Alignment>* array, deIntptr ndx)
436 : PoolArrayIteratorBase<T, Alignment> (ndx)
441 template<typename T, deUint32 Alignment>
442 inline PoolArrayConstIterator<T, Alignment>::PoolArrayConstIterator (const PoolArrayIterator<T, Alignment>& iter)
443 : PoolArrayIteratorBase<T, Alignment> (iter)
444 , m_array (iter.getArray())
448 template<typename T, deUint32 Alignment>
449 inline PoolArrayConstIterator<T, Alignment>::~PoolArrayConstIterator (void)
453 // Arithmetic operators.
455 template<typename T, deUint32 Alignment>
456 inline PoolArrayConstIterator<T, Alignment> operator+ (const PoolArrayConstIterator<T, Alignment>& iter, deIntptr offs)
458 return PoolArrayConstIterator<T, Alignment>(iter->getArray(), iter->getNdx()+offs);
461 template<typename T, deUint32 Alignment>
462 inline PoolArrayConstIterator<T, Alignment> operator+ (deUintptr offs, const PoolArrayConstIterator<T, Alignment>& iter)
464 return PoolArrayConstIterator<T, Alignment>(iter->getArray(), iter->getNdx()+offs);
467 template<typename T, deUint32 Alignment>
468 PoolArrayConstIterator<T, Alignment> operator- (const PoolArrayConstIterator<T, Alignment>& iter, deIntptr offs)
470 return PoolArrayConstIterator<T, Alignment>(iter.getArray(), iter.getNdx()-offs);
473 template<typename T, deUint32 Alignment>
474 deIntptr operator- (const PoolArrayConstIterator<T, Alignment>& iter, const PoolArrayConstIterator<T, Alignment>& other)
476 return iter.getNdx()-other.getNdx();
479 // PoolArrayIterator<T> implementation.
481 template<typename T, deUint32 Alignment>
482 inline PoolArrayIterator<T, Alignment>::PoolArrayIterator (void)
483 : PoolArrayIteratorBase<T, Alignment> (0)
488 template<typename T, deUint32 Alignment>
489 inline PoolArrayIterator<T, Alignment>::PoolArrayIterator (PoolArray<T, Alignment>* array, deIntptr ndx)
490 : PoolArrayIteratorBase<T, Alignment> (ndx)
495 template<typename T, deUint32 Alignment>
496 inline PoolArrayIterator<T, Alignment>::~PoolArrayIterator (void)
500 // Arithmetic operators.
502 template<typename T, deUint32 Alignment>
503 inline PoolArrayIterator<T, Alignment> operator+ (const PoolArrayIterator<T, Alignment>& iter, deIntptr offs)
505 return PoolArrayIterator<T, Alignment>(iter.getArray(), iter.getNdx()+offs);
508 template<typename T, deUint32 Alignment>
509 inline PoolArrayIterator<T, Alignment> operator+ (deUintptr offs, const PoolArrayIterator<T, Alignment>& iter)
511 return PoolArrayIterator<T, Alignment>(iter.getArray(), iter.getNdx()+offs);
514 template<typename T, deUint32 Alignment>
515 PoolArrayIterator<T, Alignment> operator- (const PoolArrayIterator<T, Alignment>& iter, deIntptr offs)
517 return PoolArrayIterator<T, Alignment>(iter.getArray(), iter.getNdx()-offs);
520 template<typename T, deUint32 Alignment>
521 deIntptr operator- (const PoolArrayIterator<T, Alignment>& iter, const PoolArrayIterator<T, Alignment>& other)
523 return iter.getNdx()-other.getNdx();
528 // std::iterator_traits specializations
532 template<typename T, deUint32 Alignment>
533 struct iterator_traits<de::PoolArrayConstIterator<T, Alignment> >
535 typedef deIntptr difference_type;
536 typedef T value_type;
537 typedef const T* pointer;
538 typedef const T& reference;
539 typedef random_access_iterator_tag iterator_category;
542 template<typename T, deUint32 Alignment>
543 struct iterator_traits<de::PoolArrayIterator<T, Alignment> >
545 typedef deIntptr difference_type;
546 typedef T value_type;
548 typedef T& reference;
549 typedef random_access_iterator_tag iterator_category;
554 #endif // _DEPOOLARRAY_HPP