mirror of
https://github.com/tezc/sc.git
synced 2025-01-28 07:03:06 +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_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_C_EXTENSIONS OFF)
|
set(CMAKE_C_EXTENSIONS OFF)
|
||||||
|
|
||||||
add_library(
|
add_library(sc_array SHARED
|
||||||
sc_array SHARED
|
|
||||||
sc_array.c
|
|
||||||
sc_array.h)
|
sc_array.h)
|
||||||
|
set_target_properties(sc_array PROPERTIES LINKER_LANGUAGE C)
|
||||||
|
|
||||||
|
|
||||||
target_include_directories(sc_array PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
target_include_directories(sc_array PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ if (SC_BUILD_TEST)
|
|||||||
|
|
||||||
enable_testing()
|
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)
|
target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_ARRAY_MAX=140000ul)
|
||||||
|
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
### Overview
|
### Overview
|
||||||
|
|
||||||
- Type generic array/vector.
|
- Growable array/vector.
|
||||||
- Index access is possible (e.g float* arr; 'printf("%f", arr[i]')).
|
- 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
|
### Usage
|
||||||
|
|
||||||
@ -14,39 +15,40 @@
|
|||||||
|
|
||||||
void example_str()
|
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");
|
|
||||||
|
|
||||||
printf("\nDelete first element \n\n");
|
sc_array_add(&arr, "item0");
|
||||||
sc_array_del(p, 0);
|
sc_array_add(&arr, "item1");
|
||||||
|
sc_array_add(&arr, "item2");
|
||||||
|
|
||||||
sc_array_foreach (p, it) {
|
printf("\nDelete first element \n\n");
|
||||||
printf("Elem = %s \n", it);
|
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()
|
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(&arr, 0);
|
||||||
sc_array_add(p, 1);
|
sc_array_add(&arr, 1);
|
||||||
sc_array_add(p, 2);
|
sc_array_add(&arr, 2);
|
||||||
|
|
||||||
for (size_t i = 0; i < sc_array_size(p); i++) {
|
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||||
printf("Elem = %d \n", p[i]);
|
printf("Elem = %d \n", arr.elems[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_array_destroy(p);
|
sc_array_term(&arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
@ -57,45 +59,3 @@ int main(int argc, char *argv[])
|
|||||||
return 0;
|
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()
|
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(&arr, "item0");
|
||||||
sc_array_add(p, "item1");
|
sc_array_add(&arr, "item1");
|
||||||
sc_array_add(p, "item2");
|
sc_array_add(&arr, "item2");
|
||||||
|
|
||||||
printf("\nDelete first element \n\n");
|
printf("\nDelete first element \n\n");
|
||||||
sc_array_del(p, 0);
|
sc_array_del(&arr, 0);
|
||||||
|
|
||||||
sc_array_foreach (p, it) {
|
sc_array_foreach (&arr, it) {
|
||||||
printf("Elem = %s \n", it);
|
printf("Elem = %s \n", it);
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_array_destroy(p);
|
sc_array_term(&arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void example_int()
|
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(&arr, 0);
|
||||||
sc_array_add(p, 1);
|
sc_array_add(&arr, 1);
|
||||||
sc_array_add(p, 2);
|
sc_array_add(&arr, 2);
|
||||||
|
|
||||||
for (size_t i = 0; i < sc_array_size(p); i++) {
|
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||||
printf("Elem = %d \n", p[i]);
|
printf("Elem = %d \n", arr.elems[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_array_destroy(p);
|
sc_array_term(&arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
|
@ -4,34 +4,42 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
int example()
|
void example_str()
|
||||||
{
|
{
|
||||||
int *p;
|
const char *it;
|
||||||
int val;
|
struct sc_array_str arr;
|
||||||
|
|
||||||
sc_array_create(p, 0);
|
sc_array_init(&arr);
|
||||||
|
|
||||||
sc_array_add(p, 0);
|
sc_array_add(&arr, "item0");
|
||||||
sc_array_add(p, 1);
|
sc_array_add(&arr, "item1");
|
||||||
sc_array_add(p, 3);
|
sc_array_add(&arr, "item2");
|
||||||
|
|
||||||
printf("\nRemoving first element \n\n");
|
printf("\nDelete first element \n\n");
|
||||||
sc_array_del(p, 0);
|
sc_array_del(&arr, 0);
|
||||||
|
|
||||||
printf("Capacity %zu \n", sc_array_cap(p));
|
sc_array_foreach (&arr, it) {
|
||||||
printf("Element count %zu \n", sc_array_size(p));
|
printf("Elem = %s \n", it);
|
||||||
|
|
||||||
for (size_t i = 0; i < sc_array_size(p); i++) {
|
|
||||||
printf("Elem = %d \n", p[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_array_foreach (p, val) {
|
sc_array_term(&arr);
|
||||||
printf("Elem = %d \n", val);
|
}
|
||||||
|
|
||||||
|
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);
|
sc_array_term(&arr);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int compare(const void *a, const void *b)
|
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)
|
static void test1(void)
|
||||||
{
|
{
|
||||||
int *arr, total = 0;
|
|
||||||
|
|
||||||
sc_array_create(arr, 10);
|
int total = 0;
|
||||||
assert(arr != NULL);
|
struct sc_array_int arr;
|
||||||
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);
|
|
||||||
|
|
||||||
sc_array_create(arr, 5);
|
sc_array_init(&arr);
|
||||||
sc_array_add(arr, 3);
|
sc_array_term(&arr);
|
||||||
sc_array_add(arr, 4);
|
assert(sc_array_size(&arr) == 0);
|
||||||
sc_array_add(arr, 5);
|
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(sc_array_size(&arr) == 3);
|
||||||
assert(arr[0] == 4);
|
|
||||||
sc_array_del_last(arr);
|
|
||||||
assert(arr[0] == 4);
|
|
||||||
|
|
||||||
sc_array_add(arr, 1);
|
sc_array_del(&arr, 0);
|
||||||
sc_array_add(arr, 3);
|
assert(arr.elems[0] == 4);
|
||||||
sc_array_add(arr, 2);
|
sc_array_del_last(&arr);
|
||||||
sc_array_add(arr, 0);
|
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++) {
|
sc_array_sort(&arr, compare);
|
||||||
total += arr[i];
|
|
||||||
|
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||||
|
total += arr.elems[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(total == 10);
|
assert(total == 10);
|
||||||
|
|
||||||
for (size_t i = 0; i < sc_array_size(arr); i++) {
|
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||||
assert(arr[i] == (int) i);
|
assert(arr.elems[i] == (int) i);
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_array_destroy(arr);
|
sc_array_term(&arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test2()
|
void test2()
|
||||||
{
|
{
|
||||||
int *arr;
|
|
||||||
int val;
|
int val;
|
||||||
bool b;
|
struct sc_array_int arr;
|
||||||
|
|
||||||
b = sc_array_create(arr, 0);
|
sc_array_init(&arr);
|
||||||
assert(b);
|
|
||||||
|
|
||||||
sc_array_foreach (arr, val) {
|
sc_array_foreach (&arr, val) {
|
||||||
assert(true);
|
assert(true);
|
||||||
}
|
}
|
||||||
sc_array_destroy(arr);
|
sc_array_term(&arr);
|
||||||
|
|
||||||
b = sc_array_create(arr, 2);
|
sc_array_init(&arr);
|
||||||
assert(b);
|
|
||||||
|
|
||||||
sc_array_foreach (arr, val) {
|
sc_array_foreach (&arr, val) {
|
||||||
assert(true);
|
assert(true);
|
||||||
}
|
}
|
||||||
sc_array_destroy(arr);
|
sc_array_term(&arr);
|
||||||
|
|
||||||
b = sc_array_create(arr, 2);
|
sc_array_init(&arr);
|
||||||
assert(b);
|
|
||||||
|
|
||||||
b = sc_array_add(arr, 1);
|
sc_array_add(&arr, 1);
|
||||||
assert(b);
|
assert(!sc_array_oom(&arr));
|
||||||
|
|
||||||
sc_array_foreach (arr, val) {
|
sc_array_foreach (&arr, val) {
|
||||||
assert(val == 1);
|
assert(val == 1);
|
||||||
}
|
}
|
||||||
sc_array_del_last(arr);
|
sc_array_del_last(&arr);
|
||||||
sc_array_foreach (arr, val) {
|
sc_array_foreach (&arr, val) {
|
||||||
assert(true);
|
assert(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
b = sc_array_add(arr, 1);
|
sc_array_add(&arr, 1);
|
||||||
assert(b == true);
|
assert(!sc_array_oom(&arr));
|
||||||
sc_array_del_unordered(arr, 0);
|
|
||||||
sc_array_foreach (arr, val) {
|
sc_array_del_unordered(&arr, 0);
|
||||||
|
|
||||||
|
sc_array_foreach (&arr, val) {
|
||||||
assert(true);
|
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()
|
void bounds_test()
|
||||||
{
|
{
|
||||||
int *arr, total = 0;
|
int total = 0;
|
||||||
int val;
|
int val;
|
||||||
|
struct sc_array_int arr;
|
||||||
|
|
||||||
sc_array_create(arr, 2);
|
sc_array_init(&arr);
|
||||||
sc_array_add(arr, 3);
|
sc_array_add(&arr, 3);
|
||||||
sc_array_add(arr, 4);
|
sc_array_add(&arr, 4);
|
||||||
|
|
||||||
sc_array_foreach (arr, val) {
|
sc_array_foreach (&arr, val) {
|
||||||
total += val;
|
total += val;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(total == 7);
|
assert(total == 7);
|
||||||
|
|
||||||
sc_array_destroy(arr);
|
sc_array_term(&arr);
|
||||||
|
|
||||||
total = 0;
|
total = 0;
|
||||||
|
|
||||||
sc_array_create(arr, 0);
|
sc_array_init(&arr);
|
||||||
sc_array_foreach (arr, val) {
|
sc_array_foreach (&arr, val) {
|
||||||
total += val;
|
total += val;
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_array_foreach (arr, val) {
|
sc_array_foreach (&arr, val) {
|
||||||
total += val;
|
total += val;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(total == 0);
|
assert(total == 0);
|
||||||
|
|
||||||
sc_array_destroy(arr);
|
sc_array_term(&arr);
|
||||||
|
|
||||||
sc_array_create(arr, 0);
|
sc_array_init(&arr);
|
||||||
sc_array_add(arr, 0);
|
sc_array_add(&arr, 0);
|
||||||
sc_array_add(arr, 1);
|
sc_array_add(&arr, 1);
|
||||||
sc_array_add(arr, 2);
|
sc_array_add(&arr, 2);
|
||||||
sc_array_add(arr, 4);
|
sc_array_add(&arr, 4);
|
||||||
sc_array_add(arr, 3);
|
sc_array_add(&arr, 3);
|
||||||
|
|
||||||
sc_array_del(arr, 3);
|
sc_array_del(&arr, 3);
|
||||||
for (size_t i = 0; i < sc_array_size(arr); i++) {
|
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||||
assert((int) i == arr[i]);
|
assert((int) i == arr.elems[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_array_add(arr, 3);
|
sc_array_add(&arr, 3);
|
||||||
sc_array_add(arr, 4);
|
sc_array_add(&arr, 4);
|
||||||
|
|
||||||
sc_array_del(arr, 3);
|
sc_array_del(&arr, 3);
|
||||||
for (size_t i = 0; i < sc_array_size(arr); i++) {
|
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||||
assert((int) i == arr[i]);
|
assert((int) i == arr.elems[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_array_destroy(arr);
|
sc_array_term(&arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SC_HAVE_WRAP
|
#ifdef SC_HAVE_WRAP
|
||||||
@ -210,99 +228,108 @@ void *__wrap_realloc(void *p, size_t n)
|
|||||||
void fail_test()
|
void fail_test()
|
||||||
{
|
{
|
||||||
int tmp;
|
int tmp;
|
||||||
int *arr, total = 0;
|
int total = 0;
|
||||||
|
struct sc_array_int arr;
|
||||||
|
|
||||||
assert(sc_array_create(arr, SIZE_MAX) == false);
|
sc_array_init(&arr);
|
||||||
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_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(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(sc_array_create(arr, 0) == true);
|
size_t count = SC_ARRAY_MAX / sizeof(int);
|
||||||
|
|
||||||
size_t count = SC_ARRAY_MAX / sizeof(*arr);
|
|
||||||
bool success = false;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < count + 5; i++) {
|
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_term(&arr);
|
||||||
sc_array_create(arr, 0);
|
|
||||||
assert(sc_array_size(arr) == 0);
|
sc_array_init(&arr);
|
||||||
|
assert(sc_array_size(&arr) == 0);
|
||||||
|
|
||||||
fail_realloc = true;
|
fail_realloc = true;
|
||||||
success = sc_array_add(arr, 0);
|
sc_array_add(&arr, 0);
|
||||||
assert(!success);
|
assert(sc_array_oom(&arr));
|
||||||
|
|
||||||
fail_realloc = false;
|
fail_realloc = false;
|
||||||
success = sc_array_add(arr, 222);
|
sc_array_add(&arr, 222);
|
||||||
assert(success);
|
assert(!sc_array_oom(&arr));
|
||||||
sc_array_destroy(arr);
|
sc_array_term(&arr);
|
||||||
|
|
||||||
fail_realloc = true;
|
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;
|
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;
|
fail_realloc = true;
|
||||||
success = sc_array_add(arr, 222);
|
sc_array_add(&arr, 222);
|
||||||
assert(!success);
|
assert(sc_array_oom(&arr));
|
||||||
fail_realloc = false;
|
fail_realloc = false;
|
||||||
|
|
||||||
sc_array_add(arr, 3);
|
sc_array_add(&arr, 3);
|
||||||
sc_array_add(arr, 4);
|
sc_array_add(&arr, 4);
|
||||||
sc_array_add(arr, 5);
|
sc_array_add(&arr, 5);
|
||||||
|
|
||||||
assert(sc_array_size(arr) == 3);
|
assert(sc_array_size(&arr) == 3);
|
||||||
|
|
||||||
sc_array_del(arr, 0);
|
sc_array_del(&arr, 0);
|
||||||
assert(arr[0] == 4);
|
assert(arr.elems[0] == 4);
|
||||||
sc_array_del_last(arr);
|
sc_array_del_last(&arr);
|
||||||
assert(arr[0] == 4);
|
assert(arr.elems[0] == 4);
|
||||||
|
|
||||||
sc_array_add(arr, 1);
|
sc_array_add(&arr, 1);
|
||||||
sc_array_add(arr, 3);
|
sc_array_add(&arr, 3);
|
||||||
sc_array_add(arr, 2);
|
sc_array_add(&arr, 2);
|
||||||
sc_array_add(arr, 0);
|
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++) {
|
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||||
total += arr[i];
|
total += arr.elems[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(total == 10);
|
assert(total == 10);
|
||||||
|
|
||||||
for (size_t i = 0; i < sc_array_size(arr); i++) {
|
for (size_t i = 0; i < sc_array_size(&arr); i++) {
|
||||||
assert(arr[i] == (int) i);
|
assert(arr.elems[i] == (int) i);
|
||||||
}
|
}
|
||||||
|
|
||||||
total = 0;
|
total = 0;
|
||||||
sc_array_foreach (arr, tmp) {
|
sc_array_foreach (&arr, tmp) {
|
||||||
total += tmp;
|
total += tmp;
|
||||||
}
|
}
|
||||||
assert(total == 10);
|
assert(total == 10);
|
||||||
|
|
||||||
sc_array_sort(arr, compare);
|
sc_array_sort(&arr, compare);
|
||||||
sc_array_del_unordered(arr, 0);
|
sc_array_del_unordered(&arr, 0);
|
||||||
assert(arr[0] == 4);
|
assert(arr.elems[0] == 4);
|
||||||
assert(sc_array_size(arr) == 4);
|
assert(sc_array_size(&arr) == 4);
|
||||||
sc_array_clear(arr);
|
sc_array_clear(&arr);
|
||||||
assert(sc_array_size(arr) == 0);
|
assert(sc_array_size(&arr) == 0);
|
||||||
sc_array_add(arr, 10);
|
sc_array_add(&arr, 10);
|
||||||
assert(sc_array_size(arr) == 1);
|
assert(sc_array_size(&arr) == 1);
|
||||||
assert(arr[0] == 10);
|
assert(arr.elems[0] == 10);
|
||||||
|
|
||||||
sc_array_destroy(arr);
|
sc_array_term(&arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -316,7 +343,8 @@ int main(int argc, char *argv[])
|
|||||||
(void) argc;
|
(void) argc;
|
||||||
(void) argv;
|
(void) argv;
|
||||||
|
|
||||||
example();
|
example_str();
|
||||||
|
example_int();
|
||||||
test1();
|
test1();
|
||||||
test2();
|
test2();
|
||||||
fail_test();
|
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
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SC_ARRAY_H
|
#ifndef SC_ARRAY_H
|
||||||
#define SC_ARRAY_H
|
#define SC_ARRAY_H
|
||||||
|
|
||||||
@ -38,63 +37,103 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#else
|
#else
|
||||||
#define sc_array_realloc realloc
|
#define sc_array_realloc realloc
|
||||||
#define sc_array_free free
|
#define sc_array_free free
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Internals, do not use
|
#ifndef SC_ARRAY_MAX
|
||||||
struct sc_array {
|
#define SC_ARRAY_MAX SIZE_MAX
|
||||||
size_t size;
|
#endif
|
||||||
size_t cap;
|
|
||||||
unsigned char elems[];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define sc_array_meta(a) \
|
#define sc_array_def(T, name) \
|
||||||
((struct sc_array *) ((char *) (a) -offsetof(struct sc_array, elems)))
|
struct sc_array_##name { \
|
||||||
|
bool oom; \
|
||||||
bool sc_array_init(void *a, size_t elem_size, size_t cap);
|
size_t cap; \
|
||||||
void sc_array_term(void *a);
|
size_t size; \
|
||||||
bool sc_array_expand(void *a, size_t elem_size);
|
/* NOLINTNEXTLINE */ \
|
||||||
#define sc_array_sizeof(a) (sizeof(a)) // NOLINT
|
T *elems; \
|
||||||
// Internals end
|
}
|
||||||
|
/**
|
||||||
|
* Init array
|
||||||
|
* @param a array
|
||||||
|
*/
|
||||||
|
#define sc_array_init(a) \
|
||||||
|
do { \
|
||||||
|
memset((a), 0, sizeof(*(a))); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param arr array
|
* Term array
|
||||||
* @param cap initial capacity. '0' is a valid initial capacity.
|
* @param a array
|
||||||
* @return 'true' on success, 'false' on out of memory
|
|
||||||
*/
|
*/
|
||||||
#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
|
* Deletes items from the array without deallocating underlying memory
|
||||||
* @return current allocated capacity
|
* @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
|
* @param a array
|
||||||
* @return current element count
|
* @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
|
* Get element at index i, if 'i' is out of range, result is undefined.
|
||||||
* @param a array
|
*
|
||||||
|
* @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 a array
|
||||||
* @param elem element to be appended
|
* @return element count
|
||||||
* @return 'true' on success, 'false' on out of memory.
|
|
||||||
*/
|
*/
|
||||||
#define sc_array_add(a, elem) \
|
#define sc_array_size(a) ((a)->size)
|
||||||
sc_array_expand(&(a), sc_array_sizeof(*(a))) == true ? \
|
|
||||||
(a)[sc_array_meta(a)->size++] = (elem), true : false
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param a array
|
* @param a array
|
||||||
@ -102,61 +141,71 @@ bool sc_array_expand(void *a, size_t elem_size);
|
|||||||
*/
|
*/
|
||||||
#define sc_array_del(a, i) \
|
#define sc_array_del(a, i) \
|
||||||
do { \
|
do { \
|
||||||
assert((i) < sc_array_meta(a)->size); \
|
assert((i) < (a)->size); \
|
||||||
const size_t cnt = sc_array_size(a) - (i) -1; \
|
const size_t _cnt = (a)->size - (i) -1; \
|
||||||
if (cnt > 0) { \
|
if (_cnt > 0) { \
|
||||||
memmove(&(a)[i], &(a)[(i) + 1], cnt * sizeof(*(a))); \
|
memmove(&((a)->elems[i]), &((a)->elems[(i) + 1]), \
|
||||||
|
_cnt * sizeof(*((a)->elems))); \
|
||||||
} \
|
} \
|
||||||
sc_array_meta((a))->size--; \
|
(a)->size--; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the element at index i, replaces last element with the deleted
|
* Deletes the element at index i, replaces last element with the deleted
|
||||||
* element unless deleted element is the last element. This is faster than
|
* element unless deleted element is the last element. This is faster than
|
||||||
* moving elements but elements will no longer be in the 'add order'
|
* 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 a array
|
||||||
* @param i index. If 'i' is out of the range, result is undefined.
|
* @param i index. If 'i' is out of the range, result is undefined.
|
||||||
*/
|
*/
|
||||||
#define sc_array_del_unordered(a, i) \
|
#define sc_array_del_unordered(a, i) \
|
||||||
do { \
|
do { \
|
||||||
assert((i) < sc_array_meta(a)->size); \
|
assert((i) < (a)->size); \
|
||||||
(a)[i] = (a)[(--sc_array_meta((a))->size)]; \
|
(a)->elems[i] = (a)->elems[(--(a)->size)]; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the last element. If current size is zero, result is undefined.
|
* Deletes the last element. If current size is zero, result is undefined.
|
||||||
* @param a array
|
* @param a array
|
||||||
*/
|
*/
|
||||||
#define sc_array_del_last(a) \
|
#define sc_array_del_last(a) \
|
||||||
do { \
|
do { \
|
||||||
assert(sc_array_meta(a)->size != 0); \
|
assert((a)->size != 0); \
|
||||||
sc_array_meta(a)->size--; \
|
(a)->size--; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts the array using qsort()
|
* Sorts the array using qsort()
|
||||||
* @param a array.
|
* @param a array
|
||||||
* @param cmp comparator, check qsort() documentation for details
|
* @param cmp comparator, check qsort() documentation for details
|
||||||
*/
|
*/
|
||||||
#define sc_array_sort(a, cmp) \
|
#define sc_array_sort(a, cmp) (qsort((a)->elems, (a)->size, *(a)->elems, cmp))
|
||||||
(qsort((a), sc_array_size((a)), sc_array_sizeof(*(a)), cmp))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param a array
|
* Returns last element. If array is empty, result is undefined.
|
||||||
* @param elem elem
|
* @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) \
|
#define sc_array_foreach(a, elem) \
|
||||||
for (size_t _k = 1, _i = 0; _k && _i != sc_array_size(a); \
|
for (size_t _k = 1, _i = 0; _k && _i != (a)->size; _k = !_k, _i++) \
|
||||||
_k = !_k, _i++) \
|
for ((elem) = (a)->elems[_i]; _k; _k = !_k)
|
||||||
for ((elem) = (a)[_i]; _k; _k = !_k)
|
|
||||||
|
|
||||||
/**
|
// (type, name)
|
||||||
* Returns last element. If array is empty, result is undefined.
|
sc_array_def(int, int);
|
||||||
* @param a array
|
sc_array_def(unsigned int, uint);
|
||||||
*/
|
sc_array_def(long, long);
|
||||||
#define sc_array_last(a) (a)[sc_array_size(a) - 1]
|
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
|
#endif
|
||||||
|
@ -7,9 +7,10 @@ set(CMAKE_C_EXTENSIONS OFF)
|
|||||||
|
|
||||||
add_library(
|
add_library(
|
||||||
sc_queue SHARED
|
sc_queue SHARED
|
||||||
sc_queue.c
|
|
||||||
sc_queue.h)
|
sc_queue.h)
|
||||||
|
|
||||||
|
set_target_properties(sc_queue PROPERTIES LINKER_LANGUAGE C)
|
||||||
|
|
||||||
target_include_directories(sc_queue PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
target_include_directories(sc_queue PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
if (NOT CMAKE_C_COMPILER_ID MATCHES "MSVC")
|
if (NOT CMAKE_C_COMPILER_ID MATCHES "MSVC")
|
||||||
@ -37,7 +38,7 @@ if (SC_BUILD_TEST)
|
|||||||
|
|
||||||
enable_testing()
|
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)
|
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 -fno-omit-frame-pointer)
|
||||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_HAVE_WRAP)
|
target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_HAVE_WRAP)
|
||||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -fno-builtin)
|
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 ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
### Overview
|
### 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,
|
- Add/remove from head/tail is possible so it can be used as list, stack,
|
||||||
queue, dequeue etc.
|
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
|
### Usage
|
||||||
@ -17,68 +19,27 @@
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
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_foreach (&queue, elem) {
|
||||||
sc_queue_add_last(queue, 3);
|
printf("elem = [%d] \n", elem);
|
||||||
sc_queue_add_last(queue, 4);
|
}
|
||||||
sc_queue_add_first(queue, 1);
|
|
||||||
|
|
||||||
sc_queue_foreach (queue, elem) {
|
elem = sc_queue_del_last(&queue);
|
||||||
printf("elem = [%d] \n", elem);
|
printf("Last element was : [%d] \n", elem);
|
||||||
}
|
|
||||||
|
|
||||||
elem = sc_queue_del_last(queue);
|
elem = sc_queue_del_first(&queue);
|
||||||
printf("Last element was : [%d] \n", elem);
|
printf("First element was : [%d] \n", elem);
|
||||||
|
|
||||||
elem = sc_queue_del_first(queue);
|
sc_queue_term(&queue);
|
||||||
printf("First element was : [%d] \n", elem);
|
return 0;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -2,29 +2,28 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main()
|
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, 2);
|
||||||
sc_queue_add_last(queue, 3);
|
sc_queue_add_last(&queue, 3);
|
||||||
sc_queue_add_last(queue, 4);
|
sc_queue_add_last(&queue, 4);
|
||||||
sc_queue_add_first(queue, 1);
|
sc_queue_add_first(&queue, 1);
|
||||||
|
|
||||||
sc_queue_foreach (queue, elem) {
|
sc_queue_foreach (&queue, elem) {
|
||||||
printf("elem = [%d] \n", 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);
|
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);
|
printf("First element was : [%d] \n", elem);
|
||||||
|
|
||||||
sc_queue_destroy(queue);
|
sc_queue_term(&queue);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -5,62 +5,90 @@
|
|||||||
|
|
||||||
#ifdef SC_HAVE_WRAP
|
#ifdef SC_HAVE_WRAP
|
||||||
|
|
||||||
bool fail_realloc = false;
|
bool fail_calloc = false;
|
||||||
void *__real_realloc(void *p, size_t size);
|
void *__real_calloc(size_t m, size_t n);
|
||||||
void *__wrap_realloc(void *p, size_t n)
|
void *__wrap_calloc(size_t m, size_t n)
|
||||||
{
|
{
|
||||||
if (fail_realloc) {
|
if (fail_calloc) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return __real_realloc(p, n);
|
return __real_calloc(m, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fail_test(void)
|
void fail_test(void)
|
||||||
{
|
{
|
||||||
double *q;
|
struct sc_queue_int q;
|
||||||
|
|
||||||
fail_realloc = true;
|
fail_calloc = true;
|
||||||
assert(sc_queue_create(q, 1000) == false);
|
sc_queue_init(&q);
|
||||||
fail_realloc = false;
|
assert(sc_queue_oom(&q) == true);
|
||||||
assert(sc_queue_create(q, 1000));
|
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;
|
assert(sc_queue_oom(&q) == true);
|
||||||
bool success = false;
|
fail_calloc = false;
|
||||||
for (int i = 0; i < 1024; i++) {
|
sc_queue_add_last(&q, 3);
|
||||||
success = sc_queue_add_last(q, i);
|
assert(sc_queue_oom(&q) == false);
|
||||||
if (!success) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!success);
|
assert(sc_queue_oom(&q));
|
||||||
assert(sc_queue_size(q) == 1023);
|
assert(sc_queue_size(&q) == 7);
|
||||||
fail_realloc = false;
|
fail_calloc = false;
|
||||||
assert(sc_queue_add_last(q, 1023) == true);
|
sc_queue_add_last(&q, 7);
|
||||||
for (int i = 0; i < 1024; i++) {
|
assert(sc_queue_oom(&q) == false);
|
||||||
assert(sc_queue_del_first(q) == i);
|
|
||||||
}
|
|
||||||
assert(sc_queue_size(q) == 0);
|
|
||||||
assert(sc_queue_cap(q) == 2048);
|
|
||||||
|
|
||||||
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;
|
size_t max = SC_QUEUE_MAX;
|
||||||
success = true;
|
|
||||||
for (size_t i = 0; i < max + 500; i++) {
|
for (size_t i = 0; i < max + 500; i++) {
|
||||||
success = sc_queue_add_last(q, i);
|
sc_queue_add_last(&q, i);
|
||||||
if (!success) {
|
if (sc_queue_oom(&q)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!success);
|
assert(sc_queue_oom(&q));
|
||||||
sc_queue_clear(q);
|
fail_calloc = false;
|
||||||
assert(sc_queue_size(q) == 0);
|
sc_queue_add_last(&q, 100);
|
||||||
sc_queue_destroy(q);
|
assert(sc_queue_oom(&q));
|
||||||
assert(sc_queue_create(q, max + 100) == false);
|
sc_queue_clear(&q);
|
||||||
fail_realloc = false;
|
assert(sc_queue_size(&q) == 0);
|
||||||
|
sc_queue_term(&q);
|
||||||
|
sc_queue_init(&q);
|
||||||
|
sc_queue_term(&q);
|
||||||
|
fail_calloc = false;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
void fail_test(void)
|
void fail_test(void)
|
||||||
@ -71,29 +99,27 @@ void fail_test(void)
|
|||||||
|
|
||||||
void example(void)
|
void example(void)
|
||||||
{
|
{
|
||||||
int *queue;
|
|
||||||
int elem;
|
int elem;
|
||||||
|
struct sc_queue_int queue;
|
||||||
|
|
||||||
sc_queue_create(queue, 0);
|
sc_queue_init(&queue);
|
||||||
sc_queue_destroy(queue);
|
|
||||||
|
|
||||||
sc_queue_create(queue, 0);
|
sc_queue_add_last(&queue, 2);
|
||||||
sc_queue_add_last(queue, 2);
|
sc_queue_add_last(&queue, 3);
|
||||||
sc_queue_add_last(queue, 3);
|
sc_queue_add_last(&queue, 4);
|
||||||
sc_queue_add_last(queue, 4);
|
sc_queue_add_first(&queue, 1);
|
||||||
sc_queue_add_first(queue, 1);
|
|
||||||
|
|
||||||
sc_queue_foreach (queue, elem) {
|
sc_queue_foreach (&queue, elem) {
|
||||||
printf("elem = [%d] \n", 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);
|
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);
|
printf("First element was : [%d] \n", elem);
|
||||||
|
|
||||||
sc_queue_destroy(queue);
|
sc_queue_term(&queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test1(void)
|
void test1(void)
|
||||||
@ -101,81 +127,101 @@ void test1(void)
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
int t;
|
int t;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int *p;
|
struct sc_queue_int p;
|
||||||
|
|
||||||
p = NULL;
|
sc_queue_init(&p);
|
||||||
sc_queue_destroy(p);
|
sc_queue_term(&p);
|
||||||
|
|
||||||
assert(sc_queue_create(p, 2) == true);
|
sc_queue_init(&p);
|
||||||
sc_queue_destroy(p);
|
sc_queue_term(&p);
|
||||||
sc_queue_destroy(p);
|
sc_queue_term(&p);
|
||||||
|
|
||||||
sc_queue_add_first(p, 1);
|
sc_queue_init(&p);
|
||||||
sc_queue_add_first(p, 2);
|
sc_queue_add_first(&p, 1);
|
||||||
sc_queue_add_first(p, 3);
|
sc_queue_add_first(&p, 2);
|
||||||
assert(sc_queue_del_first(p) == 3);
|
sc_queue_add_first(&p, 3);
|
||||||
assert(sc_queue_del_first(p) == 2);
|
assert(sc_queue_del_first(&p) == 3);
|
||||||
assert(sc_queue_del_first(p) == 1);
|
assert(sc_queue_del_first(&p) == 2);
|
||||||
sc_queue_destroy(p);
|
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;
|
(void) t;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
assert(count == 0);
|
assert(count == 0);
|
||||||
assert(sc_queue_empty(p) == true);
|
assert(sc_queue_empty(&p) == true);
|
||||||
assert(sc_queue_size(p) == 0);
|
assert(sc_queue_size(&p) == 0);
|
||||||
|
|
||||||
assert(sc_queue_add_first(p, 2) == true);
|
sc_queue_add_first(&p, 2);
|
||||||
assert(sc_queue_add_first(p, 3) == true);
|
sc_queue_add_first(&p, 3);
|
||||||
assert(sc_queue_add_first(p, 4) == true);
|
sc_queue_add_first(&p, 4);
|
||||||
assert(sc_queue_add_first(p, 5) == true);
|
sc_queue_add_first(&p, 5);
|
||||||
assert(sc_queue_add_first(p, 6) == true);
|
sc_queue_add_first(&p, 6);
|
||||||
assert(sc_queue_add_last(p, 1) == true);
|
sc_queue_add_last(&p, 1);
|
||||||
assert(sc_queue_add_last(p, 0) == true);
|
sc_queue_add_last(&p, 0);
|
||||||
|
|
||||||
assert(sc_queue_empty(p) == false);
|
assert(sc_queue_empty(&p) == false);
|
||||||
|
|
||||||
i = 6;
|
i = 6;
|
||||||
sc_queue_foreach (p, t) {
|
sc_queue_foreach (&p, t) {
|
||||||
assert(t == i--);
|
assert(t == i--);
|
||||||
count += t;
|
count += t;
|
||||||
}
|
}
|
||||||
assert(count == 6 * 7 / 2);
|
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_peek_first(&p) == 6);
|
||||||
assert(sc_queue_size(p) == 7);
|
assert(sc_queue_size(&p) == 7);
|
||||||
assert(sc_queue_peek_last(p) == 0);
|
assert(sc_queue_peek_last(&p) == 0);
|
||||||
assert(sc_queue_size(p) == 7);
|
assert(sc_queue_size(&p) == 7);
|
||||||
|
|
||||||
t = sc_queue_del_first(p);
|
t = sc_queue_del_first(&p);
|
||||||
assert(t == 6);
|
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(t == 0);
|
||||||
assert(sc_queue_size(p) == 5);
|
assert(sc_queue_size(&p) == 5);
|
||||||
|
|
||||||
sc_queue_clear(p);
|
sc_queue_clear(&p);
|
||||||
assert(sc_queue_size(p) == 0);
|
assert(sc_queue_size(&p) == 0);
|
||||||
assert(sc_queue_cap(p) == 8);
|
assert(sc_queue_empty(&p) == true);
|
||||||
assert(sc_queue_empty(p) == true);
|
|
||||||
|
|
||||||
sc_queue_destroy(p);
|
sc_queue_term(&p);
|
||||||
sc_queue_destroy(p);
|
sc_queue_term(&p);
|
||||||
|
|
||||||
assert(sc_queue_create(p, 0) == true);
|
sc_queue_init(&p);
|
||||||
sc_queue_add_first(p, 100);
|
sc_queue_add_first(&p, 100);
|
||||||
sc_queue_add_first(p, 200);
|
sc_queue_add_first(&p, 200);
|
||||||
sc_queue_add_first(p, 300);
|
sc_queue_add_first(&p, 300);
|
||||||
sc_queue_add_first(p, 400);
|
sc_queue_add_first(&p, 400);
|
||||||
sc_queue_add_first(p, 500);
|
sc_queue_add_first(&p, 500);
|
||||||
assert(sc_queue_at(p, 0) == 500);
|
assert(sc_queue_at(&p, 0) == 500);
|
||||||
assert(sc_queue_at(p, 4) == 100);
|
assert(sc_queue_at(&p, 4) == 100);
|
||||||
sc_queue_destroy(p);
|
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()
|
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
|
#ifdef SC_HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#else
|
#else
|
||||||
#define sc_queue_realloc realloc
|
#define sc_queue_calloc calloc
|
||||||
#define sc_queue_free free
|
#define sc_queue_free free
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Internals
|
#ifndef SC_QUEUE_MAX
|
||||||
struct sc_queue {
|
#define SC_QUEUE_MAX (SIZE_MAX)
|
||||||
size_t cap;
|
#endif
|
||||||
size_t first;
|
|
||||||
size_t last;
|
|
||||||
unsigned char elems[];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define sc_queue_meta(q) \
|
#define sc_queue_def(T, name) \
|
||||||
((struct sc_queue *) ((char *) (q) -offsetof(struct sc_queue, elems)))
|
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)
|
#define sc_queue_expand(q) \
|
||||||
{
|
do { \
|
||||||
struct sc_queue *m = sc_queue_meta(q);
|
size_t _cap, _len, _off; \
|
||||||
size_t tmp = m->first;
|
size_t _pos = ((q)->last + 1) & ((q)->cap - 1); \
|
||||||
|
void *_dst, *_src; \
|
||||||
m->first = (m->first + 1) & (m->cap - 1);
|
\
|
||||||
return tmp;
|
if (_pos == (q)->first) { \
|
||||||
}
|
if ((q)->cap > SC_QUEUE_MAX / 2ul) { \
|
||||||
|
(q)->oom = true; \
|
||||||
static inline size_t sc_queue_inc_last(void *q)
|
break; \
|
||||||
{
|
} \
|
||||||
struct sc_queue *m = sc_queue_meta(q);
|
_cap = (q)->cap * 2; \
|
||||||
size_t tmp = m->last;
|
_dst = sc_queue_calloc(_cap, sizeof(*((q)->elems))); \
|
||||||
|
if (_dst == NULL) { \
|
||||||
m->last = (m->last + 1) & (m->cap - 1);
|
(q)->oom = true; \
|
||||||
return tmp;
|
break; \
|
||||||
}
|
} \
|
||||||
|
_len = ((q)->cap - (q)->first) * sizeof(*(q)->elems); \
|
||||||
static inline size_t sc_queue_dec_first(void *q)
|
_off = ((q)->first * sizeof(*((q)->elems))); \
|
||||||
{
|
_src = ((char *) (q)->elems) + _off; \
|
||||||
struct sc_queue *m = sc_queue_meta(q);
|
\
|
||||||
|
memcpy(_dst, _src, _len); \
|
||||||
m->first = (m->first - 1) & (m->cap - 1);
|
memcpy(((char *) _dst) + _len, (q)->elems, _off); \
|
||||||
return m->first;
|
(q)->oom = false; \
|
||||||
}
|
(q)->last = (q)->cap - 1; \
|
||||||
|
(q)->first = 0; \
|
||||||
static inline size_t sc_queue_dec_last(void *q)
|
(q)->cap = _cap; \
|
||||||
{
|
sc_queue_free((q)->elems); \
|
||||||
struct sc_queue *m = sc_queue_meta(q);
|
(q)->elems = _dst; \
|
||||||
|
} \
|
||||||
m->last = (m->last - 1) & (m->cap - 1);
|
} while (0)
|
||||||
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
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param q queue
|
* Init queue. Call sc_queue_oom(q) to see if memory allocation succeeded.
|
||||||
* @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
|
|
||||||
* @param q queue
|
* @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
|
* @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
|
* @param q queue
|
||||||
* @return element count
|
* @return element count
|
||||||
*/
|
*/
|
||||||
#define sc_queue_size(q) \
|
#define sc_queue_size(q) (((q)->last - (q)->first) & ((q)->cap - 1))
|
||||||
((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))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the queue without deallocating underlying memory.
|
* 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) \
|
#define sc_queue_clear(q) \
|
||||||
do { \
|
do { \
|
||||||
sc_queue_meta(q)->first = 0; \
|
(q)->first = 0; \
|
||||||
sc_queue_meta(q)->last = 0; \
|
(q)->last = 0; \
|
||||||
|
(q)->oom = false; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param q queue
|
||||||
|
* @return true if queue is empty
|
||||||
|
*/
|
||||||
|
#define sc_queue_empty(q) (((q)->last == (q)->first))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param q queue
|
* @param q queue
|
||||||
* @return index of the first element. If queue is empty, result is undefined.
|
* @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
|
* @param q queue
|
||||||
* @return index of the last element. If queue is empty, result is undefined.
|
* @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.
|
* 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 :
|
* 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
|
* @param q queue
|
||||||
* @return element at index i
|
* @return element at index i
|
||||||
*/
|
*/
|
||||||
#define sc_queue_at(q, i) \
|
#define sc_queue_at(q, i) (q)->elems[(((q)->first) + (i)) & ((q)->cap - 1)]
|
||||||
(q)[((sc_queue_meta(q)->first) + (i)) & (sc_queue_cap(q) - 1)]
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param q queue
|
* @param q queue
|
||||||
* @return peek first element, if queue is empty, result is undefined
|
* @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
|
* @param q queue
|
||||||
* @return peek last element, if queue is empty, result is undefined
|
* @return peek last element, if queue is empty, result is undefined
|
||||||
*/
|
*/
|
||||||
#define sc_queue_peek_last(q) \
|
#define sc_queue_peek_last(q) (q)->elems[((q)->last - 1) & ((q)->cap - 1)]
|
||||||
(q)[(sc_queue_meta(q)->last - 1) & (sc_queue_meta(q)->cap - 1)]
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Call sc_queue_oom(q) after this function to check out of memory condition.
|
||||||
|
*
|
||||||
* @param q queue
|
* @param q queue
|
||||||
* @param elem elem to be added at the end of the list
|
* @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) \
|
#define sc_queue_add_last(q, elem) \
|
||||||
sc_queue_expand(&(q), sc_queue_sizeof(*(q))) == true ? \
|
do { \
|
||||||
(q)[sc_queue_inc_last((q))] = (elem), true : false
|
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
|
* @param q queue
|
||||||
* @return delete the last element from the queue and return its value.
|
* @return delete the last element from the queue and return its value.
|
||||||
* If queue is empty, result is undefined.
|
* 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 q queue.
|
||||||
* @param elem elem to be added at the head of the list.
|
* @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) \
|
#define sc_queue_add_first(q, elem) \
|
||||||
sc_queue_expand(&(q), sc_queue_sizeof(*(q))) == true ? \
|
do { \
|
||||||
(q)[sc_queue_dec_first((q))] = (elem), true : false
|
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
|
* @param q queue
|
||||||
* @return delete the first element from the queue and return its value.
|
* @return delete the first element from the queue and return its value.
|
||||||
* If queue is empty, result is undefined.
|
* 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,
|
* For each loop,
|
||||||
*
|
*
|
||||||
* int *queue;
|
* int *queue;
|
||||||
* sc_queue_create(queue, 4);
|
* sc_queue_create(queue, 4);"
|
||||||
*
|
*
|
||||||
* int elem;
|
* int elem;
|
||||||
* sc_queue_foreach(queue, 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); \
|
for (size_t _k = 1, _i = sc_queue_first(q); \
|
||||||
_k && _i != sc_queue_last(q); \
|
_k && _i != sc_queue_last(q); \
|
||||||
_k = !_k, _i = sc_queue_next(q, _i)) \
|
_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
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user