Vector reword + map
This commit is contained in:
+5
-2
@@ -5,6 +5,8 @@ semv: 1.0.0
|
||||
requires:
|
||||
- remote: git@git.erasit.com:malunal/allocators
|
||||
branch: v1.0.0
|
||||
- remote: git@git.erasit.com:malunal/assert
|
||||
branch: v1.0.0
|
||||
- remote: git@git.erasit.com:malunal/microtest
|
||||
branch: v1.0.0
|
||||
- remote: git@git.erasit.com:malunal/types
|
||||
@@ -15,11 +17,12 @@ targets:
|
||||
type: archive
|
||||
deps:
|
||||
- malunal.allocators
|
||||
- malunal.assert
|
||||
- malunal.types
|
||||
srcs:
|
||||
- ./sources/container.c
|
||||
- ./sources/vector.c
|
||||
- ./sources/table.c
|
||||
- ./sources/map.c
|
||||
|
||||
tests:
|
||||
- name: malunal.containers.allinone
|
||||
@@ -29,7 +32,7 @@ tests:
|
||||
- malunal.microtest
|
||||
srcs:
|
||||
- ./tests/vector_container.c
|
||||
- ./tests/table_container.c
|
||||
- ./tests/map_container.c
|
||||
- ./tests/containers.c
|
||||
|
||||
exports:
|
||||
|
||||
+69
-18
@@ -85,6 +85,32 @@ typedef error_t
|
||||
malunal_size_t* capacity
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief A type definition for a pointer to a function which will attempt to
|
||||
* resize the provided @c container to the provided @c capacity.
|
||||
* @param container A pointer to the container to resize.
|
||||
* @param capacity The capacity to resize the container to.
|
||||
* @returns An error code if the container could not be resized.
|
||||
*/
|
||||
typedef error_t
|
||||
(*container_resize_pfn_t)(
|
||||
malunal_mptr_t container,
|
||||
malunal_size_t capacity
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief A type definition for a pointer to a function which will attempt to
|
||||
* reserve the provided @c capacity of memory in the @c container.
|
||||
* @param container A pointer to the container to reserve memory for.
|
||||
* @param capacity The capacity of memory to reserve for the container.
|
||||
* @returns An error code if the container could not reserve memory.
|
||||
*/
|
||||
typedef error_t
|
||||
(*container_reserve_pfn_t)(
|
||||
malunal_mptr_t container,
|
||||
malunal_size_t capacity
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief A type definition for a pointer to a function which will attempt to
|
||||
* append the provided @c element into the provided @c container.
|
||||
@@ -136,12 +162,13 @@ typedef error_t
|
||||
);
|
||||
|
||||
/**
|
||||
* @struct container_vtable
|
||||
* @brief Defines the container virtual function table.
|
||||
* @details Implementing classes of the container interface are expected to
|
||||
* provided valid pointers to these functions that are implementation
|
||||
* specific.
|
||||
*/
|
||||
typedef struct {
|
||||
define_struct(container_vtable) {
|
||||
/**
|
||||
* @brief A pointer for a function which will attempt to provide the
|
||||
* allocator for a provided @c container into the @c out parameter.
|
||||
@@ -166,6 +193,18 @@ typedef struct {
|
||||
*/
|
||||
container_capacity_pfn_t const capacity;
|
||||
|
||||
/**
|
||||
* @brief A type definition for a pointer to a function which will attempt to
|
||||
* resize the provided @c container to the provided @c capacity.
|
||||
*/
|
||||
container_resize_pfn_t const resize;
|
||||
|
||||
/**
|
||||
* @brief A type definition for a pointer to a function which will attempt to
|
||||
* reserve the provided @c capacity of memory in the @c container.
|
||||
*/
|
||||
container_reserve_pfn_t const reserve;
|
||||
|
||||
/**
|
||||
* @brief A pointer to a function which will attempt to append the provided
|
||||
* @c element into the provided @c container.
|
||||
@@ -188,37 +227,24 @@ typedef struct {
|
||||
* @brief A pointer to a function which will clear the provided @c container.
|
||||
*/
|
||||
container_clear_pfn_t const clear;
|
||||
} container_vtable_t;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct container
|
||||
* @brief Defines an abstract class type for containers.
|
||||
* @details Containers are objects which simply store data. They provide ways to
|
||||
* @c append, @c remove, @c find, and @c clear the container. Being an
|
||||
* abstract class like object, it provides some useful member variables
|
||||
* and a virtual function table for container specific functions.
|
||||
*/
|
||||
typedef struct {
|
||||
define_struct(container) {
|
||||
/**
|
||||
* @brief A pointer to an immutable container virtual function table.
|
||||
* @details Contains the function pointer to the container specific functions
|
||||
* that make this container function as one.
|
||||
*/
|
||||
const container_vtable_t* vtable;
|
||||
} container_t;
|
||||
|
||||
/**
|
||||
* @brief A pointer to a mutable container.
|
||||
* @details This is provided to simplify type declarations for functions
|
||||
* requiring containers that are meant to be mutable.
|
||||
*/
|
||||
typedef container_t* container_mptr_t;
|
||||
|
||||
/**
|
||||
* @brief A pointer to an immutable container.
|
||||
* @details This is provided to simplify type declarations for functions
|
||||
* requiring containers that are meant to be immutable.
|
||||
*/
|
||||
typedef const container_t* container_iptr_t;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@@ -229,6 +255,7 @@ typedef const container_t* container_iptr_t;
|
||||
typedef enum {
|
||||
CONTAINER_ERROR_FAILURE,
|
||||
CONTAINER_ERROR_NULL_CONTAINER,
|
||||
CONTAINER_ERROR_NULL_RECEIVER,
|
||||
CONTAINER_ERROR_OUT_OF_BOUNDS,
|
||||
} container_error_t;
|
||||
|
||||
@@ -281,6 +308,30 @@ container_capacity(
|
||||
malunal_size_t* out
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Resizes the container to the specified capacity.
|
||||
* @param container A pointer to the container to resize.
|
||||
* @param capacity The amount of slots to allocate in the container.
|
||||
* @returns An error if the container could not be resized.
|
||||
*/
|
||||
error_t
|
||||
container_resize(
|
||||
container_mptr_t container,
|
||||
malunal_size_t capacity
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Reserves the specified amount of space in the container.
|
||||
* @param container A pointer to the container to reserve space for.
|
||||
* @param capacity The amount of slots in the container to reserve.
|
||||
* @returns An error if the container could not reserve the memory.
|
||||
*/
|
||||
error_t
|
||||
container_reserve(
|
||||
container_mptr_t container,
|
||||
malunal_size_t capacity
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Appends a new element to the container.
|
||||
* @param container A pointer to the container to append the element to.
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
/**
|
||||
* @file map.h
|
||||
* @brief Contains the structures and functions necessary to utilize a map
|
||||
* container implementation.
|
||||
* @author John Christman (sorakatadzuma@gmail.com)
|
||||
* @copyright Malunal Studios, LLC.
|
||||
*/
|
||||
#include "../container.h"
|
||||
|
||||
#ifndef MALUNAL_CONTAINERS_MAP_HEADER
|
||||
#define MALUNAL_CONTAINERS_MAP_HEADER
|
||||
|
||||
/**
|
||||
* @def MALUNAL_CONTAINERS_MAP_INIT_CAPACITY
|
||||
* @brief Defines the initial capacity of maps to simplify initialization.
|
||||
* @details This will tell all maps what their initial capacity should be, which
|
||||
* can be overriden simply by calling the appropriate @c resize or
|
||||
* @c reserve functions.
|
||||
*/
|
||||
#ifndef MALUNAL_CONTAINERS_MAP_INIT_CAPACITY
|
||||
#define MALUNAL_CONTAINERS_MAP_INIT_CAPACITY 16
|
||||
#endif /* MALUNAL_CONTAINERS_MAP_INIT_CAPACITY */
|
||||
|
||||
|
||||
/**
|
||||
* @struct map_container
|
||||
* @brief Defines a class type for maps.
|
||||
* @details Maps store their data contiguously in memory, but are hashed into
|
||||
* their locations within the unreserved portion of the container.
|
||||
* The reserved portion is one control byte per slot, which records
|
||||
* whether the slot is empty, filled, or holds a pair that has been
|
||||
* erased. Maps extend the functionality of containers, so they may be
|
||||
* used in container functions.
|
||||
*/
|
||||
define_struct(map_container) {
|
||||
malunal_size_t __opaque[7];
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct map_pair
|
||||
* @brief Defines a key and its value as a single element.
|
||||
* @details The container interface appends one element at a time, so a map
|
||||
* needs a way to be handed both halves of a pair at once. This is
|
||||
* that way, and it is only ever borrowed by the map: the key and the
|
||||
* value are copied into the map itself.
|
||||
*/
|
||||
define_struct(map_pair) {
|
||||
malunal_iptr_t key;
|
||||
malunal_iptr_t value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initializes a map container with the following @c keystride,
|
||||
* @c valstride, and @c allocator.
|
||||
* @param keystride The size of the key object in bytes.
|
||||
* @param valstride The size of the value object in bytes.
|
||||
* @param allocator The allocator it should use to obtain memory.
|
||||
* @param map A pointer to the map to initialize.
|
||||
* @returns An error if the map could not be initialized.
|
||||
*/
|
||||
error_t
|
||||
map_container_init(
|
||||
malunal_size_t keystride,
|
||||
malunal_size_t valstride,
|
||||
allocator_mptr_t allocator,
|
||||
map_container_mptr_t map
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Frees the backing memory of the map.
|
||||
* @param map A pointer to the map to free.
|
||||
* @returns An error if the map could not be freed.
|
||||
*/
|
||||
error_t
|
||||
map_container_free(
|
||||
map_container_mptr_t map
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Obtains the allocator for the given map.
|
||||
* @param map A pointer to the map to obtain the allocator from.
|
||||
* @param out A pointer to where to store the obtained allocator pointer.
|
||||
* @returns An error if the given map could not provide the allocator.
|
||||
*/
|
||||
error_t
|
||||
map_container_allocator(
|
||||
map_container_iptr_t map,
|
||||
allocator_mptr_t* out
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Obtains the stride for the given map.
|
||||
* @param map A pointer to the map to obtain the stride from.
|
||||
* @param out A pointer to where to store the obtained stride.
|
||||
* @returns An error if the given map could not provide the stride.
|
||||
* @remarks This will get the stride of the key and value together.
|
||||
*/
|
||||
error_t
|
||||
map_container_stride(
|
||||
map_container_iptr_t map,
|
||||
malunal_size_t* out
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Obtains the key stride for the given map.
|
||||
* @param map A pointer to the map to obtain the stride from.
|
||||
* @param out A pointer to where to store the obtained stride.
|
||||
* @returns An error if the given map could not provide the key stride.
|
||||
*/
|
||||
error_t
|
||||
map_container_key_stride(
|
||||
map_container_iptr_t map,
|
||||
malunal_size_t* out
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Obtains the value stride for the given map.
|
||||
* @param map A pointer to the map to obtain the stride from.
|
||||
* @param out A pointer to where to store the obtained stride.
|
||||
* @returns An error if the given map could not provide the value stride.
|
||||
*/
|
||||
error_t
|
||||
map_container_value_stride(
|
||||
map_container_iptr_t map,
|
||||
malunal_size_t* out
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Obtains the count for the given map.
|
||||
* @param map A pointer to the map to obtain the count from.
|
||||
* @param out A pointer to where to store the obtained count.
|
||||
* @returns An error if the given map could not provide the count.
|
||||
*/
|
||||
error_t
|
||||
map_container_count(
|
||||
map_container_iptr_t map,
|
||||
malunal_size_t* out
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Obtains the capacity for the given map.
|
||||
* @param map A pointer to the map to obtain the capacity from.
|
||||
* @param out A pointer to where to store the obtained capacity.
|
||||
* @returns An error if the given map could not provide the capacity.
|
||||
*/
|
||||
error_t
|
||||
map_container_capacity(
|
||||
map_container_iptr_t map,
|
||||
malunal_size_t* out
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Obtains the keys for the given map.
|
||||
* @param map A pointer to the map to obtain the keys of.
|
||||
* @param container A pointer to the container to place the keys in.
|
||||
* @returns An error if the given map could not provide its keys.
|
||||
* @remarks The keys are appended to the container, which must therefore have a
|
||||
* stride equal to the key stride of the map. They are appended in the
|
||||
* order the map happens to store them in, which is not the order they
|
||||
* were inserted in.
|
||||
*/
|
||||
error_t
|
||||
map_container_keys(
|
||||
map_container_iptr_t map,
|
||||
container_mptr_t container
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Obtains the values for the given map.
|
||||
* @param map A pointer to the map to obtain the values of.
|
||||
* @param container A pointer to the container to place the values in.
|
||||
* @returns An error if the given map could not provide its values.
|
||||
* @remarks The values are appended to the container, which must therefore have
|
||||
* a stride equal to the value stride of the map. They are appended in
|
||||
* the same order as the keys of @c map_container_keys, so the two line
|
||||
* up with each other.
|
||||
*/
|
||||
error_t
|
||||
map_container_values(
|
||||
map_container_iptr_t map,
|
||||
container_mptr_t container
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Resizes the map to the specified capacity.
|
||||
* @param map A pointer to the map to resize.
|
||||
* @param capacity The amount of slots to allocate in the map.
|
||||
* @returns An error if the map could not be resized.
|
||||
* @remarks The capacity is rounded up to a power of two and the pairs already
|
||||
* within the map are rehashed into the new slots. Maps only ever
|
||||
* grow, so a capacity which is not greater than the current one is
|
||||
* ignored. Unlike a vector, this does not change the count of the map,
|
||||
* because a slot only holds a pair once one is inserted into it.
|
||||
*/
|
||||
error_t
|
||||
map_container_resize(
|
||||
map_container_mptr_t map,
|
||||
malunal_size_t capacity
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Reserves the specified amount of space in the map.
|
||||
* @param map A pointer to the map to reserve space for.
|
||||
* @param capacity The amount of pairs the map should be able to hold.
|
||||
* @returns An error if the map could not reserve the memory.
|
||||
* @remarks Maps keep slots to spare so that their probe sequences stay short,
|
||||
* so this allocates more slots than the pairs asked for. After this,
|
||||
* that many pairs may be inserted without the map rehashing itself.
|
||||
*/
|
||||
error_t
|
||||
map_container_reserve(
|
||||
map_container_mptr_t map,
|
||||
malunal_size_t capacity
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Appends a new key/value pair to the map.
|
||||
* @param map A pointer to the map to append the pair to.
|
||||
* @param pair A pointer to the key and value pointers.
|
||||
* @returns An error if the map could not append the pair.
|
||||
* @remarks This is @c map_container_insert given a pair instead of two
|
||||
* separate pointers, and it exists so that maps satisfy the append of
|
||||
* the container interface.
|
||||
*/
|
||||
error_t
|
||||
map_container_append(
|
||||
map_container_mptr_t map,
|
||||
map_pair_iptr_t pair
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Inserts a new key/value pair into the map.
|
||||
* @param map A pointer to the map to insert the pair into.
|
||||
* @param key A pointer to the data of the key to insert.
|
||||
* @param value A pointer to the data of the value to insert.
|
||||
* @returns An error if the map could not insert the pair.
|
||||
* @remarks Both the key and the value are copied into the map. When the key is
|
||||
* already present, its value is overwritten and the count of the map
|
||||
* is left alone.
|
||||
*/
|
||||
error_t
|
||||
map_container_insert(
|
||||
map_container_mptr_t map,
|
||||
malunal_iptr_t key,
|
||||
malunal_iptr_t value
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Removes the specified key, with its value, from the map.
|
||||
* @param map A pointer to the map to remove the key from.
|
||||
* @param key A pointer to the data of the key to remove.
|
||||
* @returns An error if the map could not remove the key.
|
||||
* @remarks Removing a key which is not within the map is not an error, it
|
||||
* simply leaves the map as it was.
|
||||
*/
|
||||
error_t
|
||||
map_container_remove(
|
||||
map_container_mptr_t map,
|
||||
malunal_iptr_t key
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Checks the map for the given key.
|
||||
* @param map A pointer to the map to find the key within.
|
||||
* @param key A pointer to the data of the key to search for.
|
||||
* @returns An error if the map could not find the key.
|
||||
* @remarks A key which is not within the map is reported as a
|
||||
* @c CONTAINER_ERROR_FAILURE, which is how the container interface
|
||||
* says that it does not contain something.
|
||||
*/
|
||||
error_t
|
||||
map_container_contains(
|
||||
map_container_iptr_t map,
|
||||
malunal_iptr_t key
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Clears the map, removing all elements from it.
|
||||
* @param map A pointer to the map to clear.
|
||||
* @returns An error if the map could not clear all its elements.
|
||||
*/
|
||||
error_t
|
||||
map_container_clear(
|
||||
map_container_mptr_t map
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Gets the value at the given key from the given map, copying
|
||||
* the data into the memory region of the @c value address.
|
||||
* @param map A pointer to the map to get the value from.
|
||||
* @param key A pointer to the key of the value to obtain.
|
||||
* @param value A pointer to the memory region to copy the value to.
|
||||
* @returns An error if the given map can not get the value.
|
||||
* @remarks A key which is not within the map is reported as a
|
||||
* @c CONTAINER_ERROR_OUT_OF_BOUNDS, the same as an index which is
|
||||
* past the end of a vector.
|
||||
*/
|
||||
error_t
|
||||
map_container_get(
|
||||
map_container_iptr_t map,
|
||||
malunal_iptr_t key,
|
||||
malunal_mptr_t value
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Sets the value of the given key within the given map, copying the
|
||||
* data from the memory region of the @c value.
|
||||
* @param map A pointer to the map to set the value into.
|
||||
* @param key A pointer to the key of the value to set.
|
||||
* @param value A pointer to the value to set within the map.
|
||||
* @returns An error if the given map can not set the value.
|
||||
* @remarks This only overwrites the value of a key which is already within the
|
||||
* map. A key which is not within it is reported as a
|
||||
* @c CONTAINER_ERROR_OUT_OF_BOUNDS, rather than being inserted, which
|
||||
* is what @c map_container_insert is for.
|
||||
*/
|
||||
error_t
|
||||
map_container_set(
|
||||
map_container_mptr_t map,
|
||||
malunal_iptr_t key,
|
||||
malunal_iptr_t value
|
||||
);
|
||||
|
||||
#endif /* MALUNAL_CONTAINERS_MAP_HEADER */
|
||||
@@ -7,43 +7,36 @@
|
||||
*/
|
||||
#include "../container.h"
|
||||
|
||||
#ifndef MALUNAL_VECTOR_HEADER
|
||||
#define MALUNAL_VECTOR_HEADER
|
||||
#ifndef MALUNAL_CONTAINERS_VECTOR_HEADER
|
||||
#define MALUNAL_CONTAINERS_VECTOR_HEADER
|
||||
|
||||
/**
|
||||
* @brief Defines an class type for vectors.
|
||||
* @def MALUNAL_CONTAINERS_VECTOR_INIT_CAPACITY
|
||||
* @brief Defines the initial capacity of vectors to simplify initialization.
|
||||
* @details This will tell all vectors what their initial capacity should be,
|
||||
* which can be overriden simply by calling the appropriate @c resize
|
||||
* or @c reserve functions.
|
||||
*/
|
||||
#ifndef MALUNAL_CONTAINERS_VECTOR_INIT_CAPACITY
|
||||
#define MALUNAL_CONTAINERS_VECTOR_INIT_CAPACITY 16
|
||||
#endif /* MALUNAL_CONTAINERS_VECTOR_INIT_CAPACITY */
|
||||
|
||||
/**
|
||||
* @struct vector_container
|
||||
* @brief Defines a class type for vectors.
|
||||
* @details Vectors store their data contiguously in memory. They extend the
|
||||
* functionality of containers, so they maybe used in container
|
||||
* functions.
|
||||
* @remarks The purpose of defining a separate type definition from @c container
|
||||
* is to make it physically distinct from a container. This also makes
|
||||
* it so other containers cannot accidentally be used in operations
|
||||
* meant for vectors.
|
||||
*/
|
||||
typedef struct {
|
||||
malunal_size_t __opaque[7];
|
||||
} vector_container_t;
|
||||
|
||||
/**
|
||||
* @brief A pointer to a mutable vector.
|
||||
* @details This is provided to simplify type declarations for functions
|
||||
* requiring vectors that are meant to be mutable.
|
||||
*/
|
||||
typedef vector_container_t* vector_container_mptr_t;
|
||||
|
||||
/**
|
||||
* @brief A pointer to an immutable vector.
|
||||
* @details This is provided to simplify type declarations for functions
|
||||
* requiring vectors that are meant to be immutable.
|
||||
*/
|
||||
typedef const vector_container_t* vector_container_iptr_t;
|
||||
define_struct(vector_container) {
|
||||
malunal_size_t __opaque[6];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initializes a vector with the given @c stride, @c capacity, and
|
||||
* @c allocator.
|
||||
* @param stride The size of the objects that it stores in bytes.
|
||||
* @param capacity The initial capacity of objects that it stores.
|
||||
* @param allocator The allocator it should use to obtain memory.
|
||||
* @param vector A pointer to the vector to initialize.
|
||||
* @returns An error if the vector could not be initialized.
|
||||
@@ -51,7 +44,6 @@ typedef const vector_container_t* vector_container_iptr_t;
|
||||
error_t
|
||||
vector_container_init(
|
||||
malunal_size_t stride,
|
||||
malunal_size_t capacity,
|
||||
allocator_mptr_t allocator,
|
||||
vector_container_mptr_t vector
|
||||
);
|
||||
@@ -114,6 +106,30 @@ vector_container_capacity(
|
||||
malunal_size_t* out
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Resizes the vector to the specified capacity.
|
||||
* @param vector A pointer to the vector to resize.
|
||||
* @param capacity The amount of slots to allocate in the vector.
|
||||
* @returns An error if the vector could not be resized.
|
||||
*/
|
||||
error_t
|
||||
vector_container_resize(
|
||||
vector_container_mptr_t vector,
|
||||
malunal_size_t capacity
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Reserves the specified amount of space in the vector.
|
||||
* @param vector A pointer to the vector to reserve space for.
|
||||
* @param capacity The amount of slots in the vector to reserve.
|
||||
* @returns An error if the vector could not reserve the memory.
|
||||
*/
|
||||
error_t
|
||||
vector_container_reserve(
|
||||
vector_container_mptr_t vector,
|
||||
malunal_size_t capacity
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Appends a new element to the vector.
|
||||
* @param vector A pointer to the vector to append the element to.
|
||||
@@ -232,4 +248,4 @@ vector_container_index_of(
|
||||
malunal_size_t* outidx
|
||||
);
|
||||
|
||||
#endif /* MALUNAL_VECTOR_HEADER */
|
||||
#endif /* MALUNAL_CONTAINERS_VECTOR_HEADER */
|
||||
|
||||
+43
-48
@@ -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
@@ -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;
|
||||
}
|
||||
+75
-76
@@ -3,9 +3,7 @@
|
||||
|
||||
|
||||
typedef struct {
|
||||
object_t object;
|
||||
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
|
||||
) {
|
||||
@@ -120,21 +83,16 @@ vector_container_init(
|
||||
};
|
||||
|
||||
impl_mptr_t self = (impl_mptr_t)vector;
|
||||
error_t result = allocator_acquire(
|
||||
allocator,
|
||||
stride * capacity,
|
||||
&self->buffer
|
||||
);
|
||||
|
||||
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 ((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);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,562 @@
|
||||
#include "malunal/containers/map.h"
|
||||
#include "malunal/containers/vector.h"
|
||||
#include "malunal/microtest.h"
|
||||
|
||||
MICROTEST(map_container, can_init_and_free) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
malunal_size_t temporary = 0;
|
||||
|
||||
result = map_container_init(4, 8, libc_allocator(), &map);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
allocator_mptr_t allocator;
|
||||
result = map_container_allocator(&map, &allocator);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_PTR_EQ(allocator, libc_allocator());
|
||||
|
||||
result = map_container_key_stride(&map, &temporary);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(temporary, 4);
|
||||
|
||||
result = map_container_value_stride(&map, &temporary);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(temporary, 8);
|
||||
|
||||
result = map_container_stride(&map, &temporary);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(temporary, 12);
|
||||
|
||||
result = map_container_count(&map, &temporary);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(temporary, 0);
|
||||
|
||||
result = map_container_capacity(&map, &temporary);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(temporary, MALUNAL_CONTAINERS_MAP_INIT_CAPACITY);
|
||||
|
||||
result = map_container_free(&map);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
result = map_container_stride(&map, &temporary);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(temporary, 0);
|
||||
|
||||
result = map_container_count(&map, &temporary);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(temporary, 0);
|
||||
|
||||
result = map_container_capacity(&map, &temporary);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(temporary, 0);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, reports_a_null_map) {
|
||||
error_t result = {};
|
||||
malunal_size_t temporary = 0;
|
||||
|
||||
result = map_container_count(null, &temporary);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_EQ(result.code, CONTAINER_ERROR_NULL_CONTAINER);
|
||||
|
||||
malunal_int32_t key = 1;
|
||||
malunal_int32_t value = 2;
|
||||
result = map_container_insert(null, &key, &value);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_EQ(result.code, CONTAINER_ERROR_NULL_CONTAINER);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, insert_then_get_round_trips_value) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
malunal_int32_t key = 42;
|
||||
malunal_int32_t value = 1337;
|
||||
result = map_container_insert(&map, &key, &value);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
malunal_size_t count = 0;
|
||||
result = map_container_count(&map, &count);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(count, 1);
|
||||
|
||||
malunal_int32_t out = 0;
|
||||
result = map_container_get(&map, &key, &out);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(out, 1337);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, insert_of_existing_key_overwrites_value) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
malunal_int32_t key = 7;
|
||||
malunal_int32_t first = 10;
|
||||
malunal_int32_t second = 20;
|
||||
map_container_insert(&map, &key, &first);
|
||||
result = map_container_insert(&map, &key, &second);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
malunal_size_t count = 0;
|
||||
map_container_count(&map, &count);
|
||||
MICROTEST_EXPECT_EQ(count, 1);
|
||||
|
||||
malunal_int32_t out = 0;
|
||||
map_container_get(&map, &key, &out);
|
||||
MICROTEST_EXPECT_EQ(out, 20);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, append_inserts_the_pair) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
malunal_int32_t key = 3;
|
||||
malunal_int32_t value = 300;
|
||||
map_pair_t pair = { .key = &key, .value = &value };
|
||||
result = map_container_append(&map, &pair);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
malunal_int32_t out = 0;
|
||||
result = map_container_get(&map, &key, &out);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(out, 300);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, get_reports_a_missing_key) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
malunal_int32_t key = 1;
|
||||
malunal_int32_t value = 100;
|
||||
map_container_insert(&map, &key, &value);
|
||||
|
||||
malunal_int32_t missing = 404;
|
||||
malunal_int32_t out = 0;
|
||||
result = map_container_get(&map, &missing, &out);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_EQ(result.code, CONTAINER_ERROR_OUT_OF_BOUNDS);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, set_overwrites_an_existing_key_only) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
malunal_int32_t key = 5;
|
||||
malunal_int32_t value = 50;
|
||||
map_container_insert(&map, &key, &value);
|
||||
|
||||
malunal_int32_t replacement = 555;
|
||||
result = map_container_set(&map, &key, &replacement);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
malunal_int32_t out = 0;
|
||||
map_container_get(&map, &key, &out);
|
||||
MICROTEST_EXPECT_EQ(out, 555);
|
||||
|
||||
malunal_int32_t missing = 404;
|
||||
result = map_container_set(&map, &missing, &replacement);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_EQ(result.code, CONTAINER_ERROR_OUT_OF_BOUNDS);
|
||||
|
||||
malunal_size_t count = 0;
|
||||
map_container_count(&map, &count);
|
||||
MICROTEST_EXPECT_EQ(count, 1);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, contains_finds_a_present_key) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
malunal_int32_t key = 9;
|
||||
malunal_int32_t value = 90;
|
||||
map_container_insert(&map, &key, &value);
|
||||
|
||||
result = map_container_contains(&map, &key);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, contains_rejects_an_absent_key) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
malunal_int32_t key = 9;
|
||||
malunal_int32_t value = 90;
|
||||
map_container_insert(&map, &key, &value);
|
||||
|
||||
malunal_int32_t missing = 404;
|
||||
result = map_container_contains(&map, &missing);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_EQ(result.code, CONTAINER_ERROR_FAILURE);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, remove_erases_the_key) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
malunal_int32_t keys[2] = { 1, 2 };
|
||||
malunal_int32_t vals[2] = { 10, 20 };
|
||||
map_container_insert(&map, &keys[0], &vals[0]);
|
||||
map_container_insert(&map, &keys[1], &vals[1]);
|
||||
|
||||
result = map_container_remove(&map, &keys[0]);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
malunal_size_t count = 0;
|
||||
map_container_count(&map, &count);
|
||||
MICROTEST_EXPECT_EQ(count, 1);
|
||||
|
||||
result = map_container_contains(&map, &keys[0]);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
|
||||
malunal_int32_t out = 0;
|
||||
result = map_container_get(&map, &keys[1], &out);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(out, 20);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, remove_of_absent_key_succeeds) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
malunal_int32_t key = 1;
|
||||
malunal_int32_t value = 10;
|
||||
map_container_insert(&map, &key, &value);
|
||||
|
||||
malunal_int32_t missing = 404;
|
||||
result = map_container_remove(&map, &missing);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
malunal_size_t count = 0;
|
||||
map_container_count(&map, &count);
|
||||
MICROTEST_EXPECT_EQ(count, 1);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, remove_keeps_the_other_keys_reachable) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
for (malunal_int32_t index = 0; index < 256; index++) {
|
||||
malunal_int32_t value = index * 3;
|
||||
map_container_insert(&map, &index, &value);
|
||||
}
|
||||
|
||||
for (malunal_int32_t index = 0; index < 256; index += 2)
|
||||
map_container_remove(&map, &index);
|
||||
|
||||
malunal_size_t count = 0;
|
||||
map_container_count(&map, &count);
|
||||
MICROTEST_EXPECT_EQ(count, 128);
|
||||
|
||||
for (malunal_int32_t index = 1; index < 256; index += 2) {
|
||||
malunal_int32_t out = 0;
|
||||
result = map_container_get(&map, &index, &out);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(out, index * 3);
|
||||
}
|
||||
|
||||
for (malunal_int32_t index = 0; index < 256; index += 2) {
|
||||
result = map_container_contains(&map, &index);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
}
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, remove_reuses_the_erased_slots) {
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
malunal_size_t oldcap = 0;
|
||||
map_container_capacity(&map, &oldcap);
|
||||
for (malunal_int32_t index = 0; index < 4096; index++) {
|
||||
malunal_int32_t value = index * 2;
|
||||
map_container_insert(&map, &index, &value);
|
||||
map_container_remove(&map, &index);
|
||||
}
|
||||
|
||||
malunal_size_t newcap = 0;
|
||||
malunal_size_t count = 0;
|
||||
map_container_capacity(&map, &newcap);
|
||||
map_container_count(&map, &count);
|
||||
MICROTEST_EXPECT_EQ(count, 0);
|
||||
MICROTEST_EXPECT_EQ(newcap, oldcap);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, clear_resets_count_but_keeps_capacity) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
malunal_int32_t keys[2] = { 1, 2 };
|
||||
malunal_int32_t vals[2] = { 10, 20 };
|
||||
map_container_insert(&map, &keys[0], &vals[0]);
|
||||
map_container_insert(&map, &keys[1], &vals[1]);
|
||||
|
||||
result = map_container_clear(&map);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
malunal_size_t count = 99;
|
||||
malunal_size_t capacity = 0;
|
||||
map_container_count(&map, &count);
|
||||
map_container_capacity(&map, &capacity);
|
||||
MICROTEST_EXPECT_EQ(count, 0);
|
||||
MICROTEST_EXPECT_EQ(capacity, MALUNAL_CONTAINERS_MAP_INIT_CAPACITY);
|
||||
|
||||
result = map_container_contains(&map, &keys[0]);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, insert_past_load_factor_grows_the_map) {
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
malunal_size_t capacity = 0;
|
||||
for (malunal_int32_t index = 0; index < 11; index++) {
|
||||
malunal_int32_t value = index * 10;
|
||||
map_container_insert(&map, &index, &value);
|
||||
}
|
||||
|
||||
map_container_capacity(&map, &capacity);
|
||||
MICROTEST_EXPECT_EQ(capacity, MALUNAL_CONTAINERS_MAP_INIT_CAPACITY);
|
||||
|
||||
malunal_int32_t key = 11;
|
||||
malunal_int32_t value = 110;
|
||||
map_container_insert(&map, &key, &value);
|
||||
map_container_capacity(&map, &capacity);
|
||||
MICROTEST_EXPECT_EQ(capacity, MALUNAL_CONTAINERS_MAP_INIT_CAPACITY * 2);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, growth_preserves_every_pair) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
for (malunal_int32_t index = 0; index < 1000; index++) {
|
||||
malunal_int32_t value = index * 7;
|
||||
result = map_container_insert(&map, &index, &value);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
}
|
||||
|
||||
malunal_size_t count = 0;
|
||||
malunal_size_t capacity = 0;
|
||||
map_container_count(&map, &count);
|
||||
map_container_capacity(&map, &capacity);
|
||||
MICROTEST_EXPECT_EQ(count, 1000);
|
||||
MICROTEST_EXPECT_GE(capacity, 1334);
|
||||
|
||||
for (malunal_int32_t index = 0; index < 1000; index++) {
|
||||
malunal_int32_t out = 0;
|
||||
result = map_container_get(&map, &index, &out);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(out, index * 7);
|
||||
}
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, resize_rounds_to_power_of_two) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
result = map_container_resize(&map, 24);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
malunal_size_t capacity = 0;
|
||||
map_container_capacity(&map, &capacity);
|
||||
MICROTEST_EXPECT_EQ(capacity, 32);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, resize_preserves_pairs_and_the_count) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
for (malunal_int32_t index = 0; index < 8; index++) {
|
||||
malunal_int32_t value = index * 11;
|
||||
map_container_insert(&map, &index, &value);
|
||||
}
|
||||
|
||||
result = map_container_resize(&map, 128);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
malunal_size_t count = 0;
|
||||
map_container_count(&map, &count);
|
||||
MICROTEST_EXPECT_EQ(count, 8);
|
||||
|
||||
for (malunal_int32_t index = 0; index < 8; index++) {
|
||||
malunal_int32_t out = 0;
|
||||
result = map_container_get(&map, &index, &out);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(out, index * 11);
|
||||
}
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, reserve_holds_the_pairs_without_regrowing) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
|
||||
result = map_container_reserve(&map, 100);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
malunal_size_t reserved = 0;
|
||||
map_container_capacity(&map, &reserved);
|
||||
MICROTEST_EXPECT_GE(reserved, 134);
|
||||
|
||||
for (malunal_int32_t index = 0; index < 100; index++) {
|
||||
malunal_int32_t value = index;
|
||||
map_container_insert(&map, &index, &value);
|
||||
}
|
||||
|
||||
malunal_size_t capacity = 0;
|
||||
map_container_capacity(&map, &capacity);
|
||||
MICROTEST_EXPECT_EQ(capacity, reserved);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, keys_and_values_line_up_with_each_other) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
vector_container_t keys = {};
|
||||
vector_container_t values = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
vector_container_init(sizeof(malunal_int32_t), libc_allocator(), &keys);
|
||||
vector_container_init(sizeof(malunal_int32_t), libc_allocator(), &values);
|
||||
|
||||
for (malunal_int32_t index = 0; index < 50; index++) {
|
||||
malunal_int32_t value = index * 5;
|
||||
map_container_insert(&map, &index, &value);
|
||||
}
|
||||
|
||||
result = map_container_keys(&map, (container_mptr_t)&keys);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
result = map_container_values(&map, (container_mptr_t)&values);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
malunal_size_t keycount = 0;
|
||||
malunal_size_t valcount = 0;
|
||||
vector_container_count(&keys, &keycount);
|
||||
vector_container_count(&values, &valcount);
|
||||
MICROTEST_EXPECT_EQ(keycount, 50);
|
||||
MICROTEST_EXPECT_EQ(valcount, 50);
|
||||
|
||||
for (malunal_size_t index = 0; index < keycount; index++) {
|
||||
malunal_int32_t key = 0;
|
||||
malunal_int32_t value = 0;
|
||||
malunal_int32_t expected = 0;
|
||||
vector_container_get(&keys, index, &key);
|
||||
vector_container_get(&values, index, &value);
|
||||
map_container_get(&map, &key, &expected);
|
||||
MICROTEST_EXPECT_EQ(value, expected);
|
||||
MICROTEST_EXPECT_EQ(value, key * 5);
|
||||
}
|
||||
|
||||
vector_container_free(&values);
|
||||
vector_container_free(&keys);
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, keys_rejects_a_mismatched_container) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
vector_container_t keys = {};
|
||||
map_container_init(sizeof(malunal_int32_t), sizeof(malunal_int32_t),
|
||||
libc_allocator(), &map);
|
||||
vector_container_init(sizeof(malunal_int64_t), libc_allocator(), &keys);
|
||||
|
||||
result = map_container_keys(&map, (container_mptr_t)&keys);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_EQ(result.code, CONTAINER_ERROR_FAILURE);
|
||||
|
||||
result = map_container_keys(&map, null);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_EQ(result.code, CONTAINER_ERROR_NULL_RECEIVER);
|
||||
|
||||
vector_container_free(&keys);
|
||||
map_container_free(&map);
|
||||
}
|
||||
|
||||
MICROTEST(map_container, handles_keys_which_are_not_scalars) {
|
||||
error_t result = {};
|
||||
map_container_t map = {};
|
||||
map_container_init(8, sizeof(malunal_int32_t), libc_allocator(), &map);
|
||||
|
||||
malunal_char_t keys[3][8] = { "alpha", "beta", "gamma" };
|
||||
for (malunal_int32_t index = 0; index < 3; index++) {
|
||||
malunal_int32_t value = index + 1;
|
||||
result = map_container_insert(&map, keys[index], &value);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
}
|
||||
|
||||
for (malunal_int32_t index = 0; index < 3; index++) {
|
||||
malunal_int32_t out = 0;
|
||||
result = map_container_get(&map, keys[index], &out);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(out, index + 1);
|
||||
}
|
||||
|
||||
malunal_char_t missing[8] = "delta";
|
||||
result = map_container_contains(&map, missing);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
|
||||
map_container_free(&map);
|
||||
}
|
||||
+74
-33
@@ -6,13 +6,13 @@ MICROTEST(vector_container, can_init_and_free) {
|
||||
vector_container_t vector = {};
|
||||
malunal_size_t temporary = 0;
|
||||
|
||||
result = vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
result = vector_container_init(4, libc_allocator(), &vector);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
allocator_mptr_t allocator;
|
||||
result = vector_container_allocator(&vector, &allocator);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(allocator, libc_allocator());
|
||||
MICROTEST_EXPECT_PTR_EQ(allocator, libc_allocator());
|
||||
|
||||
result = vector_container_stride(&vector, &temporary);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
@@ -24,7 +24,7 @@ MICROTEST(vector_container, can_init_and_free) {
|
||||
|
||||
result = vector_container_capacity(&vector, &temporary);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
MICROTEST_EXPECT_EQ(temporary, 32);
|
||||
MICROTEST_EXPECT_EQ(temporary, MALUNAL_CONTAINERS_VECTOR_INIT_CAPACITY);
|
||||
|
||||
result = vector_container_free(&vector);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
@@ -42,10 +42,49 @@ MICROTEST(vector_container, can_init_and_free) {
|
||||
MICROTEST_EXPECT_EQ(temporary, 0);
|
||||
}
|
||||
|
||||
MICROTEST(vector_container, resize_rounds_to_power_of_two) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
result = vector_container_resize(&vector, 24);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
|
||||
malunal_size_t capacity = 0;
|
||||
vector_container_capacity(&vector, &capacity);
|
||||
MICROTEST_EXPECT_EQ(capacity, 32);
|
||||
printf("Capacity = %d\n", capacity);
|
||||
|
||||
vector_container_free(&vector);
|
||||
}
|
||||
|
||||
MICROTEST(vector_container, resize_perserves_elements) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_size_t capacity = 0;
|
||||
vector_container_capacity(&vector, &capacity);
|
||||
for (malunal_int32_t index = 0; index < capacity; index++) {
|
||||
malunal_int32_t value = (index + 1) * 10;
|
||||
vector_container_append(&vector, &value);
|
||||
}
|
||||
|
||||
result = vector_container_resize(&vector, 24);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
for (malunal_int32_t index = 0; index < capacity; index++) {
|
||||
malunal_int32_t out = 0;
|
||||
vector_container_get(&vector, index, &out);
|
||||
MICROTEST_EXPECT_EQ(out, (index + 1) * 10);
|
||||
}
|
||||
|
||||
vector_container_free(&vector);
|
||||
}
|
||||
|
||||
MICROTEST(vector_container, append_then_get_round_trips_value) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t a = 42;
|
||||
result = vector_container_append(&vector, &a);
|
||||
@@ -67,24 +106,26 @@ MICROTEST(vector_container, append_then_get_round_trips_value) {
|
||||
MICROTEST(vector_container, append_past_capacity_grows_and_preserves) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 4, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t vals[5] = { 10, 20, 30, 40, 50 };
|
||||
for (malunal_int32_t index = 0; index < 5; index++) {
|
||||
result = vector_container_append(&vector, &vals[index]);
|
||||
malunal_size_t oldcap = 0;
|
||||
vector_container_capacity(&vector, &oldcap);
|
||||
for (malunal_int32_t index = 0; index < oldcap + 1; index++) {
|
||||
malunal_int32_t value = (index + 1) * 10;
|
||||
result = vector_container_append(&vector, &value);
|
||||
MICROTEST_EXPECT_NULL(result.domain);
|
||||
}
|
||||
|
||||
malunal_size_t capacity = 0;
|
||||
malunal_size_t newcap = 0;
|
||||
malunal_size_t count = 0;
|
||||
vector_container_capacity(&vector, &capacity);
|
||||
vector_container_capacity(&vector, &newcap);
|
||||
vector_container_count(&vector, &count);
|
||||
MICROTEST_EXPECT_GT(capacity, 5);
|
||||
MICROTEST_EXPECT_EQ(count, 5);
|
||||
for (malunal_int32_t index = 0; index < 5; index++) {
|
||||
MICROTEST_EXPECT_GE(newcap, oldcap * 2);
|
||||
MICROTEST_EXPECT_EQ(count, oldcap + 1);
|
||||
for (malunal_int32_t index = 0; index < oldcap; index++) {
|
||||
malunal_int32_t out = 0;
|
||||
vector_container_get(&vector, index, &out);
|
||||
MICROTEST_EXPECT_EQ(out, vals[index]);
|
||||
MICROTEST_EXPECT_EQ(out, (index + 1) * 10);
|
||||
}
|
||||
|
||||
vector_container_free(&vector);
|
||||
@@ -93,7 +134,7 @@ MICROTEST(vector_container, append_past_capacity_grows_and_preserves) {
|
||||
MICROTEST(vector_container, remove_first_matching_element) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t vals[3] = { 10, 20, 30 };
|
||||
vector_container_append(&vector, &vals[0]);
|
||||
@@ -117,7 +158,7 @@ MICROTEST(vector_container, remove_first_matching_element) {
|
||||
MICROTEST(vector_container, remove_of_absent_element_succeeds) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t a = 1;
|
||||
vector_container_append(&vector, &a);
|
||||
@@ -134,7 +175,7 @@ MICROTEST(vector_container, remove_of_absent_element_succeeds) {
|
||||
MICROTEST(vector_container, contains_finds_a_present_element) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t a = 1;
|
||||
malunal_int32_t b = 2;
|
||||
@@ -150,7 +191,7 @@ MICROTEST(vector_container, contains_finds_a_present_element) {
|
||||
MICROTEST(vector_container, contains_rejects_an_absent_element) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t a = 1;
|
||||
malunal_int32_t b = 2;
|
||||
@@ -159,7 +200,7 @@ MICROTEST(vector_container, contains_rejects_an_absent_element) {
|
||||
|
||||
malunal_int32_t missing = 404;
|
||||
result = vector_container_contains(&vector, &missing);
|
||||
MICROTEST_EXPECT_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_EQ(result.code, CONTAINER_ERROR_FAILURE);
|
||||
|
||||
vector_container_free(&vector);
|
||||
@@ -168,7 +209,7 @@ MICROTEST(vector_container, contains_rejects_an_absent_element) {
|
||||
MICROTEST(vector_container, clear_resets_count_but_keeps_capacity) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t a = 1;
|
||||
malunal_int32_t b = 2;
|
||||
@@ -183,7 +224,7 @@ MICROTEST(vector_container, clear_resets_count_but_keeps_capacity) {
|
||||
vector_container_count(&vector, &count);
|
||||
vector_container_capacity(&vector, &capacity);
|
||||
MICROTEST_EXPECT_EQ(count, 0);
|
||||
MICROTEST_EXPECT_EQ(capacity, 32);
|
||||
MICROTEST_EXPECT_EQ(capacity, MALUNAL_CONTAINERS_VECTOR_INIT_CAPACITY);
|
||||
|
||||
vector_container_free(&vector);
|
||||
}
|
||||
@@ -191,7 +232,7 @@ MICROTEST(vector_container, clear_resets_count_but_keeps_capacity) {
|
||||
MICROTEST(vector_container, set_overwrites_existing_element) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t vals[3] = { 10, 20, 333 };
|
||||
vector_container_append(&vector, &vals[0]);
|
||||
@@ -210,17 +251,17 @@ MICROTEST(vector_container, set_overwrites_existing_element) {
|
||||
MICROTEST(vector_container, get_set_reports_out_of_bounds_at_count) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t a = 10;
|
||||
malunal_int32_t out = 0;
|
||||
result = vector_container_get(&vector, 4, &out);
|
||||
MICROTEST_EXPECT_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_EQ(result.code, CONTAINER_ERROR_OUT_OF_BOUNDS);
|
||||
|
||||
result = NO_ERROR;
|
||||
result = vector_container_set(&vector, 4, &out);
|
||||
MICROTEST_EXPECT_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_EQ(result.code, CONTAINER_ERROR_OUT_OF_BOUNDS);
|
||||
|
||||
vector_container_free(&vector);
|
||||
@@ -229,7 +270,7 @@ MICROTEST(vector_container, get_set_reports_out_of_bounds_at_count) {
|
||||
MICROTEST(vector_container, insert_at_end_appends_value) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t vals[3] = { 10, 20, 30 };
|
||||
vector_container_append(&vector, &vals[0]);
|
||||
@@ -248,7 +289,7 @@ MICROTEST(vector_container, insert_at_end_appends_value) {
|
||||
MICROTEST(vector_container, insert_at_middle_shifts_later_elements) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t vals[3] = { 10, 20, 30 };
|
||||
vector_container_append(&vector, &vals[0]);
|
||||
@@ -271,7 +312,7 @@ MICROTEST(vector_container, insert_at_middle_shifts_later_elements) {
|
||||
MICROTEST(vector_container, remove_at_last_preserves_earlier_elements) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t vals[3] = { 10, 20, 30 };
|
||||
vector_container_append(&vector, &vals[0]);
|
||||
@@ -297,7 +338,7 @@ MICROTEST(vector_container, remove_at_last_preserves_earlier_elements) {
|
||||
MICROTEST(vector_container, remove_at_middle_shifts_later_elements_left) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t vals[3] = { 10, 20, 30 };
|
||||
vector_container_append(&vector, &vals[0]);
|
||||
@@ -323,10 +364,10 @@ MICROTEST(vector_container, remove_at_middle_shifts_later_elements_left) {
|
||||
MICROTEST(vector_container, remove_at_on_empty_vector_is_out_of_bounds) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
result = vector_container_remove_at(&vector, 0);
|
||||
MICROTEST_EXPECT_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_PTR_EQ(result.domain, &ERROR_DOMAIN_CONTAINER_T);
|
||||
MICROTEST_EXPECT_EQ(result.code, CONTAINER_ERROR_OUT_OF_BOUNDS);
|
||||
|
||||
vector_container_free(&vector);
|
||||
@@ -335,7 +376,7 @@ MICROTEST(vector_container, remove_at_on_empty_vector_is_out_of_bounds) {
|
||||
MICROTEST(vector_container, index_of_finds_present_element) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t vals[3] = { 50, 60, 70 };
|
||||
vector_container_append(&vector, &vals[0]);
|
||||
@@ -353,7 +394,7 @@ MICROTEST(vector_container, index_of_finds_present_element) {
|
||||
MICROTEST(vector_container, index_of_reports_missing_element) {
|
||||
error_t result = {};
|
||||
vector_container_t vector = {};
|
||||
vector_container_init(4, 32, libc_allocator(), &vector);
|
||||
vector_container_init(4, libc_allocator(), &vector);
|
||||
|
||||
malunal_int32_t a = 50;
|
||||
vector_container_append(&vector, &a);
|
||||
|
||||
Reference in New Issue
Block a user