gallery/include/varray.h

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