#include "array.h" #include #include #include #include #include #include static void array_release(struct b_object *obj); static void array_to_string(struct b_object *obj, struct b_stream *out); static struct b_object_type array_type = { .t_flags = B_OBJECT_FUNDAMENTAL, .t_id = B_OBJECT_TYPE_ARRAY, .t_name = "corelib::array", .t_instance_size = sizeof(struct b_array), .t_release = array_release, .t_to_string = array_to_string, }; struct b_array *b_array_create(void) { struct b_array *array = (struct b_array *)b_object_type_instantiate(&array_type); if (!array) { return NULL; } return array; } struct b_array *b_array_create_with_values( struct b_object *const *values, size_t nr_values) { struct b_array *array = b_array_create(); if (!array) { return NULL; } size_t real_nr_values = 0; for (size_t i = 0; i < nr_values; i++) { if (values[i]) { real_nr_values++; } } array->ar_len = real_nr_values; array->ar_cap = real_nr_values; array->ar_data = calloc(real_nr_values, sizeof(struct b_object *)); if (!array->ar_data) { b_array_release(array); return NULL; } size_t index = 0; for (size_t i = 0; i < nr_values; i++) { array->ar_data[index++] = b_retain(values[i]); } return array; } static b_status resize_array(struct b_array *array, size_t new_capacity) { if (array->ar_cap < new_capacity) { void *new_data = realloc( array->ar_data, new_capacity * sizeof(struct b_object *)); if (!new_data) { return B_ERR_NO_MEMORY; } array->ar_data = new_data; } else { for (size_t i = new_capacity; i < array->ar_len; i++) { b_release(array->ar_data[i]); } void *new_data = realloc( array->ar_data, new_capacity * sizeof(struct b_object *)); if (!new_data) { return B_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 B_SUCCESS; } b_status b_array_append(struct b_array *array, struct b_object *value) { return b_array_insert(array, value, B_NPOS); } b_status b_array_prepend(struct b_array *array, struct b_object *value) { return b_array_insert(array, value, 0); } b_status b_array_insert(struct b_array *array, struct b_object *value, size_t at) { if (at == B_NPOS) { at = array->ar_len; } if (at > array->ar_len) { return B_ERR_OUT_OF_BOUNDS; } b_status status = B_SUCCESS; if (array->ar_len + 1 > array->ar_cap) { status = resize_array(array, array->ar_cap + 8); if (status != B_SUCCESS) { return status; } } struct b_object **src = array->ar_data + at; struct b_object **dest = src + 1; size_t move_len = (array->ar_len - at) * sizeof(struct b_object *); memmove(dest, src, move_len); array->ar_data[at] = b_retain(value); array->ar_len++; return B_SUCCESS; } b_status b_array_remove(struct b_array *array, size_t at) { if (at >= array->ar_len) { return B_ERR_OUT_OF_BOUNDS; } struct b_object **src = array->ar_data + at; struct b_object **dest = src + 1; size_t move_len = array->ar_len * sizeof(struct b_object *); b_release(array->ar_data[at]); memmove(dest, src, move_len); array->ar_len--; return B_SUCCESS; } b_status b_array_remove_front(struct b_array *array) { return b_array_remove(array, 0); } b_status b_array_remove_back(struct b_array *array) { return b_array_remove(array, array->ar_len - 1); } struct b_object *b_array_pop(b_array *array, size_t at) { if (at >= array->ar_len) { return NULL; } struct b_object **src = array->ar_data + at; struct b_object **dest = src + 1; size_t move_len = array->ar_len * sizeof(struct b_object *); struct b_object *out = array->ar_data[at]; memmove(dest, src, move_len); array->ar_len--; return out; } struct b_object *b_array_pop_front(struct b_array *array) { return b_array_pop(array, 0); } struct b_object *b_array_pop_back(struct b_array *array) { return b_array_pop(array, array->ar_len - 1); } struct b_object *b_array_at(const struct b_array *array, size_t at) { if (at >= array->ar_len) { return NULL; } return array->ar_data[at]; } struct b_object *b_array_get(struct b_array *array, size_t at) { if (at >= array->ar_len) { return NULL; } return b_retain(array->ar_data[at]); } size_t b_array_size(const struct b_array *array) { return array->ar_len; } size_t b_array_capacity(const struct b_array *array) { return array->ar_cap; } static void array_to_string(struct b_object *obj, struct b_stream *out) { struct b_array *array = B_ARRAY(obj); if (!array->ar_len) { b_stream_write_string(out, "[]", NULL); return; } b_stream_write_string(out, "[\n", NULL); b_stream_push_indent(out, 1); size_t len = b_array_size(array); b_array_iterator it; b_array_foreach(&it, array) { bool is_string = b_typeid(it.value) == B_OBJECT_TYPE_STRING; if (is_string) { b_stream_write_char(out, '"'); } b_to_string(it.value, out); if (is_string) { b_stream_write_char(out, '"'); } if (it.i < len - 1) { b_stream_write_string(out, ",", NULL); } b_stream_write_char(out, '\n'); } b_stream_pop_indent(out); b_stream_write_char(out, ']'); } static void array_release(struct b_object *obj) { struct b_array *array = B_ARRAY(obj); if (array->ar_data) { for (size_t i = 0; i < array->ar_len; i++) { b_release(array->ar_data[i]); } free(array->ar_data); array->ar_data = NULL; } } void b_array_clear(struct b_array *array) { while (array->ar_len) { b_array_remove_back(array); } } static bool array_iterator_next(struct b_iterator *it) { return b_array_iterator_next((struct b_array_iterator *)it); } static b_status array_iterator_erase(struct b_iterator *it) { return b_array_iterator_erase((struct b_array_iterator *)it); } static bool array_iterator_is_valid(const struct b_iterator *it) { return b_array_iterator_is_valid((const struct b_array_iterator *)it); } static b_iterator_ops it_ops = { .it_next = array_iterator_next, .it_close = NULL, .it_erase = array_iterator_erase, .it_is_valid = array_iterator_is_valid, }; int b_array_iterator_begin(struct b_array *array, struct b_array_iterator *it) { it->_a = array; it->i = 0; it->_base.it_ops = &it_ops; if (array->ar_len > 0) { it->value = array->ar_data[0]; } else { it->value = NULL; } return 0; } bool b_array_iterator_next(struct b_array_iterator *it) { struct b_array *array = it->_a; 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; } b_status b_array_iterator_erase(struct b_array_iterator *it) { struct b_array *array = it->_a; if (it->i >= array->ar_len) { return B_ERR_OUT_OF_BOUNDS; } if (array->ar_data[it->i] != it->value) { return B_ERR_BAD_STATE; } b_array_remove(array, it->i); if (it->i < array->ar_len) { it->value = array->ar_data[it->i]; } else { it->value = NULL; } return B_SUCCESS; } bool b_array_iterator_is_valid(const struct b_array_iterator *it) { struct b_array *array = it->_a; if (it->i >= array->ar_len) { return false; } if (array->ar_data[it->i] != it->value) { return false; } return it->value != NULL; } b_object_type_id b_array_type_id(void) { return (b_object_type_id)&array_type; }