Rework, no version bump
This commit is contained in:
+89
-135
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user