1 #ifndef _DEPOOLARRAY_H
2 #define _DEPOOLARRAY_H
3 /*-------------------------------------------------------------------------
4  * drawElements Memory Pool 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 Memory pool array class.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "deDefs.h"
27 #include "deMemPool.h"
28 
29 enum
30 {
31 	DE_ARRAY_ELEMENTS_PER_PAGE_LOG2	= 4		/*!< \internal 16 */
32 };
33 
34 /*--------------------------------------------------------------------*//*!
35  * \internal
36  * \brief Type-independent version of the array template class.
37  *//*--------------------------------------------------------------------*/
38 typedef struct dePoolArray_s
39 {
40 	deMemPool*		pool;				/*!< Pool from which all memory is allocated from.	*/
41 
42 	int				elementSize;		/*!< Size of the element (in bytes).				*/
43 	int				numElements;		/*!< Number of elements in the array.				*/
44 	int				capacity;			/*!< Number of allocated elements in the array.		*/
45 
46 	int				pageTableCapacity;	/*!< Size of the page table.						*/
47 	void**			pageTable;			/*!< Pointer to the page table.						*/
48 } dePoolArray;
49 
50 DE_BEGIN_EXTERN_C
51 
52 dePoolArray*	dePoolArray_create			(deMemPool* pool, int elementSize);
53 deBool			dePoolArray_reserve			(dePoolArray* arr, int capacity);
54 deBool			dePoolArray_setSize			(dePoolArray* arr, int size);
55 
56 void			dePoolArray_selfTest		(void);
57 
58 DE_END_EXTERN_C
59 
60 /*--------------------------------------------------------------------*//*!
61  * \brief Declare a template pool array class.
62  * \param TYPENAME	Type name of the declared array.
63  * \param VALUETYPE	Type of the value contained in the array.
64  *
65  * This macro declares a pool array with all the necessary functions for
66  * operating with it. All allocated memory is taken from the memory pool
67  * given to the constructor.
68  *
69  * The array is implemented by having a set of pages (which store the
70  * elements) and a page table with pointers to each of them. The pages
71  * are allocated individually whenever they are needed, but the page
72  * table grows exponentially. This keeps the memory overhead for large
73  * arrays very small. On the other hand, the relative overhead for very
74  * small arrays is prohibitive (the minimum allocation is 16 elements).
75  *
76  * The functions for operating the array are:
77  * \todo [petri] Figure out how to comment these in Doxygen-style.
78  *
79  * \code
80  * Array*   Array_create            (deMemPool* pool);
81  * int      Array_getNumElements    (const Array* array);
82  * deBool   Array_reserve           (Array* array, int size);
83  * deBool   Array_setSize           (Array* array, int size);
84  * void		Array_reset				(Array* array);
85  * Element  Array_get               (Array* array, int ndx);
86  * deBool   Array_set               (Array* array, int ndx, Element elem);
87  * deBool   Array_pushBack          (Array* array, Element elem);
88  * Element  Array_popBack           (Array* array);
89  * void     Array_swap              (Array* array, int aNdx, int bNdx);
90  * \endcode
91 *//*--------------------------------------------------------------------*/
92 #define DE_DECLARE_POOL_ARRAY(TYPENAME, VALUETYPE)		\
93     \
94 typedef struct TYPENAME##_s    \
95 {    \
96 	deMemPool*		pool;    \
97 \
98 	int				elementSize;    \
99 	int				numElements;    \
100 	int				capacity;    \
101 \
102 	int				pageTableCapacity;    \
103 	VALUETYPE**		pageTable;    \
104 } TYPENAME;    \
105 \
106 DE_INLINE TYPENAME*	TYPENAME##_create			(deMemPool* pool);												\
107 DE_INLINE int		TYPENAME##_getNumElements	(const TYPENAME* arr)						DE_UNUSED_FUNCTION;	\
108 DE_INLINE deBool	TYPENAME##_reserve			(TYPENAME* arr, int capacity)				DE_UNUSED_FUNCTION;	\
109 DE_INLINE deBool	TYPENAME##_setSize			(TYPENAME* arr, int size)					DE_UNUSED_FUNCTION;	\
110 DE_INLINE void		TYPENAME##_reset			(TYPENAME* arr)								DE_UNUSED_FUNCTION;	\
111 DE_INLINE VALUETYPE	TYPENAME##_get				(const TYPENAME* arr, int ndx)				DE_UNUSED_FUNCTION;	\
112 DE_INLINE void		TYPENAME##_set				(TYPENAME* arr, int ndx, VALUETYPE elem)	DE_UNUSED_FUNCTION;	\
113 DE_INLINE deBool	TYPENAME##_pushBack			(TYPENAME* arr, VALUETYPE elem)				DE_UNUSED_FUNCTION;	\
114 DE_INLINE VALUETYPE	TYPENAME##_popBack			(TYPENAME* arr)								DE_UNUSED_FUNCTION;	\
115 DE_INLINE deBool	TYPENAME##_copy				(TYPENAME* dst, const TYPENAME* src)		DE_UNUSED_FUNCTION;	\
116 DE_INLINE void		TYPENAME##_swap				(TYPENAME* arr, int aNdx, int bNdx)			DE_UNUSED_FUNCTION;	\
117 \
118 DE_INLINE TYPENAME* TYPENAME##_create (deMemPool* pool)    \
119 {    \
120 	return (TYPENAME*)dePoolArray_create(pool, sizeof(VALUETYPE));    \
121 }    \
122 \
123 DE_INLINE int TYPENAME##_getNumElements (const TYPENAME* arr)    \
124 {    \
125 	return arr->numElements;    \
126 }    \
127 \
128 DE_INLINE deBool TYPENAME##_reserve (TYPENAME* arr, int capacity)    \
129 {    \
130 	if (capacity > arr->capacity)    \
131 		return dePoolArray_reserve((dePoolArray*)arr, capacity);    \
132 	return  DE_TRUE;    \
133 }    \
134 \
135 DE_INLINE deBool TYPENAME##_setSize (TYPENAME* arr, int size)    \
136 {    \
137 	if (size > arr->capacity)    \
138 		return dePoolArray_setSize((dePoolArray*)arr, size);    \
139 \
140 	arr->numElements = size;    \
141 	return DE_TRUE;    \
142 }    \
143 \
144 DE_INLINE void TYPENAME##_reset (TYPENAME* arr)    \
145 {    \
146 	arr->numElements = 0;    \
147 }    \
148 \
149 DE_INLINE VALUETYPE TYPENAME##_get (const TYPENAME* arr, int ndx)    \
150 {    \
151 	DE_ASSERT(ndx >= 0 && ndx < arr->numElements);    \
152 	{    \
153 		int pageNdx	= (ndx >> DE_ARRAY_ELEMENTS_PER_PAGE_LOG2);    \
154 		int subNdx	= ndx & ((1 << DE_ARRAY_ELEMENTS_PER_PAGE_LOG2) - 1);    \
155 		return ((VALUETYPE*)arr->pageTable[pageNdx])[subNdx];    \
156 	}    \
157 }    \
158 \
159 DE_INLINE void TYPENAME##_set (TYPENAME* arr, int ndx, VALUETYPE elem)    \
160 {    \
161 	DE_ASSERT(ndx >= 0 && ndx < arr->numElements);    \
162 	{    \
163 		int pageNdx	= (ndx >> DE_ARRAY_ELEMENTS_PER_PAGE_LOG2);    \
164 		int subNdx	= ndx & ((1 << DE_ARRAY_ELEMENTS_PER_PAGE_LOG2) - 1);    \
165 		((VALUETYPE*)arr->pageTable[pageNdx])[subNdx] = elem;    \
166 	}    \
167 }    \
168 \
169 DE_INLINE deBool TYPENAME##_pushBack (TYPENAME* arr, VALUETYPE elem)    \
170 {    \
171 	if ((arr->numElements + 1 >= arr->capacity) && !TYPENAME##_reserve(arr, arr->numElements + 1)) \
172 		return DE_FALSE; \
173 	arr->numElements++; \
174 	TYPENAME##_set(arr, arr->numElements - 1, elem); \
175 	return DE_TRUE;    \
176 }    \
177 \
178 DE_INLINE VALUETYPE TYPENAME##_popBack (TYPENAME* arr)    \
179 {    \
180 	int ndx		= arr->numElements - 1; \
181 	int pageNdx	= (ndx >> DE_ARRAY_ELEMENTS_PER_PAGE_LOG2);    \
182 	int subNdx	= ndx & ((1 << DE_ARRAY_ELEMENTS_PER_PAGE_LOG2) - 1);    \
183 	DE_ASSERT(arr->numElements > 0); \
184 	arr->numElements--; \
185 	/* \note We access a value which is out-of-bounds, but we know it to be safe. */ \
186 	return ((VALUETYPE*)arr->pageTable[pageNdx])[subNdx];    \
187 }    \
188 \
189 DE_INLINE deBool TYPENAME##_copy (TYPENAME* dst, const TYPENAME* src)		\
190 {																			\
191 	DE_ASSERT(dst && src);													\
192 	{																		\
193 		int numElements = src->numElements;									\
194 		int ndx;															\
195 		if (!TYPENAME##_setSize(dst, numElements))							\
196 			return DE_FALSE;												\
197 		for (ndx = 0; ndx < numElements; ndx++)								\
198 			TYPENAME##_set(dst, ndx, TYPENAME##_get(src, ndx));				\
199 	}																		\
200 	return DE_TRUE;															\
201 }																			\
202 \
203 DE_INLINE void TYPENAME##_swap (TYPENAME* arr, int aNdx, int bNdx)	\
204 {	\
205 	VALUETYPE tmp = TYPENAME##_get(arr, aNdx);	\
206 	TYPENAME##_set(arr, aNdx, TYPENAME##_get(arr, bNdx));	\
207 	TYPENAME##_set(arr, bNdx, tmp);	\
208 }	\
209 \
210 struct TYPENAME##Dummy_s { int dummy; }
211 
212 /*--------------------------------------------------------------------*//*!
213  * \brief Declare a sort function for an array.
214  * \param TYPENAME	Type name of the declared array.
215  * \param VALUETYPE	Type of the value contained in the array.
216  * \param SORTNAME	Name for this specific sort.
217  * \param CMPFUNC	Comparison function for sorting.
218  *
219  * This macro declares a sort function for an array declared using
220  * DE_DECLARE_POOL_ARRAY macro.
221  *
222  * Sorting algorithm is heap sort since it requires constant amount of
223  * auxiliary space and is in-place sort. Worst-case run-time is O(n log n)
224  * and sort is NOT stable.
225  *
226  * CMPFUNC is used to compare elements in array. It must accept two
227  * parameters and return negative integer if first is smaller than, 0 if
228  * both are equal and positive integer if first is larger than second.
229  *
230  * The functions for sorting array are:
231  * \todo [petri] Figure out how to comment these in Doxygen-style.
232  *
233  * \code
234  * void		Array_sortName			(Array* array);
235  * void		Array_sortNameHeapify	(Array* array);
236  * void		Array_sortNameShiftDown	(Array* array, int start, int end);
237  * \endcode
238 *//*--------------------------------------------------------------------*/
239 #define DE_DECLARE_POOL_ARRAY_SORT(TYPENAME, VALUETYPE, SORTNAME, CMPFUNC)	\
240 \
241 DE_INLINE void TYPENAME##_##SORTNAME##ShiftDown (TYPENAME* arr, int startNdx, int endNdx)	\
242 {	\
243 	int rootNdx = startNdx;	\
244 	\
245 	while (rootNdx * 2 + 1 <= endNdx)	\
246 	{	\
247 		int childNdx = rootNdx * 2 + 1;	\
248 		\
249 		if ((childNdx + 1 <= endNdx) && (CMPFUNC(TYPENAME##_get(arr, childNdx), TYPENAME##_get(arr, childNdx + 1)) < 0))	\
250 			childNdx += 1;	\
251 		\
252 		if (CMPFUNC(TYPENAME##_get(arr, rootNdx), TYPENAME##_get(arr, childNdx)) < 0)	\
253 		{	\
254 			TYPENAME##_swap(arr, rootNdx, childNdx);	\
255 			rootNdx = childNdx;	\
256 		}	\
257 		else	\
258 			break;	\
259 	}	\
260 }	\
261 \
262 DE_INLINE void TYPENAME##_##SORTNAME##Heapify (TYPENAME* arr)	\
263 {	\
264 	int startNdx = (TYPENAME##_getNumElements(arr) - 2) / 2;	\
265 	\
266 	while (startNdx >= 0)	\
267 	{	\
268 		TYPENAME##_##SORTNAME##ShiftDown(arr, startNdx, TYPENAME##_getNumElements(arr) - 1);	\
269 		startNdx -= 1;	\
270 	}	\
271 }	\
272 \
273 DE_INLINE void TYPENAME##_##SORTNAME (TYPENAME* arr)	\
274 {	\
275 	int endNdx = TYPENAME##_getNumElements(arr) - 1;	\
276 	\
277 	TYPENAME##_##SORTNAME##Heapify(arr);	\
278 	\
279 	while (endNdx > 0)	\
280 	{	\
281 		TYPENAME##_swap(arr, endNdx, 0);	\
282 		endNdx -= 1;	\
283 		TYPENAME##_##SORTNAME##ShiftDown(arr, 0, endNdx);	\
284 	}	\
285 }	\
286 \
287 struct TYPENAME##SORTNAME##Dummy_s { int dummy; }
288 
289 /* Basic array types. */
290 
291 DE_DECLARE_POOL_ARRAY(deIntArray, int);
292 DE_DECLARE_POOL_ARRAY(deInt8Array, deInt8);
293 DE_DECLARE_POOL_ARRAY(deUint8Array, deUint8);
294 DE_DECLARE_POOL_ARRAY(deInt16Array, deInt16);
295 DE_DECLARE_POOL_ARRAY(deUint16Array, deUint16);
296 DE_DECLARE_POOL_ARRAY(deInt32Array, deInt32);
297 DE_DECLARE_POOL_ARRAY(deUint32Array, deUint32);
298 
299 #endif /* _DEPOOLARRAY_H */
300