Skip to content

Instantly share code, notes, and snippets.

@nulldatamap
Last active August 29, 2015 13:56
Show Gist options
  • Save nulldatamap/9309140 to your computer and use it in GitHub Desktop.
Save nulldatamap/9309140 to your computer and use it in GitHub Desktop.
A single file that let's you easily define generic lists in C.
#ifndef __H_GLIST__
#define __H_GLIST__
#include "error.h"
// Generic List
typedef struct
{
int length;
int capasity;
void* elements;
} GenericList;
// ==================
// Method definitions
// ==================
// The list error definitions
#define GLIST_ERR const Error ERR_LIST_INDEX_OUT_OF_RANGE = { 0x1020 , \
"The given list index is out of range." }; const Error ERR_LIST_POP_FROM_EMPTY\
= { 0x1021 , "Can't pop an element from an empty list." }; const Error \
ERR_LIST_ALLOCATION_FAIL = { 0x1022 , "Failed to allocate memory for list." };
// The body of the struct
#define GLIST_BODY(T) typedef struct{ int length; int capasity; T* elements; }\
T ## List;
// The initializer
#define GLIST_NEW(T,N) T ## List new_ ## N ()
#define GLIST_NEW_IMPL(T,N) GLIST_NEW(T,N) { return ( T ## List ) { 0 , 10 , \
( T* ) malloc( 10 * sizeof( T ) ) }; }
// The array based list initializer
#define GLIST_NEWFROM(T,N) T ## List newfrom_ ## N ( int length , \
const T* array )
#define GLIST_NEWFROM_IMPL(T,N) GLIST_NEWFROM(T,N) { T ## List self = ( T ## \
List ){ length , length , ( T* ) malloc( length * sizeof( T ) ) }; for( int i =\
0; i < length; i++ ) self.elements[i] = array[i]; return self; }
// The length getter method
#define GLIST_LENGTH(T,N) int length_ ## N ( T ## List* self )
#define GLIST_LENGTH_IMPL(T,N) GLIST_LENGTH(T,N) { return self->length; }
// The capasity getter method
#define GLIST_CAPASITY(T,N) int capasity_ ## N ( T ## List* self )
#define GLIST_CAPASITY_IMPL(T,N) GLIST_CAPASITY(T,N) { return self->capasity; }
// The array getter method
#define GLIST_ARRAY(T,N) T* array_ ## N ( T ## List* self )
#define GLIST_ARRAY_IMPL(T,N) GLIST_ARRAY(T,N) { return self->elements; }
// The element access method
#define GLIST_AT(T,N) T at_ ## N ( T ## List* self , int index )
#define GLIST_AT_IMPL(T,N) GLIST_AT(T,N) { if( index < 0 )\
index += self->length; if( index < 0 || index >= self->length )\
throw( ERR_LIST_INDEX_OUT_OF_RANGE ); return self->elements[index]; }
// The element assignment method
#define GLIST_SETAT(T,N) void setat_ ## N ( T ## List* self , T element , \
int index )
#define GLIST_SETAT_IMPL(T,N) GLIST_SETAT(T,N) { if( index < 0 )\
index += self->length; if( index < 0 || index >= self->length )\
throw( ERR_LIST_INDEX_OUT_OF_RANGE ); self->elements[index] = element; }
// The element push method
#define GLIST_PUSH(T,N) int push_ ## N ( T ## List* self , T element )
#define GLIST_PUSH_IMPL(T,N) GLIST_PUSH(T,N) { self->elements[self->length++]\
= element; if( self->length == self->capasity ) resize_ ## N ( self ); return \
self->length; }
// The element pop method
#define GLIST_POP(T,N) T pop_ ## N ( T ## List* self )
#define GLIST_POP_IMPL(T,N) GLIST_POP(T,N) { if( self->length == 0 ) \
throw( ERR_LIST_POP_FROM_EMPTY ); T element = self->elements[--self->length];\
if( self->length == 0 ) resize_ ## N ( self ); return element; }
// The list comparation method
#define GLIST_COMPARE(T,N) int compare_ ## N( T ## List* self, T ## List other )
#define GLIST_COMPARE_IMPL(T,N) GLIST_COMPARE(T,N) {\
if( self->length != other.length ) return 0;\
for( int i = 0; i < other.length; i++ )\
if( self->elements[i] != other.elements[i] ) return 0; return 1; }
// The list resizing method
#define GLIST_RESIZE(T,N) void resize_ ## N ( T ## List* self )
#define GLIST_RESIZE_IMPL(T,N) GLIST_RESIZE(T,N) {T * newaddr = self->elements;\
int newcap = self->capasity; if( self->length == 0 && self->capasity > 10 ) {\
newcap = 10; }else if( self->length == self->capasity ) { newcap = self->length\
+ ( self->length >> 1 ); if( newcap <= 0 ) throw( ERR_LIST_ALLOCATION_FAIL );\
}else if( self->length > self->capasity ){ newcap = self->length; }else return;\
newaddr = realloc( self->elements , newcap * sizeof( T ) );\
if( newaddr == 0 ) throw( ERR_LIST_ALLOCATION_FAIL ); else { self->capasity\
= newcap; self->elements = newaddr; } }
// The element removal method
#define GLIST_REMOVE(T,N) T remove_ ## N ( T ## List* self , int index )
#define GLIST_REMOVE_IMPL(T,N) GLIST_REMOVE(T,N) { T removed; if( index < 0 )\
index += self->length; if( index < 0 || index >= self->length )\
throw( ERR_LIST_INDEX_OUT_OF_RANGE ); removed = self->elements[index];\
for( int i = 0; i < ( self->length - 1 ) - index; i++ )\
self->elements[index+i] = self->elements[index+i+1]; self->length--;\
if( self->length == 0 ) resize_ ## N ( self ); return removed; }
// The list element insertion
#define GLIST_INSERT(T,N) void insert_ ## N ( T ## List* self , T element , \
int index )
#define GLIST_INSERT_IMPL(T,N) GLIST_INSERT(T,N) { if( index < 0 ) index += \
self->length; if( index < 0 || index >= self->length ) \
throw( ERR_LIST_INDEX_OUT_OF_RANGE ); int moved = self->length - index;\
for( int i = 0; i < moved; i++ ) self->elements[index + ( moved - i)] = \
self->elements[index + ( moved - i - 1 )]; self->elements[index] = element; \
self->length++; if( self->length == self->capasity )resize_ ## N ( self );}
// The raw list appendtion method
#define GLIST_APPEND(T,N) void append_ ## N ( T ## List* self , int length , \
const T * array )
#define GLIST_APPEND_IMPL(T,N) GLIST_APPEND(T,N) { int len = self->length; \
self->length += length; if( self->length >= self->capasity ) resize_ ## N \
( self ); for( int i = 0; i < length; i++ ) self->elements[len+i] = array[i]; }
// The list combination method
#define GLIST_COMBINE(T,N) void combine_ ## N ( T ## List* self , T ## List \
other )
#define GLIST_COMBINE_IMPL(T,N) GLIST_COMBINE(T,N){ append_ ## N ( self , \
other.length , other.elements ); }
// The list copy method
#define GLIST_COPY(T,N) T ## List copy_ ## N ( T ## List* self )
#define GLIST_COPY_IMPL(T,N) GLIST_COPY(T,N){ return newfrom_ ## N ( \
self->length , self->elements ); }
// The sublist method
#define GLIST_
// The destructor method
#define GLIST_DEL(T,N) void del_ ## N ( T ## List* self)
#define GLIST_DEL_IMPL(T,N) GLIST_DEL(T,N) { self->length = 0;\
self->capasity = 0; free( self->elements ); self->elements = 0; }
// ===============================
// Generic list header constructor
// ===============================
#define GenericListHeader(T,N) GLIST_ERR \
GLIST_BODY(T) \
GLIST_NEW(T,N);\
GLIST_NEWFROM(T,N);\
GLIST_LENGTH(T,N);\
GLIST_CAPASITY(T,N);\
GLIST_AT(T,N);\
GLIST_SETAT(T,N);\
GLIST_PUSH(T,N);\
GLIST_POP(T,N);\
GLIST_COMPARE(T,N);\
GLIST_RESIZE(T,N);\
GLIST_REMOVE(T,N);\
GLIST_INSERT(T,N);\
GLIST_APPEND(T,N);\
GLIST_COMBINE(T,N);\
GLIST_COPY(T,N);\
GLIST_DEL(T,N);
// =======================================
// Generic list implementation constructor
// =======================================
#define GenericList(T,N) GLIST_NEW_IMPL(T,N);\
GLIST_NEWFROM_IMPL(T,N);\
GLIST_LENGTH_IMPL(T,N);\
GLIST_CAPASITY_IMPL(T,N);\
GLIST_AT_IMPL(T,N);\
GLIST_SETAT_IMPL(T,N);\
GLIST_PUSH_IMPL(T,N);\
GLIST_POP_IMPL(T,N);\
GLIST_COMPARE_IMPL(T,N);\
GLIST_RESIZE_IMPL(T,N);\
GLIST_REMOVE_IMPL(T,N);\
GLIST_INSERT_IMPL(T,N);\
GLIST_APPEND_IMPL(T,N);\
GLIST_COMBINE_IMPL(T,N);\
GLIST_COPY_IMPL(T,N);\
GLIST_DEL_IMPL(T,N);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment