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