#include #include "malunal/containers/vector.h" typedef struct { object_t object; container_t container; allocator_mptr_t allocator; malunal_size_t stride; malunal_size_t count; malunal_size_t capacity; malunal_mptr_t buffer; } impl_t; typedef impl_t* impl_mptr_t; typedef const impl_t* impl_iptr_t; _Static_assert( sizeof(vector_container_t) == sizeof(impl_t), "Vector container must be the size of its implementation" ); static error_t vector_object_cast_impl( malunal_mptr_t object, uuid_iptr_t uuid, malunal_mptr_t* out ) { if (object == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; impl_mptr_t self = (impl_mptr_t)object; if (uuid_equals(&UUID_OBJECT_T, uuid)) { *out = &self->object; return NO_ERROR; } if (uuid_equals(&UUID_CONTAINER_T, uuid)) { *out = &self->container; return NO_ERROR; } *out = null; return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_FAILURE }; } static malunal_uint32_t vector_object_retain_impl( malunal_mptr_t object ) { // TODO: figure out how to handle this. } static malunal_uint32_t vector_object_release_impl( malunal_mptr_t object ) { // TODO: figure out how to handle this. } static const object_vtable_t vector_object_vtable = { .cast = &vector_object_cast_impl, .retain = &vector_object_retain_impl, .release = &vector_object_release_impl }; static const container_vtable_t vector_container_vtable = { .allocator = (container_allocator_pfn_t)&vector_container_allocator, .stride = (container_stride_pfn_t)&vector_container_stride, .count = (container_count_pfn_t)&vector_container_count, .capacity = (container_capacity_pfn_t)&vector_container_capacity, .append = (container_append_pfn_t)&vector_container_append, .remove = (container_remove_pfn_t)&vector_container_remove, .contains = (container_contains_pfn_t)&vector_container_contains, .clear = (container_clear_pfn_t)&vector_container_clear }; static error_t vector_container_realloc(impl_mptr_t self) { if ((float)self->count / self->capacity < 0.75f) return NO_ERROR; malunal_mptr_t buffer; malunal_size_t oldcap = self->stride * self->capacity; error_t result = allocator_acquire(self->allocator, oldcap * 2, &buffer); if (result.domain != null) return result; buffer = memmove(buffer, self->buffer, oldcap); result = allocator_dispose(self->allocator, self->buffer, oldcap); self->buffer = buffer; self->capacity = self->capacity * 2; return NO_ERROR; } error_t vector_container_init( malunal_size_t stride, malunal_size_t capacity, allocator_mptr_t allocator, vector_container_mptr_t vector ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; impl_mptr_t self = (impl_mptr_t)vector; error_t result = allocator_acquire( allocator, stride * capacity, &self->buffer ); if (result.domain != null) return result; self->object = (object_t) { &vector_object_vtable }; self->container = (container_t){ &vector_container_vtable }; self->allocator = allocator; self->stride = stride; self->count = 0; self->capacity = capacity; return NO_ERROR; } error_t vector_container_free( vector_container_mptr_t vector ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; impl_mptr_t self = (impl_mptr_t)vector; error_t result = allocator_dispose( self->allocator, self->buffer, self->stride * self->capacity ); if (result.domain != null) return result; self->stride = 0; self->count = 0; self->capacity = 0; self->buffer = null; return NO_ERROR; } error_t vector_container_allocator( vector_container_iptr_t vector, allocator_mptr_t* out ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; impl_iptr_t self = (impl_iptr_t)vector; *out = self->allocator; return NO_ERROR; } error_t vector_container_stride( vector_container_iptr_t vector, malunal_size_t* out ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; impl_iptr_t self = (impl_iptr_t)vector; *out = self->stride; return NO_ERROR; } error_t vector_container_count( vector_container_iptr_t vector, malunal_size_t* out ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; impl_iptr_t self = (impl_iptr_t)vector; *out = self->count; return NO_ERROR; } error_t vector_container_capacity( vector_container_iptr_t vector, malunal_size_t* out ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; impl_iptr_t self = (impl_iptr_t)vector; *out = self->capacity; return NO_ERROR; } error_t vector_container_append( vector_container_mptr_t vector, malunal_iptr_t element ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; impl_mptr_t self = (impl_mptr_t)vector; error_t result = vector_container_realloc(self); if (result.domain != null) return result; malunal_uint8_t* buffer = self->buffer; buffer += self->stride * self->count; memcpy(buffer, element, self->stride); self->count++; return NO_ERROR; } error_t vector_container_remove( vector_container_mptr_t vector, malunal_iptr_t element ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; malunal_size_t index; impl_mptr_t self = (impl_mptr_t)vector; error_t result = vector_container_index_of(vector, element, &index); if (result.domain != null) return result; return index != (malunal_size_t)-1 ? vector_container_remove_at(vector, index) : NO_ERROR; } error_t vector_container_contains( vector_container_iptr_t vector, malunal_iptr_t element ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; malunal_size_t index; impl_iptr_t self = (impl_iptr_t)vector; error_t result = vector_container_index_of(vector, element, &index); if (result.domain != null) return result; return index == (malunal_size_t)-1 ? (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_FAILURE } : NO_ERROR; } error_t vector_container_clear( vector_container_mptr_t vector ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; impl_mptr_t self = (impl_mptr_t)vector; self->count = 0; return NO_ERROR; } error_t vector_container_get( vector_container_iptr_t vector, malunal_size_t index, malunal_mptr_t element ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; impl_iptr_t self = (impl_iptr_t)vector; if (index >= self->count) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_OUT_OF_BOUNDS }; malunal_uint8_t* buffer = self->buffer; buffer += self->stride * index; memcpy(element, buffer, self->stride); return NO_ERROR; } error_t vector_container_set( vector_container_mptr_t vector, malunal_size_t index, malunal_iptr_t element ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; impl_mptr_t self = (impl_mptr_t)vector; if (index >= self->count) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_OUT_OF_BOUNDS }; malunal_uint8_t* buffer = self->buffer; buffer += self->stride * index; memcpy(buffer, element, self->stride); return NO_ERROR; } error_t vector_container_insert_at( vector_container_mptr_t vector, malunal_size_t index, malunal_iptr_t element ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; impl_mptr_t self = (impl_mptr_t)vector; if (index > self->count) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_OUT_OF_BOUNDS }; error_t result = vector_container_realloc(self); if (result.domain != null) return result; malunal_uint8_t* orig = self->buffer; orig += self->stride * index; malunal_uint8_t* dest = orig + self->stride; memmove(dest, orig, self->stride * self->count - index); memcpy(orig, element, self->stride); self->count++; return NO_ERROR; } error_t vector_container_remove_at( vector_container_mptr_t vector, malunal_size_t index ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; impl_mptr_t self = (impl_mptr_t)vector; if (self->count == 0 || index >= self->count) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_OUT_OF_BOUNDS }; malunal_uint8_t* dest = self->buffer; dest += self->stride * index; malunal_uint8_t* orig = dest + self->stride; memmove(dest, orig, self->stride * self->count - index); self->count--; return NO_ERROR; } error_t vector_container_index_of( vector_container_iptr_t vector, malunal_iptr_t element, malunal_size_t* outidx ) { if (vector == null) return (error_t) { .domain = &ERROR_DOMAIN_CONTAINER_T, .code = CONTAINER_ERROR_NULL_CONTAINER }; malunal_size_t index = 0; impl_iptr_t self = (impl_iptr_t)vector; malunal_uint8_t* buffer = self->buffer; while (index < self->count) { if (memcmp(buffer, element, self->stride) == 0) { *outidx = index; return NO_ERROR; } index += 1; buffer += self->stride; } *outidx = (malunal_size_t)-1; return NO_ERROR; }