Last active
August 29, 2015 13:56
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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