overview about the design choices behind Datum. While both structures use `void*` to represent values, the way they manage memory is orthogonally different
from one another. Let's start with the `Map` data type.
`Map` is an hash table implementation that uses open addressing with linear probing for collision resolution and the
[FNV-1a algorithm](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function) as its hashing function. Resizing is performed automatically
by doubling the capacity when load factor exceeds 75%. Internally, this data structure is represented
by the following structures:
```c
typedef struct {
char *key;
void *value;
element_state_t state;
} map_element_t;
typedef struct {
map_element_t *elements;
size_t capacity;
size_t size;
size_t tombstone_count;
} map_t;
```
where the `key` represent a string used to index the `value`. The state, instead, indicates
whether the entry is empty, occupied or deleted and is primarily used by the garbage collector
for internal memory management. An array of `map_element_t` as well as variables indicating
the capacity, the current size and the tombstone count (that is, the number of deleted entries)
forms a `map_t` data type.
The keys are **copied** by the hashmap. This means that the hashmap **owns** them and is responsible
to manage their memory. Values, on the other hand, **are stored as pointers**. This means that the hashmap **does NOT own them** and that the caller is responsible
for managing their memory; this includes: allocate enough memory for them, ensure that the pointers remain valid for their whole lifecycle on the map,
The `Map` data structures supports the following methods:
-`map_result_t map_new()`: initialize a new map;
-`map_result_t map_add(map, key, value)`: add a `(key, value)` pair to the map;
-`map_result_t map_get(map, key)`: retrieve a values indexed by `key` if it exists;
-`map_result_t map_remove(map, key)`: remove a key from the map if it exists;
-`map_result_t map_clear(map)`: reset the map state;
-`map_result_t map_destroy(map)`: delete the map;
-`size_t map_size(map)`: returns map size (i.e., the number of elements);
-`size_t map_capacity(map)`: returns map capacity (i.e., map total size).
As you can see, most methods that operates on the `Map` data type return a custom type called `map_result_t` which is defined as follows:
```c
typedef enum {
MAP_OK = 0x0,
MAP_ERR_ALLOCATE,
MAP_ERR_INVALID,
MAP_ERR_NOT_FOUND
} map_status_t;
typedef struct {
map_status_t status;
uint8_t message[RESULT_MSG_SIZE];
union {
map_t *map;
void *element;
} value;
} map_result_t;
```
Each method that returns a `map_result_t` indicates whether the operation was successful or not by setting the `status` field and by providing a descriptive message on the `message` field.
If the operation was successful (that is, `status == MAP_OK`), you can either move on with the flow
of the program or read the returned
value from the sum data type. Of course,
you can choose to ignore the return value (if you're brave enough :D), as illustrated in the first example of this document.
### Vector
`Vector` is a dynamic array with generic data type support, this means that you can store any kind of homogenous value on this data structure. As in the `Map`'s case,
resizing is performed automatically by increasing the capacity by 1.5 times when the array is full. Internally, this data structure is represented as follows:
```c
typedef struct {
size_t count;
size_t capacity;
size_t data_size;
void *elements;
} vector_t;
```
where the `elements` represents the actual dynamic and generic array, the `data_size`
variable indicates the size (in bytes) of the data type while the count and
the capacity represent the number of stored elements and the total
size of the structure, respectively. The dynamic array copies the values upon
insertion, thus **it owns the data** and is therefore responsible for their
allocation and their deletion.
The dynamic array copies the values upon insertion, thus it is responsible