• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
ArrayBuffer(void)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>
ArrayBuffer(size_t numElements)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>
ArrayBuffer(const T * ptr,size_t numElements)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>
ArrayBuffer(const ArrayBuffer<T,Alignment,Stride> & other)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>
~ArrayBuffer(void)147 ArrayBuffer<T,Alignment,Stride>::~ArrayBuffer (void) throw()
148 {
149 	clear();
150 }
151 
152 template <typename T, size_t Alignment, size_t Stride>
operator =(const ArrayBuffer & other)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>
clear(void)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>
setStorage(size_t numElements)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>
swap(ArrayBuffer & other)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>
size(void) const190 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>
empty(void) const196 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>
getElementPtr(size_t elementNdx)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>
getElementPtr(size_t elementNdx) const208 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>
getPtr(void)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>
getPtr(void) const220 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