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