#include #include #include "common.h" #include "function.h" #include "collection.h" #include "array.h" static void array_allocate(Array *self, uint capacity); static void array_grow(Array *self); static void array_grow_by_factor(Array *self, uint factor); enum { ARRAY_DEFAULT_SIZE = COLLECTION_DEFAULT_SIZE, ARRAY_GROWTH_FACTOR = 2 }; static void array_init_size(Array *self, uint size) { assert_valid(self); memset(self, 0, sizeof(*self)); array_allocate(self, size); } static void array_init(Array *self) { assert_valid(self); array_init_size(self, ARRAY_DEFAULT_SIZE); } Array *array_new(void) { Array *result = (Array *)emalloc_fs(sizeof(*result)); array_init(result); return result; } Array *array_new_size(uint size) { Array *result = (Array *)emalloc_fs(sizeof(*result)); array_init_size(result, size); return result; } static void array_destroy(Array *self) { assert_valid(self); free(self->elements); self->elements = nil; self->total = 0; self->capacity = 0; } void array_free(Array *self) { if(self == nil) { return; } array_destroy(self); free(self); } void array_free_with(Array *self, functionunary free_each) { array_unary_do(self, free_each); array_free(self); } static void array_allocate(Array *self, uint capacity) { assert_valid(self); self->capacity = capacity; self->elements = erealloc_fs(self->elements, sizeof(self->elements[0]) * self->capacity); } void array_clear(Array *self) { assert_valid(self); self->total = 0; } void array_clear_with(Array *self, functionunary clear) { assert_valid(self); assert_valid(clear); array_unary_do(self, clear); array_clear(self); } void *array_at(Array *self, uint index) { assert_valid(self); assert_valid(self->elements); assert(index < array_size(self)); return self->elements[index]; } void array_put(Array *self, uint index, void *p) { assert_valid(self); assert(index < array_size(self)); self->elements[index] = p; } static bool array_isfull(Array *self) { assert_valid(self); return self->total == self->capacity; } static void array_grow_if_full(Array *self) { if(array_isfull(self)) { array_grow(self); } } void array_add(Array *self, void *p) { assert_valid(self); assert_valid(self->elements); array_grow_if_full(self); assert(array_size(self) < self->capacity); self->elements[self->total] = p; ++(self->total); } uint array_size(Array *self) { assert_valid(self); return self->total; } void *array_default_nil_value(void) { return nil; } void array_resize(Array *self, uint size) { array_resize_with(self, size, array_default_nil_value); } void array_resize_with(Array *self, uint size, generator default_value) { assert_valid(self); assert_valid(default_value); while(array_size(self) < size) { array_add(self, default_value()); } self->total = size; } static void array_grow(Array *self) { assert_valid(self); array_grow_by_factor(self, ARRAY_GROWTH_FACTOR); } static void array_grow_by_factor(Array *self, uint factor) { assert_valid(self); array_allocate(self, self->capacity * factor); } void array_do(Array *self, collectioneach each, void *arg) { int i; assert_valid(self); assert_valid(each); assert_valid(self->elements); for(i = 0; i < array_size(self); ++i) { if(each(self->elements[i], arg) == COLLECTION_DO_STOP) { break; } } } void array_unary_do(Array *self, functionunary each) { int i; assert_valid(self); assert_valid(each); for(i = 0; i < array_size(self); ++i) { each(self->elements[i]); } } typedef struct ArrayDetectData { collectiondetect detect; bool found; void *result; void *arg; } ArrayDetectData; static collection_do_ret array_detect_each(void *p, void *arg) { ArrayDetectData *data = (ArrayDetectData *)arg; assert_valid(data); if(data->detect(p, data->arg)) { data->found = true; data->result = p; return COLLECTION_DO_STOP; } return COLLECTION_DO_CONTINUE; } bool array_detect(Array *self, collectiondetect detect, void **result, void *arg) { ArrayDetectData data = (ArrayDetectData){detect, false, nil, arg}; assert_valid(self); assert_valid(detect); array_do(self, array_detect_each, &data); if(result != nil) { *result = data.result; } return data.found; } void array_push(Array *self, void *p) { array_add(self, p); } void *array_last(Array *self) { assert_valid(self); assert(array_notempty(self)); return array_at(self, array_size(self) - 1); } void *array_pop(Array *self) { void *result = array_last(self); --(self->total); return result; } bool array_isempty(Array *self) { assert_valid(self); return self->total == 0; } bool array_notempty(Array *self) { return !array_isempty(self); }