1 /*
2  * Copyright (C) 2009      Citrix Ltd.
3  * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published
7  * by the Free Software Foundation; version 2.1 only. with the special
8  * exception on linking described in file LICENSE.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  */
15 
16 #include "libxl_internal.h"
17 #include <stdarg.h>
18 
19 /*
20  * It is safe to store gc in the struct because:
21  * - If it an actual gc, then the flexarray should not be used after the gc
22  *   have been freed.
23  * - If it is a NOGC, then this point to a structure embedded in libxl_ctx,
24  *   therefore will survive across several libxl calls.
25  */
26 
flexarray_make(libxl__gc * gc,int size,int autogrow)27 flexarray_t *flexarray_make(libxl__gc *gc, int size, int autogrow)
28 {
29     flexarray_t *array;
30 
31     GCNEW(array);
32     array->size = size;
33     array->autogrow = autogrow;
34     array->count = 0;
35     array->gc = gc;
36     GCNEW_ARRAY(array->data, size);
37 
38     return array;
39 }
40 
flexarray_free(flexarray_t * array)41 void flexarray_free(flexarray_t *array)
42 {
43     assert(!libxl__gc_is_real(array->gc));
44     free(array->data);
45     free(array);
46 }
47 
flexarray_grow(flexarray_t * array,int extents)48 void flexarray_grow(flexarray_t *array, int extents)
49 {
50     int newsize;
51     libxl__gc *gc = array->gc;
52 
53     newsize = array->size + extents;
54     GCREALLOC_ARRAY(array->data, newsize);
55     array->size += extents;
56 }
57 
flexarray_set(flexarray_t * array,unsigned int idx,void * ptr)58 int flexarray_set(flexarray_t *array, unsigned int idx, void *ptr)
59 {
60     if (idx >= array->size) {
61         int newsize;
62         if (!array->autogrow)
63             return 1;
64         newsize = (array->size * 2 < idx) ? idx + 1 : array->size * 2;
65         flexarray_grow(array, newsize - array->size);
66     }
67     if ( idx + 1 > array->count )
68         array->count = idx + 1;
69     array->data[idx] = ptr;
70     return 0;
71 }
72 
flexarray_append(flexarray_t * array,void * ptr)73 int flexarray_append(flexarray_t *array, void *ptr)
74 {
75     return flexarray_set(array, array->count, ptr);
76 }
77 
flexarray_append_pair(flexarray_t * array,void * ptr1,void * ptr2)78 int flexarray_append_pair(flexarray_t *array, void *ptr1, void *ptr2)
79 {
80     int rc = flexarray_append(array, ptr1);
81     if (!rc)
82         rc = flexarray_append(array, ptr2);
83     return rc;
84 }
85 
flexarray_vappend(flexarray_t * array,...)86 int flexarray_vappend(flexarray_t *array, ...)
87 {
88     va_list va;
89     void *ptr;
90     int ret;
91 
92     va_start(va, array);
93     for(ret = 0; (ptr = va_arg(va, void *)); ret++) {
94         if ( flexarray_append(array, ptr) )
95             break;
96     }
97     va_end(va);
98     return ret;
99 }
100 
flexarray_get(flexarray_t * array,int idx,void ** ptr)101 int flexarray_get(flexarray_t *array, int idx, void **ptr)
102 {
103     if (idx >= array->size)
104         return 1;
105     *ptr = array->data[idx];
106     return 0;
107 }
108 
flexarray_contents(flexarray_t * array)109 void **flexarray_contents(flexarray_t *array)
110 {
111     void **data;
112     data = array->data;
113     if (!libxl__gc_is_real(array->gc))
114         free(array);
115     return data;
116 }
117 
118 /*
119  * Local variables:
120  * mode: C
121  * c-basic-offset: 4
122  * indent-tabs-mode: nil
123  * End:
124  */
125