#ifndef _DEPOOLARRAY_HPP #define _DEPOOLARRAY_HPP /*------------------------------------------------------------------------- * drawElements C++ Base Library * ----------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Array template backed by memory pool. *//*--------------------------------------------------------------------*/ #include "deDefs.hpp" #include "deMemPool.hpp" #include "deInt32.h" #include namespace de { //! Self-test for PoolArray void PoolArray_selfTest (void); template class PoolArrayConstIterator; template class PoolArrayIterator; /*--------------------------------------------------------------------*//*! * \brief Array template backed by memory pool * * \note Memory in PoolArray is not contiguous so pointer arithmetic * to access next element(s) doesn't work. * \todo [2013-02-11 pyry] Make elements per page template argument. *//*--------------------------------------------------------------------*/ template sizeof(void*) ? (deUint32)sizeof(void*) : (deUint32)sizeof(T))> class PoolArray { public: typedef PoolArrayIterator Iterator; typedef PoolArrayConstIterator ConstIterator; typedef Iterator iterator; typedef ConstIterator const_iterator; explicit PoolArray (MemPool* pool); PoolArray (MemPool* pool, const PoolArray& other); ~PoolArray (void); void clear (void); void reserve (deUintptr capacity); void resize (deUintptr size); void resize (deUintptr size, const T& value); deUintptr size (void) const { return m_numElements; } bool empty (void) const { return m_numElements == 0;} void pushBack (const T& value); T popBack (void); const T& at (deIntptr ndx) const { return *getPtr(ndx); } T& at (deIntptr ndx) { return *getPtr(ndx); } const T& operator[] (deIntptr ndx) const { return at(ndx); } T& operator[] (deIntptr ndx) { return at(ndx); } Iterator begin (void) { return Iterator(this, 0); } Iterator end (void) { return Iterator(this, (deIntptr)m_numElements); } ConstIterator begin (void) const { return ConstIterator(this, 0); } ConstIterator end (void) const { return ConstIterator(this, (deIntptr)m_numElements); } const T& front (void) const { return at(0); } T& front (void) { return at(0); } const T& back (void) const { return at(m_numElements-1); } T& back (void) { return at(m_numElements-1); } private: enum { ELEMENTS_PER_PAGE_LOG2 = 4 //!< 16 elements per page. }; PoolArray (const PoolArray& other); // \note Default copy ctor is not allowed, use PoolArray(pool, copy) instead. T* getPtr (deIntptr ndx) const; MemPool* m_pool; deUintptr m_numElements; //!< Number of elements in the array. deUintptr m_capacity; //!< Number of allocated elements in the array. deUintptr m_pageTableCapacity; //!< Size of the page table. void** m_pageTable; //!< Pointer to the page table. }; template class PoolArrayIteratorBase { public: PoolArrayIteratorBase (deUintptr ndx) : m_ndx(ndx) {} ~PoolArrayIteratorBase (void) {} deIntptr getNdx (void) const throw() { return m_ndx; } protected: deIntptr m_ndx; }; template class PoolArrayConstIterator : public PoolArrayIteratorBase { public: PoolArrayConstIterator (void); PoolArrayConstIterator (const PoolArray* array, deIntptr ndx); PoolArrayConstIterator (const PoolArrayIterator& iterator); ~PoolArrayConstIterator (void); // \note Default assignment and copy-constructor are auto-generated. const PoolArray* getArray (void) const throw() { return m_array; } // De-reference operators. const T* operator-> (void) const throw() { return &(*m_array)[this->m_ndx]; } const T& operator* (void) const throw() { return (*m_array)[this->m_ndx]; } const T& operator[] (deUintptr offs) const throw() { return (*m_array)[this->m_ndx+offs]; } // Pre-increment and decrement. PoolArrayConstIterator& operator++ (void) { this->m_ndx += 1; return *this; } PoolArrayConstIterator& operator-- (void) { this->m_ndx -= 1; return *this; } // Post-increment and decrement. PoolArrayConstIterator operator++ (int) { PoolArrayConstIterator copy(*this); this->m_ndx +=1; return copy; } PoolArrayConstIterator operator-- (int) { PoolArrayConstIterator copy(*this); this->m_ndx -=1; return copy; } // Compound assignment. PoolArrayConstIterator& operator+= (deIntptr offs) { this->m_ndx += offs; return *this; } PoolArrayConstIterator& operator-= (deIntptr offs) { this->m_ndx -= offs; return *this; } // Assignment from non-const. PoolArrayConstIterator& operator= (const PoolArrayIterator& iter); private: const PoolArray* m_array; }; template class PoolArrayIterator : public PoolArrayIteratorBase { public: PoolArrayIterator (void); PoolArrayIterator (PoolArray* array, deIntptr ndx); ~PoolArrayIterator (void); // \note Default assignment and copy-constructor are auto-generated. PoolArray* getArray (void) const throw() { return m_array; } // De-reference operators. T* operator-> (void) const throw() { return &(*m_array)[this->m_ndx]; } T& operator* (void) const throw() { return (*m_array)[this->m_ndx]; } T& operator[] (deUintptr offs) const throw() { return (*m_array)[this->m_ndx+offs]; } // Pre-increment and decrement. PoolArrayIterator& operator++ (void) { this->m_ndx += 1; return *this; } PoolArrayIterator& operator-- (void) { this->m_ndx -= 1; return *this; } // Post-increment and decrement. PoolArrayIterator operator++ (int) { PoolArrayIterator copy(*this); this->m_ndx +=1; return copy; } PoolArrayIterator operator-- (int) { PoolArrayIterator copy(*this); this->m_ndx -=1; return copy; } // Compound assignment. PoolArrayIterator& operator+= (deIntptr offs) { this->m_ndx += offs; return *this; } PoolArrayIterator& operator-= (deIntptr offs) { this->m_ndx -= offs; return *this; } private: PoolArray* m_array; }; // Initializer helper for array. template struct PoolArrayElement { static void constructDefault (void* ptr) { new (ptr) T(); } //!< Called for non-initialized memory. static void constructCopy (void* ptr, const T& val) { new (ptr) T(val); } //!< Called for non-initialized memory when initial value is provided. static void destruct (T* ptr) { ptr->~T(); } //!< Called when element is destructed. }; // Specialization for basic types. #define DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(TYPE) \ template<> struct PoolArrayElement { \ static void constructDefault (void*) {} \ static void constructCopy (void* ptr, TYPE val) { *(TYPE*)ptr = val; } \ static void destruct (TYPE*) {} \ } DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deUint8); DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deUint16); DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deUint32); DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deUint64); DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deInt8); DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deInt16); DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deInt32); DE_SPECIALIZE_POOL_ARRAY_ELEMENT_BASIC_TYPE(deInt64); // PoolArray implementation. template PoolArray::PoolArray (MemPool* pool) : m_pool (pool) , m_numElements (0) , m_capacity (0) , m_pageTableCapacity (0) , m_pageTable (0) { DE_ASSERT(deIsPowerOfTwo32(Alignment)); } template PoolArray::~PoolArray (void) { // Clear resets values to T() clear(); } template inline void PoolArray::clear (void) { resize(0); } template inline void PoolArray::resize (deUintptr newSize) { if (newSize < m_numElements) { // Destruct elements that are no longer active. for (deUintptr ndx = newSize; ndx < m_numElements; ndx++) PoolArrayElement::destruct(getPtr(ndx)); m_numElements = newSize; } else if (newSize > m_numElements) { deUintptr prevSize = m_numElements; reserve(newSize); m_numElements = newSize; // Fill new elements with default values for (deUintptr ndx = prevSize; ndx < m_numElements; ndx++) PoolArrayElement::constructDefault(getPtr(ndx)); } } template inline void PoolArray::resize (deUintptr newSize, const T& value) { if (newSize < m_numElements) resize(newSize); // value is not used else if (newSize > m_numElements) { deUintptr prevSize = m_numElements; reserve(newSize); m_numElements = newSize; // Fill new elements with copies of value for (deUintptr ndx = prevSize; ndx < m_numElements; ndx++) PoolArrayElement::constructCopy(getPtr(ndx), value); } } template inline void PoolArray::reserve (deUintptr capacity) { if (capacity >= m_capacity) { void* oldPageTable = DE_NULL; deUintptr oldPageTableSize = 0; deUintptr newCapacity = (deUintptr)deAlignPtr((void*)capacity, 1 << ELEMENTS_PER_PAGE_LOG2); deUintptr reqPageTableCapacity = newCapacity >> ELEMENTS_PER_PAGE_LOG2; if (m_pageTableCapacity < reqPageTableCapacity) { deUintptr newPageTableCapacity = max(2*m_pageTableCapacity, reqPageTableCapacity); void** newPageTable = (void**)m_pool->alloc(newPageTableCapacity * sizeof(void*)); deUintptr i; for (i = 0; i < m_pageTableCapacity; i++) newPageTable[i] = m_pageTable[i]; for (; i < newPageTableCapacity; i++) newPageTable[i] = DE_NULL; // Grab information about old page table for recycling purposes. oldPageTable = m_pageTable; oldPageTableSize = m_pageTableCapacity * sizeof(T*); m_pageTable = newPageTable; m_pageTableCapacity = newPageTableCapacity; } // Allocate new pages. { deUintptr elementSize = (deUintptr)deAlignPtr((void*)(deUintptr)sizeof(T), Alignment); deUintptr pageAllocSize = elementSize << ELEMENTS_PER_PAGE_LOG2; deUintptr pageTableNdx = m_capacity >> ELEMENTS_PER_PAGE_LOG2; // Allocate new pages from recycled old page table. for (;;) { void* newPage = deAlignPtr(oldPageTable, Alignment); deUintptr alignPadding = (deUintptr)newPage - (deUintptr)oldPageTable; if (oldPageTableSize < pageAllocSize+alignPadding) break; // No free space for alloc + alignment. DE_ASSERT(m_pageTableCapacity > pageTableNdx); DE_ASSERT(!m_pageTable[pageTableNdx]); m_pageTable[pageTableNdx++] = newPage; oldPageTable = (void*)((deUint8*)newPage + pageAllocSize); oldPageTableSize -= pageAllocSize+alignPadding; } // Allocate the rest of the needed pages from the pool. for (; pageTableNdx < reqPageTableCapacity; pageTableNdx++) { DE_ASSERT(!m_pageTable[pageTableNdx]); m_pageTable[pageTableNdx] = m_pool->alignedAlloc(pageAllocSize, Alignment); } m_capacity = pageTableNdx << ELEMENTS_PER_PAGE_LOG2; DE_ASSERT(m_capacity >= newCapacity); } } } template inline void PoolArray::pushBack (const T& value) { resize(size()+1); at(size()-1) = value; } template inline T PoolArray::popBack (void) { T val = at(size()-1); resize(size()-1); return val; } template inline T* PoolArray::getPtr (deIntptr ndx) const { DE_ASSERT(inBounds(ndx, 0, (deIntptr)m_numElements)); deUintptr pageNdx = ((deUintptr)ndx >> ELEMENTS_PER_PAGE_LOG2); deUintptr subNdx = (deUintptr)ndx & ((1 << ELEMENTS_PER_PAGE_LOG2) - 1); deUintptr elemSize = (deUintptr)deAlignPtr((void*)(deUintptr)sizeof(T), Alignment); T* ptr = (T*)((deUint8*)m_pageTable[pageNdx] + (subNdx*elemSize)); DE_ASSERT(deIsAlignedPtr(ptr, Alignment)); return ptr; } // PoolArrayIteratorBase implementation template inline bool operator== (const PoolArrayIteratorBase& a, const PoolArrayIteratorBase& b) { // \todo [2013-02-08 pyry] Compare array ptr. return a.getNdx() == b.getNdx(); } template inline bool operator!= (const PoolArrayIteratorBase& a, const PoolArrayIteratorBase& b) { // \todo [2013-02-08 pyry] Compare array ptr. return a.getNdx() != b.getNdx(); } template inline bool operator< (const PoolArrayIteratorBase& a, const PoolArrayIteratorBase& b) { return a.getNdx() < b.getNdx(); } template inline bool operator> (const PoolArrayIteratorBase& a, const PoolArrayIteratorBase& b) { return a.getNdx() > b.getNdx(); } template inline bool operator<= (const PoolArrayIteratorBase& a, const PoolArrayIteratorBase& b) { return a.getNdx() <= b.getNdx(); } template inline bool operator>= (const PoolArrayIteratorBase& a, const PoolArrayIteratorBase& b) { return a.getNdx() >= b.getNdx(); } // PoolArrayConstIterator implementation template inline PoolArrayConstIterator::PoolArrayConstIterator (void) : PoolArrayIteratorBase (0) , m_array (DE_NULL) { } template inline PoolArrayConstIterator::PoolArrayConstIterator (const PoolArray* array, deIntptr ndx) : PoolArrayIteratorBase (ndx) , m_array (array) { } template inline PoolArrayConstIterator::PoolArrayConstIterator (const PoolArrayIterator& iter) : PoolArrayIteratorBase (iter) , m_array (iter.getArray()) { } template inline PoolArrayConstIterator::~PoolArrayConstIterator (void) { } // Arithmetic operators. template inline PoolArrayConstIterator operator+ (const PoolArrayConstIterator& iter, deIntptr offs) { return PoolArrayConstIterator(iter->getArray(), iter->getNdx()+offs); } template inline PoolArrayConstIterator operator+ (deUintptr offs, const PoolArrayConstIterator& iter) { return PoolArrayConstIterator(iter->getArray(), iter->getNdx()+offs); } template PoolArrayConstIterator operator- (const PoolArrayConstIterator& iter, deIntptr offs) { return PoolArrayConstIterator(iter.getArray(), iter.getNdx()-offs); } template deIntptr operator- (const PoolArrayConstIterator& iter, const PoolArrayConstIterator& other) { return iter.getNdx()-other.getNdx(); } // PoolArrayIterator implementation. template inline PoolArrayIterator::PoolArrayIterator (void) : PoolArrayIteratorBase (0) , m_array (DE_NULL) { } template inline PoolArrayIterator::PoolArrayIterator (PoolArray* array, deIntptr ndx) : PoolArrayIteratorBase (ndx) , m_array (array) { } template inline PoolArrayIterator::~PoolArrayIterator (void) { } // Arithmetic operators. template inline PoolArrayIterator operator+ (const PoolArrayIterator& iter, deIntptr offs) { return PoolArrayIterator(iter.getArray(), iter.getNdx()+offs); } template inline PoolArrayIterator operator+ (deUintptr offs, const PoolArrayIterator& iter) { return PoolArrayIterator(iter.getArray(), iter.getNdx()+offs); } template PoolArrayIterator operator- (const PoolArrayIterator& iter, deIntptr offs) { return PoolArrayIterator(iter.getArray(), iter.getNdx()-offs); } template deIntptr operator- (const PoolArrayIterator& iter, const PoolArrayIterator& other) { return iter.getNdx()-other.getNdx(); } } // de // std::iterator_traits specializations namespace std { template struct iterator_traits > { typedef deIntptr difference_type; typedef T value_type; typedef const T* pointer; typedef const T& reference; typedef random_access_iterator_tag iterator_category; }; template struct iterator_traits > { typedef deIntptr difference_type; typedef T value_type; typedef T* pointer; typedef T& reference; typedef random_access_iterator_tag iterator_category; }; } // std #endif // _DEPOOLARRAY_HPP