| #ifndef _DEARRAYBUFFER_HPP |
| #define _DEARRAYBUFFER_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 buffer |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "deDefs.hpp" |
| #include "deMemory.h" |
| |
| #include <new> |
| |
| namespace de |
| { |
| namespace detail |
| { |
| |
| void* ArrayBuffer_AlignedMalloc (size_t numBytes, size_t alignment); |
| void ArrayBuffer_AlignedFree (void*); |
| |
| } // detail |
| |
| //! Array buffer self-test. |
| void ArrayBuffer_selfTest (void); |
| |
| /*--------------------------------------------------------------------*//*! |
| * \brief Contiguous array that does not initialize its elements. |
| *//*--------------------------------------------------------------------*/ |
| template <typename T, size_t Alignment = (sizeof(T) > 4 ? 4 : sizeof(T)), size_t Stride = sizeof(T)> |
| class ArrayBuffer |
| { |
| public: |
| DE_STATIC_ASSERT(Stride >= sizeof(T)); |
| |
| ArrayBuffer (void) throw(); |
| ArrayBuffer (size_t numElements); |
| ArrayBuffer (const T* ptr, size_t numElements); |
| ArrayBuffer (const ArrayBuffer& other); |
| ~ArrayBuffer (void) throw(); |
| ArrayBuffer& operator= (const ArrayBuffer& other); |
| |
| void clear (void) throw(); |
| void setStorage (size_t numElements); // !< \note after a succesful call buffer contents are undefined |
| void swap (ArrayBuffer& other) throw(); |
| size_t size (void) const throw(); |
| bool empty (void) const throw(); |
| |
| T* getElementPtr (size_t elementNdx) throw(); |
| const T* getElementPtr (size_t elementNdx) const throw(); |
| void* getPtr (void) throw(); |
| const void* getPtr (void) const throw(); |
| |
| private: |
| void* m_ptr; |
| size_t m_cap; |
| } DE_WARN_UNUSED_TYPE; |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (void) throw() |
| : m_ptr (DE_NULL) |
| , m_cap (0) |
| { |
| } |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (size_t numElements) |
| : m_ptr (DE_NULL) |
| , m_cap (0) |
| { |
| if (numElements) |
| { |
| // \note no need to allocate stride for the last element, sizeof(T) is enough. Also handles cases where sizeof(T) > Stride |
| const size_t storageSize = (numElements - 1) * Stride + sizeof(T); |
| void* const ptr = detail::ArrayBuffer_AlignedMalloc(storageSize, Alignment); |
| |
| if (!ptr) |
| throw std::bad_alloc(); |
| |
| m_ptr = ptr; |
| m_cap = numElements; |
| } |
| } |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (const T* ptr, size_t numElements) |
| : m_ptr (DE_NULL) |
| , m_cap (0) |
| { |
| if (numElements) |
| { |
| // create new buffer of wanted size, copy to it, and swap to it |
| ArrayBuffer<T,Alignment,Stride> tmp(numElements); |
| |
| if (Stride == sizeof(T)) |
| { |
| // tightly packed |
| const size_t storageSize = sizeof(T) * numElements; |
| deMemcpy(tmp.m_ptr, ptr, (int)storageSize); |
| } |
| else |
| { |
| // sparsely packed |
| for (size_t ndx = 0; ndx < numElements; ++ndx) |
| *tmp.getElementPtr(ndx) = ptr[ndx]; |
| } |
| |
| swap(tmp); |
| } |
| } |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (const ArrayBuffer<T,Alignment,Stride>& other) |
| : m_ptr (DE_NULL) |
| , m_cap (0) |
| { |
| if (other.m_cap) |
| { |
| // copy to temporary and swap to it |
| |
| const size_t storageSize = (other.m_cap - 1) * Stride + sizeof(T); |
| ArrayBuffer tmp (other.m_cap); |
| |
| deMemcpy(tmp.m_ptr, other.m_ptr, (int)storageSize); |
| swap(tmp); |
| } |
| } |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| ArrayBuffer<T,Alignment,Stride>::~ArrayBuffer (void) throw() |
| { |
| clear(); |
| } |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| ArrayBuffer<T,Alignment,Stride>& ArrayBuffer<T,Alignment,Stride>::operator= (const ArrayBuffer& other) |
| { |
| ArrayBuffer copied(other); |
| swap(copied); |
| return *this; |
| } |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| void ArrayBuffer<T,Alignment,Stride>::clear (void) throw() |
| { |
| detail::ArrayBuffer_AlignedFree(m_ptr); |
| |
| m_ptr = DE_NULL; |
| m_cap = 0; |
| } |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| void ArrayBuffer<T,Alignment,Stride>::setStorage (size_t numElements) |
| { |
| // create new buffer of the wanted size, swap to it |
| ArrayBuffer<T,Alignment,Stride> newBuffer(numElements); |
| swap(newBuffer); |
| } |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| void ArrayBuffer<T,Alignment,Stride>::swap (ArrayBuffer& other) throw() |
| { |
| void* const otherPtr = other.m_ptr; |
| const size_t otherCap = other.m_cap; |
| |
| other.m_ptr = m_ptr; |
| other.m_cap = m_cap; |
| m_ptr = otherPtr; |
| m_cap = otherCap; |
| } |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| size_t ArrayBuffer<T,Alignment,Stride>::size (void) const throw() |
| { |
| return m_cap; |
| } |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| bool ArrayBuffer<T,Alignment,Stride>::empty (void) const throw() |
| { |
| return size() == 0; |
| } |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| T* ArrayBuffer<T,Alignment,Stride>::getElementPtr (size_t elementNdx) throw() |
| { |
| return (T*)(((deUint8*)m_ptr) + Stride * elementNdx); |
| } |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| const T* ArrayBuffer<T,Alignment,Stride>::getElementPtr (size_t elementNdx) const throw() |
| { |
| return (T*)(((deUint8*)m_ptr) + Stride * elementNdx); |
| } |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| void* ArrayBuffer<T,Alignment,Stride>::getPtr (void) throw() |
| { |
| return m_ptr; |
| } |
| |
| template <typename T, size_t Alignment, size_t Stride> |
| const void* ArrayBuffer<T,Alignment,Stride>::getPtr (void) const throw() |
| { |
| return m_ptr; |
| } |
| |
| } // de |
| |
| #endif // _DEARRAYBUFFER_HPP |