495 lines
20 KiB
C
495 lines
20 KiB
C
#ifndef _VARRAY_H
|
|
#define _VARRAY_H
|
|
|
|
/*
|
|
* Variable array implementation. The following implements a linked-list
|
|
* allowing for easy dynamic array manipulation.
|
|
*
|
|
* Since there's significant overhead in indexing such linked lists, the
|
|
* contents can be exported out to a static array (embedded in a struct)
|
|
* for efficient indexing once the content is settled.
|
|
*/
|
|
#include <sys/types.h>
|
|
|
|
struct vararray_node {
|
|
struct vararray_node* prev; /* Pointer to prev node */
|
|
struct vararray_node* next; /* Pointer to next node */
|
|
/* This may look ridiculous, but it allows flexibility in data storage
|
|
* at the cost of memory efficiency.
|
|
*/
|
|
int using_ptr; /* Set to 1 to indicate a pointer type */
|
|
union {
|
|
void* as_ptr; /* Plain data pointer */
|
|
char* as_string; /* Char pointer */
|
|
/* Integer types */
|
|
char as_char; /* Character */
|
|
unsigned char as_uchar;
|
|
short as_short; /* Short Integer */
|
|
unsigned short as_ushort;
|
|
int as_int; /* Plain Integer */
|
|
unsigned int as_uint;
|
|
long as_long; /* Long Integer */
|
|
unsigned long as_ulong;
|
|
long long as_llong; /* Very long Integer */
|
|
unsigned long long as_ullong;
|
|
/* Float types */
|
|
float as_float;
|
|
double as_double;
|
|
} data;
|
|
};
|
|
|
|
struct vararray {
|
|
size_t length; /* Length of the linked list */
|
|
size_t data_size; /* Size of data being stored...
|
|
* only used for object storage.
|
|
*/
|
|
void* (*copy_func)(void* orig, size_t size);
|
|
void (*destroy_func)(void* orig);
|
|
struct vararray_node* head; /* Head node */
|
|
struct vararray_node* tail; /* Tail node */
|
|
};
|
|
|
|
/* Create a new vararray
|
|
* This function will either create from scratch a new variable array struct,
|
|
* or can initialise a pre-allocated struct. Pass NULL to allocate a new struct
|
|
* that can be freed later.
|
|
*
|
|
* The size parameter specifies the size of objects being stored in the array.
|
|
* This should be zero for plain types such as char, etc.
|
|
*
|
|
* In the case of object pointers, copy_func should point to a function that,
|
|
* when given a pointer to an object, allocates and returns a copy of the
|
|
* object, using deep copy techniques. It may be set to NULL, in which case a
|
|
* default shallow-copy routine is used.
|
|
*
|
|
* Likewise with destroy_func, this points to a function for destroying
|
|
* objects. By default, it points to free();
|
|
*/
|
|
struct vararray* create_vararray( struct vararray* dest, size_t obj_size,
|
|
void* (*copy_func)(void* orig, size_t size),
|
|
void (*destroy_func)(void* orig) );
|
|
|
|
/* Destroy a vararray
|
|
*
|
|
* This destroys a vararray and all its contents
|
|
*/
|
|
void destroy_vararray( struct vararray* dest );
|
|
|
|
/* Copy a vararray
|
|
*
|
|
* This does a deep copy of the entire contents in the array.
|
|
*
|
|
* Returns the copy on success, or NULL on failure
|
|
*/
|
|
struct vararray* copy_vararray( struct vararray* src );
|
|
|
|
/* Fetch a node value. There's one function for each type.
|
|
*
|
|
* They are provided to allow easy fetching of simple types without needing to
|
|
* cast. Obviously void* will need to be casted to the necessary type, but
|
|
* everything else should be covered. I hope! ;-)
|
|
*
|
|
* The end parameter defines which end to start counting. When set non-zero,
|
|
* the index is subtracted from the array's length -- thus an index of 0 while
|
|
* end is non-zero, will point to the element *after* the tail of the array
|
|
* (invalid in this context). An index of 1 with a non-zero end, yields the
|
|
* last element in the array (length-1 counting from the start).
|
|
*/
|
|
#define VARARRAY_INDEX_FROM_START 0
|
|
#define VARARRAY_INDEX_FROM_END 1
|
|
inline void* get_vararray_ptr( struct vararray* array,
|
|
size_t index, int end );
|
|
inline char* get_vararray_string( struct vararray* array,
|
|
size_t index, int end );
|
|
inline char get_vararray_char( struct vararray* array,
|
|
size_t index, int end );
|
|
inline unsigned char get_vararray_uchar( struct vararray* array,
|
|
size_t index, int end );
|
|
inline short get_vararray_short( struct vararray* array,
|
|
size_t index, int end );
|
|
inline unsigned short get_vararray_ushort( struct vararray* array,
|
|
size_t index, int end );
|
|
inline int get_vararray_int( struct vararray* array,
|
|
size_t index, int end );
|
|
inline unsigned int get_vararray_uint( struct vararray* array,
|
|
size_t index, int end );
|
|
inline long get_vararray_long( struct vararray* array,
|
|
size_t index, int end );
|
|
inline unsigned long get_vararray_ulong( struct vararray* array,
|
|
size_t index, int end );
|
|
inline long long get_vararray_llong( struct vararray* array,
|
|
size_t index, int end );
|
|
inline unsigned long long get_vararray_ullong( struct vararray* array,
|
|
size_t index, int end );
|
|
inline float get_vararray_float( struct vararray* array,
|
|
size_t index, int end );
|
|
inline double get_vararray_double( struct vararray* array,
|
|
size_t index, int end );
|
|
|
|
/* Insert a node value. Again, one for each type. The position parameter
|
|
* indicates where in the array to place the new item.
|
|
*
|
|
* They return 1 on success, 0 otherwise.
|
|
*/
|
|
inline int insert_vararray_ptr( struct vararray* array,
|
|
void* obj,
|
|
size_t index, int end );
|
|
inline int insert_vararray_string( struct vararray* array,
|
|
char* str,
|
|
size_t index, int end );
|
|
inline int insert_vararray_char( struct vararray* array,
|
|
char value,
|
|
size_t index, int end );
|
|
inline int insert_vararray_uchar( struct vararray* array,
|
|
unsigned char value,
|
|
size_t index, int end );
|
|
inline int insert_vararray_short( struct vararray* array,
|
|
short value,
|
|
size_t index, int end );
|
|
inline int insert_vararray_ushort( struct vararray* array,
|
|
unsigned short value,
|
|
size_t index, int end );
|
|
inline int insert_vararray_int( struct vararray* array,
|
|
int value,
|
|
size_t index, int end );
|
|
inline int insert_vararray_uint( struct vararray* array,
|
|
unsigned int value,
|
|
size_t index, int end );
|
|
inline int insert_vararray_long( struct vararray* array,
|
|
long value,
|
|
size_t index, int end );
|
|
inline int insert_vararray_ulong( struct vararray* array,
|
|
unsigned long value,
|
|
size_t index, int end );
|
|
inline int insert_vararray_llong( struct vararray* array,
|
|
long long value,
|
|
size_t index, int end );
|
|
inline int insert_vararray_ullong( struct vararray* array,
|
|
unsigned long long value,
|
|
size_t index, int end );
|
|
inline int insert_vararray_float( struct vararray* array,
|
|
float value,
|
|
size_t index, int end );
|
|
inline int insert_vararray_double( struct vararray* array,
|
|
double value,
|
|
size_t index, int end );
|
|
|
|
/* Update a node value. Again, one for each type. The position parameter
|
|
* indicates where in the array to perform the update.
|
|
*
|
|
* Index 0 is invalid when end is non-zero.
|
|
*
|
|
* They return 1 on success, 0 otherwise.
|
|
*/
|
|
inline int update_vararray_ptr( struct vararray* array,
|
|
void* obj,
|
|
size_t index, int end );
|
|
inline int update_vararray_string( struct vararray* array,
|
|
char* str,
|
|
size_t index, int end );
|
|
inline int update_vararray_char( struct vararray* array,
|
|
char value,
|
|
size_t index, int end );
|
|
inline int update_vararray_uchar( struct vararray* array,
|
|
unsigned char value,
|
|
size_t index, int end );
|
|
inline int update_vararray_short( struct vararray* array,
|
|
short value,
|
|
size_t index, int end );
|
|
inline int update_vararray_ushort( struct vararray* array,
|
|
unsigned short value,
|
|
size_t index, int end );
|
|
inline int update_vararray_int( struct vararray* array,
|
|
int value,
|
|
size_t index, int end );
|
|
inline int update_vararray_uint( struct vararray* array,
|
|
unsigned int value,
|
|
size_t index, int end );
|
|
inline int update_vararray_long( struct vararray* array,
|
|
long value,
|
|
size_t index, int end );
|
|
inline int update_vararray_ulong( struct vararray* array,
|
|
unsigned long value,
|
|
size_t index, int end );
|
|
inline int update_vararray_llong( struct vararray* array,
|
|
long long value,
|
|
size_t index, int end );
|
|
inline int update_vararray_ullong( struct vararray* array,
|
|
unsigned long long value,
|
|
size_t index, int end );
|
|
inline int update_vararray_float( struct vararray* array,
|
|
float value,
|
|
size_t index, int end );
|
|
inline int update_vararray_double( struct vararray* array,
|
|
double value,
|
|
size_t index, int end );
|
|
|
|
/* Delete the specified node from the array.
|
|
*
|
|
* Returns 1 on success, 0 on failure.
|
|
*/
|
|
inline int delete_vararray_node( struct vararray* array,
|
|
size_t index, int end );
|
|
|
|
/* Stack-like operators. The following functions are borrowed from Perl's
|
|
* functions of the same name.
|
|
*
|
|
* push_vararray_TYPE pushes an element onto the end (append),
|
|
* and is in fact, implemented as a macro around insert.
|
|
*
|
|
* pop_vararray_TYPE pops an element from the end of the array.
|
|
*
|
|
* shift_vararray_TYPE pops an element from the start of the array.
|
|
*
|
|
* unshift_vararray_TYPE pushes an element onto the start,
|
|
* and again, is a macro around insert.
|
|
*
|
|
* push and shift macros are listed here:
|
|
*/
|
|
|
|
#define push_vararray_ptr( a, v ) \
|
|
insert_vararray_ptr( a, v, 0, VARARRAY_INDEX_FROM_END )
|
|
#define push_vararray_string( a, v ) \
|
|
insert_vararray_string( a, v, 0, VARARRAY_INDEX_FROM_END )
|
|
#define push_vararray_char( a, v ) \
|
|
insert_vararray_char( a, v, 0, VARARRAY_INDEX_FROM_END )
|
|
#define push_vararray_uchar( a, v ) \
|
|
insert_vararray_uchar( a, v, 0, VARARRAY_INDEX_FROM_END )
|
|
#define push_vararray_short( a, v ) \
|
|
insert_vararray_short( a, v, 0, VARARRAY_INDEX_FROM_END )
|
|
#define push_vararray_ushort( a, v ) \
|
|
insert_vararray_ushort( a, v, 0, VARARRAY_INDEX_FROM_END )
|
|
#define push_vararray_int( a, v ) \
|
|
insert_vararray_int( a, v, 0, VARARRAY_INDEX_FROM_END )
|
|
#define push_vararray_uint( a, v ) \
|
|
insert_vararray_uint( a, v, 0, VARARRAY_INDEX_FROM_END )
|
|
#define push_vararray_long( a, v ) \
|
|
insert_vararray_long( a, v, 0, VARARRAY_INDEX_FROM_END )
|
|
#define push_vararray_ulong( a, v ) \
|
|
insert_vararray_ulong( a, v, 0, VARARRAY_INDEX_FROM_END )
|
|
#define push_vararray_llong( a, v ) \
|
|
insert_vararray_llong( a, v, 0, VARARRAY_INDEX_FROM_END )
|
|
#define push_vararray_ullong( a, v ) \
|
|
insert_vararray_ullong( a, v, 0, VARARRAY_INDEX_FROM_END )
|
|
#define push_vararray_float( a, v ) \
|
|
insert_vararray_float( a, v, 0, VARARRAY_INDEX_FROM_END )
|
|
#define push_vararray_double( a, v ) \
|
|
insert_vararray_double( a, v, 0, VARARRAY_INDEX_FROM_END )
|
|
|
|
#define unshift_vararray_ptr( a, v ) \
|
|
insert_vararray_ptr( a, v, 0, VARARRAY_INDEX_FROM_START )
|
|
#define unshift_vararray_string( a, v ) \
|
|
insert_vararray_string( a, v, 0, VARARRAY_INDEX_FROM_START )
|
|
#define unshift_vararray_char( a, v ) \
|
|
insert_vararray_char( a, v, 0, VARARRAY_INDEX_FROM_START )
|
|
#define unshift_vararray_uchar( a, v ) \
|
|
insert_vararray_uchar( a, v, 0, VARARRAY_INDEX_FROM_START )
|
|
#define unshift_vararray_short( a, v ) \
|
|
insert_vararray_short( a, v, 0, VARARRAY_INDEX_FROM_START )
|
|
#define unshift_vararray_ushort( a, v ) \
|
|
insert_vararray_ushort( a, v, 0, VARARRAY_INDEX_FROM_START )
|
|
#define unshift_vararray_int( a, v ) \
|
|
insert_vararray_int( a, v, 0, VARARRAY_INDEX_FROM_START )
|
|
#define unshift_vararray_uint( a, v ) \
|
|
insert_vararray_uint( a, v, 0, VARARRAY_INDEX_FROM_START )
|
|
#define unshift_vararray_long( a, v ) \
|
|
insert_vararray_long( a, v, 0, VARARRAY_INDEX_FROM_START )
|
|
#define unshift_vararray_ulong( a, v ) \
|
|
insert_vararray_ulong( a, v, 0, VARARRAY_INDEX_FROM_START )
|
|
#define unshift_vararray_llong( a, v ) \
|
|
insert_vararray_llong( a, v, 0, VARARRAY_INDEX_FROM_START )
|
|
#define unshift_vararray_ullong( a, v ) \
|
|
insert_vararray_ullong( a, v, 0, VARARRAY_INDEX_FROM_START )
|
|
#define unshift_vararray_float( a, v ) \
|
|
insert_vararray_float( a, v, 0, VARARRAY_INDEX_FROM_START )
|
|
#define unshift_vararray_double( a, v ) \
|
|
insert_vararray_double( a, v, 0, VARARRAY_INDEX_FROM_START )
|
|
|
|
/* Now for shift and pop.
|
|
*
|
|
* I *could* implement this with a get and delete, but that would be like
|
|
* plucking a sheet of paper of a pile, photocopying it, then throwing away the
|
|
* original. Far better to just return the pointer internally, it's up to the
|
|
* caller to look after it now.
|
|
*/
|
|
inline void* pop_vararray_ptr( struct vararray* array );
|
|
inline char* pop_vararray_string( struct vararray* array );
|
|
inline char pop_vararray_char( struct vararray* array );
|
|
inline unsigned char pop_vararray_uchar( struct vararray* array );
|
|
inline short pop_vararray_short( struct vararray* array );
|
|
inline unsigned short pop_vararray_ushort( struct vararray* array );
|
|
inline int pop_vararray_int( struct vararray* array );
|
|
inline unsigned int pop_vararray_uint( struct vararray* array );
|
|
inline long pop_vararray_long( struct vararray* array );
|
|
inline unsigned long pop_vararray_ulong( struct vararray* array );
|
|
inline long long pop_vararray_llong( struct vararray* array );
|
|
inline unsigned long long pop_vararray_ullong( struct vararray* array );
|
|
inline float pop_vararray_float( struct vararray* array );
|
|
inline double pop_vararray_double( struct vararray* array );
|
|
|
|
inline void* shift_vararray_ptr( struct vararray* array );
|
|
inline char* shift_vararray_string( struct vararray* array );
|
|
inline char shift_vararray_char( struct vararray* array );
|
|
inline unsigned char shift_vararray_uchar( struct vararray* array );
|
|
inline short shift_vararray_short( struct vararray* array );
|
|
inline unsigned short shift_vararray_ushort( struct vararray* array );
|
|
inline int shift_vararray_int( struct vararray* array );
|
|
inline unsigned int shift_vararray_uint( struct vararray* array );
|
|
inline long shift_vararray_long( struct vararray* array );
|
|
inline unsigned long shift_vararray_ulong( struct vararray* array );
|
|
inline long long shift_vararray_llong( struct vararray* array );
|
|
inline unsigned long long shift_vararray_ullong(struct vararray* array );
|
|
inline float shift_vararray_float( struct vararray* array );
|
|
inline double shift_vararray_double( struct vararray* array );
|
|
|
|
/*
|
|
* Imported and Exported values.
|
|
*
|
|
* For convenience when indexing the array, it can be imported and exported
|
|
* to a plain C array. It's wrapped in a struct that specifies the size of
|
|
* each element (for object arrays) and the length of the array.
|
|
*/
|
|
|
|
/* The first type is for object arrays */
|
|
struct static_obj_array {
|
|
size_t length;
|
|
size_t obj_size;
|
|
void* (*copy_func)(void* orig, size_t size);
|
|
void (*destroy_func)(void* orig);
|
|
void** object;
|
|
};
|
|
|
|
/* The following macro allows creation of structs that will neatly cast
|
|
* against the above struct. The purpose of this is to allow strong typing
|
|
* when used elsewhere in an application.
|
|
*
|
|
* Example usage:
|
|
* CREATE_STATIC_ARRAY_STRUCT( foo_array, foo*, foo_obj );
|
|
* would create
|
|
* struct foo_array {
|
|
* size_t length;
|
|
* size_t obj_size;
|
|
* void* (*copy_func)(void* orig, size_t size);
|
|
* void (*destroy_func)(void* orig);
|
|
* foo* foo_obj;
|
|
* };
|
|
*/
|
|
#define CREATE_STATIC_ARRAY_STRUCT( struct_name, pointer_type, content_name ) \
|
|
struct struct_name { \
|
|
size_t length; \
|
|
size_t obj_size; \
|
|
void* (*copy_func)(void* orig, size_t size); \
|
|
void (*destroy_func)(void* orig); \
|
|
pointer_type* content_name ; \
|
|
}
|
|
|
|
/* The following defines a struct for housing strings */
|
|
CREATE_STATIC_ARRAY_STRUCT( static_string_array, char*, string );
|
|
|
|
/* The following are for all the simple types in use. Note that the
|
|
* size parameter is omitted. They all match the generic type array
|
|
* (static_simple_array), which is used when duplicating the arrays.
|
|
*/
|
|
struct static_simple_array { size_t length; void* value; };
|
|
struct static_char_array { size_t length; char* value; };
|
|
struct static_uchar_array { size_t length; unsigned char* value; };
|
|
struct static_short_array { size_t length; short* value; };
|
|
struct static_ushort_array { size_t length; unsigned short* value; };
|
|
struct static_int_array { size_t length; int* value; };
|
|
struct static_uint_array { size_t length; unsigned int* value; };
|
|
struct static_long_array { size_t length; long* value; };
|
|
struct static_ulong_array { size_t length; unsigned long* value; };
|
|
struct static_llong_array { size_t length; long long* value; };
|
|
struct static_ullong_array { size_t length; unsigned long long* value; };
|
|
struct static_float_array { size_t length; float* value; };
|
|
struct static_double_array { size_t length; double* value; };
|
|
|
|
/* Import functions. The following take plain C arrays or one of the above
|
|
* struct types, and import them into a linked list for manipulation.
|
|
*
|
|
* They return the vararray created, or NULL on failure.
|
|
*/
|
|
struct vararray* import_obj_array( struct static_obj_array* sa );
|
|
struct vararray* import_string_array( struct static_string_array* sa );
|
|
struct vararray* import_char_array( struct static_char_array* sa );
|
|
struct vararray* import_uchar_array( struct static_uchar_array* sa );
|
|
struct vararray* import_short_array( struct static_short_array* sa );
|
|
struct vararray* import_ushort_array( struct static_ushort_array* sa );
|
|
struct vararray* import_int_array( struct static_int_array* sa );
|
|
struct vararray* import_uint_array( struct static_uint_array* sa );
|
|
struct vararray* import_long_array( struct static_long_array* sa );
|
|
struct vararray* import_ulong_array( struct static_ulong_array* sa );
|
|
struct vararray* import_llong_array( struct static_llong_array* sa );
|
|
struct vararray* import_ullong_array( struct static_ullong_array* sa );
|
|
struct vararray* import_float_array( struct static_float_array* sa );
|
|
struct vararray* import_double_array( struct static_double_array* sa );
|
|
|
|
/* Export functions. These take a variable array and output a plain static
|
|
* C array of the specified type, or NULL if this can't be achieved.
|
|
*/
|
|
struct static_obj_array* export_obj_array( struct vararray* va );
|
|
struct static_string_array* export_string_array( struct vararray* va);
|
|
struct static_char_array* export_char_array( struct vararray* va );
|
|
struct static_uchar_array* export_uchar_array( struct vararray* va );
|
|
struct static_short_array* export_short_array( struct vararray* va );
|
|
struct static_ushort_array* export_ushort_array( struct vararray* va);
|
|
struct static_int_array* export_int_array( struct vararray* va );
|
|
struct static_uint_array* export_uint_array( struct vararray* va );
|
|
struct static_long_array* export_long_array( struct vararray* va );
|
|
struct static_ulong_array* export_ulong_array( struct vararray* va );
|
|
struct static_llong_array* export_llong_array( struct vararray* va );
|
|
struct static_ullong_array* export_ullong_array( struct vararray* va);
|
|
struct static_float_array* export_float_array( struct vararray* va );
|
|
struct static_double_array* export_double_array( struct vararray* va);
|
|
|
|
/* Free a static array. The following can be used to free any
|
|
* statically-allocated array. Macros are provided to free the above static
|
|
* array types.
|
|
*
|
|
* container is the pointer to the struct containing the array -- it may be
|
|
* NULL.
|
|
* elements is a pointer to the array of elements to be freed.
|
|
*
|
|
* If free_content is specified, then elements is cast to void**, and each
|
|
* pointer in the array elements, is freed as well.
|
|
*/
|
|
void destroy_array( struct static_obj_array* container, size_t length,
|
|
void* elements, int free_content );
|
|
|
|
/* Free an object array. ptr_member should be set to the structure member (e.g.
|
|
* object, in the case of static_obj_array)
|
|
*/
|
|
#define destroy_obj_array( array, ptr_member ) \
|
|
destroy_array( array, array->length, array->ptr_member, 1 )
|
|
|
|
/* Free an array of strings. */
|
|
#define destroy_string_array( array ) \
|
|
destroy_obj_array( array, string )
|
|
|
|
/* Free simple array types */
|
|
#define destroy_simple_array( array ) \
|
|
destroy_array( array, array->length, array->value, 0 )
|
|
|
|
/* Duplicate a static array. The following will make a deep copy of any
|
|
* statically-allocated array in one of the above structs.
|
|
*
|
|
* For convenience, a macro is provided that casts your array to the
|
|
* right type for use. You should use this, rather than calling the
|
|
* function directly. The macro assumes at least one element is present
|
|
* in the array.
|
|
*
|
|
* Returns the copy on success, NULL on failure.
|
|
*/
|
|
struct static_simple_array* duplicate_simple_array_impl(
|
|
struct static_simple_array* src, size_t data_size );
|
|
#define duplicate_static_array( array, type ) \
|
|
(type*)duplicate_simple_array_impl( \
|
|
(struct static_simple_array*)array, \
|
|
sizeof( array->value[0] ) )
|
|
|
|
struct static_obj_array* duplicate_obj_array_impl(
|
|
struct static_obj_array* src );
|
|
#define duplicate_static_obj_array( array, type ) \
|
|
(type*)duplicate_obj_array_impl( (struct static_obj_array*)array )
|
|
#endif
|