mirror of
https://github.com/tezc/sc.git
synced 2025-01-14 06:43:04 +08:00
queue and array v2
This commit is contained in:
parent
3c8e0f9f70
commit
cce603126f
@ -5,10 +5,10 @@ set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
add_library(
|
||||
sc_array SHARED
|
||||
sc_array.c
|
||||
add_library(sc_array SHARED
|
||||
sc_array.h)
|
||||
set_target_properties(sc_array PROPERTIES LINKER_LANGUAGE C)
|
||||
|
||||
|
||||
target_include_directories(sc_array PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
@ -37,7 +37,7 @@ if (SC_BUILD_TEST)
|
||||
|
||||
enable_testing()
|
||||
|
||||
add_executable(${PROJECT_NAME}_test array_test.c sc_array.c)
|
||||
add_executable(${PROJECT_NAME}_test array_test.c)
|
||||
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_ARRAY_MAX=140000ul)
|
||||
|
||||
|
@ -2,8 +2,9 @@
|
||||
|
||||
### Overview
|
||||
|
||||
- Type generic array/vector.
|
||||
- Index access is possible (e.g float* arr; 'printf("%f", arr[i]')).
|
||||
- Growable array/vector.
|
||||
- It comes with predefined types, check out at the end of sc_array.h, you can
|
||||
add there (sc_array_def) if you need more.
|
||||
|
||||
### Usage
|
||||
|
||||
@ -14,39 +15,40 @@
|
||||
|
||||
void example_str()
|
||||
{
|
||||
char **p, *it;
|
||||
const char *it;
|
||||
struct sc_array_str arr;
|
||||
|
||||
sc_array_create(p, 0);
|
||||
|
||||
sc_array_add(p, "item0");
|
||||
sc_array_add(p, "item1");
|
||||
sc_array_add(p, "item2");
|
||||
sc_array_init(&arr);
|
||||
|
||||
printf("\nDelete first element \n\n");
|
||||
sc_array_del(p, 0);
|
||||
sc_array_add(&arr, "item0");
|
||||
sc_array_add(&arr, "item1");
|
||||
sc_array_add(&arr, "item2");
|
||||
|
||||
sc_array_foreach (p, it) {
|
||||
printf("Elem = %s \n", it);
|
||||
}
|
||||
printf("\nDelete first element \n\n");
|
||||
sc_array_del(&arr, 0);
|
||||
|
||||
sc_array_destroy(p);
|
||||
sc_array_foreach (&arr, it) {
|
||||
printf("Elem = %s \n", it);
|
||||
}
|
||||
|
||||
sc_array_term(&arr);
|
||||
}
|
||||
|
||||
void example_int()
|
||||
{
|
||||
int *p;
|
||||
struct sc_array_int arr;
|
||||
|
||||
sc_array_create(p, 0);
|
||||
sc_array_init(&arr);
|
||||
|
||||
sc_array_add(p, 0);
|
||||
sc_array_add(p, 1);
|
||||
sc_array_add(p, 2);
|
||||
sc_array_add(&arr, 0);
|
||||
sc_array_add(&arr, 1);
|
||||
sc_array_add(&arr, 2);
|
||||
|
||||
for (size_t i = 0; i < sc_array_size(p); i++) {
|
||||
printf("Elem = %d \n", p[i]);
|
||||
}
|
||||
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||
printf("Elem = %d \n", arr.elems[i]);
|
||||
}
|
||||
|
||||
sc_array_destroy(p);
|
||||
sc_array_term(&arr);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -57,45 +59,3 @@ int main(int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
##### Note
|
||||
|
||||
Array pointer is not stable. If you pass the array to another function which
|
||||
can add items, do it by passing reference of the array pointer :
|
||||
|
||||
```c
|
||||
void some_function_to_add_elems(long **p)
|
||||
{
|
||||
sc_array_add(*p, 500);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
long *p;
|
||||
|
||||
sc_array_create(p, 0);
|
||||
sc_array_add(p, 300);
|
||||
|
||||
// Pass via address of p
|
||||
some_function_to_add_elems(&p);
|
||||
sc_array_destroy(p);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Most probably you will hold array pointer in a struct anyway, so you have a
|
||||
stable address of the pointer, "*numbers" might change but "numbers" is stable :
|
||||
|
||||
```c
|
||||
struct my_app {
|
||||
int *numbers;
|
||||
};
|
||||
|
||||
void func(struct my_app* app)
|
||||
{
|
||||
sc_array_add(app->numbers, 0);
|
||||
sc_array_add(app->numbers, 1);
|
||||
sc_array_add(app->numbers, 2);
|
||||
}
|
||||
|
||||
```
|
@ -4,39 +4,40 @@
|
||||
|
||||
void example_str()
|
||||
{
|
||||
char **p, *it;
|
||||
const char *it;
|
||||
struct sc_array_str arr;
|
||||
|
||||
sc_array_create(p, 0);
|
||||
sc_array_init(&arr);
|
||||
|
||||
sc_array_add(p, "item0");
|
||||
sc_array_add(p, "item1");
|
||||
sc_array_add(p, "item2");
|
||||
sc_array_add(&arr, "item0");
|
||||
sc_array_add(&arr, "item1");
|
||||
sc_array_add(&arr, "item2");
|
||||
|
||||
printf("\nDelete first element \n\n");
|
||||
sc_array_del(p, 0);
|
||||
sc_array_del(&arr, 0);
|
||||
|
||||
sc_array_foreach (p, it) {
|
||||
printf("Elem = %s \n", it);
|
||||
}
|
||||
sc_array_foreach (&arr, it) {
|
||||
printf("Elem = %s \n", it);
|
||||
}
|
||||
|
||||
sc_array_destroy(p);
|
||||
sc_array_term(&arr);
|
||||
}
|
||||
|
||||
void example_int()
|
||||
{
|
||||
int *p;
|
||||
struct sc_array_int arr;
|
||||
|
||||
sc_array_create(p, 0);
|
||||
sc_array_init(&arr);
|
||||
|
||||
sc_array_add(p, 0);
|
||||
sc_array_add(p, 1);
|
||||
sc_array_add(p, 2);
|
||||
sc_array_add(&arr, 0);
|
||||
sc_array_add(&arr, 1);
|
||||
sc_array_add(&arr, 2);
|
||||
|
||||
for (size_t i = 0; i < sc_array_size(p); i++) {
|
||||
printf("Elem = %d \n", p[i]);
|
||||
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||
printf("Elem = %d \n", arr.elems[i]);
|
||||
}
|
||||
|
||||
sc_array_destroy(p);
|
||||
sc_array_term(&arr);
|
||||
}
|
||||
|
||||
int main()
|
||||
|
@ -4,34 +4,42 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int example()
|
||||
void example_str()
|
||||
{
|
||||
int *p;
|
||||
int val;
|
||||
const char *it;
|
||||
struct sc_array_str arr;
|
||||
|
||||
sc_array_create(p, 0);
|
||||
sc_array_init(&arr);
|
||||
|
||||
sc_array_add(p, 0);
|
||||
sc_array_add(p, 1);
|
||||
sc_array_add(p, 3);
|
||||
sc_array_add(&arr, "item0");
|
||||
sc_array_add(&arr, "item1");
|
||||
sc_array_add(&arr, "item2");
|
||||
|
||||
printf("\nRemoving first element \n\n");
|
||||
sc_array_del(p, 0);
|
||||
printf("\nDelete first element \n\n");
|
||||
sc_array_del(&arr, 0);
|
||||
|
||||
printf("Capacity %zu \n", sc_array_cap(p));
|
||||
printf("Element count %zu \n", sc_array_size(p));
|
||||
|
||||
for (size_t i = 0; i < sc_array_size(p); i++) {
|
||||
printf("Elem = %d \n", p[i]);
|
||||
sc_array_foreach (&arr, it) {
|
||||
printf("Elem = %s \n", it);
|
||||
}
|
||||
|
||||
sc_array_foreach (p, val) {
|
||||
printf("Elem = %d \n", val);
|
||||
sc_array_term(&arr);
|
||||
}
|
||||
|
||||
void example_int()
|
||||
{
|
||||
struct sc_array_int arr;
|
||||
|
||||
sc_array_init(&arr);
|
||||
|
||||
sc_array_add(&arr, 0);
|
||||
sc_array_add(&arr, 1);
|
||||
sc_array_add(&arr, 2);
|
||||
|
||||
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||
printf("Elem = %d \n", arr.elems[i]);
|
||||
}
|
||||
|
||||
sc_array_destroy(p);
|
||||
|
||||
return 0;
|
||||
sc_array_term(&arr);
|
||||
}
|
||||
|
||||
static int compare(const void *a, const void *b)
|
||||
@ -44,154 +52,164 @@ static int compare(const void *a, const void *b)
|
||||
|
||||
static void test1(void)
|
||||
{
|
||||
int *arr, total = 0;
|
||||
|
||||
sc_array_create(arr, 10);
|
||||
assert(arr != NULL);
|
||||
sc_array_destroy(arr);
|
||||
assert(sc_array_cap(arr) == 0);
|
||||
assert(sc_array_size(arr) == 0);
|
||||
sc_array_add(arr, 1);
|
||||
sc_array_add(arr, 2);
|
||||
sc_array_add(arr, 3);
|
||||
assert(arr[0] == 1);
|
||||
assert(arr[1] == 2);
|
||||
assert(arr[2] == 3);
|
||||
sc_array_destroy(arr);
|
||||
int total = 0;
|
||||
struct sc_array_int arr;
|
||||
|
||||
sc_array_create(arr, 5);
|
||||
sc_array_add(arr, 3);
|
||||
sc_array_add(arr, 4);
|
||||
sc_array_add(arr, 5);
|
||||
sc_array_init(&arr);
|
||||
sc_array_term(&arr);
|
||||
assert(sc_array_size(&arr) == 0);
|
||||
sc_array_add(&arr, 1);
|
||||
sc_array_add(&arr, 2);
|
||||
sc_array_add(&arr, 3);
|
||||
assert(arr.elems[0] == 1);
|
||||
assert(arr.elems[1] == 2);
|
||||
assert(arr.elems[2] == 3);
|
||||
sc_array_term(&arr);
|
||||
|
||||
assert(sc_array_size(arr) == 3);
|
||||
sc_array_init(&arr);
|
||||
sc_array_add(&arr, 3);
|
||||
sc_array_add(&arr, 4);
|
||||
sc_array_add(&arr, 5);
|
||||
|
||||
sc_array_del(arr, 0);
|
||||
assert(arr[0] == 4);
|
||||
sc_array_del_last(arr);
|
||||
assert(arr[0] == 4);
|
||||
assert(sc_array_size(&arr) == 3);
|
||||
|
||||
sc_array_add(arr, 1);
|
||||
sc_array_add(arr, 3);
|
||||
sc_array_add(arr, 2);
|
||||
sc_array_add(arr, 0);
|
||||
sc_array_del(&arr, 0);
|
||||
assert(arr.elems[0] == 4);
|
||||
sc_array_del_last(&arr);
|
||||
assert(arr.elems[0] == 4);
|
||||
|
||||
assert(sc_array_last(arr) == 0);
|
||||
sc_array_add(&arr, 1);
|
||||
sc_array_add(&arr, 3);
|
||||
sc_array_add(&arr, 2);
|
||||
sc_array_add(&arr, 0);
|
||||
|
||||
sc_array_sort(arr, compare);
|
||||
assert(sc_array_last(&arr) == 0);
|
||||
|
||||
for (size_t i = 0; i < sc_array_size(arr); i++) {
|
||||
total += arr[i];
|
||||
sc_array_sort(&arr, compare);
|
||||
|
||||
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||
total += arr.elems[i];
|
||||
}
|
||||
|
||||
assert(total == 10);
|
||||
|
||||
for (size_t i = 0; i < sc_array_size(arr); i++) {
|
||||
assert(arr[i] == (int) i);
|
||||
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||
assert(arr.elems[i] == (int) i);
|
||||
}
|
||||
|
||||
sc_array_destroy(arr);
|
||||
sc_array_term(&arr);
|
||||
}
|
||||
|
||||
void test2()
|
||||
{
|
||||
int *arr;
|
||||
int val;
|
||||
bool b;
|
||||
struct sc_array_int arr;
|
||||
|
||||
b = sc_array_create(arr, 0);
|
||||
assert(b);
|
||||
sc_array_init(&arr);
|
||||
|
||||
sc_array_foreach (arr, val) {
|
||||
sc_array_foreach (&arr, val) {
|
||||
assert(true);
|
||||
}
|
||||
sc_array_destroy(arr);
|
||||
sc_array_term(&arr);
|
||||
|
||||
b = sc_array_create(arr, 2);
|
||||
assert(b);
|
||||
sc_array_init(&arr);
|
||||
|
||||
sc_array_foreach (arr, val) {
|
||||
sc_array_foreach (&arr, val) {
|
||||
assert(true);
|
||||
}
|
||||
sc_array_destroy(arr);
|
||||
sc_array_term(&arr);
|
||||
|
||||
b = sc_array_create(arr, 2);
|
||||
assert(b);
|
||||
sc_array_init(&arr);
|
||||
|
||||
b = sc_array_add(arr, 1);
|
||||
assert(b);
|
||||
sc_array_add(&arr, 1);
|
||||
assert(!sc_array_oom(&arr));
|
||||
|
||||
sc_array_foreach (arr, val) {
|
||||
sc_array_foreach (&arr, val) {
|
||||
assert(val == 1);
|
||||
}
|
||||
sc_array_del_last(arr);
|
||||
sc_array_foreach (arr, val) {
|
||||
sc_array_del_last(&arr);
|
||||
sc_array_foreach (&arr, val) {
|
||||
assert(true);
|
||||
}
|
||||
|
||||
b = sc_array_add(arr, 1);
|
||||
assert(b == true);
|
||||
sc_array_del_unordered(arr, 0);
|
||||
sc_array_foreach (arr, val) {
|
||||
sc_array_add(&arr, 1);
|
||||
assert(!sc_array_oom(&arr));
|
||||
|
||||
sc_array_del_unordered(&arr, 0);
|
||||
|
||||
sc_array_foreach (&arr, val) {
|
||||
assert(true);
|
||||
}
|
||||
|
||||
sc_array_destroy(arr);
|
||||
sc_array_term(&arr);
|
||||
|
||||
sc_array_init(&arr);
|
||||
sc_array_add(&arr, 100);
|
||||
sc_array_add(&arr, 200);
|
||||
sc_array_add(&arr, 300);
|
||||
assert(sc_array_at(&arr, 0) == 100);
|
||||
sc_array_del_last(&arr);
|
||||
assert(sc_array_at(&arr, 0) == 100);
|
||||
sc_array_del(&arr, 0);
|
||||
assert(sc_array_at(&arr, 0) == 200);
|
||||
sc_array_term(&arr);
|
||||
}
|
||||
|
||||
void bounds_test()
|
||||
{
|
||||
int *arr, total = 0;
|
||||
int total = 0;
|
||||
int val;
|
||||
struct sc_array_int arr;
|
||||
|
||||
sc_array_create(arr, 2);
|
||||
sc_array_add(arr, 3);
|
||||
sc_array_add(arr, 4);
|
||||
sc_array_init(&arr);
|
||||
sc_array_add(&arr, 3);
|
||||
sc_array_add(&arr, 4);
|
||||
|
||||
sc_array_foreach (arr, val) {
|
||||
sc_array_foreach (&arr, val) {
|
||||
total += val;
|
||||
}
|
||||
|
||||
assert(total == 7);
|
||||
|
||||
sc_array_destroy(arr);
|
||||
sc_array_term(&arr);
|
||||
|
||||
total = 0;
|
||||
|
||||
sc_array_create(arr, 0);
|
||||
sc_array_foreach (arr, val) {
|
||||
sc_array_init(&arr);
|
||||
sc_array_foreach (&arr, val) {
|
||||
total += val;
|
||||
}
|
||||
|
||||
sc_array_foreach (arr, val) {
|
||||
sc_array_foreach (&arr, val) {
|
||||
total += val;
|
||||
}
|
||||
|
||||
assert(total == 0);
|
||||
|
||||
sc_array_destroy(arr);
|
||||
sc_array_term(&arr);
|
||||
|
||||
sc_array_create(arr, 0);
|
||||
sc_array_add(arr, 0);
|
||||
sc_array_add(arr, 1);
|
||||
sc_array_add(arr, 2);
|
||||
sc_array_add(arr, 4);
|
||||
sc_array_add(arr, 3);
|
||||
sc_array_init(&arr);
|
||||
sc_array_add(&arr, 0);
|
||||
sc_array_add(&arr, 1);
|
||||
sc_array_add(&arr, 2);
|
||||
sc_array_add(&arr, 4);
|
||||
sc_array_add(&arr, 3);
|
||||
|
||||
sc_array_del(arr, 3);
|
||||
for (size_t i = 0; i < sc_array_size(arr); i++) {
|
||||
assert((int) i == arr[i]);
|
||||
sc_array_del(&arr, 3);
|
||||
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||
assert((int) i == arr.elems[i]);
|
||||
}
|
||||
|
||||
sc_array_add(arr, 3);
|
||||
sc_array_add(arr, 4);
|
||||
sc_array_add(&arr, 3);
|
||||
sc_array_add(&arr, 4);
|
||||
|
||||
sc_array_del(arr, 3);
|
||||
for (size_t i = 0; i < sc_array_size(arr); i++) {
|
||||
assert((int) i == arr[i]);
|
||||
sc_array_del(&arr, 3);
|
||||
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||
assert((int) i == arr.elems[i]);
|
||||
}
|
||||
|
||||
sc_array_destroy(arr);
|
||||
sc_array_term(&arr);
|
||||
}
|
||||
|
||||
#ifdef SC_HAVE_WRAP
|
||||
@ -210,99 +228,108 @@ void *__wrap_realloc(void *p, size_t n)
|
||||
void fail_test()
|
||||
{
|
||||
int tmp;
|
||||
int *arr, total = 0;
|
||||
int total = 0;
|
||||
struct sc_array_int arr;
|
||||
|
||||
assert(sc_array_create(arr, SIZE_MAX) == false);
|
||||
assert(arr == NULL);
|
||||
assert(sc_array_create(arr, 0) == true);
|
||||
assert(arr != NULL);
|
||||
sc_array_destroy(arr);
|
||||
assert(sc_array_cap(arr) == 0);
|
||||
assert(sc_array_size(arr) == 0);
|
||||
sc_array_init(&arr);
|
||||
|
||||
sc_array_foreach (arr, tmp) {
|
||||
sc_array_add(&arr, 0);
|
||||
assert(!sc_array_oom(&arr));
|
||||
sc_array_term(&arr);
|
||||
|
||||
sc_array_init(&arr);
|
||||
assert(sc_array_size(&arr) == 0);
|
||||
|
||||
sc_array_foreach (&arr, tmp) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
assert(sc_array_create(arr, 0) == true);
|
||||
|
||||
size_t count = SC_ARRAY_MAX / sizeof(*arr);
|
||||
bool success = false;
|
||||
size_t count = SC_ARRAY_MAX / sizeof(int);
|
||||
|
||||
for (size_t i = 0; i < count + 5; i++) {
|
||||
success = sc_array_add(arr, i);
|
||||
sc_array_add(&arr, i);
|
||||
}
|
||||
|
||||
assert(!success);
|
||||
assert(sc_array_oom(&arr));
|
||||
sc_array_del(&arr, 0);
|
||||
sc_array_add(&arr, 400);
|
||||
assert(sc_array_oom(&arr) == false);
|
||||
|
||||
sc_array_destroy(arr);
|
||||
sc_array_create(arr, 0);
|
||||
assert(sc_array_size(arr) == 0);
|
||||
sc_array_term(&arr);
|
||||
|
||||
sc_array_init(&arr);
|
||||
assert(sc_array_size(&arr) == 0);
|
||||
|
||||
fail_realloc = true;
|
||||
success = sc_array_add(arr, 0);
|
||||
assert(!success);
|
||||
sc_array_add(&arr, 0);
|
||||
assert(sc_array_oom(&arr));
|
||||
|
||||
fail_realloc = false;
|
||||
success = sc_array_add(arr, 222);
|
||||
assert(success);
|
||||
sc_array_destroy(arr);
|
||||
sc_array_add(&arr, 222);
|
||||
assert(!sc_array_oom(&arr));
|
||||
sc_array_term(&arr);
|
||||
|
||||
fail_realloc = true;
|
||||
assert(sc_array_create(arr, 222) == false);
|
||||
sc_array_init(&arr);
|
||||
sc_array_add(&arr, 3);
|
||||
assert(sc_array_oom(&arr));
|
||||
fail_realloc = false;
|
||||
sc_array_add(&arr, 3);
|
||||
assert(sc_array_size(&arr) == 1);
|
||||
assert(sc_array_oom(&arr) == false);
|
||||
sc_array_term(&arr);
|
||||
|
||||
assert(sc_array_create(arr, 0) == true);
|
||||
sc_array_init(&arr);
|
||||
fail_realloc = true;
|
||||
success = sc_array_add(arr, 222);
|
||||
assert(!success);
|
||||
sc_array_add(&arr, 222);
|
||||
assert(sc_array_oom(&arr));
|
||||
fail_realloc = false;
|
||||
|
||||
sc_array_add(arr, 3);
|
||||
sc_array_add(arr, 4);
|
||||
sc_array_add(arr, 5);
|
||||
sc_array_add(&arr, 3);
|
||||
sc_array_add(&arr, 4);
|
||||
sc_array_add(&arr, 5);
|
||||
|
||||
assert(sc_array_size(arr) == 3);
|
||||
assert(sc_array_size(&arr) == 3);
|
||||
|
||||
sc_array_del(arr, 0);
|
||||
assert(arr[0] == 4);
|
||||
sc_array_del_last(arr);
|
||||
assert(arr[0] == 4);
|
||||
sc_array_del(&arr, 0);
|
||||
assert(arr.elems[0] == 4);
|
||||
sc_array_del_last(&arr);
|
||||
assert(arr.elems[0] == 4);
|
||||
|
||||
sc_array_add(arr, 1);
|
||||
sc_array_add(arr, 3);
|
||||
sc_array_add(arr, 2);
|
||||
sc_array_add(arr, 0);
|
||||
sc_array_add(&arr, 1);
|
||||
sc_array_add(&arr, 3);
|
||||
sc_array_add(&arr, 2);
|
||||
sc_array_add(&arr, 0);
|
||||
|
||||
sc_array_sort(arr, compare);
|
||||
sc_array_sort(&arr, compare);
|
||||
|
||||
for (size_t i = 0; i < sc_array_size(arr); i++) {
|
||||
total += arr[i];
|
||||
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||
total += arr.elems[i];
|
||||
}
|
||||
|
||||
assert(total == 10);
|
||||
|
||||
for (size_t i = 0; i < sc_array_size(arr); i++) {
|
||||
assert(arr[i] == (int) i);
|
||||
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||
assert(arr.elems[i] == (int) i);
|
||||
}
|
||||
|
||||
total = 0;
|
||||
sc_array_foreach (arr, tmp) {
|
||||
sc_array_foreach (&arr, tmp) {
|
||||
total += tmp;
|
||||
}
|
||||
assert(total == 10);
|
||||
|
||||
sc_array_sort(arr, compare);
|
||||
sc_array_del_unordered(arr, 0);
|
||||
assert(arr[0] == 4);
|
||||
assert(sc_array_size(arr) == 4);
|
||||
sc_array_clear(arr);
|
||||
assert(sc_array_size(arr) == 0);
|
||||
sc_array_add(arr, 10);
|
||||
assert(sc_array_size(arr) == 1);
|
||||
assert(arr[0] == 10);
|
||||
sc_array_sort(&arr, compare);
|
||||
sc_array_del_unordered(&arr, 0);
|
||||
assert(arr.elems[0] == 4);
|
||||
assert(sc_array_size(&arr) == 4);
|
||||
sc_array_clear(&arr);
|
||||
assert(sc_array_size(&arr) == 0);
|
||||
sc_array_add(&arr, 10);
|
||||
assert(sc_array_size(&arr) == 1);
|
||||
assert(arr.elems[0] == 10);
|
||||
|
||||
sc_array_destroy(arr);
|
||||
sc_array_term(&arr);
|
||||
}
|
||||
|
||||
#else
|
||||
@ -316,7 +343,8 @@ int main(int argc, char *argv[])
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
example();
|
||||
example_str();
|
||||
example_int();
|
||||
test1();
|
||||
test2();
|
||||
fail_test();
|
||||
|
111
array/sc_array.c
111
array/sc_array.c
@ -1,111 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2021 Ozan Tezcan
|
||||
*
|
||||
* 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 "sc_array.h"
|
||||
|
||||
#ifndef SC_ARRAY_MAX
|
||||
#define SC_ARRAY_MAX SIZE_MAX
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Empty array instance.
|
||||
* Zero element arrays point at it to avoid initial allocation, so unused
|
||||
* arrays will not allocate memory.
|
||||
*/
|
||||
static const struct sc_array sc_empty = {.size = 0, .cap = 0};
|
||||
|
||||
bool sc_array_init(void *a, size_t elem_size, size_t cap)
|
||||
{
|
||||
const size_t max = SC_ARRAY_MAX / elem_size;
|
||||
const size_t bytes = sizeof(struct sc_array) + (elem_size * cap);
|
||||
|
||||
void **p = a;
|
||||
struct sc_array *m;
|
||||
|
||||
if (cap == 0) {
|
||||
*p = (void *) sc_empty.elems;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cap > max) {
|
||||
*p = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
m = sc_array_realloc(NULL, bytes);
|
||||
if (m == NULL) {
|
||||
*p = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
m->size = 0;
|
||||
m->cap = cap;
|
||||
*p = m->elems;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void sc_array_term(void *a)
|
||||
{
|
||||
void **p = a;
|
||||
struct sc_array *m = sc_array_meta(*p);
|
||||
|
||||
if (m != &sc_empty) {
|
||||
sc_array_free(m);
|
||||
}
|
||||
|
||||
*p = (void *) sc_empty.elems;
|
||||
}
|
||||
|
||||
bool sc_array_expand(void *a, size_t elem_size)
|
||||
{
|
||||
const size_t max = SC_ARRAY_MAX / elem_size;
|
||||
|
||||
size_t size, cap, bytes;
|
||||
void **p = a;
|
||||
struct sc_array *prev;
|
||||
struct sc_array *m = sc_array_meta(*p);
|
||||
|
||||
if (m->size == m->cap) {
|
||||
if (m->cap > max / 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size = m->size;
|
||||
cap = (m != &sc_empty) ? m->cap * 2 : 2;
|
||||
prev = (m != &sc_empty) ? m : NULL;
|
||||
|
||||
bytes = sizeof(*m) + (elem_size * cap);
|
||||
m = sc_array_realloc(prev, bytes);
|
||||
if (m == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m->size = size;
|
||||
m->cap = cap;
|
||||
*p = m->elems;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
187
array/sc_array.h
187
array/sc_array.h
@ -21,7 +21,6 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SC_ARRAY_H
|
||||
#define SC_ARRAY_H
|
||||
|
||||
@ -38,63 +37,103 @@
|
||||
#include "config.h"
|
||||
#else
|
||||
#define sc_array_realloc realloc
|
||||
#define sc_array_free free
|
||||
#define sc_array_free free
|
||||
#endif
|
||||
|
||||
// Internals, do not use
|
||||
struct sc_array {
|
||||
size_t size;
|
||||
size_t cap;
|
||||
unsigned char elems[];
|
||||
};
|
||||
#ifndef SC_ARRAY_MAX
|
||||
#define SC_ARRAY_MAX SIZE_MAX
|
||||
#endif
|
||||
|
||||
#define sc_array_meta(a) \
|
||||
((struct sc_array *) ((char *) (a) -offsetof(struct sc_array, elems)))
|
||||
|
||||
bool sc_array_init(void *a, size_t elem_size, size_t cap);
|
||||
void sc_array_term(void *a);
|
||||
bool sc_array_expand(void *a, size_t elem_size);
|
||||
#define sc_array_sizeof(a) (sizeof(a)) // NOLINT
|
||||
// Internals end
|
||||
#define sc_array_def(T, name) \
|
||||
struct sc_array_##name { \
|
||||
bool oom; \
|
||||
size_t cap; \
|
||||
size_t size; \
|
||||
/* NOLINTNEXTLINE */ \
|
||||
T *elems; \
|
||||
}
|
||||
/**
|
||||
* Init array
|
||||
* @param a array
|
||||
*/
|
||||
#define sc_array_init(a) \
|
||||
do { \
|
||||
memset((a), 0, sizeof(*(a))); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @param arr array
|
||||
* @param cap initial capacity. '0' is a valid initial capacity.
|
||||
* @return 'true' on success, 'false' on out of memory
|
||||
* Term array
|
||||
* @param a array
|
||||
*/
|
||||
#define sc_array_create(a, cap) sc_array_init(&(a), sc_array_sizeof(*(a)), cap)
|
||||
#define sc_array_term(a) \
|
||||
do { \
|
||||
sc_array_free((a)->elems); \
|
||||
sc_array_init(a); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @param a array to be destroyed
|
||||
* Add elem to array, call sc_array_oom(v) to see if 'add' failed because of out
|
||||
* of memory.
|
||||
*
|
||||
* @param a array
|
||||
* @param k elem
|
||||
*/
|
||||
#define sc_array_destroy(a) sc_array_term(&(a));
|
||||
#define sc_array_add(a, k) \
|
||||
do { \
|
||||
const size_t _max = SC_ARRAY_MAX / sizeof(*(a)->elems); \
|
||||
size_t _cap; \
|
||||
void *_p; \
|
||||
\
|
||||
if ((a)->cap == (a)->size) { \
|
||||
if ((a)->cap > _max / 2) { \
|
||||
(a)->oom = true; \
|
||||
break; \
|
||||
} \
|
||||
_cap = (a)->cap == 0 ? 8 : (a)->cap * 2; \
|
||||
_p = sc_array_realloc((a)->elems, \
|
||||
_cap * sizeof(*((a)->elems))); \
|
||||
if (_p == NULL) { \
|
||||
(a)->oom = true; \
|
||||
break; \
|
||||
} \
|
||||
(a)->cap = _cap; \
|
||||
(a)->elems = _p; \
|
||||
} \
|
||||
(a)->oom = false; \
|
||||
(a)->elems[(a)->size++] = k; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @param a array
|
||||
* @return current allocated capacity
|
||||
* Deletes items from the array without deallocating underlying memory
|
||||
* @param a array
|
||||
*/
|
||||
#define sc_array_cap(a) (sc_array_meta((a))->cap)
|
||||
#define sc_array_clear(a) \
|
||||
do { \
|
||||
(a)->cap = 0; \
|
||||
(a)->size = 0; \
|
||||
(a)->oom = false; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @param a array
|
||||
* @return current element count
|
||||
* @param a array
|
||||
* @return true if last add operation failed, false otherwise.
|
||||
*/
|
||||
#define sc_array_size(a) (sc_array_meta((a))->size)
|
||||
#define sc_array_oom(a) ((a)->oom)
|
||||
|
||||
/**
|
||||
* Deletes items from the array without deallocating underlying memory
|
||||
* @param a array
|
||||
* Get element at index i, if 'i' is out of range, result is undefined.
|
||||
*
|
||||
* @param a array
|
||||
* @param i index
|
||||
* @return element at index 'i'
|
||||
*/
|
||||
#define sc_array_clear(a) (sc_array_meta((a))->size = 0)
|
||||
#define sc_array_at(a, i) ((a)->elems[i])
|
||||
|
||||
/**
|
||||
* @param a array
|
||||
* @param elem element to be appended
|
||||
* @return 'true' on success, 'false' on out of memory.
|
||||
* @param a array
|
||||
* @return element count
|
||||
*/
|
||||
#define sc_array_add(a, elem) \
|
||||
sc_array_expand(&(a), sc_array_sizeof(*(a))) == true ? \
|
||||
(a)[sc_array_meta(a)->size++] = (elem), true : false
|
||||
#define sc_array_size(a) ((a)->size)
|
||||
|
||||
/**
|
||||
* @param a array
|
||||
@ -102,61 +141,71 @@ bool sc_array_expand(void *a, size_t elem_size);
|
||||
*/
|
||||
#define sc_array_del(a, i) \
|
||||
do { \
|
||||
assert((i) < sc_array_meta(a)->size); \
|
||||
const size_t cnt = sc_array_size(a) - (i) -1; \
|
||||
if (cnt > 0) { \
|
||||
memmove(&(a)[i], &(a)[(i) + 1], cnt * sizeof(*(a))); \
|
||||
assert((i) < (a)->size); \
|
||||
const size_t _cnt = (a)->size - (i) -1; \
|
||||
if (_cnt > 0) { \
|
||||
memmove(&((a)->elems[i]), &((a)->elems[(i) + 1]), \
|
||||
_cnt * sizeof(*((a)->elems))); \
|
||||
} \
|
||||
sc_array_meta((a))->size--; \
|
||||
(a)->size--; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Deletes the element at index i, replaces last element with the deleted
|
||||
* element unless deleted element is the last element. This is faster than
|
||||
* moving elements but elements will no longer be in the 'add order'
|
||||
* Deletes the element at index i, replaces last element with the deleted
|
||||
* element unless deleted element is the last element. This is faster than
|
||||
* moving elements but elements will no longer be in the 'add order'
|
||||
*
|
||||
* arr[a,b,c,d,e,f] -> sc_array_del_unordered(vec, 2) - > arr[a,b,f,d,e]
|
||||
* arr[a,b,c,d,e,f] -> sc_array_del_unordered(arr, 2) - > arr[a,b,f,d,e]
|
||||
*
|
||||
* @param a array
|
||||
* @param i index. If 'i' is out of the range, result is undefined.
|
||||
* @param a array
|
||||
* @param i index. If 'i' is out of the range, result is undefined.
|
||||
*/
|
||||
#define sc_array_del_unordered(a, i) \
|
||||
do { \
|
||||
assert((i) < sc_array_meta(a)->size); \
|
||||
(a)[i] = (a)[(--sc_array_meta((a))->size)]; \
|
||||
assert((i) < (a)->size); \
|
||||
(a)->elems[i] = (a)->elems[(--(a)->size)]; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Deletes the last element. If current size is zero, result is undefined.
|
||||
* @param a array
|
||||
* Deletes the last element. If current size is zero, result is undefined.
|
||||
* @param a array
|
||||
*/
|
||||
#define sc_array_del_last(a) \
|
||||
do { \
|
||||
assert(sc_array_meta(a)->size != 0); \
|
||||
sc_array_meta(a)->size--; \
|
||||
assert((a)->size != 0); \
|
||||
(a)->size--; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Sorts the array using qsort()
|
||||
* @param a array.
|
||||
* @param cmp comparator, check qsort() documentation for details
|
||||
* Sorts the array using qsort()
|
||||
* @param a array
|
||||
* @param cmp comparator, check qsort() documentation for details
|
||||
*/
|
||||
#define sc_array_sort(a, cmp) \
|
||||
(qsort((a), sc_array_size((a)), sc_array_sizeof(*(a)), cmp))
|
||||
#define sc_array_sort(a, cmp) (qsort((a)->elems, (a)->size, *(a)->elems, cmp))
|
||||
|
||||
/**
|
||||
* @param a array
|
||||
* @param elem elem
|
||||
* Returns last element. If array is empty, result is undefined.
|
||||
* @param a array
|
||||
*/
|
||||
#define sc_array_last(a) (a)->elems[(a)->size - 1]
|
||||
|
||||
/**
|
||||
* @param a array
|
||||
* @param elem elem
|
||||
*/
|
||||
#define sc_array_foreach(a, elem) \
|
||||
for (size_t _k = 1, _i = 0; _k && _i != sc_array_size(a); \
|
||||
_k = !_k, _i++) \
|
||||
for ((elem) = (a)[_i]; _k; _k = !_k)
|
||||
for (size_t _k = 1, _i = 0; _k && _i != (a)->size; _k = !_k, _i++) \
|
||||
for ((elem) = (a)->elems[_i]; _k; _k = !_k)
|
||||
|
||||
/**
|
||||
* Returns last element. If array is empty, result is undefined.
|
||||
* @param a array
|
||||
*/
|
||||
#define sc_array_last(a) (a)[sc_array_size(a) - 1]
|
||||
// (type, name)
|
||||
sc_array_def(int, int);
|
||||
sc_array_def(unsigned int, uint);
|
||||
sc_array_def(long, long);
|
||||
sc_array_def(unsigned long, ulong);
|
||||
sc_array_def(uint32_t, 32);
|
||||
sc_array_def(uint64_t, 64);
|
||||
sc_array_def(double, double);
|
||||
sc_array_def(const char *, str);
|
||||
sc_array_def(void *, ptr);
|
||||
|
||||
#endif
|
||||
|
@ -7,9 +7,10 @@ set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
add_library(
|
||||
sc_queue SHARED
|
||||
sc_queue.c
|
||||
sc_queue.h)
|
||||
|
||||
set_target_properties(sc_queue PROPERTIES LINKER_LANGUAGE C)
|
||||
|
||||
target_include_directories(sc_queue PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
if (NOT CMAKE_C_COMPILER_ID MATCHES "MSVC")
|
||||
@ -37,7 +38,7 @@ if (SC_BUILD_TEST)
|
||||
|
||||
enable_testing()
|
||||
|
||||
add_executable(${PROJECT_NAME}_test queue_test.c sc_queue.c)
|
||||
add_executable(${PROJECT_NAME}_test queue_test.c)
|
||||
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_QUEUE_MAX=1400000ul)
|
||||
|
||||
@ -48,7 +49,7 @@ if (SC_BUILD_TEST)
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -fno-omit-frame-pointer)
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_HAVE_WRAP)
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -fno-builtin)
|
||||
target_link_options(${PROJECT_NAME}_test PRIVATE -Wl,--wrap=realloc)
|
||||
target_link_options(${PROJECT_NAME}_test PRIVATE -Wl,--wrap=calloc)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
@ -2,9 +2,11 @@
|
||||
|
||||
### Overview
|
||||
|
||||
- Type generic queue which grows when you add elements.
|
||||
- Queue implementation which grows when you add elements.
|
||||
- Add/remove from head/tail is possible so it can be used as list, stack,
|
||||
queue, dequeue etc.
|
||||
- It comes with predefined types, check out at the end of sc_queue.h, you can
|
||||
add there (sc_queue_def) if you need more.
|
||||
|
||||
|
||||
### Usage
|
||||
@ -17,68 +19,27 @@
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int *queue;
|
||||
int elem;
|
||||
int elem;
|
||||
struct sc_queue_int queue;
|
||||
|
||||
sc_queue_create(queue, 0);
|
||||
sc_queue_init(&queue);
|
||||
|
||||
sc_queue_add_last(&queue, 2);
|
||||
sc_queue_add_last(&queue, 3);
|
||||
sc_queue_add_last(&queue, 4);
|
||||
sc_queue_add_first(&queue, 1);
|
||||
|
||||
sc_queue_add_last(queue, 2);
|
||||
sc_queue_add_last(queue, 3);
|
||||
sc_queue_add_last(queue, 4);
|
||||
sc_queue_add_first(queue, 1);
|
||||
sc_queue_foreach (&queue, elem) {
|
||||
printf("elem = [%d] \n", elem);
|
||||
}
|
||||
|
||||
sc_queue_foreach (queue, elem) {
|
||||
printf("elem = [%d] \n", elem);
|
||||
}
|
||||
elem = sc_queue_del_last(&queue);
|
||||
printf("Last element was : [%d] \n", elem);
|
||||
|
||||
elem = sc_queue_del_last(queue);
|
||||
printf("Last element was : [%d] \n", elem);
|
||||
elem = sc_queue_del_first(&queue);
|
||||
printf("First element was : [%d] \n", elem);
|
||||
|
||||
elem = sc_queue_del_first(queue);
|
||||
printf("First element was : [%d] \n", elem);
|
||||
|
||||
sc_queue_destroy(queue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Note
|
||||
|
||||
Queue pointer is not stable, it may change if it expands the memory. If you
|
||||
pass the queue to another function which can add items, do it by passing
|
||||
reference of the queue pointer.
|
||||
|
||||
```c
|
||||
void some_function_to_add_elems(long **q)
|
||||
{
|
||||
sc_queue_add_last(*q, 500);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
long *q;
|
||||
|
||||
sc_queue_create(q, 0);
|
||||
sc_queue_add_last(q, 300);
|
||||
|
||||
some_function_to_add_elems(&q);
|
||||
sc_array_destroy(q);
|
||||
}
|
||||
```
|
||||
|
||||
Most probably you will hold queue pointer in a struct anyway, so you have a
|
||||
stable address of the pointer, "*numbers" might change but "numbers" is stable :
|
||||
|
||||
```c
|
||||
struct my_app {
|
||||
int *numbers;
|
||||
};
|
||||
|
||||
void func(struct my_app* app)
|
||||
{
|
||||
sc_queue_add_last(app->numbers, 300);
|
||||
sc_queue_add_last(app->numbers, 400);
|
||||
sc_queue_add_last(app->numbers, 500);
|
||||
sc_queue_term(&queue);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
@ -2,29 +2,28 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int *queue;
|
||||
int elem;
|
||||
struct sc_queue_int queue;
|
||||
|
||||
sc_queue_create(queue, 0);
|
||||
sc_queue_init(&queue);
|
||||
|
||||
sc_queue_add_last(queue, 2);
|
||||
sc_queue_add_last(queue, 3);
|
||||
sc_queue_add_last(queue, 4);
|
||||
sc_queue_add_first(queue, 1);
|
||||
sc_queue_add_last(&queue, 2);
|
||||
sc_queue_add_last(&queue, 3);
|
||||
sc_queue_add_last(&queue, 4);
|
||||
sc_queue_add_first(&queue, 1);
|
||||
|
||||
sc_queue_foreach (queue, elem) {
|
||||
printf("elem = [%d] \n", elem);
|
||||
}
|
||||
sc_queue_foreach (&queue, elem) {
|
||||
printf("elem = [%d] \n", elem);
|
||||
}
|
||||
|
||||
elem = sc_queue_del_last(queue);
|
||||
elem = sc_queue_del_last(&queue);
|
||||
printf("Last element was : [%d] \n", elem);
|
||||
|
||||
elem = sc_queue_del_first(queue);
|
||||
elem = sc_queue_del_first(&queue);
|
||||
printf("First element was : [%d] \n", elem);
|
||||
|
||||
sc_queue_destroy(queue);
|
||||
|
||||
sc_queue_term(&queue);
|
||||
return 0;
|
||||
}
|
||||
|
@ -5,62 +5,90 @@
|
||||
|
||||
#ifdef SC_HAVE_WRAP
|
||||
|
||||
bool fail_realloc = false;
|
||||
void *__real_realloc(void *p, size_t size);
|
||||
void *__wrap_realloc(void *p, size_t n)
|
||||
bool fail_calloc = false;
|
||||
void *__real_calloc(size_t m, size_t n);
|
||||
void *__wrap_calloc(size_t m, size_t n)
|
||||
{
|
||||
if (fail_realloc) {
|
||||
if (fail_calloc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return __real_realloc(p, n);
|
||||
return __real_calloc(m, n);
|
||||
}
|
||||
|
||||
void fail_test(void)
|
||||
{
|
||||
double *q;
|
||||
struct sc_queue_int q;
|
||||
|
||||
fail_realloc = true;
|
||||
assert(sc_queue_create(q, 1000) == false);
|
||||
fail_realloc = false;
|
||||
assert(sc_queue_create(q, 1000));
|
||||
fail_calloc = true;
|
||||
sc_queue_init(&q);
|
||||
assert(sc_queue_oom(&q) == true);
|
||||
fail_calloc = false;
|
||||
sc_queue_init(&q);
|
||||
assert(sc_queue_oom(&q) == false);
|
||||
fail_calloc = true;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
sc_queue_add_last(&q, 3);
|
||||
}
|
||||
|
||||
fail_realloc = true;
|
||||
bool success = false;
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
success = sc_queue_add_last(q, i);
|
||||
if (!success) {
|
||||
assert(sc_queue_oom(&q) == true);
|
||||
fail_calloc = false;
|
||||
sc_queue_add_last(&q, 3);
|
||||
assert(sc_queue_oom(&q) == false);
|
||||
sc_queue_term(&q);
|
||||
|
||||
sc_queue_init(&q);
|
||||
fail_calloc = true;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
sc_queue_add_first(&q, 3);
|
||||
}
|
||||
assert(sc_queue_oom(&q) == true);
|
||||
fail_calloc = false;
|
||||
sc_queue_add_first(&q, 3);
|
||||
assert(sc_queue_oom(&q) == false);
|
||||
sc_queue_term(&q);
|
||||
|
||||
sc_queue_init(&q);
|
||||
|
||||
fail_calloc = true;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
sc_queue_add_last(&q, i);
|
||||
if (sc_queue_oom(&q)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(!success);
|
||||
assert(sc_queue_size(q) == 1023);
|
||||
fail_realloc = false;
|
||||
assert(sc_queue_add_last(q, 1023) == true);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
assert(sc_queue_del_first(q) == i);
|
||||
}
|
||||
assert(sc_queue_size(q) == 0);
|
||||
assert(sc_queue_cap(q) == 2048);
|
||||
assert(sc_queue_oom(&q));
|
||||
assert(sc_queue_size(&q) == 7);
|
||||
fail_calloc = false;
|
||||
sc_queue_add_last(&q, 7);
|
||||
assert(sc_queue_oom(&q) == false);
|
||||
|
||||
fail_realloc = false;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
assert(sc_queue_del_first(&q) == i);
|
||||
}
|
||||
assert(sc_queue_size(&q) == 0);
|
||||
|
||||
fail_calloc = false;
|
||||
|
||||
size_t max = SC_QUEUE_MAX;
|
||||
success = true;
|
||||
for (size_t i = 0; i < max + 500; i++) {
|
||||
success = sc_queue_add_last(q, i);
|
||||
if (!success) {
|
||||
sc_queue_add_last(&q, i);
|
||||
if (sc_queue_oom(&q)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(!success);
|
||||
sc_queue_clear(q);
|
||||
assert(sc_queue_size(q) == 0);
|
||||
sc_queue_destroy(q);
|
||||
assert(sc_queue_create(q, max + 100) == false);
|
||||
fail_realloc = false;
|
||||
assert(sc_queue_oom(&q));
|
||||
fail_calloc = false;
|
||||
sc_queue_add_last(&q, 100);
|
||||
assert(sc_queue_oom(&q));
|
||||
sc_queue_clear(&q);
|
||||
assert(sc_queue_size(&q) == 0);
|
||||
sc_queue_term(&q);
|
||||
sc_queue_init(&q);
|
||||
sc_queue_term(&q);
|
||||
fail_calloc = false;
|
||||
}
|
||||
#else
|
||||
void fail_test(void)
|
||||
@ -71,29 +99,27 @@ void fail_test(void)
|
||||
|
||||
void example(void)
|
||||
{
|
||||
int *queue;
|
||||
int elem;
|
||||
struct sc_queue_int queue;
|
||||
|
||||
sc_queue_create(queue, 0);
|
||||
sc_queue_destroy(queue);
|
||||
sc_queue_init(&queue);
|
||||
|
||||
sc_queue_create(queue, 0);
|
||||
sc_queue_add_last(queue, 2);
|
||||
sc_queue_add_last(queue, 3);
|
||||
sc_queue_add_last(queue, 4);
|
||||
sc_queue_add_first(queue, 1);
|
||||
sc_queue_add_last(&queue, 2);
|
||||
sc_queue_add_last(&queue, 3);
|
||||
sc_queue_add_last(&queue, 4);
|
||||
sc_queue_add_first(&queue, 1);
|
||||
|
||||
sc_queue_foreach (queue, elem) {
|
||||
sc_queue_foreach (&queue, elem) {
|
||||
printf("elem = [%d] \n", elem);
|
||||
}
|
||||
|
||||
elem = sc_queue_del_last(queue);
|
||||
elem = sc_queue_del_last(&queue);
|
||||
printf("Last element was : [%d] \n", elem);
|
||||
|
||||
elem = sc_queue_del_first(queue);
|
||||
elem = sc_queue_del_first(&queue);
|
||||
printf("First element was : [%d] \n", elem);
|
||||
|
||||
sc_queue_destroy(queue);
|
||||
sc_queue_term(&queue);
|
||||
}
|
||||
|
||||
void test1(void)
|
||||
@ -101,81 +127,101 @@ void test1(void)
|
||||
int count = 0;
|
||||
int t;
|
||||
int i = 0;
|
||||
int *p;
|
||||
struct sc_queue_int p;
|
||||
|
||||
p = NULL;
|
||||
sc_queue_destroy(p);
|
||||
sc_queue_init(&p);
|
||||
sc_queue_term(&p);
|
||||
|
||||
assert(sc_queue_create(p, 2) == true);
|
||||
sc_queue_destroy(p);
|
||||
sc_queue_destroy(p);
|
||||
sc_queue_init(&p);
|
||||
sc_queue_term(&p);
|
||||
sc_queue_term(&p);
|
||||
|
||||
sc_queue_add_first(p, 1);
|
||||
sc_queue_add_first(p, 2);
|
||||
sc_queue_add_first(p, 3);
|
||||
assert(sc_queue_del_first(p) == 3);
|
||||
assert(sc_queue_del_first(p) == 2);
|
||||
assert(sc_queue_del_first(p) == 1);
|
||||
sc_queue_destroy(p);
|
||||
sc_queue_init(&p);
|
||||
sc_queue_add_first(&p, 1);
|
||||
sc_queue_add_first(&p, 2);
|
||||
sc_queue_add_first(&p, 3);
|
||||
assert(sc_queue_del_first(&p) == 3);
|
||||
assert(sc_queue_del_first(&p) == 2);
|
||||
assert(sc_queue_del_first(&p) == 1);
|
||||
sc_queue_term(&p);
|
||||
|
||||
assert(sc_queue_create(p, 0) == true);
|
||||
sc_queue_init(&p);
|
||||
assert(sc_queue_oom(&p) == false);
|
||||
|
||||
sc_queue_foreach (p, t) {
|
||||
sc_queue_foreach (&p, t) {
|
||||
(void) t;
|
||||
count++;
|
||||
}
|
||||
assert(count == 0);
|
||||
assert(sc_queue_empty(p) == true);
|
||||
assert(sc_queue_size(p) == 0);
|
||||
assert(sc_queue_empty(&p) == true);
|
||||
assert(sc_queue_size(&p) == 0);
|
||||
|
||||
assert(sc_queue_add_first(p, 2) == true);
|
||||
assert(sc_queue_add_first(p, 3) == true);
|
||||
assert(sc_queue_add_first(p, 4) == true);
|
||||
assert(sc_queue_add_first(p, 5) == true);
|
||||
assert(sc_queue_add_first(p, 6) == true);
|
||||
assert(sc_queue_add_last(p, 1) == true);
|
||||
assert(sc_queue_add_last(p, 0) == true);
|
||||
sc_queue_add_first(&p, 2);
|
||||
sc_queue_add_first(&p, 3);
|
||||
sc_queue_add_first(&p, 4);
|
||||
sc_queue_add_first(&p, 5);
|
||||
sc_queue_add_first(&p, 6);
|
||||
sc_queue_add_last(&p, 1);
|
||||
sc_queue_add_last(&p, 0);
|
||||
|
||||
assert(sc_queue_empty(p) == false);
|
||||
assert(sc_queue_empty(&p) == false);
|
||||
|
||||
i = 6;
|
||||
sc_queue_foreach (p, t) {
|
||||
sc_queue_foreach (&p, t) {
|
||||
assert(t == i--);
|
||||
count += t;
|
||||
}
|
||||
assert(count == 6 * 7 / 2);
|
||||
assert(sc_queue_size(p) == 7);
|
||||
assert(sc_queue_size(&p) == 7);
|
||||
|
||||
assert(sc_queue_peek_first(p) == 6);
|
||||
assert(sc_queue_size(p) == 7);
|
||||
assert(sc_queue_peek_last(p) == 0);
|
||||
assert(sc_queue_size(p) == 7);
|
||||
assert(sc_queue_peek_first(&p) == 6);
|
||||
assert(sc_queue_size(&p) == 7);
|
||||
assert(sc_queue_peek_last(&p) == 0);
|
||||
assert(sc_queue_size(&p) == 7);
|
||||
|
||||
t = sc_queue_del_first(p);
|
||||
t = sc_queue_del_first(&p);
|
||||
assert(t == 6);
|
||||
assert(sc_queue_size(p) == 6);
|
||||
assert(sc_queue_size(&p) == 6);
|
||||
|
||||
t = sc_queue_del_last(p);
|
||||
t = sc_queue_del_last(&p);
|
||||
assert(t == 0);
|
||||
assert(sc_queue_size(p) == 5);
|
||||
assert(sc_queue_size(&p) == 5);
|
||||
|
||||
sc_queue_clear(p);
|
||||
assert(sc_queue_size(p) == 0);
|
||||
assert(sc_queue_cap(p) == 8);
|
||||
assert(sc_queue_empty(p) == true);
|
||||
sc_queue_clear(&p);
|
||||
assert(sc_queue_size(&p) == 0);
|
||||
assert(sc_queue_empty(&p) == true);
|
||||
|
||||
sc_queue_destroy(p);
|
||||
sc_queue_destroy(p);
|
||||
sc_queue_term(&p);
|
||||
sc_queue_term(&p);
|
||||
|
||||
assert(sc_queue_create(p, 0) == true);
|
||||
sc_queue_add_first(p, 100);
|
||||
sc_queue_add_first(p, 200);
|
||||
sc_queue_add_first(p, 300);
|
||||
sc_queue_add_first(p, 400);
|
||||
sc_queue_add_first(p, 500);
|
||||
assert(sc_queue_at(p, 0) == 500);
|
||||
assert(sc_queue_at(p, 4) == 100);
|
||||
sc_queue_destroy(p);
|
||||
sc_queue_init(&p);
|
||||
sc_queue_add_first(&p, 100);
|
||||
sc_queue_add_first(&p, 200);
|
||||
sc_queue_add_first(&p, 300);
|
||||
sc_queue_add_first(&p, 400);
|
||||
sc_queue_add_first(&p, 500);
|
||||
assert(sc_queue_at(&p, 0) == 500);
|
||||
assert(sc_queue_at(&p, 4) == 100);
|
||||
sc_queue_term(&p);
|
||||
|
||||
sc_queue_init(&p);
|
||||
|
||||
sc_queue_foreach (&p, t) {
|
||||
assert(true);
|
||||
}
|
||||
|
||||
sc_queue_add_last(&p, 2);
|
||||
sc_queue_add_first(&p, 1);
|
||||
sc_queue_add_first(&p, 0);
|
||||
sc_queue_add_last(&p, 3);
|
||||
|
||||
i = 0;
|
||||
sc_queue_foreach (&p, t) {
|
||||
assert(sc_queue_at(&p, i) == i);
|
||||
i++;
|
||||
}
|
||||
|
||||
sc_queue_term(&p);
|
||||
}
|
||||
|
||||
int main()
|
||||
|
158
queue/sc_queue.c
158
queue/sc_queue.c
@ -1,158 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2021 Ozan Tezcan
|
||||
*
|
||||
* 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 "sc_queue.h"
|
||||
|
||||
#ifndef SC_QUEUE_MAX
|
||||
#define SC_QUEUE_MAX ((SIZE_MAX - sizeof(struct sc_queue)) / 2ul)
|
||||
#endif
|
||||
|
||||
static const struct sc_queue sc_empty = {.cap = 1, .first = 0, .last = 0};
|
||||
|
||||
static void *queue_alloc(void *prev, size_t elem_size, size_t *cap)
|
||||
{
|
||||
size_t alloc, v = *cap;
|
||||
|
||||
if (*cap > SC_QUEUE_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find next power of two.
|
||||
v = v < 4 ? 4 : v;
|
||||
v--;
|
||||
for (size_t i = 1; i < sizeof(v) * 8; i *= 2) {
|
||||
v |= v >> i;
|
||||
}
|
||||
v++;
|
||||
|
||||
*cap = v;
|
||||
alloc = sizeof(struct sc_queue) + (elem_size * v);
|
||||
|
||||
return sc_queue_realloc(prev, alloc);
|
||||
}
|
||||
|
||||
bool sc_queue_init(void *q, size_t elem_size, size_t cap)
|
||||
{
|
||||
size_t p = cap;
|
||||
void **ptr = q;
|
||||
struct sc_queue *meta;
|
||||
|
||||
if (cap == 0) {
|
||||
*ptr = (void *) sc_empty.elems;
|
||||
return true;
|
||||
}
|
||||
|
||||
meta = queue_alloc(NULL, elem_size, &p);
|
||||
if (meta == NULL) {
|
||||
*ptr = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
meta->cap = p;
|
||||
meta->first = 0;
|
||||
meta->last = 0;
|
||||
*ptr = meta->elems;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void sc_queue_term(void *q)
|
||||
{
|
||||
struct sc_queue *meta;
|
||||
void **ptr = q;
|
||||
|
||||
if (*ptr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
meta = sc_queue_meta(*ptr);
|
||||
|
||||
if (meta != &sc_empty) {
|
||||
sc_queue_free(meta);
|
||||
}
|
||||
|
||||
*ptr = (void *) sc_empty.elems;
|
||||
}
|
||||
|
||||
bool sc_queue_expand(void *q, size_t elem_size)
|
||||
{
|
||||
void **ptr = q;
|
||||
struct sc_queue *tmp;
|
||||
struct sc_queue *meta = sc_queue_meta(*ptr);
|
||||
size_t cap, cnt, sz;
|
||||
size_t pos = (meta->last + 1) & (meta->cap - 1);
|
||||
uint8_t *e;
|
||||
|
||||
if (pos == meta->first) {
|
||||
if (meta == &sc_empty) {
|
||||
return sc_queue_init(ptr, elem_size, 4);
|
||||
}
|
||||
|
||||
cap = meta->cap * 2;
|
||||
tmp = queue_alloc(meta, elem_size, &cap);
|
||||
if (tmp == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move items to make empty slots at the end.
|
||||
*
|
||||
* Doing a lot here to work with realloc, normally
|
||||
* 1 - allocating new memory
|
||||
* 2 - copy items
|
||||
* 3 - free old memory
|
||||
*
|
||||
* would be easier. But I use this code with a specific
|
||||
* allocator, it's much more efficient with realloc, so leaving
|
||||
* this one as it is for now.
|
||||
*
|
||||
* e.g :
|
||||
* last first
|
||||
* | |
|
||||
* Step 0 : | 2 | 3 | - | 1 | // tmp->cap : 4
|
||||
* Step 1 : | 2 | 3 | - | 1 | - | - | - | - | // realloc
|
||||
* Step 2 : | 2 | 3 | - | 1 | 1 | - | - | - | // memcpy
|
||||
* Step 3 : | 2 | 2 | 3 | 1 | 1 | - | - | - | // memmove
|
||||
* Step 4 : | 1 | 2 | 3 | 1 | 1 | - | - | - | // memcpy
|
||||
* Step 5 : | 1 | 2 | 3 | - | - | - | - | - | // tmp->last =
|
||||
* cap - 1; | | first last
|
||||
*
|
||||
*/
|
||||
|
||||
e = tmp->elems;
|
||||
cnt = tmp->cap - tmp->first;
|
||||
sz = elem_size;
|
||||
|
||||
memcpy(e + (sz * tmp->cap), e + (sz * tmp->first), cnt * sz);
|
||||
memmove(e + (cnt * sz), e, tmp->first * sz);
|
||||
memcpy(e, e + (sz * tmp->cap), cnt * sz);
|
||||
|
||||
tmp->last = tmp->cap - 1;
|
||||
tmp->first = 0;
|
||||
tmp->cap = cap;
|
||||
*ptr = tmp->elems;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
230
queue/sc_queue.h
230
queue/sc_queue.h
@ -37,93 +37,97 @@
|
||||
#ifdef SC_HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#else
|
||||
#define sc_queue_realloc realloc
|
||||
#define sc_queue_free free
|
||||
#define sc_queue_calloc calloc
|
||||
#define sc_queue_free free
|
||||
#endif
|
||||
|
||||
// Internals
|
||||
struct sc_queue {
|
||||
size_t cap;
|
||||
size_t first;
|
||||
size_t last;
|
||||
unsigned char elems[];
|
||||
};
|
||||
#ifndef SC_QUEUE_MAX
|
||||
#define SC_QUEUE_MAX (SIZE_MAX)
|
||||
#endif
|
||||
|
||||
#define sc_queue_meta(q) \
|
||||
((struct sc_queue *) ((char *) (q) -offsetof(struct sc_queue, elems)))
|
||||
#define sc_queue_def(T, name) \
|
||||
struct sc_queue_##name { \
|
||||
bool oom; \
|
||||
size_t cap; \
|
||||
size_t first; \
|
||||
size_t last; \
|
||||
/* NOLINTNEXTLINE */ \
|
||||
T *elems; \
|
||||
}
|
||||
|
||||
static inline size_t sc_queue_inc_first(void *q)
|
||||
{
|
||||
struct sc_queue *m = sc_queue_meta(q);
|
||||
size_t tmp = m->first;
|
||||
|
||||
m->first = (m->first + 1) & (m->cap - 1);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static inline size_t sc_queue_inc_last(void *q)
|
||||
{
|
||||
struct sc_queue *m = sc_queue_meta(q);
|
||||
size_t tmp = m->last;
|
||||
|
||||
m->last = (m->last + 1) & (m->cap - 1);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static inline size_t sc_queue_dec_first(void *q)
|
||||
{
|
||||
struct sc_queue *m = sc_queue_meta(q);
|
||||
|
||||
m->first = (m->first - 1) & (m->cap - 1);
|
||||
return m->first;
|
||||
}
|
||||
|
||||
static inline size_t sc_queue_dec_last(void *q)
|
||||
{
|
||||
struct sc_queue *m = sc_queue_meta(q);
|
||||
|
||||
m->last = (m->last - 1) & (m->cap - 1);
|
||||
return m->last;
|
||||
}
|
||||
|
||||
bool sc_queue_init(void *q, size_t elem_size, size_t cap);
|
||||
void sc_queue_term(void *q);
|
||||
bool sc_queue_expand(void *q, size_t elem_size);
|
||||
#define sc_queue_sizeof(a) (sizeof(a)) // NOLINT
|
||||
#define sc_queue_expand(q) \
|
||||
do { \
|
||||
size_t _cap, _len, _off; \
|
||||
size_t _pos = ((q)->last + 1) & ((q)->cap - 1); \
|
||||
void *_dst, *_src; \
|
||||
\
|
||||
if (_pos == (q)->first) { \
|
||||
if ((q)->cap > SC_QUEUE_MAX / 2ul) { \
|
||||
(q)->oom = true; \
|
||||
break; \
|
||||
} \
|
||||
_cap = (q)->cap * 2; \
|
||||
_dst = sc_queue_calloc(_cap, sizeof(*((q)->elems))); \
|
||||
if (_dst == NULL) { \
|
||||
(q)->oom = true; \
|
||||
break; \
|
||||
} \
|
||||
_len = ((q)->cap - (q)->first) * sizeof(*(q)->elems); \
|
||||
_off = ((q)->first * sizeof(*((q)->elems))); \
|
||||
_src = ((char *) (q)->elems) + _off; \
|
||||
\
|
||||
memcpy(_dst, _src, _len); \
|
||||
memcpy(((char *) _dst) + _len, (q)->elems, _off); \
|
||||
(q)->oom = false; \
|
||||
(q)->last = (q)->cap - 1; \
|
||||
(q)->first = 0; \
|
||||
(q)->cap = _cap; \
|
||||
sc_queue_free((q)->elems); \
|
||||
(q)->elems = _dst; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @param q queue
|
||||
* @param count initial capacity, '0' is accepted.
|
||||
* @return 'true' on success, 'false' on out of memory.
|
||||
*/
|
||||
#define sc_queue_create(q, count) \
|
||||
sc_queue_init(&(q), sc_queue_sizeof(*(q)), count)
|
||||
|
||||
/**
|
||||
* Destroy queue
|
||||
* Init queue. Call sc_queue_oom(q) to see if memory allocation succeeded.
|
||||
* @param q queue
|
||||
*/
|
||||
#define sc_queue_destroy(q) sc_queue_term((&(q)))
|
||||
#define sc_queue_init(q) \
|
||||
do { \
|
||||
(q)->oom = false; \
|
||||
(q)->cap = 8; \
|
||||
(q)->first = 0; \
|
||||
(q)->last = 0; \
|
||||
(q)->elems = sc_queue_calloc(1, sizeof(*(q)->elems) * 8); \
|
||||
if ((q)->elems == NULL) { \
|
||||
(q)->oom = true; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Term queue
|
||||
* @param q queue
|
||||
* @return current capacity
|
||||
*/
|
||||
#define sc_queue_cap(q) (sc_queue_meta((q))->cap)
|
||||
#define sc_queue_term(q) \
|
||||
do { \
|
||||
sc_queue_free((q)->elems); \
|
||||
(q)->elems = NULL; \
|
||||
(q)->cap = 0; \
|
||||
(q)->first = 0; \
|
||||
(q)->last = 0; \
|
||||
(q)->oom = false; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @param q queue
|
||||
* @return true if last add operation failed, false otherwise.
|
||||
*/
|
||||
#define sc_queue_oom(q) ((q)->oom)
|
||||
|
||||
/**
|
||||
* @param q queue
|
||||
* @return element count
|
||||
*/
|
||||
#define sc_queue_size(q) \
|
||||
((sc_queue_meta(q)->last - sc_queue_meta(q)->first) & \
|
||||
(sc_queue_meta(q)->cap - 1))
|
||||
|
||||
/**
|
||||
* @param q queue
|
||||
* @return true if queue is empty
|
||||
*/
|
||||
#define sc_queue_empty(q) ((sc_queue_meta(q)->last == sc_queue_meta(q)->first))
|
||||
#define sc_queue_size(q) (((q)->last - (q)->first) & ((q)->cap - 1))
|
||||
|
||||
/**
|
||||
* Clear the queue without deallocating underlying memory.
|
||||
@ -131,27 +135,36 @@ bool sc_queue_expand(void *q, size_t elem_size);
|
||||
*/
|
||||
#define sc_queue_clear(q) \
|
||||
do { \
|
||||
sc_queue_meta(q)->first = 0; \
|
||||
sc_queue_meta(q)->last = 0; \
|
||||
(q)->first = 0; \
|
||||
(q)->last = 0; \
|
||||
(q)->oom = false; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @param q queue
|
||||
* @return true if queue is empty
|
||||
*/
|
||||
#define sc_queue_empty(q) (((q)->last == (q)->first))
|
||||
|
||||
/**
|
||||
* @param q queue
|
||||
* @return index of the first element. If queue is empty, result is undefined.
|
||||
*/
|
||||
#define sc_queue_first(q) (sc_queue_meta(q)->first)
|
||||
#define sc_queue_first(q) ((q)->first)
|
||||
|
||||
/**
|
||||
* @param q queue
|
||||
* @return index of the last element. If queue is empty, result is undefined.
|
||||
*/
|
||||
#define sc_queue_last(q) (sc_queue_meta(q)->last)
|
||||
#define sc_queue_last(q) ((q)->last)
|
||||
|
||||
/**
|
||||
* @return index of the next element after i, if i is the last element,
|
||||
* @param q queue
|
||||
* @param i index
|
||||
* @return index of the next element after i, if i is the last element,
|
||||
* result is undefined.
|
||||
*/
|
||||
#define sc_queue_next(q, i) (((i) + 1) & (sc_queue_meta(q)->cap - 1))
|
||||
#define sc_queue_next(q, i) (((i) + 1) & ((q)->cap - 1))
|
||||
|
||||
/**
|
||||
* Returns element at index 'i', so regular loops are possible :
|
||||
@ -163,59 +176,83 @@ bool sc_queue_expand(void *q, size_t elem_size);
|
||||
* @param q queue
|
||||
* @return element at index i
|
||||
*/
|
||||
#define sc_queue_at(q, i) \
|
||||
(q)[((sc_queue_meta(q)->first) + (i)) & (sc_queue_cap(q) - 1)]
|
||||
#define sc_queue_at(q, i) (q)->elems[(((q)->first) + (i)) & ((q)->cap - 1)]
|
||||
|
||||
/**
|
||||
* @param q queue
|
||||
* @return peek first element, if queue is empty, result is undefined
|
||||
*/
|
||||
#define sc_queue_peek_first(q) ((q)[sc_queue_meta(q)->first])
|
||||
#define sc_queue_peek_first(q) ((q)->elems[(q)->first])
|
||||
|
||||
/**
|
||||
* @param q queue
|
||||
* @return peek last element, if queue is empty, result is undefined
|
||||
*/
|
||||
#define sc_queue_peek_last(q) \
|
||||
(q)[(sc_queue_meta(q)->last - 1) & (sc_queue_meta(q)->cap - 1)]
|
||||
#define sc_queue_peek_last(q) (q)->elems[((q)->last - 1) & ((q)->cap - 1)]
|
||||
|
||||
/**
|
||||
* Call sc_queue_oom(q) after this function to check out of memory condition.
|
||||
*
|
||||
* @param q queue
|
||||
* @param elem elem to be added at the end of the list
|
||||
* @return 'true' on success, 'false' on out of memory.
|
||||
*/
|
||||
#define sc_queue_add_last(q, elem) \
|
||||
sc_queue_expand(&(q), sc_queue_sizeof(*(q))) == true ? \
|
||||
(q)[sc_queue_inc_last((q))] = (elem), true : false
|
||||
do { \
|
||||
sc_queue_expand(q); \
|
||||
if ((q)->oom) { \
|
||||
break; \
|
||||
} \
|
||||
(q)->oom = false; \
|
||||
(q)->elems[(q)->last] = elem; \
|
||||
(q)->last = ((q)->last + 1) & ((q)->cap - 1); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @param q queue
|
||||
* @return delete the last element from the queue and return its value.
|
||||
* If queue is empty, result is undefined.
|
||||
*/
|
||||
#define sc_queue_del_last(q) ((q)[sc_queue_dec_last((q))])
|
||||
#define sc_queue_del_last(q) \
|
||||
((q)->elems[((q)->last = ((q)->last - 1) & ((q)->cap - 1))])
|
||||
|
||||
/**
|
||||
* Call sc_queue_oom(q) after this function to check out of memory condition.
|
||||
*
|
||||
* @param q queue.
|
||||
* @param elem elem to be added at the head of the list.
|
||||
* @return 'true' on success, 'false' on out of memory.
|
||||
*/
|
||||
#define sc_queue_add_first(q, elem) \
|
||||
sc_queue_expand(&(q), sc_queue_sizeof(*(q))) == true ? \
|
||||
(q)[sc_queue_dec_first((q))] = (elem), true : false
|
||||
do { \
|
||||
sc_queue_expand(q); \
|
||||
if ((q)->oom) { \
|
||||
break; \
|
||||
} \
|
||||
(q)->oom = false; \
|
||||
(q)->first = ((q)->first - 1) & ((q)->cap - 1); \
|
||||
(q)->elems[(q)->first] = elem; \
|
||||
} while (0)
|
||||
|
||||
static inline size_t sc_queue_inc_first(size_t* first, size_t cap)
|
||||
{
|
||||
size_t tmp = *first;
|
||||
|
||||
*first = (*first + 1) & (cap - 1);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param q queue
|
||||
* @return delete the first element from the queue and return its value.
|
||||
* If queue is empty, result is undefined.
|
||||
*/
|
||||
#define sc_queue_del_first(q) (q)[sc_queue_inc_first((q))]
|
||||
#define sc_queue_del_first(q) \
|
||||
(q)->elems[sc_queue_inc_first(&(q)->first, (q)->cap)]
|
||||
|
||||
/**
|
||||
* For each loop,
|
||||
*
|
||||
* int *queue;
|
||||
* sc_queue_create(queue, 4);
|
||||
* sc_queue_create(queue, 4);"
|
||||
*
|
||||
* int elem;
|
||||
* sc_queue_foreach(queue, elem) {
|
||||
@ -226,6 +263,17 @@ bool sc_queue_expand(void *q, size_t elem_size);
|
||||
for (size_t _k = 1, _i = sc_queue_first(q); \
|
||||
_k && _i != sc_queue_last(q); \
|
||||
_k = !_k, _i = sc_queue_next(q, _i)) \
|
||||
for ((elem) = (q)[_i]; _k; _k = !_k)
|
||||
for ((elem) = (q)->elems[_i]; _k; _k = !_k)
|
||||
|
||||
// (type, name)
|
||||
sc_queue_def(int, int);
|
||||
sc_queue_def(unsigned int, uint);
|
||||
sc_queue_def(long, long);
|
||||
sc_queue_def(unsigned long, ulong);
|
||||
sc_queue_def(uint32_t, 32);
|
||||
sc_queue_def(uint64_t, 64);
|
||||
sc_queue_def(double, double);
|
||||
sc_queue_def(const char *, str);
|
||||
sc_queue_def(void *, ptr);
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user