1 /*
2  * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
3  *                         University Research and Technology
4  *                         Corporation.  All rights reserved.
5  * Copyright (c) 2004-2006 The University of Tennessee and The University
6  *                         of Tennessee Research Foundation.  All rights
7  *                         reserved.
8  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
9  *                         University of Stuttgart.  All rights reserved.
10  * Copyright (c) 2004-2005 The Regents of the University of California.
11  *                         All rights reserved.
12  * $COPYRIGHT$
13  *
14  * Additional copyrights may follow
15  *
16  * $HEADER$
17  */
18 
19 #ifndef OPAL_VALUE_ARRAY_H
20 #define OPAL_VALUE_ARRAY_H
21 
22 #include "opal_config.h"
23 
24 #include <string.h>
25 #ifdef HAVE_STRINGS_H
26 #include <strings.h>
27 #endif /* HAVE_STRINGS_H */
28 
29 #include "opal/class/opal_object.h"
30 #if OPAL_ENABLE_DEBUG
31 #include "opal/util/output.h"
32 #endif
33 #include "opal/constants.h"
34 
35 BEGIN_C_DECLS
36 
37 /*
38  *  @file  Array of elements maintained by value.
39  */
40 
41 struct opal_value_array_t
42 {
43     opal_object_t    super;
44     unsigned char*  array_items;
45     size_t          array_item_sizeof;
46     size_t          array_size;
47     size_t          array_alloc_size;
48 };
49 typedef struct opal_value_array_t opal_value_array_t;
50 
51 OPAL_DECLSPEC OBJ_CLASS_DECLARATION(opal_value_array_t);
52 
53 /**
54  *  Initialize the array to hold items by value. This routine must
55  *  be called prior to using the array.
56  *
57  *  @param   array       The array to initialize (IN).
58  *  @param   item_size   The sizeof each array element (IN).
59  *  @return  OPAL error code
60  *
61  * Note that there is no corresponding "finalize" function -- use
62  * OBJ_DESTRUCT (for stack arrays) or OBJ_RELEASE (for heap arrays) to
63  * delete it.
64  */
65 
opal_value_array_init(opal_value_array_t * array,size_t item_sizeof)66 static inline int opal_value_array_init(opal_value_array_t *array, size_t item_sizeof)
67 {
68     array->array_item_sizeof = item_sizeof;
69     array->array_alloc_size = 1;
70     array->array_size = 0;
71     array->array_items = (unsigned char*)realloc(array->array_items, item_sizeof * array->array_alloc_size);
72     return (NULL != array->array_items) ? OPAL_SUCCESS : OPAL_ERR_OUT_OF_RESOURCE;
73 }
74 
75 
76 /**
77  *  Reserve space in the array for new elements, but do not change the size.
78  *
79  *  @param   array   The input array (IN).
80  *  @param   size    The anticipated size of the array (IN).
81  *  @return  OPAL error code.
82  */
83 
opal_value_array_reserve(opal_value_array_t * array,size_t size)84 static inline int opal_value_array_reserve(opal_value_array_t* array, size_t size)
85 {
86      if(size > array->array_alloc_size) {
87          array->array_items = (unsigned char*)realloc(array->array_items, array->array_item_sizeof * size);
88          if(NULL == array->array_items) {
89              array->array_size = 0;
90              array->array_alloc_size = 0;
91              return OPAL_ERR_OUT_OF_RESOURCE;
92          }
93          array->array_alloc_size = size;
94      }
95      return OPAL_SUCCESS;
96 }
97 
98 
99 
100 /**
101  *  Retreives the number of elements in the array.
102  *
103  *  @param   array   The input array (IN).
104  *  @return  The number of elements currently in use.
105  */
106 
opal_value_array_get_size(opal_value_array_t * array)107 static inline size_t opal_value_array_get_size(opal_value_array_t* array)
108 {
109     return array->array_size;
110 }
111 
112 
113 /**
114  *  Set the number of elements in the array.
115  *
116  *  @param  array   The input array (IN).
117  *  @param  size    The new array size.
118  *
119  *  @return  OPAL error code.
120  *
121  *  Note that resizing the array to a smaller size may not change
122  *  the underlying memory allocated by the array. However, setting
123  *  the size larger than the current allocation will grow it. In either
124  *  case, if the routine is successful, opal_value_array_get_size() will
125  *  return the new size.
126  */
127 
128 OPAL_DECLSPEC int opal_value_array_set_size(opal_value_array_t* array, size_t size);
129 
130 
131 /**
132  *  Macro to retrieve an item from the array by value.
133  *
134  *  @param  array       The input array (IN).
135  *  @param  item_type   The C datatype of the array item (IN).
136  *  @param  item_index  The array index (IN).
137  *
138  *  @returns item       The requested item.
139  *
140  *  Note that this does not change the size of the array - this macro is
141  *  strictly for performance - the user assumes the responsibility of
142  *  ensuring the array index is valid (0 <= item index < array size).
143  */
144 
145 #define OPAL_VALUE_ARRAY_GET_ITEM(array, item_type, item_index) \
146     ((item_type*)((array)->array_items))[item_index]
147 
148 /**
149  *  Retrieve an item from the array by reference.
150  *
151  *  @param  array          The input array (IN).
152  *  @param  item_index     The array index (IN).
153  *
154  *  @return ptr Pointer to the requested item.
155  *
156  *  Note that if the specified item_index is larger than the current
157  *  array size, the array is grown to satisfy the request.
158  */
159 
opal_value_array_get_item(opal_value_array_t * array,size_t item_index)160 static inline void* opal_value_array_get_item(opal_value_array_t *array, size_t item_index)
161 {
162     if(item_index >= array->array_size && opal_value_array_set_size(array, item_index+1) != OPAL_SUCCESS)
163         return NULL;
164     return array->array_items + (item_index * array->array_item_sizeof);
165 }
166 
167 /**
168  *  Macro to set an array element by value.
169  *
170  *  @param  array       The input array (IN).
171  *  @param  item_type   The C datatype of the array item (IN).
172  *  @param  item_index  The array index (IN).
173  *  @param  item_value  The new value for the specified index (IN).
174  *
175  *  Note that this does not change the size of the array - this macro is
176  *  strictly for performance - the user assumes the responsibility of
177  *  ensuring the array index is valid (0 <= item index < array size).
178  *
179  * It is safe to free the item after returning from this call; it is
180  * copied into the array by value.
181  */
182 
183 #define OPAL_VALUE_ARRAY_SET_ITEM(array, item_type, item_index, item_value) \
184     (((item_type*)((array)->array_items))[item_index] = item_value)
185 
186 /**
187  *  Set an array element by value.
188  *
189  *  @param   array       The input array (IN).
190  *  @param   item_index  The array index (IN).
191  *  @param   item_value  A pointer to the item, which is copied into
192  *                       the array.
193  *
194  *  @return  OPAL error code.
195  *
196  * It is safe to free the item after returning from this call; it is
197  * copied into the array by value.
198  */
199 
opal_value_array_set_item(opal_value_array_t * array,size_t item_index,const void * item)200 static inline int opal_value_array_set_item(opal_value_array_t *array, size_t item_index, const void* item)
201 {
202     int rc;
203     if(item_index >= array->array_size &&
204        (rc = opal_value_array_set_size(array, item_index+1)) != OPAL_SUCCESS)
205         return rc;
206     memcpy(array->array_items + (item_index * array->array_item_sizeof), item, array->array_item_sizeof);
207     return OPAL_SUCCESS;
208 }
209 
210 
211 /**
212  *  Appends an item to the end of the array.
213  *
214  *  @param   array    The input array (IN).
215  *  @param   item     A pointer to the item to append, which is copied
216  *                    into the array.
217  *
218  *  @return  OPAL error code
219  *
220  * This will grow the array if it is not large enough to contain the
221  * item.  It is safe to free the item after returning from this call;
222  * it is copied by value into the array.
223  */
224 
opal_value_array_append_item(opal_value_array_t * array,const void * item)225 static inline int opal_value_array_append_item(opal_value_array_t *array, const void *item)
226 {
227     return opal_value_array_set_item(array, array->array_size, item);
228 }
229 
230 
231 /**
232  *  Remove a specific item from the array.
233  *
234  *  @param   array       The input array (IN).
235  *  @param   item_index  The index to remove, which must be less than
236  *                       the current array size (IN).
237  *
238  *  @return  OPAL error code.
239  *
240  * All elements following this index are shifted down.
241  */
242 
opal_value_array_remove_item(opal_value_array_t * array,size_t item_index)243 static inline int opal_value_array_remove_item(opal_value_array_t *array, size_t item_index)
244 {
245 #if OPAL_ENABLE_DEBUG
246     if (item_index >= array->array_size) {
247         opal_output(0, "opal_value_array_remove_item: invalid index %lu\n", (unsigned long)item_index);
248         return OPAL_ERR_BAD_PARAM;
249     }
250 #endif
251     memmove(array->array_items+(array->array_item_sizeof * item_index),
252             array->array_items+(array->array_item_sizeof * (item_index+1)),
253             array->array_item_sizeof * (array->array_size - item_index - 1));
254     array->array_size--;
255     return OPAL_SUCCESS;
256 }
257 
258 /**
259  * Get the base pointer of the underlying array.
260  *
261  * @param array The input array (IN).
262  * @param array_type The C datatype of the array (IN).
263  *
264  * @returns ptr Pointer to the actual array.
265  *
266  * This function is helpful when you need to iterate through an
267  * entire array; simply get the base value of the array and use native
268  * C to iterate through it manually.  This can have better performance
269  * than looping over OPAL_VALUE_ARRAY_GET_ITEM() and
270  * OPAL_VALUE_ARRAY_SET_ITEM() because it will [potentially] reduce the
271  * number of pointer dereferences.
272  */
273 
274 #define OPAL_VALUE_ARRAY_GET_BASE(array, item_type) \
275   ((item_type*) ((array)->array_items))
276 
277 END_C_DECLS
278 
279 #endif
280 
281