diff --git a/README.md b/README.md index 0d4c9a8..678ffee 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,43 @@ At its simplest, you can use this library as follows: * Head of vector: 16, size is now: 1 */ +// Callback functions +vector_order_t cmp_int_asc(const void *x, const void *y); +void square(void *element, void *env); +int is_even(const void *element, void *env); +void add(void *accumulator, const void *element, void *env); + +int main(void) { + // Create an integer vector of initial capacity equal to 5 + vector_t *vec = vector_new(5, sizeof(int)).value.vector; + + // Add some elements + vector_push(vec, &(int){1}); // Equivalent as below + int nums[] = {5, 2, 4, 3}; + for (int idx = 0; idx < 4; idx++) { vector_push(vec, &nums[idx]); } + + // Sort array in ascending order: [1, 2, 3, 4, 5] + vector_sort(vec, cmp_int_asc); + + // Print 1st element + const int first = *(int*)vector_get(vec, 0).value.element; + printf("First element: %d\n", first); + + int sum = 0; + vector_map(vec, square, NULL); // Square elements: [1, 2, 3, 4, 5] -> [1, 4, 9, 16, 25] + vector_filter(vec, is_even, NULL); // Filter even elements: [1, 4, 9, 16, 25] -> [4, 16] + vector_reduce(vec, &sum, add, NULL); // Sum elements: [4, 16] -> 20 + + // 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; +} + vector_order_t cmp_int_asc(const void *x, const void *y) { int x_int = *(const int*)x; int y_int = *(const int*)y; @@ -55,42 +92,6 @@ void add(void *accumulator, const void *element, void *env) { (void)(env); *(int*)accumulator += *(int*)element; } - -int main(void) { - // Create an integer vector of initial capacity equal to 5 - vector_t *vec = vector_new(5, sizeof(int)).value.vector; - - // Add some elements - vector_push(vec, &(int){1}); // Equivalent as below - int nums[] = {5, 2, 4, 3}; - for (int idx = 0; idx < 4; idx++) { vector_push(vec, &nums[idx]); } - - // Sort array in ascending order: [1, 2, 3, 4, 5] - vector_sort(vec, cmp_int_asc); - - // Print 1st element - const int first = *(int*)vector_get(vec, 0).value.element; - printf("First element: %d\n", first); - - // Square elements: [1, 2, 3, 4, 5] -> [1, 4, 9, 16, 25] - vector_map(vec, square, NULL); - - // Filter even elements: [1, 4, 9, 16, 25] -> [4, 16] - vector_filter(vec, is_even, NULL); - - // Sume elements: [4, 16] -> 20 - int sum = 0; - vector_reduce(vec, &sum, add, NULL); - - // 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 diff --git a/docs/README.md b/docs/README.md index f7e6320..9968106 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,5 +7,4 @@ At the time being, this documentation includes the following pages: - [vector.md](vector.md): vector documentation; - [map.md](map.md): map documentation; -- [sort.md](sort.md): how to use the `vector_sort` method; - [bigint.md](bigint.md): bigint documentation. diff --git a/docs/sort.md b/docs/sort.md deleted file mode 100644 index 5f2f900..0000000 --- a/docs/sort.md +++ /dev/null @@ -1,177 +0,0 @@ -# Sorting -As indicated in the [its documentation](/docs/vector.md), the `Vector` data type -provides an efficient in-place sorting function called `vector_sort` that uses -a builtin implementation of the [Quicksort algorithm](https://en.wikipedia.org/wiki/Quicksort). This method requires an user-defined comparison procedure which allows the -caller to customize the sorting behavior. The comparison procedure must adhere to the -following specification: - -1. Must return `vector_order_t`, which is defined as follows: - -```c -typedef enum { - VECTOR_ORDER_LT = 0x0, // First element should come before the second - VECTOR_ORDER_EQ, // The two elements are equivalent - VECTOR_ORDER_GT // First element should come after the second -} vector_order_t; -``` - -and indicates the ordering relationship between any two elements. - -2. Must accept two `const void*` parameters representing two elements to compare; -3. Must be self-contained and handle all its own resources. - -Let's look at some examples. For instance, let's say that we want to sort an array -of integers in ascending and descending order: - -```c -#include -#include "src/vector.h" - -vector_order_t cmp_int_asc(const void *x, const void *y) { - int x_int = *(const int*)x; - int y_int = *(const int*)y; - - if (x_int < y_int) return VECTOR_ORDER_LT; - if (x_int > y_int) return VECTOR_ORDER_GT; - - return VECTOR_ORDER_EQ; -} - -vector_order_t cmp_int_desc(const void *x, const void *y) { - return cmp_int_asc(y, x); -} - -/* - * Compile with: gcc main.c src/vector.c - * Output: Before sorting: -8 20 -10 125 34 9 - * After sorting (ascending order): -10 -8 9 20 34 125 - * After sorting (descending order): 125 34 20 9 -8 -10 - */ -int main(void) { - vector_t *v = vector_new(5, sizeof(int)).value.vector; - - int values[] = { -8, 20, -10, 125, 34, 9 }; - for (size_t idx = 0; idx < 6; idx++) { - vector_push(v, &values[idx]); - } - - const size_t sz = vector_size(v); - - // Print unsorted array - printf("Before sorting: "); - for (size_t idx = 0; idx < sz; idx++) { - printf("%d ", *(int*)vector_get(v, idx).value.element); - } - - // Sort array in ascending order - vector_sort(v, cmp_int_asc); - - // Print sorted array - printf("\nAfter sorting (ascending order): "); - for (size_t idx = 0; idx < sz; idx++) { - printf("%d ", *(int*)vector_get(v, idx).value.element); - } - - // Sort array in descending order - vector_sort(v, cmp_int_desc); - - // Print sorted array - printf("\nAfter sorting (descending order): "); - for (size_t idx = 0; idx < sz; idx++) { - printf("%d ", *(int*)vector_get(v, idx).value.element); - } - - printf("\n"); - - vector_destroy(v); - - return 0; -} -``` - -Obviously, you can use the `vector_sort` method on custom data type as well. -For instance, let's suppose that you have a structure representing the employees of -a company and you wish to sort them based on their age and on their name (lexicographic sort): - -```c -#include -#include -#include "src/vector.h" - -typedef struct { - char name[256]; - int age; -} Employee; - -vector_order_t cmp_person_by_age(const void *x, const void *y) { - const Employee *x_person = (const Employee*)x; - const Employee *y_person = (const Employee*)y; - - if (x_person->age < y_person->age) return VECTOR_ORDER_LT; - if (x_person->age > y_person->age) return VECTOR_ORDER_GT; - - return VECTOR_ORDER_EQ; -} - -vector_order_t cmp_person_by_name(const void *x, const void *y) { - const Employee *x_person = (const Employee*)x; - const Employee *y_person = (const Employee*)y; - - const int result = strcmp(x_person->name, y_person->name); - - if(result < 0) return VECTOR_ORDER_LT; - if(result > 0) return VECTOR_ORDER_GT; - - return VECTOR_ORDER_EQ; -} - -/* - * Compile with: gcc main.c src/vector.c - * Output: Sort by age: - * Name: Marco, Age: 25 - * Name: Alice, Age: 28 - * Name: Bob, Age: 45 - * - * Sort by name: - * Name: Alice, Age: 28 - * Name: Bob, Age: 45 - * Name: Marco, Age: 25 - */ -int main(void) { - vector_t *employees = vector_new(5, sizeof(Employee)).value.vector; - - Employee e1 = { .name = "Bob", .age = 45 }; - Employee e2 = { .name = "Alice", .age = 28 }; - Employee e3 = { .name = "Marco", .age = 25 }; - - vector_push(employees, &e1); - vector_push(employees, &e2); - vector_push(employees, &e3); - - // Sort array by age - vector_sort(employees, cmp_person_by_age); - - const size_t sz = vector_size(employees); - - // Print sorted array - printf("Sort by age:\n"); - for (size_t idx = 0; idx < sz; idx++) { - Employee *p = (Employee*)vector_get(employees, idx).value.element; - printf("Name: %s, Age: %d\n", p->name, p->age); - } - - // Sort array by name - vector_sort(employees, cmp_person_by_name); - - // Print sorted array - printf("\nSort by name:\n"); - for (size_t idx = 0; idx < sz; idx++) { - Employee *p = (Employee*)vector_get(employees, idx).value.element; - printf("Name: %s, Age: %d\n", p->name, p->age); - } - - vector_destroy(employees); - - return 0; -} -``` \ No newline at end of file diff --git a/docs/vector.md b/docs/vector.md index 4f10d4f..cd24c0b 100644 --- a/docs/vector.md +++ b/docs/vector.md @@ -84,5 +84,183 @@ In particular, you should be aware of the following design choices: - The `vector_reduce` callback method requires the caller to initialize an _"accumulator"_ variable before calling this method; - The `vector_filter` callback method is expected to return non-zero to keep the element and zero to filter it out. +- The `env` argument is an optional parameter to pass the external environment to the callback function. It is used to mock the behavior of closures, where +the lexical environment is captured when the closure is created. -The documentation for the `vector_sort(map, cmp)` method can be found in [the following document](/docs/sort.md). +## Sorting +As indicated in the [its documentation](/docs/vector.md), the `Vector` data type +provides an efficient in-place sorting function called `vector_sort` that uses +a builtin implementation of the [Quicksort algorithm](https://en.wikipedia.org/wiki/Quicksort). This method requires an user-defined comparison procedure which allows the +caller to customize the sorting behavior. The comparison procedure must adhere to the +following specification: + +1. Must return `vector_order_t`, which is defined as follows: + +```c +typedef enum { + VECTOR_ORDER_LT = 0x0, // First element should come before the second + VECTOR_ORDER_EQ, // The two elements are equivalent + VECTOR_ORDER_GT // First element should come after the second +} vector_order_t; +``` + +and indicates the ordering relationship between any two elements. + +2. Must accept two `const void*` parameters representing two elements to compare; +3. Must be self-contained and handle all its own resources. + +Let's look at some examples. For instance, let's say that we want to sort an array +of integers in ascending and descending order: + +```c +#include +#include "src/vector.h" + +vector_order_t cmp_int_asc(const void *x, const void *y) { + int x_int = *(const int*)x; + int y_int = *(const int*)y; + + if (x_int < y_int) return VECTOR_ORDER_LT; + if (x_int > y_int) return VECTOR_ORDER_GT; + + return VECTOR_ORDER_EQ; +} + +vector_order_t cmp_int_desc(const void *x, const void *y) { + return cmp_int_asc(y, x); +} + +/* + * Compile with: gcc main.c src/vector.c + * Output: Before sorting: -8 20 -10 125 34 9 + * After sorting (ascending order): -10 -8 9 20 34 125 + * After sorting (descending order): 125 34 20 9 -8 -10 + */ +int main(void) { + vector_t *v = vector_new(5, sizeof(int)).value.vector; + + int values[] = { -8, 20, -10, 125, 34, 9 }; + for (size_t idx = 0; idx < 6; idx++) { + vector_push(v, &values[idx]); + } + + const size_t sz = vector_size(v); + + // Print unsorted array + printf("Before sorting: "); + for (size_t idx = 0; idx < sz; idx++) { + printf("%d ", *(int*)vector_get(v, idx).value.element); + } + + // Sort array in ascending order + vector_sort(v, cmp_int_asc); + + // Print sorted array + printf("\nAfter sorting (ascending order): "); + for (size_t idx = 0; idx < sz; idx++) { + printf("%d ", *(int*)vector_get(v, idx).value.element); + } + + // Sort array in descending order + vector_sort(v, cmp_int_desc); + + // Print sorted array + printf("\nAfter sorting (descending order): "); + for (size_t idx = 0; idx < sz; idx++) { + printf("%d ", *(int*)vector_get(v, idx).value.element); + } + + printf("\n"); + + vector_destroy(v); + + return 0; +} +``` + +Obviously, you can use the `vector_sort` method on custom data type as well. +For instance, let's suppose that you have a structure representing the employees of +a company and you wish to sort them based on their age and on their name (lexicographic sort): + +```c +#include +#include +#include "src/vector.h" + +typedef struct { + char name[256]; + int age; +} Employee; + +vector_order_t cmp_person_by_age(const void *x, const void *y) { + const Employee *x_person = (const Employee*)x; + const Employee *y_person = (const Employee*)y; + + if (x_person->age < y_person->age) return VECTOR_ORDER_LT; + if (x_person->age > y_person->age) return VECTOR_ORDER_GT; + + return VECTOR_ORDER_EQ; +} + +vector_order_t cmp_person_by_name(const void *x, const void *y) { + const Employee *x_person = (const Employee*)x; + const Employee *y_person = (const Employee*)y; + + const int result = strcmp(x_person->name, y_person->name); + + if(result < 0) return VECTOR_ORDER_LT; + if(result > 0) return VECTOR_ORDER_GT; + + return VECTOR_ORDER_EQ; +} + +/* + * Compile with: gcc main.c src/vector.c + * Output: Sort by age: + * Name: Marco, Age: 25 + * Name: Alice, Age: 28 + * Name: Bob, Age: 45 + * + * Sort by name: + * Name: Alice, Age: 28 + * Name: Bob, Age: 45 + * Name: Marco, Age: 25 + */ +int main(void) { + vector_t *employees = vector_new(5, sizeof(Employee)).value.vector; + + Employee e1 = { .name = "Bob", .age = 45 }; + Employee e2 = { .name = "Alice", .age = 28 }; + Employee e3 = { .name = "Marco", .age = 25 }; + + vector_push(employees, &e1); + vector_push(employees, &e2); + vector_push(employees, &e3); + + // Sort array by age + vector_sort(employees, cmp_person_by_age); + + const size_t sz = vector_size(employees); + + // Print sorted array + printf("Sort by age:\n"); + for (size_t idx = 0; idx < sz; idx++) { + Employee *p = (Employee*)vector_get(employees, idx).value.element; + printf("Name: %s, Age: %d\n", p->name, p->age); + } + + // Sort array by name + vector_sort(employees, cmp_person_by_name); + + // Print sorted array + printf("\nSort by name:\n"); + for (size_t idx = 0; idx < sz; idx++) { + Employee *p = (Employee*)vector_get(employees, idx).value.element; + printf("Name: %s, Age: %d\n", p->name, p->age); + } + + vector_destroy(employees); + + return 0; +} +```