Vector reword + map

This commit is contained in:
2026-09-12 12:54:20 -05:00
parent e99d393df2
commit 71264d0f14
9 changed files with 1882 additions and 216 deletions
+43 -48
View File
@@ -1,3 +1,4 @@
#include "malunal/assert.h"
#include "malunal/container.h"
const uuid_t UUID_CONTAINER_T = {
@@ -32,17 +33,15 @@ const error_domain_t ERROR_DOMAIN_CONTAINER_T = {
.name = "malunal.container.error"
};
error_t
container_allocator(
container_iptr_t container,
allocator_mptr_t* out
) {
return container != null
? container->vtable->allocator(container, out)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
assert(container != null);
assert(out != null);
return container->vtable->allocator(container, out);
}
error_t
@@ -50,12 +49,9 @@ container_stride(
container_iptr_t container,
malunal_size_t* out
) {
return container != null
? container->vtable->stride(container, out)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
assert(container != null);
assert(out != null);
return container->vtable->stride(container, out);
}
error_t
@@ -63,12 +59,9 @@ container_count(
container_iptr_t container,
malunal_size_t* out
) {
return container != null
? container->vtable->count(container, out)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
assert(container != null);
assert(out != null);
return container->vtable->count(container, out);
}
error_t
@@ -76,12 +69,27 @@ container_capacity(
container_iptr_t container,
malunal_size_t* out
) {
return container != null
? container->vtable->capacity(container, out)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
assert(container != null);
assert(out != null);
return container->vtable->capacity(container, out);
}
error_t
container_resize(
container_mptr_t container,
malunal_size_t capacity
) {
assert(container != null);
return container->vtable->resize(container, capacity);
}
error_t
container_reserve(
container_mptr_t container,
malunal_size_t capacity
) {
assert(container != null);
return container->vtable->reserve(container, capacity);
}
error_t
@@ -89,12 +97,9 @@ container_append(
container_mptr_t container,
malunal_iptr_t element
) {
return container != null
? container->vtable->append(container, element)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
assert(container != null);
assert(element != null);
return container->vtable->append(container, element);
}
error_t
@@ -102,12 +107,9 @@ container_remove(
container_mptr_t container,
malunal_iptr_t element
) {
return container != null
? container->vtable->remove(container, element)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
assert(container != null);
assert(element != null);
return container->vtable->remove(container, element);
}
error_t
@@ -115,22 +117,15 @@ container_contains(
container_iptr_t container,
malunal_iptr_t element
) {
return container != null
? container->vtable->contains(container, element)
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
assert(container != null);
assert(element != null);
return container->vtable->contains(container, element);
}
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
};
assert(container != null);
return container->vtable->clear(container);
}
+674
View File
@@ -0,0 +1,674 @@
#include <memory.h>
#include "malunal/containers/map.h"
#define MAP_CONTROL_EMPTY ((malunal_uint8_t)0x00)
#define MAP_CONTROL_ERASED ((malunal_uint8_t)0x01)
#define MAP_CONTROL_FILLED ((malunal_uint8_t)0x02)
#define MAP_LOAD_FACTOR 0.75f
#define MAP_NO_SLOT ((malunal_size_t)-1)
#define MAP_HASH_BASIS 0xCBF29CE484222325ULL
#define MAP_HASH_PRIME 0x00000100000001B3ULL
typedef struct {
container_t container;
allocator_mptr_t allocator;
malunal_size_t keystride;
malunal_size_t valstride;
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(map_container_t) == sizeof(impl_t),
"Map container must be the size of its implementation"
);
static const
container_vtable_t map_container_vtable = {
.allocator = (container_allocator_pfn_t)&map_container_allocator,
.stride = (container_stride_pfn_t)&map_container_stride,
.count = (container_count_pfn_t)&map_container_count,
.capacity = (container_capacity_pfn_t)&map_container_capacity,
.resize = (container_resize_pfn_t)&map_container_resize,
.reserve = (container_reserve_pfn_t)&map_container_reserve,
.append = (container_append_pfn_t)&map_container_append,
.remove = (container_remove_pfn_t)&map_container_remove,
.contains = (container_contains_pfn_t)&map_container_contains,
.clear = (container_clear_pfn_t)&map_container_clear
};
static
malunal_size_t
power_2_ceil(malunal_size_t capacity) {
if (capacity <= 1)
return 1;
capacity--;
malunal_size_t power = 2;
while (capacity >>= 1)
power <<= 1;
return power;
}
static
malunal_size_t
map_container_bytes(
malunal_size_t keystride,
malunal_size_t valstride,
malunal_size_t capacity
) {
return capacity + (keystride + valstride) * capacity;
}
static
malunal_uint8_t*
map_container_control(impl_iptr_t self) {
return (malunal_uint8_t*)self->buffer;
}
static
malunal_uint8_t*
map_container_key(
impl_iptr_t self,
malunal_size_t index
) {
malunal_uint8_t* slots =
map_container_control(self) +
self->capacity;
return slots + (self->keystride + self->valstride) * index;
}
static
malunal_uint8_t*
map_container_value(
impl_iptr_t self,
malunal_size_t index
) {
return
map_container_key(self, index) +
self->keystride;
}
static
malunal_size_t
map_container_hash(
malunal_iptr_t key,
malunal_size_t keystride
) {
malunal_uint8_t* bytes = key;
malunal_uint64_t hash = MAP_HASH_BASIS;
for (malunal_size_t index = 0; index < keystride; index++) {
hash ^= (malunal_uint64_t)bytes[index];
hash *= MAP_HASH_PRIME;
}
return (malunal_size_t)hash;
}
static
malunal_bool_t
map_container_find(
impl_iptr_t self,
malunal_iptr_t key,
malunal_size_t* outidx
) {
*outidx = MAP_NO_SLOT;
if (self->buffer == null || self->capacity == 0)
return false;
malunal_uint8_t* control = map_container_control(self);
malunal_size_t mask = self->capacity - 1;
malunal_size_t index = map_container_hash(key, self->keystride) & mask;
malunal_size_t vacancy = MAP_NO_SLOT;
malunal_size_t probed = 0;
while (probed < self->capacity) {
if (control[index] == MAP_CONTROL_EMPTY) {
*outidx = vacancy != MAP_NO_SLOT ? vacancy : index;
return false;
}
if (control[index] == MAP_CONTROL_ERASED) {
if (vacancy == MAP_NO_SLOT)
vacancy = index;
} else if (memcmp(map_container_key(self, index), key, self->keystride) == 0) {
*outidx = index;
return true;
}
index = (index + 1) & mask;
probed += 1;
}
*outidx = vacancy;
return false;
}
static
malunal_void_t
map_container_place(
impl_mptr_t self,
malunal_size_t index,
malunal_iptr_t key,
malunal_iptr_t value
) {
map_container_control(self)[index] = MAP_CONTROL_FILLED;
memcpy(map_container_key(self, index), key, self->keystride);
if (self->valstride != 0)
memcpy(map_container_value(self, index), value, self->valstride);
}
static
error_t
map_container_realloc(
impl_mptr_t self,
malunal_size_t capacity
) {
if (capacity <= self->capacity)
return NO_ERROR;
malunal_mptr_t buffer;
malunal_size_t newcap = power_2_ceil(capacity);
malunal_size_t bytes = map_container_bytes(
self->keystride,
self->valstride,
newcap
);
error_t result = allocator_acquire(self->allocator, bytes, &buffer);
if (result.domain != null)
return result;
memset(buffer, MAP_CONTROL_EMPTY, newcap);
impl_t rehashed = *self;
rehashed.buffer = buffer;
rehashed.capacity = newcap;
malunal_uint8_t* control = map_container_control(self);
for (malunal_size_t index = 0; index < self->capacity; index++) {
if (control[index] != MAP_CONTROL_FILLED)
continue;
malunal_size_t slot;
malunal_uint8_t* key = map_container_key(self, index);
map_container_find(&rehashed, key, &slot);
map_container_place(&rehashed, slot, key, map_container_value(self, index));
}
if (self->buffer != null) {
bytes = map_container_bytes(
self->keystride,
self->valstride,
self->capacity
);
result = allocator_dispose(self->allocator, self->buffer, bytes);
}
self->buffer = buffer;
self->capacity = newcap;
return result;
}
error_t
map_container_init(
malunal_size_t keystride,
malunal_size_t valstride,
allocator_mptr_t allocator,
map_container_mptr_t map
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
impl_mptr_t self = (impl_mptr_t)map;
malunal_size_t capacity = power_2_ceil(MALUNAL_CONTAINERS_MAP_INIT_CAPACITY);
malunal_size_t bytes = map_container_bytes(keystride, valstride, capacity);
error_t result = allocator_acquire(allocator, bytes, &self->buffer);
if (result.domain != null)
return result;
memset(self->buffer, MAP_CONTROL_EMPTY, capacity);
self->container = (container_t){ &map_container_vtable };
self->allocator = allocator;
self->keystride = keystride;
self->valstride = valstride;
self->count = 0;
self->capacity = capacity;
return NO_ERROR;
}
error_t
map_container_free(
map_container_mptr_t map
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
impl_mptr_t self = (impl_mptr_t)map;
error_t result = allocator_dispose(
self->allocator,
self->buffer,
map_container_bytes(self->keystride, self->valstride, self->capacity)
);
if (result.domain != null)
return result;
self->keystride = 0;
self->valstride = 0;
self->count = 0;
self->capacity = 0;
self->buffer = null;
return NO_ERROR;
}
error_t
map_container_allocator(
map_container_iptr_t map,
allocator_mptr_t* out
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
impl_iptr_t self = (impl_iptr_t)map;
*out = self->allocator;
return NO_ERROR;
}
error_t
map_container_stride(
map_container_iptr_t map,
malunal_size_t* out
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
impl_iptr_t self = (impl_iptr_t)map;
*out = self->keystride + self->valstride;
return NO_ERROR;
}
error_t
map_container_key_stride(
map_container_iptr_t map,
malunal_size_t* out
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
impl_iptr_t self = (impl_iptr_t)map;
*out = self->keystride;
return NO_ERROR;
}
error_t
map_container_value_stride(
map_container_iptr_t map,
malunal_size_t* out
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
impl_iptr_t self = (impl_iptr_t)map;
*out = self->valstride;
return NO_ERROR;
}
error_t
map_container_count(
map_container_iptr_t map,
malunal_size_t* out
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
impl_iptr_t self = (impl_iptr_t)map;
*out = self->count;
return NO_ERROR;
}
error_t
map_container_capacity(
map_container_iptr_t map,
malunal_size_t* out
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
impl_iptr_t self = (impl_iptr_t)map;
*out = self->capacity;
return NO_ERROR;
}
error_t
map_container_keys(
map_container_iptr_t map,
container_mptr_t container
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
if (container == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_RECEIVER
};
malunal_size_t stride = 0;
impl_iptr_t self = (impl_iptr_t)map;
error_t result = container_stride(container, &stride);
if (result.domain != null)
return result;
if (stride != self->keystride)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_FAILURE
};
malunal_uint8_t* control = map_container_control(self);
for (malunal_size_t index = 0; index < self->capacity; index++) {
if (control[index] != MAP_CONTROL_FILLED)
continue;
result = container_append(container, map_container_key(self, index));
if (result.domain != null)
return result;
}
return NO_ERROR;
}
error_t
map_container_values(
map_container_iptr_t map,
container_mptr_t container
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
if (container == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_RECEIVER
};
malunal_size_t stride = 0;
impl_iptr_t self = (impl_iptr_t)map;
error_t result = container_stride(container, &stride);
if (result.domain != null)
return result;
if (stride != self->valstride)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_FAILURE
};
malunal_uint8_t* control = map_container_control(self);
for (malunal_size_t index = 0; index < self->capacity; index++) {
if (control[index] != MAP_CONTROL_FILLED)
continue;
result = container_append(container, map_container_value(self, index));
if (result.domain != null)
return result;
}
return NO_ERROR;
}
error_t
map_container_resize(
map_container_mptr_t map,
malunal_size_t capacity
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
impl_mptr_t self = (impl_mptr_t)map;
return map_container_realloc(self, capacity);
}
error_t
map_container_reserve(
map_container_mptr_t map,
malunal_size_t capacity
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
impl_mptr_t self = (impl_mptr_t)map;
return map_container_realloc(self, (capacity * 4) / 3 + 1);
}
error_t
map_container_append(
map_container_mptr_t map,
map_pair_iptr_t pair
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
if (pair == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_FAILURE
};
return map_container_insert(map, pair->key, pair->value);
}
error_t
map_container_insert(
map_container_mptr_t map,
malunal_iptr_t key,
malunal_iptr_t value
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
error_t result = NO_ERROR;
impl_mptr_t self = (impl_mptr_t)map;
if (self->capacity == 0) {
result = map_container_realloc(self, MALUNAL_CONTAINERS_MAP_INIT_CAPACITY);
if (result.domain != null)
return result;
}
malunal_size_t slot;
if (map_container_find(self, key, &slot)) {
if (self->valstride != 0)
memcpy(map_container_value(self, slot), value, self->valstride);
return NO_ERROR;
}
if (slot == MAP_NO_SLOT ||
(float)(self->count + 1) / self->capacity >= MAP_LOAD_FACTOR) {
result = map_container_realloc(self, self->capacity * 2);
if (result.domain != null)
return result;
map_container_find(self, key, &slot);
}
if (slot == MAP_NO_SLOT)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_FAILURE
};
map_container_place(self, slot, key, value);
self->count++;
return NO_ERROR;
}
error_t
map_container_remove(
map_container_mptr_t map,
malunal_iptr_t key
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
malunal_size_t slot;
impl_mptr_t self = (impl_mptr_t)map;
if (!map_container_find(self, key, &slot))
return NO_ERROR;
malunal_uint8_t* control = map_container_control(self);
malunal_size_t mask = self->capacity - 1;
control[slot] = MAP_CONTROL_ERASED;
self->count--;
if (control[(slot + 1) & mask] != MAP_CONTROL_EMPTY)
return NO_ERROR;
malunal_size_t index = slot;
while (control[index] == MAP_CONTROL_ERASED) {
control[index] = MAP_CONTROL_EMPTY;
index = (index - 1) & mask;
}
return NO_ERROR;
}
error_t
map_container_contains(
map_container_iptr_t map,
malunal_iptr_t key
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
malunal_size_t slot;
impl_iptr_t self = (impl_iptr_t)map;
return map_container_find(self, key, &slot)
? NO_ERROR
: (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_FAILURE
};
}
error_t
map_container_clear(
map_container_mptr_t map
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
impl_mptr_t self = (impl_mptr_t)map;
if (self->buffer != null)
memset(self->buffer, MAP_CONTROL_EMPTY, self->capacity);
self->count = 0;
return NO_ERROR;
}
error_t
map_container_get(
map_container_iptr_t map,
malunal_iptr_t key,
malunal_mptr_t value
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
malunal_size_t slot;
impl_iptr_t self = (impl_iptr_t)map;
if (!map_container_find(self, key, &slot))
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_OUT_OF_BOUNDS
};
if (self->valstride != 0)
memcpy(value, map_container_value(self, slot), self->valstride);
return NO_ERROR;
}
error_t
map_container_set(
map_container_mptr_t map,
malunal_iptr_t key,
malunal_iptr_t value
) {
if (map == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
malunal_size_t slot;
impl_mptr_t self = (impl_mptr_t)map;
if (!map_container_find(self, key, &slot))
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_OUT_OF_BOUNDS
};
if (self->valstride != 0)
memcpy(map_container_value(self, slot), value, self->valstride);
return NO_ERROR;
}
+81 -82
View File
@@ -3,9 +3,7 @@
typedef struct {
object_t object;
container_t container;
container_t container;
allocator_mptr_t allocator;
malunal_size_t stride;
malunal_size_t count;
@@ -21,95 +19,60 @@ _Static_assert(
);
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,
.resize = (container_resize_pfn_t)&vector_container_resize,
.reserve = (container_reserve_pfn_t)&vector_container_reserve,
.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
malunal_size_t
power_2_ceil(malunal_size_t capacity) {
if (capacity <= 1)
return 1;
capacity--;
malunal_size_t power = 2;
while (capacity >>= 1)
power <<= 1;
return power;
}
static
error_t
vector_container_realloc(impl_mptr_t self) {
if ((float)self->count / self->capacity < 0.75f)
vector_container_realloc(
impl_mptr_t self,
malunal_size_t capacity
) {
if (capacity <= self->capacity)
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);
malunal_size_t newcap = power_2_ceil(capacity);
malunal_size_t bytes = self->stride * newcap;
error_t result = allocator_acquire(self->allocator, bytes, &buffer);
if (result.domain != null)
return result;
buffer = memmove(buffer, self->buffer, oldcap);
result = allocator_dispose(self->allocator, self->buffer, oldcap);
bytes = self->stride * self->capacity;
buffer = memmove(buffer, self->buffer, bytes);
result = allocator_dispose(self->allocator, self->buffer, bytes);
self->buffer = buffer;
self->capacity = self->capacity * 2;
self->capacity = newcap;
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
) {
@@ -119,22 +82,17 @@ vector_container_init(
.code = CONTAINER_ERROR_NULL_CONTAINER
};
impl_mptr_t self = (impl_mptr_t)vector;
error_t result = allocator_acquire(
allocator,
stride * capacity,
&self->buffer
);
impl_mptr_t self = (impl_mptr_t)vector;
malunal_size_t bytes = stride * MALUNAL_CONTAINERS_VECTOR_INIT_CAPACITY;
error_t result = allocator_acquire(allocator, bytes, &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;
self->capacity = MALUNAL_CONTAINERS_VECTOR_INIT_CAPACITY;
return NO_ERROR;
}
@@ -229,6 +187,41 @@ vector_container_capacity(
return NO_ERROR;
}
error_t
vector_container_resize(
vector_container_mptr_t vector,
malunal_size_t capacity
) {
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, capacity);
if (result.domain != null)
return result;
self->count = capacity;
return NO_ERROR;
}
error_t
vector_container_reserve(
vector_container_mptr_t vector,
malunal_size_t capacity
) {
if (vector == null)
return (error_t) {
.domain = &ERROR_DOMAIN_CONTAINER_T,
.code = CONTAINER_ERROR_NULL_CONTAINER
};
impl_mptr_t self = (impl_mptr_t)vector;
return vector_container_realloc(self, capacity);
}
error_t
vector_container_append(
vector_container_mptr_t vector,
@@ -240,10 +233,13 @@ vector_container_append(
.code = CONTAINER_ERROR_NULL_CONTAINER
};
error_t result = {};
impl_mptr_t self = (impl_mptr_t)vector;
error_t result = vector_container_realloc(self);
if (result.domain != null)
return result;
if ((float)self->count / self->capacity >= 0.75f) {
result = vector_container_realloc(self, self->capacity * 2);
if (result.domain != null)
return result;
}
malunal_uint8_t* buffer = self->buffer;
buffer += self->stride * self->count;
@@ -383,15 +379,18 @@ vector_container_insert_at(
.code = CONTAINER_ERROR_OUT_OF_BOUNDS
};
error_t result = vector_container_realloc(self);
if (result.domain != null)
return result;
error_t result = {};
if ((float)self->count / self->capacity > 0.75f) {
result = vector_container_realloc(self, self->capacity * 2);
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);
memmove(dest, orig, self->stride * (self->count - index));
memcpy(orig, element, self->stride);
self->count++;
return NO_ERROR;
@@ -419,7 +418,7 @@ vector_container_remove_at(
dest += self->stride * index;
malunal_uint8_t* orig = dest + self->stride;
memmove(dest, orig, self->stride * self->count - index);
memmove(dest, orig, self->stride * (self->count - index));
self->count--;
return NO_ERROR;
}