#include #include #include #include #include #include /*** PRIVATE DATA *************************************************************/ struct fx_array_p { /* number of items in array */ size_t ar_len; /* maximum number of items that can currently be stored in array */ size_t ar_cap; fx_object **ar_data; }; struct fx_array_iterator_p { fx_array *_a; struct fx_array_p *_a_p; /** The index of the current value */ size_t i; /** The current value */ fx_object *value; }; /*** PRIVATE FUNCTIONS ********************************************************/ static fx_status resize_array(struct fx_array_p *array, size_t new_capacity) { if (array->ar_cap < new_capacity) { void *new_data = realloc( array->ar_data, new_capacity * sizeof(struct fx_dsref *)); if (!new_data) { return FX_ERR_NO_MEMORY; } array->ar_data = new_data; } else { for (size_t i = new_capacity; i < array->ar_len; i++) { fx_object_unref(array->ar_data[i]); } void *new_data = realloc( array->ar_data, new_capacity * sizeof(struct fx_dsref *)); if (!new_data) { return FX_ERR_NO_MEMORY; } array->ar_data = new_data; } array->ar_cap = new_capacity; if (array->ar_len > new_capacity) { array->ar_len = new_capacity; } return FX_SUCCESS; } static fx_status array_insert(struct fx_array_p *array, fx_object *value, size_t at) { if (at == FX_NPOS) { at = array->ar_len; } if (at > array->ar_len) { return FX_ERR_OUT_OF_BOUNDS; } fx_status status = FX_SUCCESS; if (array->ar_len + 1 > array->ar_cap) { status = resize_array(array, array->ar_cap + 8); if (status != FX_SUCCESS) { return status; } } fx_object **src = array->ar_data + at; fx_object **dest = src + 1; size_t move_len = (array->ar_len - at) * sizeof(struct fx_dsref *); memmove(dest, src, move_len); array->ar_data[at] = fx_object_ref(value); array->ar_len++; return FX_SUCCESS; } static fx_status array_remove(struct fx_array_p *array, size_t at) { if (at >= array->ar_len) { return FX_ERR_OUT_OF_BOUNDS; } fx_object **src = array->ar_data + at; fx_object **dest = src + 1; size_t move_len = array->ar_len * sizeof(struct fx_dsref *); fx_object_unref(array->ar_data[at]); memmove(dest, src, move_len); array->ar_len--; return FX_SUCCESS; } static fx_status array_remove_front(struct fx_array_p *array) { return array_remove(array, 0); } static fx_status array_remove_back(struct fx_array_p *array) { return array_remove(array, array->ar_len - 1); } static fx_object *array_pop(struct fx_array_p *array, size_t at) { if (at >= array->ar_len) { return NULL; } fx_object **src = array->ar_data + at; fx_object **dest = src + 1; size_t move_len = array->ar_len * sizeof(struct fx_dsref *); fx_object *out = array->ar_data[at]; memmove(dest, src, move_len); array->ar_len--; return out; } static fx_object *array_pop_front(struct fx_array_p *array) { return array_pop(array, 0); } static fx_object *array_pop_back(struct fx_array_p *array) { return array_pop(array, array->ar_len - 1); } static fx_object *array_at(const struct fx_array_p *array, size_t at) { if (at >= array->ar_len) { return NULL; } return array->ar_data[at]; } static fx_object *array_get(struct fx_array_p *array, size_t at) { if (at >= array->ar_len) { return NULL; } return fx_object_ref(array->ar_data[at]); } static size_t array_size(const struct fx_array_p *array) { return array->ar_len; } static size_t array_capacity(const struct fx_array_p *array) { return array->ar_cap; } static void array_clear(struct fx_array_p *array) { if (!array->ar_len) { return; } for (size_t i = 0; i < array->ar_len; i++) { fx_object_unref(array->ar_data[i]); } memset(array->ar_data, 0x0, array->ar_cap * sizeof(fx_object *)); array->ar_len = 0; } /*** PUBLIC FUNCTIONS *********************************************************/ fx_array *fx_array_create_with_values(fx_object *const *values, size_t nr_values) { fx_array *array = fx_array_create(); if (!array) { return NULL; } struct fx_array_p *p = fx_object_get_private(array, FX_TYPE_ARRAY); size_t real_nr_values = 0; for (size_t i = 0; i < nr_values; i++) { if (values[i]) { real_nr_values++; } } p->ar_len = real_nr_values; p->ar_cap = real_nr_values; p->ar_data = calloc(real_nr_values, sizeof(struct fx_dsref *)); if (!p->ar_data) { fx_array_unref(array); return NULL; } size_t index = 0; for (size_t i = 0; i < nr_values; i++) { p->ar_data[index++] = fx_object_ref(values[i]); } return array; } fx_status fx_array_insert(fx_array *array, fx_object *value, size_t at) { FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_insert, array, value, at); } fx_status fx_array_remove(fx_array *array, size_t at) { FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_remove, array, at); } fx_status fx_array_remove_front(fx_array *array) { FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_remove_front, array); } fx_status fx_array_remove_back(fx_array *array) { FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_remove_back, array); } fx_object *fx_array_pop(fx_array *array, size_t at) { FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_pop, array, at); } fx_object *fx_array_pop_front(fx_array *array) { FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_pop_front, array); } fx_object *fx_array_pop_back(fx_array *array) { FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_pop_back, array); } fx_object *fx_array_at(const fx_array *array, size_t at) { FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_at, array, at); } fx_object *fx_array_get(fx_array *array, size_t at) { FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_get, array, at); } size_t fx_array_size(const fx_array *array) { FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_size, array); } size_t fx_array_capacity(const fx_array *array) { FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_capacity, array); } void fx_array_clear(fx_array *array) { FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_clear, array); } /*** PUBLIC ALIAS FUNCTIONS ***************************************************/ fx_status fx_array_append(fx_array *array, fx_object *value) { return fx_array_insert(array, value, FX_NPOS); } fx_status fx_array_prepend(fx_array *array, fx_object *value) { return fx_array_insert(array, value, 0); } /*** VIRTUAL FUNCTIONS ********************************************************/ static void array_init(fx_object *obj, void *priv) { struct fx_array_p *array = priv; } static void array_fini(fx_object *obj, void *priv) { struct fx_array_p *array = priv; if (array->ar_data) { for (size_t i = 0; i < array->ar_len; i++) { fx_object_unref(array->ar_data[i]); } free(array->ar_data); array->ar_data = NULL; } } static void array_to_string(const fx_object *obj, fx_stream *out) { struct fx_array_p *array = fx_object_get_private(obj, FX_TYPE_ARRAY); if (!array->ar_len) { fx_stream_write_string(out, "[]", NULL); return; } fx_stream_write_string(out, "[\n", NULL); fx_stream_push_indent(out, 1); size_t len = array_size(array); for (size_t i = 0; i < array->ar_len; i++) { fx_object *value = array->ar_data[i]; bool is_string = fx_object_is_type(value, FX_TYPE_STRING); if (is_string) { fx_stream_write_char(out, '"'); } fx_object_to_string(value, out); if (is_string) { fx_stream_write_char(out, '"'); } if (i < len - 1) { fx_stream_write_string(out, ",", NULL); } fx_stream_write_char(out, '\n'); } fx_stream_pop_indent(out); fx_stream_write_char(out, ']'); } /*** ITERATOR FUNCTIONS *******************************************************/ static fx_iterator *iterable_begin(fx_object *obj) { fx_array_iterator *it_obj = fx_object_create(FX_TYPE_ARRAY_ITERATOR); struct fx_array_iterator_p *it = fx_object_get_private(it_obj, FX_TYPE_ARRAY_ITERATOR); it->_a = obj; it->_a_p = fx_object_get_private(obj, FX_TYPE_ARRAY); it->i = 0; if (it->_a_p->ar_len > 0) { it->value = it->_a_p->ar_data[0]; } else { fx_iterator_set_status(it_obj, FX_ERR_NO_DATA); it->value = NULL; } return it_obj; } static const fx_iterator *iterable_cbegin(const fx_object *obj) { fx_array_iterator *it_obj = fx_object_create(FX_TYPE_ARRAY_ITERATOR); struct fx_array_iterator_p *it = fx_object_get_private(it_obj, FX_TYPE_ARRAY_ITERATOR); it->_a = (fx_array *)obj; it->_a_p = fx_object_get_private(obj, FX_TYPE_ARRAY); it->i = 0; if (it->_a_p->ar_len > 0) { it->value = it->_a_p->ar_data[0]; } else { fx_iterator_set_status(it_obj, FX_ERR_NO_DATA); it->value = NULL; } return it_obj; } static enum fx_status iterator_move_next(const fx_iterator *obj) { struct fx_array_iterator_p *it = fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR); struct fx_array_p *array = it->_a_p; if (it->value == NULL || it->i >= array->ar_len) { return false; } it->i++; if (it->i >= array->ar_len) { it->value = NULL; } else { it->value = array->ar_data[it->i]; } return (it->value != NULL) ? FX_SUCCESS : FX_ERR_NO_DATA; } static enum fx_status iterator_erase(fx_iterator *obj) { struct fx_array_iterator_p *it = fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR); struct fx_array_p *array = it->_a_p; if (it->i >= array->ar_len) { return FX_ERR_OUT_OF_BOUNDS; } if (array->ar_data[it->i] != it->value) { return FX_ERR_BAD_STATE; } array_remove(array, it->i); if (it->i < array->ar_len) { it->value = array->ar_data[it->i]; } else { it->value = NULL; } return FX_SUCCESS; } static fx_iterator_value iterator_get_value(fx_iterator *obj) { struct fx_array_iterator_p *it = fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR); return FX_ITERATOR_VALUE_PTR(it->value); } static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj) { struct fx_array_iterator_p *it = fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR); return FX_ITERATOR_VALUE_CPTR(it->value); } static enum fx_status iterator_is_valid(const fx_iterator *obj) { struct fx_array_iterator_p *it = fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR); struct fx_array_p *array = it->_a_p; if (it->i >= array->ar_len) { return false; } if (array->ar_data[it->i] != it->value) { return false; } return (it->value != NULL) ? FX_SUCCESS : FX_ERR_NO_DATA; } /*** CLASS DEFINITION *********************************************************/ // ---- fx_array DEFINITION FX_TYPE_CLASS_DEFINITION_BEGIN(fx_array) FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT) FX_INTERFACE_ENTRY(to_string) = array_to_string; FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT) FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE) FX_INTERFACE_ENTRY(it_begin) = iterable_begin; FX_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin; FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE) FX_TYPE_CLASS_DEFINITION_END(fx_array) FX_TYPE_DEFINITION_BEGIN(fx_array) FX_TYPE_ID(0xe3c46da1, 0x5f37, 0x4e44, 0xb53b, 0xff5a6200191b); FX_TYPE_CLASS(fx_array_class); FX_TYPE_IMPLEMENTS(FX_TYPE_ITERABLE); FX_TYPE_INSTANCE_PRIVATE(struct fx_array_p); FX_TYPE_INSTANCE_INIT(array_init); FX_TYPE_INSTANCE_FINI(array_fini); FX_TYPE_DEFINITION_END(fx_array) // ---- fx_array_iterator DEFINITION FX_TYPE_CLASS_DEFINITION_BEGIN(fx_array_iterator) FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT) FX_INTERFACE_ENTRY(to_string) = NULL; FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT) FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR) FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next; FX_INTERFACE_ENTRY(it_erase) = iterator_erase; FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value; FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue; FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR) FX_TYPE_CLASS_DEFINITION_END(fx_array_iterator) FX_TYPE_DEFINITION_BEGIN(fx_array_iterator) FX_TYPE_ID(0xe5e9e8b8, 0x14cb, 0x4192, 0x8138, 0xf45238a2ae73); FX_TYPE_EXTENDS(FX_TYPE_ITERATOR); FX_TYPE_CLASS(fx_array_iterator_class); FX_TYPE_INSTANCE_PRIVATE(struct fx_array_iterator_p); FX_TYPE_DEFINITION_END(fx_array_iterator)