1/**************************************************************************
2 *
3 * Copyright 2010 LunarG, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28
29#include <stdlib.h>
30#include <string.h>
31
32#include "egllog.h"
33#include "eglarray.h"
34
35
36/**
37 * Grow the size of the array.
38 */
39static EGLBoolean
40_eglGrowArray(_EGLArray *array)
41{
42   EGLint new_size;
43   void **elems;
44
45   new_size = array->MaxSize;
46   while (new_size <= array->Size)
47      new_size *= 2;
48
49   elems = realloc(array->Elements, new_size * sizeof(array->Elements[0]));
50   if (!elems) {
51      _eglLog(_EGL_DEBUG, "failed to grow %s array to %d",
52            array->Name, new_size);
53      return EGL_FALSE;
54   }
55
56   array->Elements = elems;
57   array->MaxSize = new_size;
58
59   return EGL_TRUE;
60}
61
62
63/**
64 * Create an array.
65 */
66_EGLArray *
67_eglCreateArray(const char *name, EGLint init_size)
68{
69   _EGLArray *array;
70
71   array = calloc(1, sizeof(*array));
72   if (array) {
73      array->Name = name;
74      array->MaxSize = (init_size > 0) ? init_size : 1;
75      if (!_eglGrowArray(array)) {
76         free(array);
77         array = NULL;
78      }
79   }
80
81   return array;
82}
83
84
85/**
86 * Destroy an array, optionally free the data.
87 */
88void
89_eglDestroyArray(_EGLArray *array, void (*free_cb)(void *))
90{
91   if (free_cb) {
92      EGLint i;
93      for (i = 0; i < array->Size; i++)
94         free_cb(array->Elements[i]);
95   }
96   free(array->Elements);
97   free(array);
98}
99
100
101/**
102 * Append a element to an array.
103 */
104void
105_eglAppendArray(_EGLArray *array, void *elem)
106{
107   if (array->Size >= array->MaxSize && !_eglGrowArray(array))
108      return;
109
110   array->Elements[array->Size++] = elem;
111}
112
113
114/**
115 * Erase an element from an array.
116 */
117void
118_eglEraseArray(_EGLArray *array, EGLint i, void (*free_cb)(void *))
119{
120   if (free_cb)
121      free_cb(array->Elements[i]);
122   if (i < array->Size - 1) {
123      memmove(&array->Elements[i], &array->Elements[i + 1],
124            (array->Size - i - 1) * sizeof(array->Elements[0]));
125   }
126   array->Size--;
127}
128
129
130/**
131 * Find in an array for the given element.
132 */
133void *
134_eglFindArray(_EGLArray *array, void *elem)
135{
136   EGLint i;
137
138   if (!array)
139      return NULL;
140
141   for (i = 0; i < array->Size; i++)
142      if (array->Elements[i] == elem)
143         return elem;
144   return NULL;
145}
146
147
148/**
149 * Filter an array and return the number of filtered elements.
150 */
151EGLint
152_eglFilterArray(_EGLArray *array, void **data, EGLint size,
153                _EGLArrayForEach filter, void *filter_data)
154{
155   EGLint count = 0, i;
156
157   if (!array)
158      return 0;
159
160   if (filter) {
161      for (i = 0; i < array->Size; i++) {
162         if (filter(array->Elements[i], filter_data)) {
163            if (data && count < size)
164               data[count] = array->Elements[i];
165            count++;
166         }
167         if (data && count >= size)
168            break;
169      }
170   }
171   else {
172      if (data) {
173         count = (size < array->Size) ? size : array->Size;
174         memcpy(data, array->Elements, count * sizeof(array->Elements[0]));
175      }
176      else {
177         count = array->Size;
178      }
179   }
180
181   return count;
182}
183
184
185/**
186 * Flatten an array by converting array elements into another form and store
187 * them in a buffer.
188 */
189EGLint
190_eglFlattenArray(_EGLArray *array, void *buffer, EGLint elem_size, EGLint size,
191                 _EGLArrayForEach flatten)
192{
193   EGLint i, count;
194
195   if (!array)
196      return 0;
197
198   count = array->Size;
199   if (buffer) {
200      /* do not exceed buffer size */
201      if (count > size)
202         count = size;
203      for (i = 0; i < count; i++)
204         flatten(array->Elements[i],
205               (void *) ((char *) buffer + elem_size * i));
206   }
207
208   return count;
209}
210