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
31namespace de
32{
33namespace detail
34{
35
36void* ArrayBuffer_AlignedMalloc (size_t numBytes, size_t alignment);
37void ArrayBuffer_AlignedFree (void*);
38
39} // detail
40
41//! Array buffer self-test.
42void ArrayBuffer_selfTest (void);
43
44/*--------------------------------------------------------------------*//*!
45 * \brief Contiguous array that does not initialize its elements.
46 *//*--------------------------------------------------------------------*/
47template <typename T, size_t Alignment = (sizeof(T) > 4 ? 4 : sizeof(T)), size_t Stride = sizeof(T)>
48class ArrayBuffer
49{
50public:
51					ArrayBuffer		(void) throw();
52					ArrayBuffer		(size_t numElements);
53					ArrayBuffer		(const ArrayBuffer& other);
54					~ArrayBuffer	(void) throw();
55	ArrayBuffer&	operator=		(const ArrayBuffer& other);
56
57	void			clear			(void) throw();
58	void			setStorage		(size_t numElements); // !< \note after a succesful call buffer contents are undefined
59	void			swap			(ArrayBuffer& other) throw();
60	size_t			size			(void) const throw();
61	bool			empty			(void) const throw();
62
63	T*				getElementPtr	(size_t elementNdx) throw();
64	const T*		getElementPtr	(size_t elementNdx) const throw();
65	void*			getPtr			(void) throw();
66	const void*		getPtr			(void) const throw();
67
68private:
69	void*			m_ptr;
70	size_t			m_cap;
71};
72
73template <typename T, size_t Alignment, size_t Stride>
74ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (void) throw()
75	: m_ptr	(DE_NULL)
76	, m_cap	(0)
77{
78}
79
80template <typename T, size_t Alignment, size_t Stride>
81ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (size_t numElements)
82	: m_ptr	(DE_NULL)
83	, m_cap	(0)
84{
85	if (numElements)
86	{
87		// \note no need to allocate stride for the last element, sizeof(T) is enough. Also handles cases where sizeof(T) > Stride
88		const size_t	storageSize	= (numElements - 1) * Stride + sizeof(T);
89		void* const		ptr			= detail::ArrayBuffer_AlignedMalloc(storageSize, Alignment);
90
91		if (!ptr)
92			throw std::bad_alloc();
93
94		m_ptr = ptr;
95		m_cap = numElements;
96	}
97}
98
99template <typename T, size_t Alignment, size_t Stride>
100ArrayBuffer<T,Alignment,Stride>::ArrayBuffer (const ArrayBuffer<T,Alignment,Stride>& other)
101	: m_ptr	(DE_NULL)
102	, m_cap	(0)
103{
104	if (other.m_cap)
105	{
106		// copy to temporary and swap to it
107
108		const size_t	storageSize =	(other.m_cap - 1) * Stride + sizeof(T);
109		ArrayBuffer		tmp				(other.m_cap);
110
111		deMemcpy(tmp.m_ptr, other.m_ptr, (int)storageSize);
112		swap(tmp);
113	}
114}
115
116template <typename T, size_t Alignment, size_t Stride>
117ArrayBuffer<T,Alignment,Stride>::~ArrayBuffer (void) throw()
118{
119	clear();
120}
121
122template <typename T, size_t Alignment, size_t Stride>
123ArrayBuffer<T,Alignment,Stride>& ArrayBuffer<T,Alignment,Stride>::operator= (const ArrayBuffer& other)
124{
125	ArrayBuffer copied(other);
126	swap(copied);
127	return *this;
128}
129
130template <typename T, size_t Alignment, size_t Stride>
131void ArrayBuffer<T,Alignment,Stride>::clear (void) throw()
132{
133	detail::ArrayBuffer_AlignedFree(m_ptr);
134
135	m_ptr = DE_NULL;
136	m_cap = 0;
137}
138
139template <typename T, size_t Alignment, size_t Stride>
140void ArrayBuffer<T,Alignment,Stride>::setStorage (size_t numElements)
141{
142	// create new buffer of the wanted size, swap to it
143	ArrayBuffer<T,Alignment,Stride> newBuffer(numElements);
144	swap(newBuffer);
145}
146
147template <typename T, size_t Alignment, size_t Stride>
148void ArrayBuffer<T,Alignment,Stride>::swap (ArrayBuffer& other) throw()
149{
150	void* const		otherPtr = other.m_ptr;
151	const size_t	otherCap = other.m_cap;
152
153	other.m_ptr = m_ptr;
154	other.m_cap = m_cap;
155	m_ptr		= otherPtr;
156	m_cap		= otherCap;
157}
158
159template <typename T, size_t Alignment, size_t Stride>
160size_t ArrayBuffer<T,Alignment,Stride>::size (void) const throw()
161{
162	return m_cap;
163}
164
165template <typename T, size_t Alignment, size_t Stride>
166bool ArrayBuffer<T,Alignment,Stride>::empty (void) const throw()
167{
168	return size() == 0;
169}
170
171template <typename T, size_t Alignment, size_t Stride>
172T* ArrayBuffer<T,Alignment,Stride>::getElementPtr (size_t elementNdx) throw()
173{
174	return (T*)(((deUint8*)m_ptr) + Stride * elementNdx);
175}
176
177template <typename T, size_t Alignment, size_t Stride>
178const T* ArrayBuffer<T,Alignment,Stride>::getElementPtr (size_t elementNdx) const throw()
179{
180	return (T*)(((deUint8*)m_ptr) + Stride * elementNdx);
181}
182
183template <typename T, size_t Alignment, size_t Stride>
184void* ArrayBuffer<T,Alignment,Stride>::getPtr (void) throw()
185{
186	return m_ptr;
187}
188
189template <typename T, size_t Alignment, size_t Stride>
190const void* ArrayBuffer<T,Alignment,Stride>::getPtr (void) const throw()
191{
192	return m_ptr;
193}
194
195} // de
196
197#endif // _DEARRAYBUFFER_HPP
198