descriptionA set of Data Structures for the C programming language.
homepage URLhttps://wiki.saulv.es/GDS
repository URLhttps://git.saulv.es/Generic-Data-Structures/
ownersaul@saulv.es
last changeSun, 21 Apr 2024 21:17:12 +0000 (21 23:17 +0200)
last refreshSat, 27 Apr 2024 10:36:31 +0000 (27 12:36 +0200)
content tags
add:
README.adoc
= Generic Data Structures

A set of Data Structures for the C programming language.

It includes:

* Vector
* LinkedList
* AVLTree
* Graph
* Dictionary
* Heap
* Stack
* Queue

These structures are "generic" in the sense that they can store any kind
of data type, by only knowing the size of it.

[source,c]
----
int main(){
    Vector *vec = vector_init(sizeof(int), compare_int);
    int tmp = 12;
    vector_append(vec, &tmp);
    tmp = 3;
    vector_append(vec, &tmp);
    vector_free(vec);
    return 0;
}
----

In the example above, we create a vector of integers.
To do so, we pass sizeof(int) as a parameter when initializing it.
When calling ``vector_append``, the function copies the size of an integer
from the address of the variable 'tmp' into the vector.
Note that these structures store values, not references (i.e. they don't
store the pointer we pass, but rather they copy the value that's inside)

Tip: you can use https://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html[compound literals] to avoid having to declare a variable.
[source,c]
----
vector_append(vec, &(int){12});
vector_append(vec, &(int){3});
----

== How are elements compared?
Since we store "generic" data, there must be a way to compare it.
These structures require a comparator function to be passed as a
parameter when they are initialized.
That function must be like this:
[source,c]
----
int func_name(const void* e_1, const void* e_2);
----
And it must return:

* -1 if e_1 is < than e_2
* 0     if e_1 is == than e_2
* 1 if e_1 is > than e_2

For example:
[source,c]
----
int compare_int(const void* e_1, const void* e_2){
    int i_1 = * (int*) e_1;
    int i_2 = * (int*) e_2;
    return i_1 - i_2;
}

int main(){
    int a = 1;
    int b = 2;
    assert(compare_int(&a, &b) < 0);
    return 0;
}
----

The header file *comparator.h* defines functions to compare the most common data types (int, char, long, etc.)

[source,c]
----
LinkedList *list = list_init(sizeof(char), compare_char); // This list stores chars
----

If you don't need to compare elements inside the structure you can use the ``compare_equal``, ``compare_lesser`` and ``compare_greater`` functions, which always return 0, -1, and 1 respectively.

== Destructors
You can set a "destructor" function to perform additional cleanup.
Say you have a Vector of char*, and you allocate it's elements using malloc.
You can use the ``vector_set_destructor`` function, and pass the ``destroy_ptr`` function as a destructor for that vector.
When freeing the vector or removing an element from it, that "destructor" function will be called on that element(s).
You can also write your own destructors. See ``/example/destructors.c``

*Note:* To remove an element without calling the destructor on that element you can use the pop function instead.

[source,c]
----
// Signature
void destructor_func(void *e); // e is a POINTER to the element to destroy

// Example: destroy a malloc'd pointer
void destroy_ptr(void *e){
    if (e){
        void *ptr;
        memcpy(&ptr, e, sizeof(void*));
        free(ptr);
    }
}

// Example: destroy a struct
struct buffer {
    char *buf; // malloc'd
    size_t capacity;
    size_t size;
};

void destroy_buffer(void *e){
    struct buffer *buffer = (struct buffer*) e;
    free(buffer->buf);
}
----

== Building
You can use the Makefile to build and install the library.

* ``make``: builds the library
* ``make test``: builds and runs test programs
* ``make install``: installs the library on the computer.
                  The default installation path is /usr/local, but it
                  can be overriden by defining INSTALL_PATH (e.g. ``make install INSTALL_PATH=~/.local``)
* ``make uninstall``: removes the library from the computer. Remember to set INSTALL_PATH to the same value as in installation.
* ``make doxygen``: Builds the doxygen documentation.
* ``make clean``: Removes the binaries.

To use the library, just include the header(s) and add
the ``-lGDS`` or ``-lGDS-static`` flags when compiling. The headers are installed in $(INSTALL_PATH)/include/GDS.

Example:
[source,c]
----
#include <GDS/GDS.h> // or #include <GDS/Vector.h>

int main(){
        Vector *v = vector_init(sizeof(int), compare_int);
        // ....
        vector_free(v);
        return 0;
}
----

== Another example:
[source,c]
----
struct Person{
    int id;
    int age;
    char *name;
};

int compare_person(const void* e_1, const void* e_2){
    struct Person p1 = * (struct Person*) e_1;
    struct Person p2 = * (struct Person*) e_2;
    return p1.id - p2.id;
}

int main(){
    Vector *vector = vector_init(sizeof(struct Person), compare_person);
    vector_append(vector, &(struct Person){012345, 23, "My name"});
    vector_free(vector);
}
----
shortlog
5 days ago Saúl ValdelviraAdd make examples recipemain
2024-03-24 Saúl ValdelviraChange free functions
2024-03-22 Saúl ValdelviraFix integer overflow in some compare functions
2024-03-17 Saúl ValdelviraDictionary: Fix bug in dict_put
2024-03-12 Saúl ValdelviraDictionary: Improve dict_redisperse function
2024-03-12 Saúl ValdelviraVector: Add tests for indexing
2024-02-26 Saúl ValdelviraGraph: Remove print_dijkstra_data and print_floyd_data
2024-02-26 Saúl ValdelviraRemove unused <stdio.h> includes
2024-02-18 Saúl Valdelviraexamples/matrix.c: replace old function name
2024-02-12 Saúl ValdelviraDictionary: Fix double free error
2024-02-10 Saúl ValdelviraRemove unused includes
2024-01-31 Saúl ValdelviraVector: Remove check for VECTOR_GROW_FACTOR
2024-01-28 Saúl Valdelviradoxygen: Adapt to README.adoc
2024-01-27 Saúl ValdelviraVector: Rename max_elements to capacity
2024-01-26 Saúl ValdelviraREADME: Fix a few things
2024-01-12 Saúl ValdelviraDecorate make output
...
heads
5 days ago main