1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2008 VMware, Inc.
4bf215546Sopenharmony_ci * All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12bf215546Sopenharmony_ci * the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
16bf215546Sopenharmony_ci * of the Software.
17bf215546Sopenharmony_ci *
18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci **************************************************************************/
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci/**
29bf215546Sopenharmony_ci * @file
30bf215546Sopenharmony_ci * Generic handle table implementation.
31bf215546Sopenharmony_ci *
32bf215546Sopenharmony_ci * @author José Fonseca <jfonseca@vmware.com>
33bf215546Sopenharmony_ci */
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci#include "pipe/p_compiler.h"
37bf215546Sopenharmony_ci#include "util/u_debug.h"
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci#include "util/u_memory.h"
40bf215546Sopenharmony_ci#include "util/u_handle_table.h"
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci#define HANDLE_TABLE_INITIAL_SIZE 16
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_cistruct handle_table
47bf215546Sopenharmony_ci{
48bf215546Sopenharmony_ci   /** Object array. Empty handles have a null object */
49bf215546Sopenharmony_ci   void **objects;
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_ci   /** Number of objects the handle can currently hold */
52bf215546Sopenharmony_ci   unsigned size;
53bf215546Sopenharmony_ci   /** Number of consecutive objects allocated at the start of the table */
54bf215546Sopenharmony_ci   unsigned filled;
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci   /** Optional object destructor */
57bf215546Sopenharmony_ci   void (*destroy)(void *object);
58bf215546Sopenharmony_ci};
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_cistruct handle_table *
62bf215546Sopenharmony_cihandle_table_create(void)
63bf215546Sopenharmony_ci{
64bf215546Sopenharmony_ci   struct handle_table *ht;
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   ht = MALLOC_STRUCT(handle_table);
67bf215546Sopenharmony_ci   if (!ht)
68bf215546Sopenharmony_ci      return NULL;
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci   ht->objects = (void **)CALLOC(HANDLE_TABLE_INITIAL_SIZE, sizeof(void *));
71bf215546Sopenharmony_ci   if(!ht->objects) {
72bf215546Sopenharmony_ci      FREE(ht);
73bf215546Sopenharmony_ci      return NULL;
74bf215546Sopenharmony_ci   }
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci   ht->size = HANDLE_TABLE_INITIAL_SIZE;
77bf215546Sopenharmony_ci   ht->filled = 0;
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci   ht->destroy = NULL;
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ci   return ht;
82bf215546Sopenharmony_ci}
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_civoid
86bf215546Sopenharmony_cihandle_table_set_destroy(struct handle_table *ht,
87bf215546Sopenharmony_ci                         void (*destroy)(void *object))
88bf215546Sopenharmony_ci{
89bf215546Sopenharmony_ci   assert(ht);
90bf215546Sopenharmony_ci   if (!ht)
91bf215546Sopenharmony_ci      return;
92bf215546Sopenharmony_ci   ht->destroy = destroy;
93bf215546Sopenharmony_ci}
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci/**
97bf215546Sopenharmony_ci * Resize the table if necessary
98bf215546Sopenharmony_ci */
99bf215546Sopenharmony_cistatic inline int
100bf215546Sopenharmony_cihandle_table_resize(struct handle_table *ht,
101bf215546Sopenharmony_ci                    unsigned minimum_size)
102bf215546Sopenharmony_ci{
103bf215546Sopenharmony_ci   unsigned new_size;
104bf215546Sopenharmony_ci   void **new_objects;
105bf215546Sopenharmony_ci
106bf215546Sopenharmony_ci   if(ht->size > minimum_size)
107bf215546Sopenharmony_ci      return ht->size;
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci   new_size = ht->size;
110bf215546Sopenharmony_ci   while(!(new_size > minimum_size))
111bf215546Sopenharmony_ci      new_size *= 2;
112bf215546Sopenharmony_ci   assert(new_size);
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci   new_objects = (void **)REALLOC((void *)ht->objects,
115bf215546Sopenharmony_ci				  ht->size*sizeof(void *),
116bf215546Sopenharmony_ci				  new_size*sizeof(void *));
117bf215546Sopenharmony_ci   if (!new_objects)
118bf215546Sopenharmony_ci      return 0;
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci   memset(new_objects + ht->size, 0, (new_size - ht->size)*sizeof(void *));
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci   ht->size = new_size;
123bf215546Sopenharmony_ci   ht->objects = new_objects;
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci   return ht->size;
126bf215546Sopenharmony_ci}
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_cistatic inline void
130bf215546Sopenharmony_cihandle_table_clear(struct handle_table *ht,
131bf215546Sopenharmony_ci                   unsigned index)
132bf215546Sopenharmony_ci{
133bf215546Sopenharmony_ci   void *object;
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci   /* The order here is important so that the object being destroyed is not
136bf215546Sopenharmony_ci    * present in the table when seen by the destroy callback, because the
137bf215546Sopenharmony_ci    * destroy callback may directly or indirectly call the other functions in
138bf215546Sopenharmony_ci    * this module.
139bf215546Sopenharmony_ci    */
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   object = ht->objects[index];
142bf215546Sopenharmony_ci   if (object) {
143bf215546Sopenharmony_ci      ht->objects[index] = NULL;
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci      if(ht->destroy)
146bf215546Sopenharmony_ci         ht->destroy(object);
147bf215546Sopenharmony_ci   }
148bf215546Sopenharmony_ci}
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci
151bf215546Sopenharmony_ciunsigned
152bf215546Sopenharmony_cihandle_table_add(struct handle_table *ht,
153bf215546Sopenharmony_ci                 void *object)
154bf215546Sopenharmony_ci{
155bf215546Sopenharmony_ci   unsigned index;
156bf215546Sopenharmony_ci   unsigned handle;
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci   assert(ht);
159bf215546Sopenharmony_ci   assert(object);
160bf215546Sopenharmony_ci   if(!object || !ht)
161bf215546Sopenharmony_ci      return 0;
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci   /* linear search for an empty handle */
164bf215546Sopenharmony_ci   while(ht->filled < ht->size) {
165bf215546Sopenharmony_ci      if(!ht->objects[ht->filled])
166bf215546Sopenharmony_ci	 break;
167bf215546Sopenharmony_ci      ++ht->filled;
168bf215546Sopenharmony_ci   }
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci   index = ht->filled;
171bf215546Sopenharmony_ci   handle = index + 1;
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci   /* check integer overflow */
174bf215546Sopenharmony_ci   if(!handle)
175bf215546Sopenharmony_ci      return 0;
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci   /* grow the table if necessary */
178bf215546Sopenharmony_ci   if(!handle_table_resize(ht, index))
179bf215546Sopenharmony_ci      return 0;
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_ci   assert(!ht->objects[index]);
182bf215546Sopenharmony_ci   ht->objects[index] = object;
183bf215546Sopenharmony_ci   ++ht->filled;
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci   return handle;
186bf215546Sopenharmony_ci}
187bf215546Sopenharmony_ci
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ciunsigned
190bf215546Sopenharmony_cihandle_table_set(struct handle_table *ht,
191bf215546Sopenharmony_ci                 unsigned handle,
192bf215546Sopenharmony_ci                 void *object)
193bf215546Sopenharmony_ci{
194bf215546Sopenharmony_ci   unsigned index;
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci   assert(ht);
197bf215546Sopenharmony_ci   assert(handle);
198bf215546Sopenharmony_ci   if(!handle || !ht)
199bf215546Sopenharmony_ci      return 0;
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci   assert(object);
202bf215546Sopenharmony_ci   if (!object)
203bf215546Sopenharmony_ci      return 0;
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_ci   index = handle - 1;
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci   /* grow the table if necessary */
208bf215546Sopenharmony_ci   if(!handle_table_resize(ht, index))
209bf215546Sopenharmony_ci      return 0;
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_ci   handle_table_clear(ht, index);
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci   ht->objects[index] = object;
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_ci   return handle;
216bf215546Sopenharmony_ci}
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_civoid *
220bf215546Sopenharmony_cihandle_table_get(struct handle_table *ht,
221bf215546Sopenharmony_ci                 unsigned handle)
222bf215546Sopenharmony_ci{
223bf215546Sopenharmony_ci   void *object;
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci   assert(ht);
226bf215546Sopenharmony_ci   assert(handle);
227bf215546Sopenharmony_ci   if(!handle || !ht || handle > ht->size)
228bf215546Sopenharmony_ci      return NULL;
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci   object = ht->objects[handle - 1];
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci   return object;
233bf215546Sopenharmony_ci}
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_civoid
237bf215546Sopenharmony_cihandle_table_remove(struct handle_table *ht,
238bf215546Sopenharmony_ci                    unsigned handle)
239bf215546Sopenharmony_ci{
240bf215546Sopenharmony_ci   void *object;
241bf215546Sopenharmony_ci   unsigned index;
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci   assert(ht);
244bf215546Sopenharmony_ci   assert(handle);
245bf215546Sopenharmony_ci   if(!handle || !ht || handle > ht->size)
246bf215546Sopenharmony_ci      return;
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   index = handle - 1;
249bf215546Sopenharmony_ci   object = ht->objects[index];
250bf215546Sopenharmony_ci   if (!object)
251bf215546Sopenharmony_ci      return;
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_ci   handle_table_clear(ht, index);
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_ci   if(index < ht->filled)
256bf215546Sopenharmony_ci      ht->filled = index;
257bf215546Sopenharmony_ci}
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ciunsigned
261bf215546Sopenharmony_cihandle_table_get_next_handle(struct handle_table *ht,
262bf215546Sopenharmony_ci                             unsigned handle)
263bf215546Sopenharmony_ci{
264bf215546Sopenharmony_ci   unsigned index;
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_ci   for(index = handle; index < ht->size; ++index) {
267bf215546Sopenharmony_ci      if(ht->objects[index])
268bf215546Sopenharmony_ci	 return index + 1;
269bf215546Sopenharmony_ci   }
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci   return 0;
272bf215546Sopenharmony_ci}
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci
275bf215546Sopenharmony_ciunsigned
276bf215546Sopenharmony_cihandle_table_get_first_handle(struct handle_table *ht)
277bf215546Sopenharmony_ci{
278bf215546Sopenharmony_ci   return handle_table_get_next_handle(ht, 0);
279bf215546Sopenharmony_ci}
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci
282bf215546Sopenharmony_civoid
283bf215546Sopenharmony_cihandle_table_destroy(struct handle_table *ht)
284bf215546Sopenharmony_ci{
285bf215546Sopenharmony_ci   unsigned index;
286bf215546Sopenharmony_ci   assert(ht);
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_ci   if (!ht)
289bf215546Sopenharmony_ci      return;
290bf215546Sopenharmony_ci
291bf215546Sopenharmony_ci   if(ht->destroy)
292bf215546Sopenharmony_ci      for(index = 0; index < ht->size; ++index)
293bf215546Sopenharmony_ci         handle_table_clear(ht, index);
294bf215546Sopenharmony_ci
295bf215546Sopenharmony_ci   FREE(ht->objects);
296bf215546Sopenharmony_ci   FREE(ht);
297bf215546Sopenharmony_ci}
298bf215546Sopenharmony_ci
299