Home | History | Annotate | Download | only in decpp
      1 #ifndef _DEARRAYBUFFER_HPP
      2 #define _DEARRAYBUFFER_HPP
      3 /*-------------------------------------------------------------------------
      4  * drawElements C++ Base Library
      5  * -----------------------------
      6  *
      7  * Copyright 2014 The Android Open Source Project
      8  *
      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
     12  *
     13  *      http://www.apache.org/licenses/LICENSE-2.0
     14  *
     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.
     20  *
     21  *//*!
     22  * \file
     23  * \brief Array buffer
     24  *//*--------------------------------------------------------------------*/
     25 
     26 #include "deDefs.hpp"
     27 #include "deMemory.h"
     28 
     29 #include <new>
     30 
     31 namespace de
     32 {
     33 namespace detail
     34 {
     35 
     36 void* ArrayBuffer_AlignedMalloc (size_t numBytes, size_t alignment);
     37 void ArrayBuffer_AlignedFree (void*);
     38 
     39 } // detail
     40 
     41 //! Array buffer self-test.
     42 void ArrayBuffer_selfTest (void);
     43 
     44 /*--------------------------------------------------------------------*//*!
     45  * \brief Contiguous array that does not initialize its elements.
     46  *//*--------------------------------------------------------------------*/
     47 template <typename T, size_t Alignment = (sizeof(T) > 4 ? 4 : sizeof(T)), size_t Stride = sizeof(T)>
     48 class ArrayBuffer
     49 {
     50 public:
     51 	DE_STATIC_ASSERT(Stride >= sizeof(T));
     52 
     53 					ArrayBuffer		(void) throw();
     54 					ArrayBuffer		(size_t numElements);
     55 					ArrayBuffer		(const T* ptr, size_t numElements);
     56 					ArrayBuffer		(const ArrayBuffer& other);
     57 					~ArrayBuffer	(void) throw();
     58 	ArrayBuffer&	operator=		(const ArrayBuffer& other);
     59 
     60 	void			clear			(void) throw();
     61 	void			setStorage		(size_t numElements); // !< \note after a succesful call buffer contents are undefined
     62 	void			swap			(ArrayBuffer& other) throw();
     63 	size_t			size			(void) const throw();
     64 	bool			empty			(void) const throw();
     65 
     66 	T*				getElementPtr	(size_t elementNdx) throw();
     67 	const T*		getElementPtr	(size_t elementNdx) const throw();
     68 	void*			getPtr			(void) throw();
     69 	const void*		getPtr			(void) const throw();
     70 
     71 private:
     72 	void*			m_ptr;
     73 	size_t			m_cap;
     74 } DE_WARN_UNUSED_TYPE;
     75 
     76 template <typename T, size_t Alignment, size_t Stride>
     77 ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (void) throw()
     78 	: m_ptr	(DE_NULL)
     79 	, m_cap	(0)
     80 {
     81 }
     82 
     83 template <typename T, size_t Alignment, size_t Stride>
     84 ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (size_t numElements)
     85 	: m_ptr	(DE_NULL)
     86 	, m_cap	(0)
     87 {
     88 	if (numElements)
     89 	{
     90 		// \note no need to allocate stride for the last element, sizeof(T) is enough. Also handles cases where sizeof(T) > Stride
     91 		const size_t	storageSize	= (numElements - 1) * Stride + sizeof(T);
     92 		void* const		ptr			= detail::ArrayBuffer_AlignedMalloc(storageSize, Alignment);
     93 
     94 		if (!ptr)
     95 			throw std::bad_alloc();
     96 
     97 		m_ptr = ptr;
     98 		m_cap = numElements;
     99 	}
    100 }
    101 
    102 template <typename T, size_t Alignment, size_t Stride>
    103 ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (const T* ptr, size_t numElements)
    104 	: m_ptr	(DE_NULL)
    105 	, m_cap	(0)
    106 {
    107 	if (numElements)
    108 	{
    109 		// create new buffer of wanted size, copy to it, and swap to it
    110 		ArrayBuffer<T,Alignment,Stride> tmp(numElements);
    111 
    112 		if (Stride == sizeof(T))
    113 		{
    114 			// tightly packed
    115 			const size_t storageSize = sizeof(T) * numElements;
    116 			deMemcpy(tmp.m_ptr, ptr, (int)storageSize);
    117 		}
    118 		else
    119 		{
    120 			// sparsely packed
    121 			for (size_t ndx = 0; ndx < numElements; ++ndx)
    122 				*tmp.getElementPtr(ndx) = ptr[ndx];
    123 		}
    124 
    125 		swap(tmp);
    126 	}
    127 }
    128 
    129 template <typename T, size_t Alignment, size_t Stride>
    130 ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (const ArrayBuffer<T,Alignment,Stride>& other)
    131 	: m_ptr	(DE_NULL)
    132 	, m_cap	(0)
    133 {
    134 	if (other.m_cap)
    135 	{
    136 		// copy to temporary and swap to it
    137 
    138 		const size_t	storageSize =	(other.m_cap - 1) * Stride + sizeof(T);
    139 		ArrayBuffer		tmp				(other.m_cap);
    140 
    141 		deMemcpy(tmp.m_ptr, other.m_ptr, (int)storageSize);
    142 		swap(tmp);
    143 	}
    144 }
    145 
    146 template <typename T, size_t Alignment, size_t Stride>
    147 ArrayBuffer<T,Alignment,Stride>::~ArrayBuffer (void) throw()
    148 {
    149 	clear();
    150 }
    151 
    152 template <typename T, size_t Alignment, size_t Stride>
    153 ArrayBuffer<T,Alignment,Stride>& ArrayBuffer<T,Alignment,Stride>::operator= (const ArrayBuffer& other)
    154 {
    155 	ArrayBuffer copied(other);
    156 	swap(copied);
    157 	return *this;
    158 }
    159 
    160 template <typename T, size_t Alignment, size_t Stride>
    161 void ArrayBuffer<T,Alignment,Stride>::clear (void) throw()
    162 {
    163 	detail::ArrayBuffer_AlignedFree(m_ptr);
    164 
    165 	m_ptr = DE_NULL;
    166 	m_cap = 0;
    167 }
    168 
    169 template <typename T, size_t Alignment, size_t Stride>
    170 void ArrayBuffer<T,Alignment,Stride>::setStorage (size_t numElements)
    171 {
    172 	// create new buffer of the wanted size, swap to it
    173 	ArrayBuffer<T,Alignment,Stride> newBuffer(numElements);
    174 	swap(newBuffer);
    175 }
    176 
    177 template <typename T, size_t Alignment, size_t Stride>
    178 void ArrayBuffer<T,Alignment,Stride>::swap (ArrayBuffer& other) throw()
    179 {
    180 	void* const		otherPtr = other.m_ptr;
    181 	const size_t	otherCap = other.m_cap;
    182 
    183 	other.m_ptr = m_ptr;
    184 	other.m_cap = m_cap;
    185 	m_ptr		= otherPtr;
    186 	m_cap		= otherCap;
    187 }
    188 
    189 template <typename T, size_t Alignment, size_t Stride>
    190 size_t ArrayBuffer<T,Alignment,Stride>::size (void) const throw()
    191 {
    192 	return m_cap;
    193 }
    194 
    195 template <typename T, size_t Alignment, size_t Stride>
    196 bool ArrayBuffer<T,Alignment,Stride>::empty (void) const throw()
    197 {
    198 	return size() == 0;
    199 }
    200 
    201 template <typename T, size_t Alignment, size_t Stride>
    202 T* ArrayBuffer<T,Alignment,Stride>::getElementPtr (size_t elementNdx) throw()
    203 {
    204 	return (T*)(((deUint8*)m_ptr) + Stride * elementNdx);
    205 }
    206 
    207 template <typename T, size_t Alignment, size_t Stride>
    208 const T* ArrayBuffer<T,Alignment,Stride>::getElementPtr (size_t elementNdx) const throw()
    209 {
    210 	return (T*)(((deUint8*)m_ptr) + Stride * elementNdx);
    211 }
    212 
    213 template <typename T, size_t Alignment, size_t Stride>
    214 void* ArrayBuffer<T,Alignment,Stride>::getPtr (void) throw()
    215 {
    216 	return m_ptr;
    217 }
    218 
    219 template <typename T, size_t Alignment, size_t Stride>
    220 const void* ArrayBuffer<T,Alignment,Stride>::getPtr (void) const throw()
    221 {
    222 	return m_ptr;
    223 }
    224 
    225 } // de
    226 
    227 #endif // _DEARRAYBUFFER_HPP
    228