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:
- Vector: a growable, contiguous array of homogenous generic data types;
- Map: an associative array that handles generic heterogenous data types;
- BigInt: a data type for arbitrary large integers.
Usage
At its simplest, you can use this library as follows:
Vector usage
#include <stdio.h>
#include "src/vector.h"
/*
* Compile with: gcc main.c src/vector.c
* Output: First element: 5
* Head of vector: 6, size is now: 1
*/
int main(void) {
// Create an integer vector of initial capacity equal to 5
vector_t *vec = vector_new(5, sizeof(int)).value.vector;
// Add two numbers
int val = 5;
vector_push(vec, &val);
// Equivalent as above
vector_push(vec, &(int){6});
// Print 1st element
const int first = *(int*)vector_get(vec, 0).value.element;
printf("First element: %d\n", first);
// Pop second element using LIFO policy
const int head = *(int*)vector_pop(vec).value.element;
printf("Head of vector: %d, size is now: %zu\n", head, vector_size(vec));
// Remove vector from memory
vector_destroy(vec);
return 0;
}
Map usage
#include <stdio.h>
#include "src/map.h"
typedef struct {
char name[256];
char surname[256];
short age;
} Person;
/*
* Compile with: gcc main.c src/map.c
* Output: Name: Bob, Surname: Smith, Age: 34
*/
int main(void) {
// Create a new map
map_t *map = map_new().value.map;
// Add a key to the map
const Person bob = { .name = "Bob", .surname = "Smith", .age = 34 };
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 {
const Person *ret = (const Person*)bob_res.value.element;
printf("Name: %s, Surname: %s, Age: %d\n",
ret->name,
ret->surname,
ret->age
);
}
// Remove map from memory
map_destroy(map);
return 0;
}
BigInt usage
#include <stdio.h>
#include "src/bigint.h"
/*
* Compile with: gcc main.c src/bigint.c
* Output: 20000! = 1819206320230345134827641...
* Time: real 0m5.482s user 0m5.453s sys 0m0.017
*/
int main(void) {
const int n = 20000;
bigint_t *fact = bigint_from_int(1).value.number;
for (int idx = 2; idx<=n; idx++) {
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;
}
printf("%d! = ", n);
bigint_print(fact);
printf("\n");
bigint_destroy(fact);
return 0;
}
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:
$ make clean all
This will compile the library as well as the usage.c file and the unit tests. After that, you can run it by typing ./usage.
Documentation
For additional details about this library (internal design, memory management, data ownership, etc.) go to the docs folder.
Unit tests
Datum provides some unit tests for both the Vector and the Map data types. To run them, you can issue the following commands:
$ make clean all
$ ./test_vector
$ ./test_map
License
This library is released under the GPLv3 license. You can find a copy of the license with this repository or by visiting the following link.