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 <assert.h>
30#include <stdlib.h>
31#include <string.h>
32
33#include "egllog.h"
34#include "eglarray.h"
35
36
37/**
38 * Grow the size of the array.
39 */
40static EGLBoolean
41_eglGrowArray(_EGLArray *array)
42{
43   EGLint new_size;
44   void **elems;
45
46   new_size = array->MaxSize;
47   while (new_size <= array->Size)
48      new_size *= 2;
49
50   elems = realloc(array->Elements, new_size * sizeof(array->Elements[0]));
51   if (!elems) {
52      _eglLog(_EGL_DEBUG, "failed to grow %s array to %d",
53            array->Name, new_size);
54      return EGL_FALSE;
55   }
56
57   array->Elements = elems;
58   array->MaxSize = new_size;
59
60   return EGL_TRUE;
61}
62
63
64/**
65 * Create an array.
66 */
67_EGLArray *
68_eglCreateArray(const char *name, EGLint init_size)
69{
70   _EGLArray *array;
71
72   array = calloc(1, sizeof(*array));
73   if (array) {
74      array->Name = name;
75      array->MaxSize = (init_size > 0) ? init_size : 1;
76      if (!_eglGrowArray(array)) {
77         free(array);
78         array = NULL;
79      }
80   }
81
82   return array;
83}
84
85
86/**
87 * Destroy an array, optionally free the data.
88 */
89void
90_eglDestroyArray(_EGLArray *array, void (*free_cb)(void *))
91{
92   if (free_cb) {
93      EGLint i;
94      for (i = 0; i < array->Size; i++)
95         free_cb(array->Elements[i]);
96   }
97   free(array->Elements);
98   free(array);
99}
100
101
102/**
103 * Append a element to an array.
104 */
105void
106_eglAppendArray(_EGLArray *array, void *elem)
107{
108   if (array->Size >= array->MaxSize && !_eglGrowArray(array))
109      return;
110
111   array->Elements[array->Size++] = elem;
112}
113
114
115/**
116 * Erase an element from an array.
117 */
118void
119_eglEraseArray(_EGLArray *array, EGLint i, void (*free_cb)(void *))
120{
121   if (free_cb)
122      free_cb(array->Elements[i]);
123   if (i < array->Size - 1) {
124      memmove(&array->Elements[i], &array->Elements[i + 1],
125            (array->Size - i - 1) * sizeof(array->Elements[0]));
126   }
127   array->Size--;
128}
129
130
131/**
132 * Find in an array for the given element.
133 */
134void *
135_eglFindArray(_EGLArray *array, void *elem)
136{
137   EGLint i;
138
139   if (!array)
140      return NULL;
141
142   for (i = 0; i < array->Size; i++)
143      if (array->Elements[i] == elem)
144         return elem;
145   return NULL;
146}
147
148
149/**
150 * Filter an array and return the number of filtered elements.
151 */
152EGLint
153_eglFilterArray(_EGLArray *array, void **data, EGLint size,
154                _EGLArrayForEach filter, void *filter_data)
155{
156   EGLint count = 0, i;
157
158   if (!array)
159      return 0;
160
161   assert(filter);
162   for (i = 0; i < array->Size; i++) {
163      if (filter(array->Elements[i], filter_data)) {
164         if (data && count < size)
165            data[count] = array->Elements[i];
166         count++;
167      }
168      if (data && count >= size)
169         break;
170   }
171
172   return count;
173}
174
175
176/**
177 * Flatten an array by converting array elements into another form and store
178 * them in a buffer.
179 */
180EGLint
181_eglFlattenArray(_EGLArray *array, void *buffer, EGLint elem_size, EGLint size,
182                 _EGLArrayForEach flatten)
183{
184   EGLint i, count;
185
186   if (!array)
187      return 0;
188
189   count = array->Size;
190   if (buffer) {
191      /* clamp size to 0 */
192      if (size < 0)
193         size = 0;
194      /* do not exceed buffer size */
195      if (count > size)
196         count = size;
197      for (i = 0; i < count; i++)
198         flatten(array->Elements[i],
199               (void *) ((char *) buffer + elem_size * i));
200   }
201
202   return count;
203}
204