/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2016-2020 Intel, Inc. All rights reserved. * Copyright (c) 2021-2022 Nanook Consulting. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #ifndef PMIX_VALUE_ARRAY_H #define PMIX_VALUE_ARRAY_H #include "src/include/pmix_config.h" #include #ifdef HAVE_STRINGS_H # include #endif /* HAVE_STRINGS_H */ #include "src/class/pmix_object.h" #if PMIX_ENABLE_DEBUG # include "src/util/pmix_output.h" #endif #include "pmix_common.h" BEGIN_C_DECLS /* * @file Array of elements maintained by value. */ struct pmix_value_array_t { pmix_object_t super; unsigned char *array_items; size_t array_item_sizeof; size_t array_size; size_t array_alloc_size; }; typedef struct pmix_value_array_t pmix_value_array_t; PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_value_array_t); /** * Initialize the array to hold items by value. This routine must * be called prior to using the array. * * @param array The array to initialize (IN). * @param item_size The sizeof each array element (IN). * @return PMIX error code * * Note that there is no corresponding "finalize" function -- use * OBJ_DESTRUCT (for stack arrays) or OBJ_RELEASE (for heap arrays) to * delete it. */ static inline int pmix_value_array_init(pmix_value_array_t *array, size_t item_sizeof) { array->array_item_sizeof = item_sizeof; array->array_alloc_size = 1; array->array_size = 0; array->array_items = (unsigned char *) realloc(array->array_items, item_sizeof * array->array_alloc_size); return (NULL != array->array_items) ? PMIX_SUCCESS : PMIX_ERR_OUT_OF_RESOURCE; } /** * Reserve space in the array for new elements, but do not change the size. * * @param array The input array (IN). * @param size The anticipated size of the array (IN). * @return PMIX error code. */ static inline int pmix_value_array_reserve(pmix_value_array_t *array, size_t size) { if (size > array->array_alloc_size) { array->array_items = (unsigned char *) realloc(array->array_items, array->array_item_sizeof * size); if (NULL == array->array_items) { array->array_size = 0; array->array_alloc_size = 0; return PMIX_ERR_OUT_OF_RESOURCE; } array->array_alloc_size = size; } return PMIX_SUCCESS; } /** * Retrieves the number of elements in the array. * * @param array The input array (IN). * @return The number of elements currently in use. */ static inline size_t pmix_value_array_get_size(pmix_value_array_t *array) { return array->array_size; } /** * Set the number of elements in the array. * * @param array The input array (IN). * @param size The new array size. * * @return PMIX error code. * * Note that resizing the array to a smaller size may not change * the underlying memory allocated by the array. However, setting * the size larger than the current allocation will grow it. In either * case, if the routine is successful, pmix_value_array_get_size() will * return the new size. */ PMIX_EXPORT int pmix_value_array_set_size(pmix_value_array_t *array, size_t size); /** * Macro to retrieve an item from the array by value. * * @param array The input array (IN). * @param item_type The C datatype of the array item (IN). * @param item_index The array index (IN). * * @returns item The requested item. * * Note that this does not change the size of the array - this macro is * strictly for performance - the user assumes the responsibility of * ensuring the array index is valid (0 <= item index < array size). */ #define PMIX_VALUE_ARRAY_GET_ITEM(array, item_type, item_index) \ ((item_type *) ((array)->array_items))[item_index] /** * Retrieve an item from the array by reference. * * @param array The input array (IN). * @param item_index The array index (IN). * * @return ptr Pointer to the requested item. * * Note that if the specified item_index is larger than the current * array size, the array is grown to satisfy the request. */ static inline void *pmix_value_array_get_item(pmix_value_array_t *array, size_t item_index) { if (item_index >= array->array_size && pmix_value_array_set_size(array, item_index + 1) != PMIX_SUCCESS) return NULL; return array->array_items + (item_index * array->array_item_sizeof); } /** * Macro to set an array element by value. * * @param array The input array (IN). * @param item_type The C datatype of the array item (IN). * @param item_index The array index (IN). * @param item_value The new value for the specified index (IN). * * Note that this does not change the size of the array - this macro is * strictly for performance - the user assumes the responsibility of * ensuring the array index is valid (0 <= item index < array size). * * It is safe to free the item after returning from this call; it is * copied into the array by value. */ #define PMIX_VALUE_ARRAY_SET_ITEM(array, item_type, item_index, item_value) \ (((item_type *) ((array)->array_items))[item_index] = item_value) /** * Set an array element by value. * * @param array The input array (IN). * @param item_index The array index (IN). * @param item_value A pointer to the item, which is copied into * the array. * * @return PMIX error code. * * It is safe to free the item after returning from this call; it is * copied into the array by value. */ static inline int pmix_value_array_set_item(pmix_value_array_t *array, size_t item_index, const void *item) { int rc; if (item_index >= array->array_size && (rc = pmix_value_array_set_size(array, item_index + 1)) != PMIX_SUCCESS) return rc; memcpy(array->array_items + (item_index * array->array_item_sizeof), item, array->array_item_sizeof); return PMIX_SUCCESS; } /** * Appends an item to the end of the array. * * @param array The input array (IN). * @param item A pointer to the item to append, which is copied * into the array. * * @return PMIX error code * * This will grow the array if it is not large enough to contain the * item. It is safe to free the item after returning from this call; * it is copied by value into the array. */ static inline int pmix_value_array_append_item(pmix_value_array_t *array, const void *item) { return pmix_value_array_set_item(array, array->array_size, item); } /** * Remove a specific item from the array. * * @param array The input array (IN). * @param item_index The index to remove, which must be less than * the current array size (IN). * * @return PMIX error code. * * All elements following this index are shifted down. */ static inline int pmix_value_array_remove_item(pmix_value_array_t *array, size_t item_index) { #if PMIX_ENABLE_DEBUG if (item_index >= array->array_size) { pmix_output(0, "pmix_value_array_remove_item: invalid index %lu\n", (unsigned long) item_index); return PMIX_ERR_BAD_PARAM; } #endif memmove(array->array_items + (array->array_item_sizeof * item_index), array->array_items + (array->array_item_sizeof * (item_index + 1)), array->array_item_sizeof * (array->array_size - item_index - 1)); array->array_size--; return PMIX_SUCCESS; } /** * Get the base pointer of the underlying array. * * @param array The input array (IN). * @param array_type The C datatype of the array (IN). * * @returns ptr Pointer to the actual array. * * This function is helpful when you need to iterate through an * entire array; simply get the base value of the array and use native * C to iterate through it manually. This can have better performance * than looping over PMIX_VALUE_ARRAY_GET_ITEM() and * PMIX_VALUE_ARRAY_SET_ITEM() because it will [potentially] reduce the * number of pointer dereferences. */ #define PMIX_VALUE_ARRAY_GET_BASE(array, item_type) ((item_type *) ((array)->array_items)) END_C_DECLS #endif