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