#include <u.h>
#include <libc.h>
#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);
}
|