Rework, no version bump

This commit is contained in:
2026-08-24 05:16:09 -05:00
parent 83bd4a3492
commit e99d393df2
7 changed files with 1164 additions and 1297 deletions
+89 -135
View File
@@ -1,182 +1,136 @@
#include "malunal/container.h"
typedef container_exception_t
(*container_initialize_pfn_t)(
container_mptr_t container,
allocator_mptr_t allocator,
malunal_size_t stride,
malunal_size_t capacity
);
typedef container_exception_t
(*container_finalize_pfn_t)(
container_mptr_t container
);
typedef container_exception_t
(*container_clear_pfn_t)(
container_mptr_t container
);
typedef container_exception_t
(*container_append_pfn_t)(
container_mptr_t container,
malunal_iptr_t element
);
typedef container_exception_t
(*container_remove_pfn_t)(
container_mptr_t container,
malunal_iptr_t element
);
typedef container_exception_t
(*container_contains_pfn_t)(
container_iptr_t container,
malunal_iptr_t element
);
const uuid_t UUID_CONTAINER_T = {
.tl = 0xF4784CF5,
.tm = 0xFE95,
.thv = 0x4529,
.csr = 0xBD,
.csl = 0x6D,
.nbs = {
0x82, 0x53, 0x70,
0x85, 0xC4, 0xAE
}
};
typedef struct {
container_initialize_pfn_t const initialize;
container_finalize_pfn_t const finalize;
container_clear_pfn_t const clear;
container_append_pfn_t const append;
container_remove_pfn_t const remove;
container_contains_pfn_t const contains;
} virtual_table_t;
static
malunal_cstr_t
describe(malunal_int32_t code) {
switch (code) {
case CONTAINER_ERROR_FAILURE:
return "Generic container error";
case CONTAINER_ERROR_NULL_CONTAINER:
return "Container provided was null";
case CONTAINER_ERROR_OUT_OF_BOUNDS:
return "Index into container was out of bounds";
}
return "Unknown container error";
}
typedef virtual_table_t* base_vtable_mptr_t;
typedef const virtual_table_t* vtable_iptr_t;
const error_domain_t ERROR_DOMAIN_CONTAINER_T = {
.describe = &describe,
.name = "malunal.container.error"
};
typedef struct {
vtable_iptr_t const vtable;
allocator_mptr_t allocator;
malunal_mptr_t context;
malunal_size_t stride;
malunal_size_t count;
malunal_size_t capacity;
} implementation_t;
typedef implementation_t* impl_mptr_t;
typedef const implementation_t* impl_iptr_t;
// Verify these are the same.
_Static_assert(
CONTAINER_SIZE == sizeof(implementation_t),
"container_t must be the same size as its implementation"
);
container_exception_t
error_t
container_allocator(
container_iptr_t container,
allocator_mptr_t* out
) {
impl_iptr_t implementation = (impl_iptr_t)container;
if (implementation == NULL_ADDRESS)
return CONTAINER_ERROR_NULL_CONTAINER;
*out = implementation->allocator;
return CONTAINER_ERROR_SUCCESS;
return container != null
? container->vtable->allocator(container, out)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
}
container_exception_t
error_t
container_stride(
container_iptr_t container,
malunal_size_t* out
) {
impl_iptr_t implementation = (impl_iptr_t)container;
if (implementation == NULL_ADDRESS)
return CONTAINER_ERROR_NULL_CONTAINER;
*out = implementation->stride;
return CONTAINER_ERROR_SUCCESS;
return container != null
? container->vtable->stride(container, out)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
}
container_exception_t
error_t
container_count(
container_iptr_t container,
malunal_size_t* out
) {
impl_iptr_t implementation = (impl_iptr_t)container;
if (implementation == NULL_ADDRESS)
return CONTAINER_ERROR_NULL_CONTAINER;
*out = implementation->count;
return CONTAINER_ERROR_SUCCESS;
return container != null
? container->vtable->count(container, out)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
}
container_exception_t
error_t
container_capacity(
container_iptr_t container,
malunal_size_t* out
) {
impl_iptr_t implementation = (impl_iptr_t)container;
if (implementation == NULL_ADDRESS)
return CONTAINER_ERROR_NULL_CONTAINER;
*out = implementation->capacity;
return CONTAINER_ERROR_SUCCESS;
return container != null
? container->vtable->capacity(container, out)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
}
container_exception_t
container_initialize(
container_mptr_t container,
allocator_mptr_t allocator,
malunal_size_t stride,
malunal_size_t capacity
) {
impl_mptr_t implementation = (impl_mptr_t)container;
return implementation != NULL_ADDRESS
? implementation->vtable->initialize(container, allocator, stride, capacity)
: CONTAINER_ERROR_NULL_CONTAINER;
}
container_exception_t
container_finalize(container_mptr_t container) {
impl_mptr_t implementation = (impl_mptr_t)container;
return implementation != NULL_ADDRESS
? implementation->vtable->finalize(container)
: CONTAINER_ERROR_NULL_CONTAINER;
}
container_exception_t
container_clear(container_mptr_t container) {
impl_mptr_t implementation = (impl_mptr_t)container;
return implementation != NULL_ADDRESS
? implementation->vtable->clear(container)
: CONTAINER_ERROR_NULL_CONTAINER;
}
container_exception_t
error_t
container_append(
container_mptr_t container,
malunal_iptr_t element
) {
impl_mptr_t implementation = (impl_mptr_t)container;
return implementation != NULL_ADDRESS
? implementation->vtable->append(container, element)
: CONTAINER_ERROR_NULL_CONTAINER;
return container != null
? container->vtable->append(container, element)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
}
container_exception_t
error_t
container_remove(
container_mptr_t container,
malunal_iptr_t element
) {
impl_mptr_t implementation = (impl_mptr_t)container;
return implementation != NULL_ADDRESS
? implementation->vtable->remove(container, element)
: CONTAINER_ERROR_NULL_CONTAINER;
return container != null
? container->vtable->remove(container, element)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
}
container_exception_t
error_t
container_contains(
container_iptr_t container,
malunal_iptr_t element
) {
impl_iptr_t implementation = (impl_iptr_t)container;
return implementation != NULL_ADDRESS
? implementation->vtable->contains(container, element)
: CONTAINER_ERROR_NULL_CONTAINER;
return container != null
? container->vtable->contains(container, element)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
}
error_t
container_clear(
container_mptr_t container
) {
return container != null
? container->vtable->clear(container)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
}
+385 -431
View File
@@ -1,500 +1,454 @@
#include <memory.h>
#include "malunal/containers/vector.h"
typedef container_exception_t
(*vector_initialize_pfn_t)(
vector_mptr_t vector,
allocator_mptr_t allocator,
malunal_size_t stride,
malunal_size_t capacity
);
typedef container_exception_t
(*vector_finalize_pfn_t)(
vector_mptr_t vector
);
typedef container_exception_t
(*vector_clear_pfn_t)(
vector_mptr_t vector
);
typedef container_exception_t
(*vector_append_pfn_t)(
vector_mptr_t vector,
malunal_iptr_t element
);
typedef container_exception_t
(*vector_remove_pfn_t)(
vector_mptr_t vector,
malunal_iptr_t element
);
typedef container_exception_t
(*vector_contains_pfn_t)(
vector_iptr_t vector,
malunal_iptr_t element
);
typedef container_exception_t
(*vector_get_pfn_t)(
vector_iptr_t vector,
malunal_size_t index,
malunal_mptr_t outptr
);
typedef container_exception_t
(*vector_set_pfn_t)(
vector_mptr_t vector,
malunal_size_t index,
malunal_iptr_t element
);
typedef container_exception_t
(*vector_insert_at_pfn_t)(
vector_mptr_t vector,
malunal_size_t index,
malunal_iptr_t element
);
typedef container_exception_t
(*vector_remove_at_pfn_t)(
vector_mptr_t vector,
malunal_size_t index
);
typedef container_exception_t
(*vector_index_of_pfn_t)(
vector_iptr_t vector,
malunal_iptr_t element,
malunal_size_t* outidx
);
typedef struct VectorVTable {
// Container generic.
vector_initialize_pfn_t const initialize;
vector_finalize_pfn_t const finalize;
vector_clear_pfn_t const clear;
vector_append_pfn_t const append;
vector_remove_pfn_t const remove;
vector_contains_pfn_t const contains;
// Vector specific.
vector_get_pfn_t const get;
vector_set_pfn_t const set;
vector_insert_at_pfn_t const insert_at;
vector_remove_at_pfn_t const remove_at;
vector_index_of_pfn_t const index_of;
} virtual_table_t;
typedef virtual_table_t* vtable_mptr_t;
typedef const virtual_table_t* vtable_iptr_t;
// Identical to container.
typedef struct {
vtable_iptr_t const vtable;
object_t object;
container_t container;
allocator_mptr_t allocator;
malunal_mptr_t context;
malunal_size_t stride;
malunal_size_t count;
malunal_size_t capacity;
} implementation_t;
malunal_mptr_t buffer;
} impl_t;
typedef implementation_t* impl_mptr_t;
typedef const implementation_t* impl_iptr_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
container_exception_t
vector_initialize_impl(
impl_mptr_t vector,
allocator_mptr_t allocator,
malunal_size_t stride,
malunal_size_t capacity
error_t
vector_object_cast_impl(
malunal_mptr_t object,
uuid_iptr_t uuid,
malunal_mptr_t* out
) {
malunal_size_t bytes = capacity * stride;
allocation_result_t result = allocator_acquire(allocator, bytes);
if (!result.threw) {
vector->allocator = allocator;
vector->context = result.address;
vector->stride = stride;
vector->capacity = capacity;
return CONTAINER_ERROR_SUCCESS;
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;
}
switch (result.error) {
case ALLOCATION_ERROR_NULL_ALLOCATOR:
case ALLOCATION_ERROR_NULL_CONTEXT:
case ALLOCATION_ERROR_NULL_UPSTREAM:
return CONTAINER_ERROR_NULL_ALLOCATOR;
case ALLOCATION_ERROR_OUT_OF_MEMORY:
return CONTAINER_ERROR_OUT_OF_MEMORY;
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
container_exception_t
vector_finalize_impl(impl_mptr_t vector) {
malunal_size_t bytes = vector->capacity * vector->stride;
allocation_error_t error = allocator_release(
vector->allocator,
vector->context,
bytes
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
);
switch (error) {
case ALLOCATION_ERROR_SUCCESS:
return CONTAINER_ERROR_SUCCESS;
if (result.domain != null)
return result;
case ALLOCATION_ERROR_NULL_ALLOCATOR:
case ALLOCATION_ERROR_NULL_CONTEXT:
case ALLOCATION_ERROR_NULL_UPSTREAM:
return CONTAINER_ERROR_NULL_ALLOCATOR;
case ALLOCATION_ERROR_LEAKY_MEMORY:
case ALLOCATION_ERROR_NOT_MY_ADDRESS:
case ALLOCATION_ERROR_FAILURE:
return CONTAINER_ERROR_FAILURE;
}
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;
}
static
container_exception_t
vector_clear_impl(impl_mptr_t vector) {
vector->count = 0;
return CONTAINER_ERROR_SUCCESS;
}
static
container_exception_t
vector_append_impl(
impl_mptr_t vector,
malunal_iptr_t element
error_t
vector_container_free(
vector_container_mptr_t vector
) {
if (vector->context == NULL_ADDRESS)
return CONTAINER_ERROR_NULL_CONTEXT;
if (vector == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
if (vector->count < vector->capacity)
goto copy_element;
malunal_size_t doubled = vector->capacity * 2;
allocation_result_t result = allocator_reacquire(
vector->allocator,
vector->context,
vector->capacity * vector->stride,
doubled * vector->stride
impl_mptr_t self = (impl_mptr_t)vector;
error_t result = allocator_dispose(
self->allocator,
self->buffer,
self->stride * self->capacity
);
if (!result.threw) {
vector->context = result.address;
vector->capacity = doubled;
goto copy_element;
}
if (result.domain != null)
return result;
switch (result.error) {
case ALLOCATION_ERROR_NULL_ALLOCATOR:
case ALLOCATION_ERROR_NULL_UPSTREAM:
case ALLOCATION_ERROR_NULL_CONTEXT:
return CONTAINER_ERROR_NULL_ALLOCATOR;
case ALLOCATION_ERROR_LEAKY_MEMORY:
case ALLOCATION_ERROR_NOT_MY_ADDRESS:
case ALLOCATION_ERROR_FAILURE:
return CONTAINER_ERROR_FAILURE;
}
copy_element:
malunal_uint8_t* buffer = vector->context;
buffer = buffer + vector->stride * vector->count;
memcpy(buffer, element, vector->stride);
vector->count++;
return CONTAINER_ERROR_SUCCESS;
self->stride = 0;
self->count = 0;
self->capacity = 0;
self->buffer = null;
return NO_ERROR;
}
static
container_exception_t
vector_remove_impl(
impl_mptr_t vector,
malunal_iptr_t element
error_t
vector_container_allocator(
vector_container_iptr_t vector,
allocator_mptr_t* out
) {
if (vector->context == NULL_ADDRESS)
return CONTAINER_ERROR_NULL_CONTEXT;
if (vector == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
malunal_size_t index = 0;
vector_mptr_t erased = (vector_mptr_t)vector;
container_exception_t error = vector_index_of(erased, element, &index);
if (error != CONTAINER_ERROR_SUCCESS)
return error;
return index != -1
? vector_remove_at(erased, index)
: CONTAINER_ERROR_SUCCESS;
impl_iptr_t self = (impl_iptr_t)vector;
*out = self->allocator;
return NO_ERROR;
}
static
container_exception_t
vector_contains_impl(
impl_iptr_t vector,
malunal_iptr_t element
error_t
vector_container_stride(
vector_container_iptr_t vector,
malunal_size_t* out
) {
if (vector->context == NULL_ADDRESS)
return CONTAINER_ERROR_NULL_CONTEXT;
if (vector == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
malunal_size_t index = 0;
vector_mptr_t erased = (vector_mptr_t)vector;
container_exception_t error = vector_index_of(erased, element, &index);
if (error != CONTAINER_ERROR_SUCCESS)
return error;
return index != -1
? CONTAINER_ERROR_SUCCESS
: CONTAINER_ERROR_FAILURE;
impl_iptr_t self = (impl_iptr_t)vector;
*out = self->stride;
return NO_ERROR;
}
static
container_exception_t
vector_get_def_impl(
impl_iptr_t vector,
malunal_size_t index,
malunal_mptr_t outptr
error_t
vector_container_count(
vector_container_iptr_t vector,
malunal_size_t* out
) {
if (vector->context == NULL_ADDRESS)
return CONTAINER_ERROR_NULL_CONTEXT;
if (vector == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
if (index < 0 || index >= vector->count)
return CONTAINER_ERROR_OUT_OF_BOUNDS;
malunal_uint8_t* buffer = vector->context;
buffer = buffer + vector->stride * index;
memcpy(outptr, buffer, vector->stride);
return CONTAINER_ERROR_SUCCESS;
impl_iptr_t self = (impl_iptr_t)vector;
*out = self->count;
return NO_ERROR;
}
static
container_exception_t
vector_set_def_impl(
impl_mptr_t vector,
malunal_size_t index,
malunal_iptr_t element
error_t
vector_container_capacity(
vector_container_iptr_t vector,
malunal_size_t* out
) {
if (vector->context == NULL_ADDRESS)
return CONTAINER_ERROR_NULL_CONTEXT;
if (vector == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
if (index < 0 || index >= vector->count)
return CONTAINER_ERROR_OUT_OF_BOUNDS;
malunal_uint8_t* buffer = vector->context;
buffer = buffer + vector->stride * index;
memcpy(buffer, element, vector->stride);
return CONTAINER_ERROR_SUCCESS;
impl_iptr_t self = (impl_iptr_t)vector;
*out = self->capacity;
return NO_ERROR;
}
static
container_exception_t
vector_insert_at_def_impl(
impl_mptr_t vector,
malunal_size_t index,
malunal_iptr_t element
error_t
vector_container_append(
vector_container_mptr_t vector,
malunal_iptr_t element
) {
if (vector->context == NULL_ADDRESS)
return CONTAINER_ERROR_NULL_CONTEXT;
if (vector == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
if (index < 0 || index > vector->count)
return CONTAINER_ERROR_OUT_OF_BOUNDS;
impl_mptr_t self = (impl_mptr_t)vector;
error_t result = vector_container_realloc(self);
if (result.domain != null)
return result;
if (vector->count < vector->capacity)
goto insert_element;
malunal_size_t doubled = vector->capacity * 2;
allocation_result_t result = allocator_reacquire(
vector->allocator,
vector->context,
vector->capacity * vector->stride,
doubled * vector->stride
);
if (!result.threw) {
vector->context = result.address;
vector->capacity = doubled;
goto insert_element;
}
switch (result.error) {
case ALLOCATION_ERROR_NULL_ALLOCATOR:
case ALLOCATION_ERROR_NULL_UPSTREAM:
case ALLOCATION_ERROR_NULL_CONTEXT:
return CONTAINER_ERROR_NULL_ALLOCATOR;
case ALLOCATION_ERROR_LEAKY_MEMORY:
case ALLOCATION_ERROR_NOT_MY_ADDRESS:
case ALLOCATION_ERROR_FAILURE:
return CONTAINER_ERROR_FAILURE;
}
insert_element:
malunal_size_t offset = vector->stride * index;
malunal_uint8_t* orig = vector->context;
orig = orig + offset;
malunal_size_t window = vector->count - index;
malunal_size_t bytes = vector->stride * window;
malunal_uint8_t* dest = orig + vector->stride;
memmove(dest, orig, bytes);
memcpy(orig, element, vector->stride);
vector->count++;
return CONTAINER_ERROR_SUCCESS;
malunal_uint8_t* buffer = self->buffer;
buffer += self->stride * self->count;
memcpy(buffer, element, self->stride);
self->count++;
return NO_ERROR;
}
static
container_exception_t
vector_remove_at_def_impl(
impl_mptr_t vector,
malunal_size_t index
error_t
vector_container_remove(
vector_container_mptr_t vector,
malunal_iptr_t element
) {
if (vector->context == NULL_ADDRESS)
return CONTAINER_ERROR_NULL_CONTEXT;
if (vector == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
if (index < 0 || index >= vector->count)
return CONTAINER_ERROR_OUT_OF_BOUNDS;
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;
malunal_size_t offset = vector->stride * index;
malunal_uint8_t* dest = vector->context;
dest = dest + offset;
malunal_size_t window = vector->count - index;
malunal_size_t bytes = vector->stride * window;
malunal_uint8_t* orig = dest + vector->stride;
memmove(dest, orig, bytes);
vector->count--;
return CONTAINER_ERROR_SUCCESS;
return index != (malunal_size_t)-1
? vector_container_remove_at(vector, index)
: NO_ERROR;
}
static
container_exception_t
vector_index_of_def_impl(
impl_mptr_t vector,
malunal_iptr_t element,
malunal_size_t* outidx
error_t
vector_container_contains(
vector_container_iptr_t vector,
malunal_iptr_t element
) {
if (vector->context == NULL_ADDRESS)
return CONTAINER_ERROR_NULL_CONTEXT;
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;
malunal_uint8_t* buffer = vector->context;
while (index < vector->count) {
if (memcmp(buffer, element, vector->stride) == 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 CONTAINER_ERROR_SUCCESS;
return NO_ERROR;
}
index += 1;
buffer += vector->stride;
buffer += self->stride;
}
*outidx = -1;
return CONTAINER_ERROR_SUCCESS;
*outidx = (malunal_size_t)-1;
return NO_ERROR;
}
container_exception_t
vector_get(
vector_iptr_t vector,
malunal_size_t index,
malunal_mptr_t outptr
) {
impl_iptr_t implementation = (impl_iptr_t)vector;
return implementation != NULL_ADDRESS
? implementation->vtable->get(vector, index, outptr)
: CONTAINER_ERROR_NULL_CONTAINER;
}
container_exception_t
vector_set(
vector_mptr_t vector,
malunal_size_t index,
malunal_iptr_t element
) {
impl_iptr_t implementation = (impl_iptr_t)vector;
return implementation != NULL_ADDRESS
? implementation->vtable->set(vector, index, element)
: CONTAINER_ERROR_NULL_CONTAINER;
}
container_exception_t
vector_insert_at(
vector_mptr_t vector,
malunal_size_t index,
malunal_iptr_t element
) {
impl_iptr_t implementation = (impl_iptr_t)vector;
return implementation != NULL_ADDRESS
? implementation->vtable->insert_at(vector, index, element)
: CONTAINER_ERROR_NULL_CONTAINER;
}
container_exception_t
vector_remove_at(
vector_mptr_t vector,
malunal_size_t index
) {
impl_iptr_t implementation = (impl_iptr_t)vector;
return implementation != NULL_ADDRESS
? implementation->vtable->remove_at(vector, index)
: CONTAINER_ERROR_NULL_CONTAINER;
}
container_exception_t
vector_index_of(
vector_mptr_t vector,
malunal_iptr_t element,
malunal_size_t* outidx
) {
impl_iptr_t implementation = (impl_iptr_t)vector;
return implementation != NULL_ADDRESS
? implementation->vtable->index_of(vector, element, outidx)
: CONTAINER_ERROR_NULL_CONTAINER;
}
static const
virtual_table_t vector_vtable = {
.initialize = (vector_initialize_pfn_t)&vector_initialize_impl,
.finalize = (vector_finalize_pfn_t)&vector_finalize_impl,
.clear = (vector_clear_pfn_t)&vector_clear_impl,
.append = (vector_append_pfn_t)&vector_append_impl,
.remove = (vector_remove_pfn_t)&vector_remove_impl,
.contains = (vector_contains_pfn_t)&vector_contains_impl,
.get = (vector_get_pfn_t)&vector_get_def_impl,
.set = (vector_set_pfn_t)&vector_set_def_impl,
.insert_at = (vector_insert_at_pfn_t)&vector_insert_at_def_impl,
.remove_at = (vector_remove_at_pfn_t)&vector_remove_at_def_impl,
.index_of = (vector_index_of_pfn_t)&vector_index_of_def_impl
};
vector_t
vector_container() {
implementation_t implementation = {
.vtable = &vector_vtable,
.allocator = NULL_ADDRESS,
.context = NULL_ADDRESS,
.stride = 0,
.count = 0,
.capacity = 0,
};
vector_t result;
memcpy(
&result,
&implementation,
sizeof(implementation_t)
);
return result;
}