Commit 1fbaf7eb authored by mir's avatar mir

Added for_each algorithm and Doxygen documentation. Fix minors. Add ctest (not...

Added for_each algorithm and Doxygen documentation. Fix minors. Add ctest (not working at the moment)
parent ec3a17de
add_library(alg OBJECT
find.c
find.c
foreach.c
)
target_include_directories(alg PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
......
......@@ -27,19 +27,20 @@ SOFTWARE.
#include <stdlib.h>
#include <stdio.h>
void* find_if_arr_it(seq_arr_t* arr, void* start_it, void* end_it, void* value , bool(*f)(const void*, const void*))
elm_arr_t find_if_arr_it(seq_arr_t* arr, void* start_it, void* end_it, void* value , bool(*f)(const void*, const void*))
{
assert(arr != NULL);
while(start_it != end_it){
if(f(value,start_it))
return start_it;
return (elm_arr_t){.found = true, .it = start_it};
start_it = seq_arr_next(arr,start_it);
}
return start_it;
// If I trusted the average developer I should return it=start_it, but I don't.
return (elm_arr_t){.found = false, .it = NULL};
}
void* find_if_arr(seq_arr_t* arr, void* value , bool(*f)(const void*, const void*))
elm_arr_t find_if_arr(seq_arr_t* arr, void* value , bool(*f)(const void*, const void*))
{
assert(arr != NULL);
void* start_it = seq_arr_front(arr);
......
......@@ -28,13 +28,32 @@ SOFTWARE.
#include <stdbool.h>
#include "../ds/seq_arr.h"
// Sequencial containers
typedef struct{
void* it;
bool found;
} elm_arr_t;
// Returns the iterator if the predicate (i.e., f) is true. It returs the seq_arr_end() iterator if not found
void* find_if_arr(seq_arr_t* arr, void* value, bool(*f)(const void* value, const void* it));
// Sequencial containers
// Returns the iterator if the predicate (i.e., f) within the range (i.e., [start_it, end_if) ) is true. It returs the seq_arr_end() iterator if not found
void* find_if_arr_it(seq_arr_t* arr, void* start_it, void* end_it, void* value , bool(*f)(const void* value, const void* it));
/**
* @brief Find elements in an array if the predicate is true
* @param arr The sequence container
* @param value Pointer to the value that will be used by the predicate
* @param f Function representing the predicate
* @return Whether the predicate was fullfilled and the iterator to the element if true
*/
elm_arr_t find_if_arr(seq_arr_t* arr, void* value, bool(*f)(const void* value, const void* it));
/**
* @brief Find elements in an array in the semi-open range [start_it, end_it)
* @param arr The sequence container
* @param start_it Iterator to the first element
* @param end_it Iterator to the one past last element
* @param value Pointer to the value usied in the predicate
* @param f Function representing the predicate
* @return Whether the predicate was fullfilled and the iterator to the element if true
*/
elm_arr_t find_if_arr_it(seq_arr_t* arr, void* start_it, void* end_it, void* value , bool(*f)(const void* value, const void* it));
#endif
/*
MIT License
Copyright (c) 2022 Mikel Irazabal
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "foreach.h"
#include <assert.h>
#include <stdlib.h>
void for_each(seq_arr_t* arr, void* value, void (*f)(void* value, void* it))
{
assert(arr != NULL);
void* it = seq_arr_front(arr);
void* end = seq_arr_end(arr);
while(it != end){
f(value, it);
it = seq_arr_next(arr,it);
}
}
/*
MIT License
Copyright (c) 2022 Mikel Irazabal
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FOR_EACH_ALGORITHM
#define FOR_EACH_ALGORITHM
#include "../ds/seq_arr.h"
/**
* @brief Apply function to each element in the sequence container
* @param arr The sequence container
* @param value Pointer to the value that will be used by the function applied
* @param fn_apply Function called by every element in the sequence container
*/
void for_each(seq_arr_t* arr, void* value, void (*fn_apply)(void* value, void* it));
#endif
......@@ -4,3 +4,8 @@ add_library(ds OBJECT
)
target_include_directories(ds PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
if(ENABLE_TESTS)
add_subdirectory(tests)
endif()
......@@ -106,7 +106,7 @@ void seq_arr_erase(seq_arr_t* arr, void* start_it)
return seq_arr_erase_deep(arr, start_it, NULL);
}
void seq_arr_erase_deep(seq_arr_t* arr, void* start_it, seq_free_func free_func)
void seq_arr_erase_deep(seq_arr_t* arr, void* start_it, void (*free_func)(void* it))
{
// start_it must be in the range of arr->data
assert(arr != NULL);
......@@ -114,7 +114,7 @@ void seq_arr_erase_deep(seq_arr_t* arr, void* start_it, seq_free_func free_func)
return seq_arr_erase_it(arr, start_it, seq_arr_next(arr, start_it), free_func);
}
void seq_arr_erase_it(seq_arr_t* arr, void* start_it, void* end_it, seq_free_func free_func)
void seq_arr_erase_it(seq_arr_t* arr, void* start_it, void* end_it, void (*free_func)(void* it))
{
// start_it && end_it must be in the range of arr->data
assert(arr != NULL);
......@@ -147,33 +147,33 @@ void seq_arr_erase_it(seq_arr_t* arr, void* start_it, void* end_it, seq_free_fun
maybe_shrink(arr);
}
size_t seq_arr_size(seq_arr_t* arr)
size_t seq_arr_size(seq_arr_t const* arr)
{
assert(arr != NULL);
return arr->size;
}
void* seq_arr_front(seq_arr_t* arr)
void* seq_arr_front(seq_arr_t const* arr)
{
assert(arr != NULL);
return arr->data;
}
void* seq_arr_next(seq_arr_t* arr, void* it)
void* seq_arr_next(seq_arr_t const* arr, void const* it)
{
assert(arr != NULL);
assert(it != NULL);
return (uint8_t*)it + arr->elt_size;
}
void* seq_arr_end(seq_arr_t* arr)
void* seq_arr_end(seq_arr_t const* arr)
{
assert(arr != NULL);
assert(arr->data != NULL);
return &arr->data[arr->size*arr->elt_size];
}
void* seq_arr_at(seq_arr_t* arr, uint32_t pos)
void* seq_arr_at(seq_arr_t const* arr, uint32_t pos)
{
assert(arr != NULL);
assert(arr->data != NULL);
......@@ -181,7 +181,7 @@ void* seq_arr_at(seq_arr_t* arr, uint32_t pos)
return arr->data + pos*arr->elt_size;
}
ptrdiff_t seq_arr_dist(seq_arr_t* arr, void* first, void* last)
ptrdiff_t seq_arr_dist(seq_arr_t const* arr, void const* first, void const* last)
{
assert(arr != NULL);
assert(first != NULL);
......
......@@ -41,49 +41,104 @@ typedef struct seq_arr_s{
size_t cap;
} seq_arr_t;
typedef void (*seq_free_func)(void*);
// Init sequence array.
void seq_arr_init(seq_arr_t*, size_t elm_sz);
/**
* Init a sequence container, similar to a constructor
* @brief Constructor.
* @param arr The sequence container
* @param elm_sz value returned by the sizeof operator of the type that the container will hold e.g., sizeof(int).
*/
void seq_arr_init(seq_arr_t* arr, size_t elm_sz);
// Free sequence array.
void seq_arr_free(seq_arr_t*, seq_free_func );
/**
* Free a sequence container, similar to a destructor
* @brief Destructor.
* @param arr The sequence container
* @param free_func Function called for every element while destructing e.g., useful to free memory of deep objects.
*/
void seq_arr_free(seq_arr_t* arr, void (*free_func)(void* it));
// Value semantic. i.e., the void* data will be copied in the array. Shallow copy
/**
* @brief Push back elements into the sequence container. Value semantic. i.e., the void* data will be shallowly copied in the array.
* @param arr The sequence container
* @param data Pointer to the data to be copied
* @param elm_sz Size of the element to be copied e.g., sizeof(int)
*/
void seq_arr_push_back(seq_arr_t* arr, void* data, size_t elm_sz);
// Erase the element pointed by it
/**
* @brief Erase the element pointed by it
* @param arr The sequence container
* @param it Iterator to the element to erase
*/
void seq_arr_erase(seq_arr_t*, void* it);
// Erase the element pointed by it and apply deep free (i.e., call f, before removing )
void seq_arr_erase_deep(seq_arr_t*, void* it, seq_free_func f);
// Erase the elements in the semi-open range [first,last)
// Pass NULL to f, if shallow erased required
void seq_arr_erase_it(seq_arr_t*, void* first, void* last, seq_free_func f);
/**
* @brief Erase the element pointed by it and call the f function. Useful to free deep copies
* @param arr The sequence container
* @param it Iterator to the element to erase
* @param free_func Function to call while erasing element
*/
void seq_arr_erase_deep(seq_arr_t* arr, void* it, void (*free_func)(void* it));
/**
* @brief Erase the elements in the semi-open range [first,last)
* @param arr The sequence container
* @param first Iterator to the first element to erase
* @param last Iterator to the last element. Note that this element will NOT be erased
* @param f Function that will be called by every element while erasing. Useful for deep copies. Pass NULL if shallow
* erased required
*/
void seq_arr_erase_it(seq_arr_t* arr, void* first, void* last, void (*free_func)(void* it));
// Elements in the array
size_t seq_arr_size(seq_arr_t*);
/**
* @brief Elements in the array
* @param arr The sequence container
* @return The number of elements in the sequence container
*/
size_t seq_arr_size(seq_arr_t const* arr);
/////
// Iterators
/////
// Returns iterator to first element
void* seq_arr_front(seq_arr_t*);
// Returns next iterator after it
void* seq_arr_next(seq_arr_t*, void* it);
/**
* @brief First iterator
* @param arr The sequence container
* @return The iterator to the first element in the sequence container
*/
void* seq_arr_front(seq_arr_t const* arr);
// Returns one pass the last iterator
void* seq_arr_end(seq_arr_t*);
/**
* @brief Next iterator
* @param arr The sequence container
* @param it Iterator to a valid element
* @return The iterator to the next element in the sequence container
*/
void* seq_arr_next(seq_arr_t const* arr, void const* it);
// Returns iterator in positions pos
void* seq_arr_at(seq_arr_t*, uint32_t pos);
/**
* @brief End iterator
* @param arr The sequence container
* @return The iterator to one past the last element in the sequence container
*/
void* seq_arr_end(seq_arr_t const* arr);
// Returns distance between iterators
ptrdiff_t seq_arr_dist(seq_arr_t*, void* first, void* last);
/**
* @brief Returns iterator in positions pos
* @param arr The sequence container
* @param pos The position of the element in the sequence container
* @return The iterator to the element
*/
void* seq_arr_at(seq_arr_t const* arr, uint32_t pos);
/**
* @brief Distance between iterators
* @param arr The sequence container
* @param first Iterator to first element
* @param last Iterator to last element
* @return The distance among iterators
*/
ptrdiff_t seq_arr_dist(seq_arr_t const* arr, void const* first, void const* last);
#endif
add_executable(test_seq_arr test_seq_array.c ../seq_arr.c ../../alg/find.c ../../alg/foreach.c)
add_dependencies(tests test_seq_arr)
add_test(NAME test_seq_arr COMMAND my_new_test) # no options required
#include "seq_arr.h"
#include "../alg/find.h"
#include "../seq_arr.h"
#include "../../alg/find.h"
#include "../../alg/foreach.h"
#include <assert.h>
/*
Example to show seq_arr_t capabilities and usage
To compile: gcc seq_arr.c test_seq_array.c ../alg/find.c
To compile: gcc test_seq_array.c ../seq_arr.c ../../alg/find.c ../../alg/foreach.c
*/
......@@ -16,6 +17,28 @@ bool eq_int(const void* value, const void* it)
return *v == *i;
}
static
void sum_elm(void* value, void* it)
{
int* sum = (int*)value;
int* elm = (int*)it;
*sum += *elm;
}
static
int compar(const void* m0, const void* m1)
{
int* a = (int*) m0;
int* b = (int*) m1;
if(*a < *b)
return -1;
if(*a == *b)
return 0;
return 1;
}
int main()
{
......@@ -33,13 +56,19 @@ int main()
// Find element in the array
int value = 50;
void* it = find_if_arr(&arr, &value, eq_int);
elm_arr_t elm = find_if_arr(&arr, &value, eq_int);
assert(elm.found == true);
//Check
assert(*(int*)it == 50);
assert(seq_arr_dist(&arr, seq_arr_front(&arr), it) == 50);
assert(*(int*)elm.it == 50);
assert(seq_arr_dist(&arr, seq_arr_front(&arr), elm.it) == 50);
// Apply predicate to all the elements
int sum = 0;
for_each(&arr, &sum, sum_elm);
assert(sum == 4950); // N*(N+1)/2 -> 99*100/2
// Erase found element in the array
seq_arr_erase(&arr, it);
seq_arr_erase(&arr, elm.it);
// Check
assert(seq_arr_size(&arr) == 99);
assert(*(int*)seq_arr_at(&arr, 50) == 51);
......@@ -49,6 +78,15 @@ int main()
assert(seq_arr_size(&arr) == 9);
assert(*(int*)seq_arr_front(&arr) == 91);
//Recall that C functions qsort and bsearch, also work
int key = 95;
void* base = seq_arr_front(&arr);
size_t nmemb = seq_arr_size(&arr);
size_t size = sizeof(int);
void* it = bsearch(&key, base, nmemb, size, compar);
assert(seq_arr_dist(&arr, seq_arr_front(&arr), it) == 4);
// Free data structure
seq_arr_free(&arr, NULL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment