1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF.  The full HDF copyright notice, including       *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF/releases/.  *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 /* $Id$ */
15 
16 /*
17 FILE
18     dynarray.c - Internal storage routines for handling "dynamic arrays"
19 
20 REMARKS
21     Dynamic arrays are "standard" arrays which store objects in a straight-
22     forward linear array of objects (void *'s currently), but the "dynarray"
23     allows the size of the array to vary without excessive overhead.
24 
25 DESIGN
26     Each dynarray is managed as a small structure to store the current size
27     of the dynarray and a pointer to the array of pointers to the objects
28     stored within the array.
29 
30 BUGS/LIMITATIONS
31     No hashing or any other "folding" of the storage space is done, so the size
32     of the dynarray can get quite excessive in proportion to the # of elements
33     used if the elements used are "sparse" in the dynarray space.
34 
35     These are strictly useable from C, adding a FORTRAN calling facility would
36     require some re-working of the routines.
37 
38 LOCAL ROUTINES
39   None
40 EXPORTED ROUTINES
41  Element Functions:
42      DAget_elem - Get an element from a dynarray
43      DAset_elem - Set an element pointer for a dynarray
44      DAdel_elem - Delete an element from a dynarray
45  Dynarray Functions:
46      DAcreate_array - Create a dynarray
47      DAdestroy_array - Destroy a dynarray
48      DAsize_array    - Get the current dynarray size
49 
50 AUTHOR
51    Quincey Koziol
52 
53 MODIFICATION HISTORY
54    1/7/96  - Starting writing specs & coding prototype
55 */
56 
57 #define DYNARRAY_MASTER
58 #include "hdf.h"
59 #include "dynarray.h"
60 
61 
62 /* Private function prototypes */
63 /* <none yet> */
64 
65 /******************************************************************************
66  NAME
67      DAcreate_array - Create a dynarray
68 
69  DESCRIPTION
70     Create a dynarray for later use.  This routine allocates the dynarray
71     structure and creates a dynarray with the specified minimum size.
72 
73  RETURNS
74     Returns pointer to the dynarray created if successful and NULL otherwise
75 
76 *******************************************************************************/
DAcreate_array(intn start_size,intn incr_mult)77 dynarr_p DAcreate_array(intn start_size,      /* IN: Initial array size */
78     intn incr_mult                  /* IN: multiple to create additional elements in */
79 )
80 {
81     CONSTR(FUNC, "DAcreate_array");	/* for HERROR */
82     dynarr_t   *new_arr=NULL;       /* ptr to the new dynarray */
83     dynarr_p    ret_value=NULL;
84 
85     HEclear();
86     if(start_size<0 || incr_mult<=0)
87         HGOTO_ERROR(DFE_ARGS, NULL);
88 
89     new_arr=(dynarr_t *)HDcalloc(1,sizeof(dynarr_t));
90     if(new_arr==NULL)
91         HGOTO_ERROR(DFE_NOSPACE, NULL);
92 
93     new_arr->num_elems=start_size;
94     new_arr->incr_mult=incr_mult;
95     if(start_size>0)
96       { /* only allocate space if the initial size is positive */
97         new_arr->arr=(VOIDP *)HDcalloc(start_size,sizeof(VOIDP));
98         if(new_arr->arr==NULL)
99             HGOTO_ERROR(DFE_NOSPACE, NULL);
100       } /* end if */
101 
102     ret_value=(dynarr_p)new_arr;
103 
104 done:
105   if(ret_value == NULL)
106     { /* Error condition cleanup */
107         if(new_arr!=NULL)
108           {
109             if(new_arr->arr!=NULL)
110                 HDfree(new_arr->arr);
111             HDfree(new_arr);
112           } /* end if */
113     } /* end if */
114 
115   /* Normal function cleanup */
116   return ret_value;
117 }   /* end DAcreate_array() */
118 
119 /******************************************************************************
120  NAME
121      DAdestroy_array - Destroy a dynarray
122 
123  DESCRIPTION
124     Destroy an existing dynarray from use.  This routine de-allocates the
125     dynarray structure and deletes the current dynarray.
126 
127  RETURNS
128     Returns SUCCEED if successful and FAIL otherwise
129 
130 *******************************************************************************/
DAdestroy_array(dynarr_p arr,intn free_elem)131 intn DAdestroy_array(dynarr_p arr,  /* IN: Array to destroy */
132         intn free_elem              /* IN: whether to free each element */
133 )
134 {
135     CONSTR(FUNC, "DAdestroy_array");	/* for HERROR */
136     dynarr_t   *dest_arr;               /* ptr to the dynarray destroy*/
137     intn i;
138     intn    ret_value=SUCCEED;
139 
140     HEclear();
141     dest_arr=(dynarr_t *)arr;
142     if(dest_arr==NULL)
143         HGOTO_ERROR(DFE_ARGS, FAIL);
144 
145     /* Chuck all the items stored in the array */
146     if(free_elem!=0)
147         for(i=0; i<arr->num_elems; i++)
148           {
149               if(arr->arr[i]!=NULL)
150                   HDfree(arr->arr[i]);
151           } /* end for */
152 
153     if(dest_arr->arr!=NULL)
154         HDfree(dest_arr->arr);
155     HDfree(dest_arr);
156 
157 done:
158   if(ret_value == FAIL)
159     { /* Error condition cleanup */
160 
161     } /* end if */
162 
163   /* Normal function cleanup */
164   return ret_value;
165 }   /* end DAdestroy_array() */
166 
167 /******************************************************************************
168  NAME
169      DAdestroy_array - Get the current size of a dynarray
170 
171  DESCRIPTION
172     Get the number of elements in use currently.
173 
174  RETURNS
175     Returns # of dynarray elements if successful and FAIL otherwise
176 
177 *******************************************************************************/
DAsize_array(dynarr_p arr)178 intn DAsize_array(dynarr_p arr   /* IN: Array to get size of */
179 )
180 {
181     CONSTR(FUNC, "DAsize_array");	/* for HERROR */
182     dynarr_t   *arr_ptr;            /* ptr to the dynarray destroy*/
183     intn    ret_value=SUCCEED;
184 
185     HEclear();
186     arr_ptr=(dynarr_t *)arr;
187     if(arr_ptr==NULL)
188         HGOTO_ERROR(DFE_ARGS, FAIL);
189 
190     ret_value=arr_ptr->num_elems;
191 
192 done:
193   if(ret_value == FAIL)
194     { /* Error condition cleanup */
195 
196     } /* end if */
197 
198   /* Normal function cleanup */
199   return ret_value;
200 }   /* end DAsize_array() */
201 
202 /******************************************************************************
203  NAME
204      DAget_elem - Get an element from a dynarray
205 
206  DESCRIPTION
207     Retrieve an element from a dynarray.  If the element to be retrieved is
208     beyond the end of the currently allocated array elements, the array is
209     not extended, a NULL pointer is merely returned.
210 
211  RETURNS
212     Returns object ptr if successful and NULL otherwise
213 
214 *******************************************************************************/
DAget_elem(dynarr_p arr_ptr,intn elem)215 VOIDP DAget_elem(dynarr_p arr_ptr, /* IN: Array to access */
216     intn elem                       /* IN: Array element to retrieve */
217 )
218 {
219     CONSTR(FUNC, "DAget_elem");     /* for HERROR */
220     dynarr_t   *arr;                /* ptr to the dynarray */
221     VOIDP    ret_value=NULL;
222 
223     HEclear();
224     arr=(dynarr_t *)arr_ptr;
225     if(elem<0 || arr==NULL)
226         HGOTO_ERROR(DFE_ARGS, NULL);
227 
228     if(elem>=arr->num_elems)
229         ret_value=NULL;
230     else
231         ret_value=arr->arr[elem];
232 
233 done:
234   if(ret_value == NULL)
235     { /* Error condition cleanup */
236 
237     } /* end if */
238 
239   /* Normal function cleanup */
240   return ret_value;
241 }   /* end DAget_elem() */
242 
243 /******************************************************************************
244  NAME
245      DAset_elem - Set an element pointer for a dynarray
246 
247  DESCRIPTION
248     Set an element pointer for a dynarray.  If the element to be set is
249     beyond the end of the currently allocated array elements, the array is
250     extended by whatever multiple of the incr_mult is needed to expand the
251     # of array elements to include the array element to set.
252 
253  RETURNS
254     Returns SUCCEED if successful and NULL otherwise
255 
256 *******************************************************************************/
DAset_elem(dynarr_p arr_ptr,intn elem,VOIDP obj)257 intn DAset_elem(dynarr_p arr_ptr,  /* IN: Array to access */
258     intn elem,                      /* IN: Array element to set */
259     VOIDP obj                       /* IN: Pointer to the object to store */
260 )
261 {
262     CONSTR(FUNC, "DAset_elem");     /* for HERROR */
263     dynarr_t   *arr;                /* ptr to the dynarray */
264     intn        ret_value=SUCCEED;
265 
266     HEclear();
267     arr=(dynarr_t *)arr_ptr;
268     if(elem<0 || arr==NULL)
269         HGOTO_ERROR(DFE_ARGS, FAIL);
270 
271     if(elem>=arr->num_elems)
272       {
273         intn new_size;        /* new number of elements in the array */
274 
275         new_size=((elem/arr->incr_mult)+1)*arr->incr_mult;
276         if(arr->num_elems==0)
277           { /* array not currently allocated */
278             if((arr->arr=(VOIDP *)HDcalloc(new_size,sizeof(VOIDP)))==NULL)
279                 HGOTO_ERROR(DFE_NOSPACE, FAIL);
280           } /* end if */
281         else
282           { /* extend the existing array */
283             VOIDP *new_arr;   /* storage for the new array of ptrs */
284 
285             if((new_arr=(VOIDP *)HDrealloc(arr->arr,new_size*sizeof(VOIDP)))==NULL)
286                 HGOTO_ERROR(DFE_NOSPACE, FAIL);
287             HDmemset(&new_arr[arr->num_elems],0,sizeof(VOIDP)*(uintn)(new_size-arr->num_elems));
288             arr->arr=new_arr;
289           } /* end else */
290         arr->num_elems=new_size;
291       } /* end if */
292 
293     /* Set the element value */
294     arr->arr[elem]=obj;
295 
296 done:
297   if(ret_value == FAIL)
298     { /* Error condition cleanup */
299 
300     } /* end if */
301 
302   /* Normal function cleanup */
303   return ret_value;
304 }   /* end DAset_elem() */
305 
306 /*****************************************************************************
307  NAME
308      DAdel_elem - Delete an element from a dynarray
309 
310  DESCRIPTION
311     Retrieve an element from a dynarray & delete it from the dynarray.  If the
312     element to be retrieved is beyond the end of the currently allocated array
313     elements, the array is not extended, a NULL pointer is merely returned.
314 
315  RETURNS
316     Returns object ptr if successful and NULL otherwise
317 
318 *******************************************************************************/
DAdel_elem(dynarr_p arr_ptr,intn elem)319 VOIDP DAdel_elem(dynarr_p arr_ptr, /* IN: Array to access */
320     intn elem                       /* IN: Array element to retrieve */
321 )
322 {
323     CONSTR(FUNC, "DAdel_elem");     /* for HERROR */
324     dynarr_t   *arr;                /* ptr to the dynarray */
325     VOIDP    ret_value=NULL;
326 
327     HEclear();
328     arr=(dynarr_t *)arr_ptr;
329     if(elem<0 || arr==NULL)
330         HGOTO_ERROR(DFE_ARGS, NULL);
331 
332     if(elem>=arr->num_elems)
333         ret_value=NULL;
334     else
335       {
336         ret_value=arr->arr[elem];
337         arr->arr[elem]=NULL;
338       } /* end else */
339 
340 done:
341   if(ret_value == NULL)
342     { /* Error condition cleanup */
343 
344     } /* end if */
345 
346   /* Normal function cleanup */
347   return ret_value;
348 }   /* end DAdel_elem() */
349 
350