#ifndef _ARR_DESC_H_
|
#define _ARR_DESC_H_
|
|
/*--------------------------------------------------------------------------------*/
|
/* Includes */
|
/*--------------------------------------------------------------------------------*/
|
#include <stdint.h>
|
#include <string.h> /* memset() */
|
#include "../util/util.h" /* CONCAT() */
|
|
/*--------------------------------------------------------------------------------*/
|
/* Type Definitions */
|
/*--------------------------------------------------------------------------------*/
|
|
/**
|
* Array-descriptor struct.
|
*/
|
typedef struct ARR_DESC_struct
|
{
|
void * data_ptr; /* Pointer to the array contents. */
|
int32_t element_count; /* Number of current elements. */
|
int32_t element_size; /* Size of current elements in bytes. */
|
int32_t underlying_size; /* Size of underlying array in bytes. */
|
} ARR_DESC_t;
|
|
/*--------------------------------------------------------------------------------*/
|
/* Macros and Defines */
|
/*--------------------------------------------------------------------------------*/
|
|
/**
|
* Prefix of the array variable's name when creating an array and an array
|
* descriptor at the same time.
|
*/
|
#define ARR_DESC_ARR_PREFIX ARR_DESC_ARR_
|
|
/**
|
* Evaluate to the array variable's name when creating an array and an array
|
* descriptor at the same time.
|
*/
|
#define ARR_DESC_ARR_NAME(name) \
|
CONCAT(ARR_DESC_ARR_PREFIX, name)
|
|
/**
|
* Define an #ARR_DESC_t by itself.
|
*
|
* @note The user must supply an array to store the data used by the
|
* #ARR_DESC_t.
|
*/
|
#define ARR_DESC_INTERNAL_DEFINE(name, data_ptr, \
|
element_count, element_size) \
|
ARR_DESC_t name = { \
|
data_ptr, \
|
element_count, \
|
element_size, \
|
element_count * element_size \
|
} \
|
|
/**
|
* Define both an array and an #ARR_DESC_t that describes it.
|
*
|
* @note Use the #CURLY() macro for the content field; it provides the curly
|
* braces necessary for an array initialization.
|
*/
|
#define ARR_DESC_DEFINE(type, name, element_count, content) \
|
type ARR_DESC_ARR_NAME(name)[element_count] = content; \
|
ARR_DESC_INTERNAL_DEFINE(name, \
|
&ARR_DESC_ARR_NAME(name), \
|
element_count, \
|
sizeof(type)) /* Note the lacking semicolon */
|
|
/**
|
* Create a #ARR_DESC_t which refers to a subset of the data in another.
|
*
|
* The new #ARR_DESC_t shares the same underlying array as the aliased
|
* #ARR_DESC_t, but only describes a subset of the originals values.
|
*/
|
#define ARR_DESC_DEFINE_SUBSET(name, original, element_cnt) \
|
ARR_DESC_INTERNAL_DEFINE(name, \
|
&ARR_DESC_ARR_NAME(original), \
|
element_cnt, \
|
sizeof(ARR_DESC_ARR_NAME(original)[0]) \
|
) /* Note the lacking semicolon */
|
|
/**
|
* Creat an #ARR_DESC_t which points to the data in an existing array.
|
*
|
* @param start_idx Offset in array_ptr of first element.
|
* @param element_cnt Number of elements to include in the #ARR_DESC_t.
|
*
|
* @example
|
*
|
* float my_floats[4] = {0.0f, 1.0f, 2.0f, 3.0f};
|
*
|
* ARR_DESC_DEFINE_USING_ARR(my_arr_desc, my_floats, 1, 3);
|
*
|
* printf("Element 0: %f\n", ARR_DESC_ELT(float, 0, &my_arr_desc));
|
* printf("Element 1: %f\n", ARR_DESC_ELT(float, 1, &my_arr_desc));
|
*
|
* Outputs:
|
*
|
* Element 0: 1.000000
|
* Element 1: 2.000000
|
*
|
* @warning There are no checks in place to catch invalid start indices; This
|
* is left to the user.
|
*/
|
#define ARR_DESC_DEFINE_USING_ARR(type, name, array_ptr, start_idx, element_cnt) \
|
ARR_DESC_INTERNAL_DEFINE( \
|
name, \
|
(type *) (array_ptr + start_idx), \
|
element_cnt, \
|
sizeof(type) \
|
) /* Note the lacking semicolon*/
|
|
/**
|
* Declare an #ARR_DESC_t object.
|
*/
|
#define ARR_DESC_DECLARE(name) \
|
extern ARR_DESC_t name /* Note the lacking semicolon */
|
|
/**
|
* Evaluate to the number of bytes stored in the #ARR_DESC_t.
|
*/
|
#define ARR_DESC_BYTES(arr_desc_ptr) \
|
((arr_desc_ptr)->element_count * (arr_desc_ptr)->element_size)
|
|
/**
|
* Set the contents of #ARR_DESC_t to value.
|
*/
|
#define ARR_DESC_MEMSET(arr_desc_ptr, value, bytes) \
|
do \
|
{ \
|
memset((arr_desc_ptr)->data_ptr, \
|
value, \
|
BOUND(0, \
|
(arr_desc_ptr)->underlying_size, \
|
bytes) \
|
); \
|
} while (0)
|
|
/**
|
* Perform a memcpy of 'bytes' bytes from the source #ARR_DESC_t to the
|
* destination #ARR_DESC_t.
|
*/
|
#define ARR_DESC_MEMCPY(arr_desc_dest_ptr, arr_desc_src_ptr, bytes) \
|
do \
|
{ \
|
memcpy((arr_desc_dest_ptr)->data_ptr, \
|
(arr_desc_src_ptr)->data_ptr, \
|
BOUND(0, \
|
(arr_desc_dest_ptr)->underlying_size, \
|
bytes)); \
|
} while (0)
|
|
/**
|
* Evaluate to true if the source #ARR_DESC_t contents will fit into the
|
* destination #ARR_DESC_t and false otherwise.
|
*/
|
#define ARR_DESC_COPYABLE(arr_desc_dest_ptr, arr_desc_src_ptr) \
|
(ARR_DESC_BYTES(arr_desc_src_ptr) <= \
|
(arr_desc_dest_ptr)->underlying_size)
|
|
/**
|
* Copy all the data from the source #ARR_DESC_t to the destination
|
* #ARR_DESC_t.
|
*
|
* @note If the destination #ARR_DESC_t is too small to fit the source data the
|
* copy is aborted and nothing happens.
|
*/
|
#define ARR_DESC_COPY(arr_desc_dest_ptr, arr_desc_src_ptr) \
|
do \
|
{ \
|
if (ARR_DESC_COPYABLE(arr_desc_dest_ptr, \
|
arr_desc_src_ptr)) \
|
{ \
|
ARR_DESC_MEMCPY(arr_desc_dest_ptr, \
|
arr_desc_src_ptr, \
|
ARR_DESC_BYTES(arr_desc_src_ptr)); \
|
/* Update the properties*/ \
|
(arr_desc_dest_ptr)->element_count = \
|
(arr_desc_src_ptr)->element_count; \
|
(arr_desc_dest_ptr)->element_size = \
|
(arr_desc_src_ptr)->element_size; \
|
} \
|
} while (0)
|
|
/**
|
* Compare the data in two #ARR_DESC_t structs for the specified number of
|
* bytes.
|
*/
|
#define ARR_DESC_MEMCMP(arr_desc_ptr_a, arr_desc_ptr_b, bytes) \
|
memcmp((arr_desc_ptr_a)->data_ptr, \
|
(arr_desc_ptr_b)->data_ptr, \
|
bytes) /* Note the lacking semicolon */ \
|
|
/**
|
* Zero out the contents of the #ARR_DESC_t.
|
*/
|
#define ARR_DESC_ZERO(arr_desc_ptr) \
|
ARR_DESC_MEMSET(arr_desc_ptr, \
|
0, \
|
(arr_desc_ptr)->underlying_size)
|
|
/**
|
* Evaluate to the data address in #ARR_DESC_t at offset.
|
*/
|
#define ARR_DESC_DATA_ADDR(type, arr_desc_ptr, offset) \
|
((void*)(((type *) \
|
((arr_desc_ptr)->data_ptr)) \
|
+ offset))
|
|
/**
|
* Evaluate to the element in #ARR_DESC_t with type at idx.
|
*/
|
#define ARR_DESC_ELT(type, idx, arr_desc_ptr) \
|
(*((type *) ARR_DESC_DATA_ADDR(type, \
|
arr_desc_ptr, \
|
idx)))
|
|
#endif /* _ARR_DESC_H_ */
|