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