Skip to content

Instantly share code, notes, and snippets.

@vgrichina
Forked from tj/array.c
Created July 24, 2010 21:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vgrichina/488987 to your computer and use it in GitHub Desktop.
Save vgrichina/488987 to your computer and use it in GitHub Desktop.
//
// array.h - CKit
//
// (c) 2009 TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
//
#ifndef __CKIT_ARRAY__
#define __CKIT_ARRAY__
#include "ckit.h"
#define CKIT_ARRAY(N, T) \
\
typedef struct { \
int len, max; \
T *vals; \
} N; \
\
/* \
* Allocate new N. \
* \
* @api public \
*/ \
\
N * \
N##_new() { \
N *self = (N *) CKIT_MALLOC(sizeof(N)); \
self->len = 0, self->max = 0; \
self->vals = NULL; \
return self; \
} \
\
/* \
* Push _val_ onto _self_. \
* \
* @api public \
*/ \
\
N * \
N##_push(N *self, T val) { \
if (self->len == self->max) \
self->max = self->max ? self->max << 1 : 2, \
self->vals = (T *) CKIT_REALLOC(self->vals, self->max * sizeof(T)); \
self->vals[self->len++] = val; \
return self; \
} \
\
/* \
* Slice _self_ at _beg_ to _len_. \
* \
* Array_slice(array, 0, 3); \
* Array_slice(array, 5, 10); \
* Array_slice(array, 1, -1); \
* Array_slice(array, -5, -1); \
* \
* @api public \
*/ \
\
N * \
N##_slice(N *self, int beg, int len) { \
N *slice = N##_new(); \
if (beg < 0) beg = self->len + 1 -(-beg+1); \
if (len < 0) len = self->len + 2 -(-len+1); \
if (beg < 0) beg = 0; \
if (len < 0) len = 1; \
if (self->len && len != 0) \
for (; len > 0 && beg < self->len; --len, ++beg) \
if (self->vals[beg]) \
N##_push(slice, self->vals[beg]); \
return slice; \
} \
\
/* \
* Return elements after _i_. \
* \
* @api public \
*/ \
\
N * \
N##_from(N *self, int i) { \
return N##_slice(self, i, -1); \
} \
\
/* \
* Return elements upto _i_. \
* \
* @api public \
*/ \
\
N * \
N##_to(N *self, int i) { \
return N##_slice(self, 0, ++i); \
} \
\
/* \
* Return last _n_ elements. \
* \
* @api public \
*/ \
\
N * \
N##_last_n(N *self, int n) { \
return N##_slice(self, -n, n); \
} \
\
/* \
* Select from _self_ with _callback_. Returns \
* a new array of values which evaluate to 1. \
* \
* @api public \
*/ \
\
N * \
N##_select(N *self, int (* callback)()) { \
N *selected = N##_new(); \
for (int i = 0; i < self->len; ++i) \
if (callback(i, self->vals[i])) \
N##_push(selected, self->vals[i]); \
return selected; \
} \
\
/* \
* Map _self_ with _callback_. Returns a new array \
* of mapped values. \
* \
* @api public \
*/ \
\
N * \
N##_map(N *self, void *(* callback)()) { \
N *map = N##_new(); \
for (int i = 0; i < self->len; ++i) \
N##_push(map, callback(i, self->vals[i])); \
return map; \
} \
\
/* \
* Find an element in _self_ using _callback_. When _callback_ \
* evaluates to 1, the value will be returned, otherwise NULL. \
* \
* @api public \
*/ \
\
T \
N##_find(N *self, int (* callback)()) { \
for (int i = 0; i < self->len; ++i) \
if (callback(i, self->vals[i])) \
return self->vals[i]; \
return NULL; \
} \
\
/* \
* Check if an element in _self_ will evaluate to 1 \
* when passed to _callback_. \
* \
* @api public \
* @see Array_find() \
*/ \
\
int \
N##_any(N *self, int (* callback)()) { \
return !! N##_find(self, callback); \
} \
\
/* \
* Return the last element in _self_. \
*/ \
\
T \
N##_last(N *self) { \
return self->vals[self->len - 1]; \
} \
\
/* \
* Pop an element off the end of _self_'s stack. \
*/ \
\
T \
N##_pop(N *self) { \
return self->len ? \
self->vals[--self->len] : \
NULL; \
} \
\
/* \
* Merge _self_ with _other_ array. \
*/ \
\
N * \
N##_merge(N *self, N *other) { \
for (int i = 0; i < other->len; ++i) \
N##_push(self, other->vals[i]); \
return self; \
} \
\
/* \
* Unshift _val_ onto _self_'s stack, prepending it. \
*/ \
\
N * \
N##_unshift(N *self, T val) { \
*self = *N##_merge(N##_push(N##_new(), val), self); \
return self; \
} \
\
/* \
* Delete element at index _i_ from _self_. \
*/ \
\
T \
N##_delete_at(N *self, int i) { \
if (i < self->len && i > -1) { \
--self->len; \
T val = self->vals[i]; \
for (; i <= self->len; ++i) \
self->vals[i] = i == self->len ? NULL : self->vals[i+1]; \
return val; \
} \
return NULL; \
} \
\
/* \
* Remove duplicate values from _self_. \
*/ \
\
N * \
N##_unique(N *self) { \
for (int i = 0; i < self->len; ++i) \
for (int j = 0; j < self->len; ++j) \
if (self->vals[i] == self->vals[j] && i != j) \
N##_delete_at(self, i); \
return self; \
} \
\
/* \
* Sort _self_ with comparison _callback_. \
* \
* static int \
* compare_string(void *p1, void *p2) { \
* return strcmp(* (char * const *) p1, * (char * const *) p2); \
* } \
* \
* Array_sort(array, compare_string); \
* \
* @api public \
*/ \
\
N * \
N##_sort(N *self, int (* callback)(void *, void *)) { \
qsort(self->vals, self->len - 1, sizeof(T), callback); \
return self; \
} \
\
/* \
* Create a union of _self_ and _other_ array. Merging \
* and removing duplicates. \
*/ \
\
N * \
N##_union(N *self, N *other) { \
return N##_unique(N##_merge(self, other)); \
} \
\
/* \
* Shift an element off the beginning of _self_'s stack. \
*/ \
\
T \
N##_shift(N *self) { \
return N##_delete_at(self, 0); \
} \
\
/* \
* Destroy _self_. \
*/ \
\
void \
N##_destroy(N *self) { \
if (self->vals) free(self->vals); \
if (self) free(self); \
}
#endif
@Adrienne2612
Copy link

H@ckIT!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment