2025-11-06 16:36:00 +01:00
<div align="center">
<h1>Datum</h1>
<h6><i>Collection of dynamic and generic data structures.</i></h6>
2025-11-17 16:41:09 +01:00
[](https://github.com/ceticamarco/datum/actions/workflows/gcc-build.yml)
[](https://github.com/ceticamarco/datum/actions/workflows/clang-build.yml)
2025-11-06 16:36:00 +01:00
</div>
2025-11-06 12:16:27 +01:00
Datum is a collection of dynamic and generic data structures implemented from scratch in C with no external dependencies beyond
the standard library. It currently features:
2025-11-10 10:49:23 +01:00
- [**Vector** ](/docs/vector.md ): a growable, contiguous array of homogenous generic data types;
- [**Map** ](/docs/map.md ): an associative array that handles generic heterogenous data types;
2026-01-12 11:58:32 +01:00
- [**BigInt** ](/docs/bigint.md ): a data type for arbitrary large integers.
2025-11-06 12:16:27 +01:00
## Usage
At its simplest, you can use this library as follows:
2025-11-12 16:27:16 +01:00
### `Vector` usage
2025-11-06 12:16:27 +01:00
```c
#include <stdio.h>
#include "src/vector.h"
2026-01-23 17:06:13 +01:00
vector_order_t cmp_asc(const void *a, const void *b);
2025-12-22 14:56:10 +01:00
int is_even(const void *element, void *env);
2025-12-22 12:23:35 +01:00
2026-01-23 17:06:13 +01:00
/* Compile with: gcc main.c src/vector.c
* Output: '2 4'
*/
2025-11-06 12:16:27 +01:00
int main(void) {
2026-01-23 17:06:13 +01:00
vector_t *vec = vector_new(5, sizeof(int)).value.vector; // Create a vector of integers
2025-11-06 12:16:27 +01:00
2026-01-23 17:06:13 +01:00
int nums[] = {5, 4, 1, 2, 3}; // Push some elements
for (int idx = 0; idx < 5; idx++) { vector_push(vec, &nums[idx]); }
2025-11-06 12:16:27 +01:00
2026-01-23 17:06:13 +01:00
vector_sort(vec, cmp_asc); // Sort vector
vector_filter(vec, is_even, NULL); // Filter even elements
2025-12-22 12:23:35 +01:00
2026-01-23 17:06:13 +01:00
for (int idx = 0; idx < 2; idx++) {
printf("%d ", * (int * )vector_get(vec, idx).value.element);
}
putchar('\n');
2025-11-06 12:16:27 +01:00
2026-01-23 17:06:13 +01:00
vector_destroy(vec); // Remove vector from memory
2025-11-06 12:16:27 +01:00
return 0;
}
2025-12-22 14:56:10 +01:00
2026-01-23 17:06:13 +01:00
vector_order_t cmp_asc(const void *a, const void *b) {
const int x = * (int * )a, y = * (int * )b;
2025-12-22 14:56:10 +01:00
2026-01-23 17:06:13 +01:00
if (x < y) return VECTOR_ORDER_LT;
return (x > y) ? VECTOR_ORDER_GT : VECTOR_ORDER_EQ;
2025-12-22 14:56:10 +01:00
}
int is_even(const void *element, void *env) {
(void)(env);
int value = * (int * )element;
return (value % 2) == 0;
}
2025-11-06 12:16:27 +01:00
```
2025-11-12 16:27:16 +01:00
### `Map` usage
2025-11-06 12:16:27 +01:00
```c
#include <stdio.h>
#include "src/map.h"
typedef struct {
char name[256];
char surname[256];
short age;
} Person;
/*
2025-11-06 16:36:00 +01:00
* Compile with: gcc main.c src/map.c
* Output: Name: Bob, Surname: Smith, Age: 34
*/
2025-11-06 12:16:27 +01:00
int main(void) {
// Create a new map
map_t *map = map_new().value.map;
// Add a key to the map
2025-11-06 16:36:00 +01:00
const Person bob = { .name = "Bob", .surname = "Smith", .age = 34 };
2025-11-06 12:16:27 +01:00
map_add(map, "bob", (void*)&bob);
// Retrieve 'Bob' and check if it exists
map_result_t bob_res = map_get(map, "bob");
if (bob_res.status == MAP_ERR_NOT_FOUND) {
puts("This key does not exist.");
} else {
2025-11-06 16:36:00 +01:00
const Person * ret = (const Person * )bob_res.value.element;
printf("Name: %s, Surname: %s, Age: %d\n",
ret->name,
ret->surname,
ret->age
);
2025-11-06 12:16:27 +01:00
}
// Remove map from memory
map_destroy(map);
return 0;
}
```
2025-11-12 16:27:16 +01:00
### `BigInt` usage
```c
#include "src/bigint.h"
/*
2025-11-17 16:41:09 +01:00
* Compile with: gcc -O3 main.c src/bigint.c src/vector.c
2025-11-12 16:27:16 +01:00
* Output: 20000! = 1819206320230345134827641...
2025-11-17 16:41:09 +01:00
* Time: 4.01s user 0.00s system 99% cpu 4.021 total
2025-11-12 16:27:16 +01:00
*/
int main(void) {
const int n = 20000;
bigint_t *fact = bigint_from_int(1).value.number;
2025-11-17 16:41:09 +01:00
for (int idx = 2; idx <= n; idx++) {
2025-11-12 16:27:16 +01:00
bigint_t *big_idx = bigint_from_int(idx).value.number;
bigint_t *partial_fact = bigint_prod(fact, big_idx).value.number;
bigint_destroy(fact);
bigint_destroy(big_idx);
fact = partial_fact;
}
2025-11-17 16:41:09 +01:00
bigint_printf("%d! = %B\n", n, fact);
2025-11-12 16:27:16 +01:00
bigint_destroy(fact);
return 0;
}
```
2026-01-23 17:06:13 +01:00
<<<<<<< HEAD
=======
### `String` usage:
```c
#include <stdio.h>
#include "src/string.h"
/*
* Compile with: gcc main.c src/string.c
* Output: Final string: "Hello,World,😀" Splitted: ["Hello" "World" "😀" ]
*/
int main(void) {
string_t *x = string_new(" Hello, ").value.string;
string_t *x_trm = string_trim(x).value.string;
string_t *y = string_new("😀,dlroW").value.string;
string_t *y_rev = string_reverse(y).value.string;
string_t *str = string_concat(x_trm, y_rev).value.string;
string_t **strings = string_split(str, ",").value.split.strings;
printf("Final string: \"%s\" Splitted: [", str->data);
for (int idx = 0; idx < 3; idx++) { printf("\"%s\" ", strings[idx]->data); }
printf("]\n");
string_split_destroy(strings, 3); string_destroy(str);
string_destroy(x); string_destroy(y);
string_destroy(x_trm); string_destroy(y_rev);
return 0;
}
```
>>>>>>> 7d95b32 (Updated documentation)
2025-11-06 12:16:27 +01:00
For a more exhaustive example, refer to the `usage.c` file. There, you will find a program with proper error management
and a sample usage for every available method. To run it, first issue the following command:
```sh
$ make clean all
```
2025-11-25 16:46:20 +01:00
This will compile the library as well as the `usage.c` file, the unit tests and the benchmark. After that, you can run it by typing `./usage` .
2025-11-06 12:16:27 +01:00
2025-12-17 17:04:16 +01:00
> [!NOTE]
> This project is primarily developed for learning purposes and was not created with industrial
> or production use in mind. As such, it is not intended to compete with any existing C library.
> In particular, the big number implementation does not aim to match the design, the maturity and
> the performance of established solutions such as the
> GNU Multiple Precision Arithmetic Library (GMP).
2025-11-10 10:49:23 +01:00
## Documentation
2026-01-23 17:06:13 +01:00
For additional details about this library (internal design, memory management, data ownership, etc.) go to the [docs folder ](/docs ).
2025-11-07 16:54:21 +01:00
2025-11-06 12:16:27 +01:00
## Unit tests
2025-11-17 16:41:09 +01:00
Datum provides some unit tests for `Vector` , `Map` and `BigInt` . To run them, you can issue the following commands:
2025-11-06 12:16:27 +01:00
```sh
$ make clean all
$ ./test_vector
$ ./test_map
2025-11-17 16:41:09 +01:00
$ ./test_bigint
2025-11-06 12:16:27 +01:00
```
2025-11-25 16:46:20 +01:00
## Benchmark
Under the [`benchmark/` ](/benchmark/ ) folder, you can find a simple benchmark program that stress the `Vector` and the `Map` data structures. You can run it by issuing the following command:
```sh
$ ./benchmark_datum
Computing Vector average time...average time: 18 ms
Computing Map average time...average time: 31 ms
```
2025-12-17 17:04:16 +01:00
2025-11-06 12:16:27 +01:00
## License
This library is released under the GPLv3 license. You can find a copy of the license with this repository or by visiting
2025-11-06 16:36:00 +01:00
[the following link ](https://choosealicense.com/licenses/gpl-3.0/ ).