Commit ec3a17de authored by mir's avatar mir

Add a sequence container in OAI

parent 0accb601
add_subdirectory(alg)
add_subdirectory(ds)
add_boolean_option(ENABLE_TELNETSRV OFF "Whether to build telnet support in modems" OFF)
if(ENABLE_TELNETSRV)
......
add_library(alg OBJECT
find.c
)
target_include_directories(alg PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
/*
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 "find.h"
#include <assert.h>
#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*))
{
assert(arr != NULL);
while(start_it != end_it){
if(f(value,start_it))
return start_it;
start_it = seq_arr_next(arr,start_it);
}
return start_it;
}
void* 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);
void* end_it = seq_arr_end(arr);
return find_if_arr_it(arr, start_it, end_it, value, f);
}
/*
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 FIND_ALGORITHM
#define FIND_ALGORITHM
#include <stdbool.h>
#include "../ds/seq_arr.h"
// Sequencial containers
// 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));
// 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));
#endif
add_library(ds OBJECT
byte_array.c
seq_arr.c
)
target_include_directories(ds PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
/*
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 "seq_arr.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static
const size_t MIN_SIZE = 8;
static
void maybe_expand(seq_arr_t* arr)
{
if(arr->size + 1 == arr->cap){
arr->data = realloc(arr->data, 2*arr->cap*arr->elt_size);
assert(arr->data != NULL && "realloc failed to allocate memory");
arr->cap *=2;
}
}
static
void maybe_shrink(seq_arr_t* arr)
{
const float occ = (float)arr->size / (float)arr->cap;
if(arr->size > MIN_SIZE && occ < 0.25){
assert(arr->cap > MIN_SIZE);
seq_arr_t tmp = {.data = NULL, .size = arr->size, .elt_size = arr->elt_size, .cap = arr->cap/2};
tmp.data = calloc(tmp.cap, tmp.cap);
assert(tmp.data != NULL && "Memory exhausted");
assert(arr->size <= tmp.cap);
memcpy(tmp.data, arr->data, arr->size*arr->elt_size);
free(arr->data);
memcpy(arr, &tmp, sizeof(seq_arr_t));
}
}
void seq_arr_init(seq_arr_t* arr, size_t elt_size) //__attribute__(malloc)
{
assert(arr != NULL);
seq_arr_t tmp = {.data = NULL, .size = 0, .elt_size = elt_size, .cap = MIN_SIZE};
memcpy(arr, &tmp, sizeof(seq_arr_t));
arr->data = calloc(arr->cap, elt_size);
assert(arr->data != NULL);
}
void seq_arr_free(seq_arr_t* arr, void (*free_func)(void*) )
{
assert(arr != NULL);
assert(arr->data != NULL);
if(free_func != NULL) {
void* start_it = seq_arr_front(arr);
void* end_it = seq_arr_end(arr);
while(start_it != end_it){
free_func(start_it);
start_it = seq_arr_next(arr, start_it);
}
}
free(arr->data);
}
void seq_arr_push_back(seq_arr_t* arr, void* data, size_t len)
{
assert(arr != NULL);
assert(arr->data != NULL);
//assert(data != NULL);
assert(len == arr->elt_size);
maybe_expand(arr);
const size_t offset = arr->size * arr->elt_size;
memcpy(&arr->data[offset], data, arr->elt_size);
arr->size += 1;
}
void seq_arr_erase(seq_arr_t* arr, void* start_it)
{
// start_it must be in the range of arr->data
assert(arr != NULL);
assert(start_it != NULL);
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)
{
// start_it must be in the range of arr->data
assert(arr != NULL);
assert(start_it != NULL);
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)
{
// start_it && end_it must be in the range of arr->data
assert(arr != NULL);
assert(start_it != NULL);
assert(end_it != NULL);
assert(end_it >= start_it);
if(start_it == end_it) return;
if(free_func != NULL) {
void* start_it = seq_arr_front(arr);
void* end_it = seq_arr_end(arr);
while(start_it != end_it){
free_func(start_it);
start_it = seq_arr_next(arr, start_it);
}
}
const int num_bytes_move = seq_arr_end(arr) - end_it;
assert(num_bytes_move > -1);
memmove(start_it, end_it, num_bytes_move);
const int num_bytes_erase = end_it - start_it;
const int32_t num_elm_erase = num_bytes_erase/arr->elt_size;
assert(num_elm_erase > 0);
arr->size -= num_elm_erase;
memset(seq_arr_end(arr), 0, num_bytes_erase);
maybe_shrink(arr);
}
size_t seq_arr_size(seq_arr_t* arr)
{
assert(arr != NULL);
return arr->size;
}
void* seq_arr_front(seq_arr_t* arr)
{
assert(arr != NULL);
return arr->data;
}
void* seq_arr_next(seq_arr_t* arr, void* it)
{
assert(arr != NULL);
assert(it != NULL);
return (uint8_t*)it + arr->elt_size;
}
void* seq_arr_end(seq_arr_t* 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)
{
assert(arr != NULL);
assert(arr->data != NULL);
assert(pos < arr->size);
return arr->data + pos*arr->elt_size;
}
ptrdiff_t seq_arr_dist(seq_arr_t* arr, void* first, void* last)
{
assert(arr != NULL);
assert(first != NULL);
assert(last != NULL);
const ptrdiff_t pos = (last - first)/arr->elt_size;
assert(pos > -1);
return pos;
}
/*
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 SEQ_CONTAINER_ARRAY
#define SEQ_CONTAINER_ARRAY
/*
* Basic sequence container with a similar API and behaviour to C++ std::vector
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct seq_arr_s{
uint8_t* data;
size_t size;
const size_t elt_size;
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);
// Free sequence array.
void seq_arr_free(seq_arr_t*, seq_free_func );
// Value semantic. i.e., the void* data will be copied in the array. Shallow copy
void seq_arr_push_back(seq_arr_t* arr, void* data, size_t elm_sz);
// Erase the element pointed by it
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);
// Elements in the array
size_t seq_arr_size(seq_arr_t*);
/////
// 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);
// Returns one pass the last iterator
void* seq_arr_end(seq_arr_t*);
// Returns iterator in positions pos
void* seq_arr_at(seq_arr_t*, uint32_t pos);
// Returns distance between iterators
ptrdiff_t seq_arr_dist(seq_arr_t*, void* first, void* last);
#endif
#include "seq_arr.h"
#include "../alg/find.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
*/
static
bool eq_int(const void* value, const void* it)
{
const int* v = (const int *)value;
const int* i = (const int*)it;
return *v == *i;
}
int main()
{
seq_arr_t arr = {0};
seq_arr_init(&arr, sizeof(int));
// Insert data and expand
for(int i = 0; i < 100; ++i)
seq_arr_push_back(&arr, &i, sizeof(int));
// Check inserted data
assert(seq_arr_size(&arr) == 100);
assert(*(int*)seq_arr_front(&arr) == 0);
assert(*(int*)seq_arr_at(&arr, 25) == 25);
// Find element in the array
int value = 50;
void* it = find_if_arr(&arr, &value, eq_int);
//Check
assert(*(int*)it == 50);
assert(seq_arr_dist(&arr, seq_arr_front(&arr), it) == 50);
// Erase found element in the array
seq_arr_erase(&arr, it);
// Check
assert(seq_arr_size(&arr) == 99);
assert(*(int*)seq_arr_at(&arr, 50) == 51);
// Erase range and force shrink
seq_arr_erase_it(&arr, seq_arr_front(&arr), seq_arr_at(&arr, 90) ,NULL);
assert(seq_arr_size(&arr) == 9);
assert(*(int*)seq_arr_front(&arr) == 91);
// Free data structure
seq_arr_free(&arr, NULL);
return EXIT_SUCCESS;
}
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