1 /*-------------------------------------------------------------------------
2 * drawElements Memory Pool Library
3 * --------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Memory pool array class.
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 *//*--------------------------------------------------------------------*/
30 #include "dePoolArray.h"
36 /*--------------------------------------------------------------------*//*!
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 *//*--------------------------------------------------------------------*/
43 dePoolArray* dePoolArray_create (deMemPool* pool, int elementSize)
46 dePoolArray* arr = DE_POOL_NEW(pool, dePoolArray);
51 memset(arr, 0, sizeof(dePoolArray));
53 arr->elementSize = elementSize;
58 /*--------------------------------------------------------------------*//*!
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 *//*--------------------------------------------------------------------*/
65 deBool dePoolArray_reserve (dePoolArray* arr, int size)
67 if (size >= arr->capacity)
69 void* oldPageTable = DE_NULL;
70 int oldPageTableSize = 0;
72 int newCapacity = deAlign32(size, 1 << DE_ARRAY_ELEMENTS_PER_PAGE_LOG2);
73 int reqPageTableCapacity = newCapacity >> DE_ARRAY_ELEMENTS_PER_PAGE_LOG2;
75 if (arr->pageTableCapacity < reqPageTableCapacity)
77 int newPageTableCapacity = deMax32(2*arr->pageTableCapacity, reqPageTableCapacity);
78 void** newPageTable = (void**)deMemPool_alloc(arr->pool, (size_t)newPageTableCapacity * sizeof(void*));
84 for (i = 0; i < arr->pageTableCapacity; i++)
85 newPageTable[i] = arr->pageTable[i];
87 for (; i < newPageTableCapacity; i++)
88 newPageTable[i] = DE_NULL;
90 /* Grab information about old page table for recycling purposes. */
91 oldPageTable = arr->pageTable;
92 oldPageTableSize = arr->pageTableCapacity * (int)sizeof(void*);
94 arr->pageTable = newPageTable;
95 arr->pageTableCapacity = newPageTableCapacity;
98 /* Allocate new pages. */
100 int pageAllocSize = arr->elementSize << DE_ARRAY_ELEMENTS_PER_PAGE_LOG2;
101 int pageTableNdx = arr->capacity >> DE_ARRAY_ELEMENTS_PER_PAGE_LOG2;
103 /* Allocate new pages from recycled old page table. */
104 while (oldPageTableSize >= pageAllocSize)
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;
111 oldPageTable = (void*)((deUint8*)oldPageTable + pageAllocSize);
112 oldPageTableSize -= pageAllocSize;
115 /* Allocate the rest of the needed pages from the pool. */
116 for (; pageTableNdx < reqPageTableCapacity; pageTableNdx++)
118 void* newPage = deMemPool_alloc(arr->pool, (size_t)pageAllocSize);
122 DE_ASSERT(!arr->pageTable[pageTableNdx]);
123 arr->pageTable[pageTableNdx] = newPage;
126 arr->capacity = pageTableNdx << DE_ARRAY_ELEMENTS_PER_PAGE_LOG2;
127 DE_ASSERT(arr->capacity >= newCapacity);
134 /*--------------------------------------------------------------------*//*!
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 *//*--------------------------------------------------------------------*/
141 deBool dePoolArray_setSize (dePoolArray* arr, int size)
143 if (!dePoolArray_reserve(arr, size))
146 arr->numElements = size;
150 DE_DECLARE_POOL_ARRAY(dePoolIntArray, int);
151 DE_DECLARE_POOL_ARRAY(dePoolInt16Array, deInt16);
153 /*--------------------------------------------------------------------*//*!
155 * \brief Test array functionality.
156 *//*--------------------------------------------------------------------*/
157 void dePoolArray_selfTest (void)
159 deMemPool* pool = deMemPool_createRoot(DE_NULL, 0);
160 dePoolIntArray* arr = dePoolIntArray_create(pool);
161 dePoolInt16Array* arr16 = dePoolInt16Array_create(pool);
164 /* Test pushBack(). */
165 for (i = 0; i < 5000; i++)
167 /* Dummy alloc to try to break alignments. */
168 deMemPool_alloc(pool, 1);
170 dePoolIntArray_pushBack(arr, i);
171 dePoolInt16Array_pushBack(arr16, (deInt16)i);
174 DE_TEST_ASSERT(dePoolIntArray_getNumElements(arr) == 5000);
175 DE_TEST_ASSERT(dePoolInt16Array_getNumElements(arr16) == 5000);
176 for (i = 0; i < 5000; i++)
178 DE_TEST_ASSERT(dePoolIntArray_get(arr, i) == i);
179 DE_TEST_ASSERT(dePoolInt16Array_get(arr16, i) == i);
182 /* Test popBack(). */
183 for (i = 0; i < 1000; i++)
185 DE_TEST_ASSERT(dePoolIntArray_popBack(arr) == (4999 - i));
186 DE_TEST_ASSERT(dePoolInt16Array_popBack(arr16) == (4999 - i));
189 DE_TEST_ASSERT(dePoolIntArray_getNumElements(arr) == 4000);
190 DE_TEST_ASSERT(dePoolInt16Array_getNumElements(arr16) == 4000);
191 for (i = 0; i < 4000; i++)
193 DE_TEST_ASSERT(dePoolIntArray_get(arr, i) == i);
194 DE_TEST_ASSERT(dePoolInt16Array_get(arr16, i) == i);
197 /* Test setSize(). */
198 dePoolIntArray_setSize(arr, 1000);
199 dePoolInt16Array_setSize(arr16, 1000);
200 for (i = 1000; i < 5000; i++)
202 dePoolIntArray_pushBack(arr, i);
203 dePoolInt16Array_pushBack(arr16, (deInt16)i);
206 DE_TEST_ASSERT(dePoolIntArray_getNumElements(arr) == 5000);
207 DE_TEST_ASSERT(dePoolInt16Array_getNumElements(arr16) == 5000);
208 for (i = 0; i < 5000; i++)
210 DE_TEST_ASSERT(dePoolIntArray_get(arr, i) == i);
211 DE_TEST_ASSERT(dePoolInt16Array_get(arr16, i) == i);
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);
223 DE_TEST_ASSERT(dePoolIntArray_getNumElements(arr) == 5000);
224 for (i = 0; i < 5000; i++)
226 int val = dePoolIntArray_get(arr, i);
227 DE_TEST_ASSERT(val == i);
230 deMemPool_destroy(pool);