• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*-------------------------------------------------------------------------
2   * drawElements Memory Pool Library
3   * --------------------------------
4   *
5   * Copyright 2014 The Android Open Source Project
6   *
7   * Licensed under the Apache License, Version 2.0 (the "License");
8   * you may not use this file except in compliance with the License.
9   * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   *
19   *//*!
20   * \file
21   * \brief Memory pool array class.
22   *
23   * Features of the pooled arrays:
24   * - single indirection layer (grows exponentially)
25   * - constant # elements per page
26   * - recycles old indirection tables as element pages
27   * - about 10% overhead on large arrays
28   *//*--------------------------------------------------------------------*/
29  
30  #include "dePoolArray.h"
31  #include "deInt32.h"
32  
33  #include <stdlib.h>
34  #include <string.h>
35  
36  /*--------------------------------------------------------------------*//*!
37   * \internal
38   * \brief Create a new pool array.
39   * \param pool			Pool to allocate memory from.
40   * \param elementSize	Size of the element to be put in array.
41   * \param Pointer to the created array, or null on failure.
42   *//*--------------------------------------------------------------------*/
dePoolArray_create(deMemPool * pool,int elementSize)43  dePoolArray* dePoolArray_create (deMemPool* pool, int elementSize)
44  {
45  	/* Alloc struct. */
46  	dePoolArray* arr = DE_POOL_NEW(pool, dePoolArray);
47  	if (!arr)
48  		return DE_NULL;
49  
50  	/* Init array. */
51  	memset(arr, 0, sizeof(dePoolArray));
52  	arr->pool			= pool;
53  	arr->elementSize	= elementSize;
54  
55  	return arr;
56  }
57  
58  /*--------------------------------------------------------------------*//*!
59   * \internal
60   * \brief Ensure that the array can hold at least N elements.
61   * \param arr	Array pointer.
62   * \param size	Number of elements for which to reserve memory.
63   * \param True on success, false on failure.
64   *//*--------------------------------------------------------------------*/
dePoolArray_reserve(dePoolArray * arr,int size)65  deBool			dePoolArray_reserve			(dePoolArray* arr, int size)
66  {
67  	if (size >= arr->capacity)
68  	{
69  		void*	oldPageTable			= DE_NULL;
70  		int		oldPageTableSize		= 0;
71  
72  		int		newCapacity				= deAlign32(size, 1 << DE_ARRAY_ELEMENTS_PER_PAGE_LOG2);
73  		int		reqPageTableCapacity	= newCapacity >> DE_ARRAY_ELEMENTS_PER_PAGE_LOG2;
74  
75  		if (arr->pageTableCapacity < reqPageTableCapacity)
76  		{
77  			int		newPageTableCapacity	= deMax32(2*arr->pageTableCapacity, reqPageTableCapacity);
78  			void**	newPageTable			= (void**)deMemPool_alloc(arr->pool, (size_t)newPageTableCapacity * sizeof(void*));
79  			int		i;
80  
81  			if (!newPageTable)
82  				return DE_FALSE;
83  
84  			for (i = 0; i < arr->pageTableCapacity; i++)
85  				newPageTable[i] = arr->pageTable[i];
86  
87  			for (; i < newPageTableCapacity; i++)
88  				newPageTable[i] = DE_NULL;
89  
90  			/* Grab information about old page table for recycling purposes. */
91  			oldPageTable		= arr->pageTable;
92  			oldPageTableSize	= arr->pageTableCapacity * (int)sizeof(void*);
93  
94  			arr->pageTable			= newPageTable;
95  			arr->pageTableCapacity	= newPageTableCapacity;
96  		}
97  
98  		/* Allocate new pages. */
99  		{
100  			int pageAllocSize = arr->elementSize << DE_ARRAY_ELEMENTS_PER_PAGE_LOG2;
101  			int pageTableNdx = arr->capacity >> DE_ARRAY_ELEMENTS_PER_PAGE_LOG2;
102  
103  			/* Allocate new pages from recycled old page table. */
104  			while (oldPageTableSize >= pageAllocSize)
105  			{
106  				void* newPage = oldPageTable;
107  				DE_ASSERT(arr->pageTableCapacity > pageTableNdx); /* \todo [petri] is this always true? */
108  				DE_ASSERT(!arr->pageTable[pageTableNdx]);
109  				arr->pageTable[pageTableNdx++] = newPage;
110  
111  				oldPageTable = (void*)((deUint8*)oldPageTable + pageAllocSize);
112  				oldPageTableSize -= pageAllocSize;
113  			}
114  
115  			/* Allocate the rest of the needed pages from the pool. */
116  			for (; pageTableNdx < reqPageTableCapacity; pageTableNdx++)
117  			{
118  				void* newPage = deMemPool_alloc(arr->pool, (size_t)pageAllocSize);
119  				if (!newPage)
120  					return DE_FALSE;
121  
122  				DE_ASSERT(!arr->pageTable[pageTableNdx]);
123  				arr->pageTable[pageTableNdx] = newPage;
124  			}
125  
126  			arr->capacity = pageTableNdx << DE_ARRAY_ELEMENTS_PER_PAGE_LOG2;
127  			DE_ASSERT(arr->capacity >= newCapacity);
128  		}
129  	}
130  
131  	return DE_TRUE;
132  }
133  
134  /*--------------------------------------------------------------------*//*!
135   * \internal
136   * \brief Set the size of the array (also reserves capacity).
137   * \param arr	Array pointer.
138   * \param size	New size of the array (in elements).
139   * \param True on success, false on failure.
140   *//*--------------------------------------------------------------------*/
dePoolArray_setSize(dePoolArray * arr,int size)141  deBool			dePoolArray_setSize			(dePoolArray* arr, int size)
142  {
143  	if (!dePoolArray_reserve(arr, size))
144  		return DE_FALSE;
145  
146  	arr->numElements = size;
147  	return DE_TRUE;
148  }
149  
150  DE_DECLARE_POOL_ARRAY(dePoolIntArray, int);
151  DE_DECLARE_POOL_ARRAY(dePoolInt16Array, deInt16);
152  
153  /*--------------------------------------------------------------------*//*!
154   * \internal
155   * \brief Test array functionality.
156   *//*--------------------------------------------------------------------*/
dePoolArray_selfTest(void)157  void dePoolArray_selfTest (void)
158  {
159  	deMemPool*			pool	= deMemPool_createRoot(DE_NULL, 0);
160  	dePoolIntArray*		arr		= dePoolIntArray_create(pool);
161  	dePoolInt16Array*	arr16	= dePoolInt16Array_create(pool);
162  	int					i;
163  
164  	/* Test pushBack(). */
165  	for (i = 0; i < 5000; i++)
166  	{
167  		/* Dummy alloc to try to break alignments. */
168  		deMemPool_alloc(pool, 1);
169  
170  		dePoolIntArray_pushBack(arr, i);
171  		dePoolInt16Array_pushBack(arr16, (deInt16)i);
172  	}
173  
174  	DE_TEST_ASSERT(dePoolIntArray_getNumElements(arr) == 5000);
175  	DE_TEST_ASSERT(dePoolInt16Array_getNumElements(arr16) == 5000);
176  	for (i = 0; i < 5000; i++)
177  	{
178  		DE_TEST_ASSERT(dePoolIntArray_get(arr, i) == i);
179  		DE_TEST_ASSERT(dePoolInt16Array_get(arr16, i) == i);
180  	}
181  
182  	/* Test popBack(). */
183  	for (i = 0; i < 1000; i++)
184  	{
185  		DE_TEST_ASSERT(dePoolIntArray_popBack(arr) == (4999 - i));
186  		DE_TEST_ASSERT(dePoolInt16Array_popBack(arr16) == (4999 - i));
187  	}
188  
189  	DE_TEST_ASSERT(dePoolIntArray_getNumElements(arr) == 4000);
190  	DE_TEST_ASSERT(dePoolInt16Array_getNumElements(arr16) == 4000);
191  	for (i = 0; i < 4000; i++)
192  	{
193  		DE_TEST_ASSERT(dePoolIntArray_get(arr, i) == i);
194  		DE_TEST_ASSERT(dePoolInt16Array_get(arr16, i) == i);
195  	}
196  
197  	/* Test setSize(). */
198  	dePoolIntArray_setSize(arr, 1000);
199  	dePoolInt16Array_setSize(arr16, 1000);
200  	for (i = 1000; i < 5000; i++)
201  	{
202  		dePoolIntArray_pushBack(arr, i);
203  		dePoolInt16Array_pushBack(arr16, (deInt16)i);
204  	}
205  
206  	DE_TEST_ASSERT(dePoolIntArray_getNumElements(arr) == 5000);
207  	DE_TEST_ASSERT(dePoolInt16Array_getNumElements(arr16) == 5000);
208  	for (i = 0; i < 5000; i++)
209  	{
210  		DE_TEST_ASSERT(dePoolIntArray_get(arr, i) == i);
211  		DE_TEST_ASSERT(dePoolInt16Array_get(arr16, i) == i);
212  	}
213  
214  	/* Test set() and pushBack() with reserve(). */
215  	arr = dePoolIntArray_create(pool);
216  	dePoolIntArray_setSize(arr, 1500);
217  	dePoolIntArray_reserve(arr, 2000);
218  	for (i = 0; i < 1500; i++)
219  		dePoolIntArray_set(arr, i, i);
220  	for (; i < 5000; i++)
221  		dePoolIntArray_pushBack(arr, i);
222  
223  	DE_TEST_ASSERT(dePoolIntArray_getNumElements(arr) == 5000);
224  	for (i = 0; i < 5000; i++)
225  	{
226  		int val = dePoolIntArray_get(arr, i);
227  		DE_TEST_ASSERT(val == i);
228  	}
229  
230  	deMemPool_destroy(pool);
231  }
232