Add initial stuff
This commit is contained in:
1 parent
2d8bda0fe0
commit
8e9d20ba1a
45 files changed
+8901
No files matched your search
@@ -0,0 +1,18 @@
|
||||
RM=rm -f
|
||||
|
||||
all:
|
||||
@echo "Nothing to be done."
|
||||
|
||||
check:
|
||||
cd tests && make check
|
||||
cd example && make examples
|
||||
|
||||
doc: README.md
|
||||
markdown < README.md > README.html
|
||||
|
||||
clean:
|
||||
cd tests && make clean
|
||||
cd example && make clean
|
||||
$(RM) -f README.html
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
CC=gcc -std=c99
|
||||
CFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function
|
||||
CPPFLAGS=-I..
|
||||
RM=rm -f
|
||||
EXE=./a.exe
|
||||
EXAMPLES=ex01b.c ex01.c ex02.c ex03.c ex04.c ex05.c ex06.c ex07.c
|
||||
|
||||
all:
|
||||
@echo "Nothing to be done."
|
||||
|
||||
check: examples
|
||||
|
||||
examples:
|
||||
for f in $(EXAMPLES) ; do $(CC) $(CFLAGS) $(CPPFLAGS) -g $$f -o $(EXE) -pthread ; done
|
||||
|
||||
clean:
|
||||
$(RM) $(EXE) *.s *~ *.o ./a.dat
|
||||
$(RM) -r coverage *.gcda *.gcno all.info test.tar README.html
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF (charp, char *)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Create an array list
|
||||
array_charp_t al;
|
||||
array_charp_init(al);
|
||||
|
||||
// add elements to the array list
|
||||
array_charp_push_back (al,"C");
|
||||
array_charp_push_back (al,"A");
|
||||
array_charp_push_back (al,"E");
|
||||
array_charp_push_back (al,"B");
|
||||
array_charp_push_back (al,"D");
|
||||
array_charp_push_back (al,"F");
|
||||
|
||||
// Use iterator to display contents of al
|
||||
printf("Original contents of al: ");
|
||||
array_it_charp_t itr;
|
||||
for (array_charp_it(itr, al) ; !array_charp_end_p (itr); array_charp_next(itr)) {
|
||||
char *element = *array_charp_ref(itr);
|
||||
printf ("%s ", element);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// Now, display the list backwards
|
||||
printf("List backwards: ");
|
||||
for (array_charp_previous (itr) ; !array_charp_end_p (itr); array_charp_previous(itr)) {
|
||||
char *element = *array_charp_ref(itr);
|
||||
printf ("%s ", element);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
array_charp_clear(al);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF (charp, char *)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Create an array list
|
||||
M_LET (al, ARRAY_OPLIST(charp)) {
|
||||
// add elements to the array list
|
||||
array_charp_push_back (al,"C");
|
||||
array_charp_push_back (al,"A");
|
||||
array_charp_push_back (al,"E");
|
||||
array_charp_push_back (al,"B");
|
||||
array_charp_push_back (al,"D");
|
||||
array_charp_push_back (al,"F");
|
||||
|
||||
// Display contents of al
|
||||
printf("Original contents of al: ");
|
||||
for M_EACH(element, al, ARRAY_OPLIST(charp)) {
|
||||
printf ("%s ", *element);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include <stdlib.h>
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF(int, int)
|
||||
|
||||
const int n = 100000;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
array_int_t x;
|
||||
array_int_init(x);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
array_int_push_back(x, rand());
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
array_int_push_at (x, rand() % n, rand());
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
array_int_pop_at (NULL, x, rand() % n);
|
||||
}
|
||||
|
||||
array_int_clear(x);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "m-dict.h"
|
||||
#include "m-string.h"
|
||||
|
||||
DICT_DEF2(str, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
dict_str_t h;
|
||||
int max = 1;
|
||||
string_t key;
|
||||
|
||||
dict_str_init(h);
|
||||
string_init (key);
|
||||
while (!feof(stdin))
|
||||
{
|
||||
string_fgets (key, stdin, STRING_READ_PURE_LINE);
|
||||
int *v = dict_str_get (h, key);
|
||||
if (v != NULL) {
|
||||
(*v)++;
|
||||
max = M_MAX(*v, max);
|
||||
} else {
|
||||
dict_str_set_at(h, key, 1);
|
||||
}
|
||||
}
|
||||
string_clear(key);
|
||||
dict_str_clear(h);
|
||||
return 0;
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
#include "m-buffer.h"
|
||||
#include "m-shared.h"
|
||||
#include "m-mutex.h"
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
/* Define a random big data structure */
|
||||
|
||||
#define BIGDATA_SIZE 100000
|
||||
#define BIGDATA_NUM 10
|
||||
|
||||
typedef struct bigdata_s {
|
||||
char bigdata[BIGDATA_SIZE];
|
||||
char *ptr;
|
||||
} bigdata_t[1];
|
||||
|
||||
static void bigdata_init(bigdata_t d)
|
||||
{
|
||||
memset(d->bigdata, 0, BIGDATA_SIZE);
|
||||
d->ptr = malloc (BIGDATA_SIZE * 10);
|
||||
}
|
||||
|
||||
static void bigdata_clear(bigdata_t d)
|
||||
{
|
||||
free(d->ptr);
|
||||
}
|
||||
|
||||
static bigdata_t *bigdata_new (void)
|
||||
{
|
||||
bigdata_t *n = malloc (sizeof (bigdata_t));
|
||||
bigdata_init(*n);
|
||||
return n;
|
||||
}
|
||||
|
||||
static void bigdata_free(bigdata_t *d)
|
||||
{
|
||||
bigdata_clear(*d);
|
||||
free(d);
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
/* Perform some works on this big data */
|
||||
|
||||
static void perform_acquisition(bigdata_t *p)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
static void perform_computation2(bigdata_t *p)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
static void perform_computation3(bigdata_t *p)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
static void perform_computation4(bigdata_t *p)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
/* Let's do the thread scheduling */
|
||||
|
||||
#define MY_QUEUE_SIZE 10
|
||||
SHARED_PTR_DEF(bigdata, bigdata_t, (CLEAR(bigdata_clear), FREE(free)))
|
||||
BUFFER_DEF(bigdata, shared_bigdata_t, MY_QUEUE_SIZE,
|
||||
BUFFER_QUEUE|BUFFER_PUSH_INIT_POP_MOVE, SHARED_PTR_OPLIST(bigdata))
|
||||
|
||||
/* Thread synchros:
|
||||
* Thread1 ---> Thread 2
|
||||
* +-> Thread 3 --> Thread 4
|
||||
*/
|
||||
buffer_bigdata_t buf_t1tot2;
|
||||
buffer_bigdata_t buf_t1tot3;
|
||||
buffer_bigdata_t buf_t3tot4;
|
||||
bool continue_threading;
|
||||
M_THREAD_T t1, t2, t3, t4;
|
||||
|
||||
static void initbuf(void)
|
||||
{
|
||||
buffer_bigdata_init(buf_t1tot2, MY_QUEUE_SIZE);
|
||||
buffer_bigdata_init(buf_t1tot3, MY_QUEUE_SIZE);
|
||||
buffer_bigdata_init(buf_t3tot4, MY_QUEUE_SIZE);
|
||||
}
|
||||
|
||||
static void clearbuf(void)
|
||||
{
|
||||
buffer_bigdata_clear(buf_t1tot2);
|
||||
buffer_bigdata_clear(buf_t1tot3);
|
||||
buffer_bigdata_clear(buf_t3tot4);
|
||||
}
|
||||
|
||||
static void thread1 (void *arg)
|
||||
{
|
||||
while (continue_threading) {
|
||||
shared_bigdata_t ptr;
|
||||
shared_bigdata_init2 (ptr, bigdata_new());
|
||||
perform_acquisition(shared_bigdata_ref(ptr));
|
||||
buffer_bigdata_push(buf_t1tot2, ptr);
|
||||
buffer_bigdata_push(buf_t1tot3, ptr);
|
||||
shared_bigdata_clear(ptr);
|
||||
}
|
||||
}
|
||||
static void thread2 (void *arg)
|
||||
{
|
||||
while (continue_threading) {
|
||||
shared_bigdata_t ptr;
|
||||
shared_bigdata_init (ptr);
|
||||
buffer_bigdata_pop(&ptr, buf_t1tot2);
|
||||
perform_computation2(shared_bigdata_ref(ptr));
|
||||
shared_bigdata_clear(ptr);
|
||||
}
|
||||
}
|
||||
static void thread3 (void *arg)
|
||||
{
|
||||
while (continue_threading) {
|
||||
shared_bigdata_t ptr;
|
||||
shared_bigdata_init (ptr);
|
||||
buffer_bigdata_pop(&ptr, buf_t1tot3);
|
||||
perform_computation3(shared_bigdata_ref(ptr));
|
||||
buffer_bigdata_push(buf_t3tot4, ptr);
|
||||
shared_bigdata_clear(ptr);
|
||||
}
|
||||
}
|
||||
static void thread4 (void *arg)
|
||||
{
|
||||
while (continue_threading) {
|
||||
shared_bigdata_t ptr;
|
||||
shared_bigdata_init (ptr);
|
||||
buffer_bigdata_pop(&ptr, buf_t3tot4);
|
||||
perform_computation4(shared_bigdata_ref(ptr));
|
||||
shared_bigdata_clear(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
initbuf();
|
||||
continue_threading = true;
|
||||
M_THREAD_CREATE(t1, thread1, NULL);
|
||||
M_THREAD_CREATE(t2, thread2, NULL);
|
||||
M_THREAD_CREATE(t3, thread3, NULL);
|
||||
M_THREAD_CREATE(t3, thread4, NULL);
|
||||
}
|
||||
|
||||
static void clear(void)
|
||||
{
|
||||
continue_threading = false;
|
||||
M_THREAD_JOIN(t1);
|
||||
M_THREAD_JOIN(t2);
|
||||
M_THREAD_JOIN(t3);
|
||||
M_THREAD_JOIN(t4);
|
||||
clearbuf();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
//
|
||||
clear();
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/* Based on:
|
||||
https://github.com/kostya/benchmarks/blob/master/brainfuck/brainfuck.cpp */
|
||||
#include <stdio.h>
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
ARRAY_DEF(int, int)
|
||||
|
||||
typedef struct {
|
||||
int pos;
|
||||
array_int_t tape;
|
||||
} tape_t[1];
|
||||
|
||||
static void tape_init(tape_t tape) {
|
||||
tape->pos =0;
|
||||
array_int_init(tape->tape);
|
||||
array_int_push_back(tape->tape, 0);
|
||||
}
|
||||
static void tape_clear(tape_t tape) { array_int_clear(tape->tape); }
|
||||
static int tape_get(tape_t tape) { return *array_int_cget(tape->tape, tape->pos); }
|
||||
static void tape_inc(tape_t tape) { (*array_int_get(tape->tape, tape->pos)) ++; }
|
||||
static void tape_dec(tape_t tape) { (*array_int_get(tape->tape, tape->pos)) --; }
|
||||
static void tape_advance(tape_t tape) { tape->pos++; if (array_int_size(tape->tape) <= (unsigned int) tape->pos) array_int_push_back(tape->tape, 0); }
|
||||
static void tape_devance(tape_t tape) { if (tape->pos > 0) tape->pos--; }
|
||||
|
||||
typedef struct {
|
||||
string_t code;
|
||||
array_int_t bracket_map; // Should use map when possible.
|
||||
} program_t[1];
|
||||
|
||||
static void program_init(program_t p, string_t text) {
|
||||
string_init (p->code);
|
||||
array_int_init (p->bracket_map);
|
||||
array_int_t leftstack;
|
||||
string_t symbols;
|
||||
array_int_init(leftstack);
|
||||
string_init_set_str(symbols, "[]<>+-,.");
|
||||
int pc = 0;
|
||||
for (size_t i = 0; i < string_get_length(text); i++) {
|
||||
char c = string_get_char(text, i);
|
||||
|
||||
if (string_search_char(symbols, c) == STRING_FAILURE) continue;
|
||||
|
||||
if (c == '[') array_int_push_back (leftstack, pc);
|
||||
else
|
||||
if (c == ']' && array_int_size (leftstack) != 0) {
|
||||
int left;
|
||||
array_int_pop_back(&left, leftstack);
|
||||
int right = pc;
|
||||
array_int_set_at2 (p->bracket_map, left, right);
|
||||
array_int_set_at2 (p->bracket_map, right, left);
|
||||
}
|
||||
|
||||
pc++;
|
||||
string_push_back(p->code, c);
|
||||
}
|
||||
array_int_clear(leftstack);
|
||||
string_clear(symbols);
|
||||
}
|
||||
static void program_clear(program_t p) {
|
||||
string_clear(p->code);
|
||||
array_int_clear(p->bracket_map);
|
||||
}
|
||||
static void program_run(program_t p){
|
||||
tape_t tape;
|
||||
tape_init(tape);
|
||||
for(size_t pc = 0; pc < string_get_length(p->code); pc++) {
|
||||
switch (string_get_char(p->code, pc)) {
|
||||
case '+':
|
||||
tape_inc(tape);
|
||||
break;
|
||||
case '-':
|
||||
tape_dec(tape);
|
||||
break;
|
||||
case '>':
|
||||
tape_advance(tape);
|
||||
break;
|
||||
case '<':
|
||||
tape_devance(tape);
|
||||
break;
|
||||
case '[':
|
||||
if (tape_get(tape) == 0) pc = *array_int_cget(p->bracket_map, pc);
|
||||
break;
|
||||
case ']':
|
||||
if (tape_get(tape) != 0) pc = *array_int_cget(p->bracket_map, pc);
|
||||
break;
|
||||
case '.':
|
||||
printf("%c", tape_get(tape));
|
||||
fflush(stdout);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
tape_clear(tape);
|
||||
}
|
||||
|
||||
static void read_file(string_t str, const string_t filename) {
|
||||
FILE *f = fopen(string_get_cstr(filename), "rt");
|
||||
if (!f) abort();
|
||||
string_fgets (str, f, STRING_READ_FILE);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
int main(int argc, const char*argv[])
|
||||
{
|
||||
string_t filename, text;
|
||||
assert (argc >= 2);
|
||||
string_init_set_str(filename, argv[1]);
|
||||
string_init(text);
|
||||
read_file(text, filename);
|
||||
program_t p;
|
||||
program_init(p, text);
|
||||
program_run(p);
|
||||
program_clear(p);
|
||||
string_clear(text);
|
||||
string_clear(filename);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "m-list.h"
|
||||
#include "m-string.h"
|
||||
#include "m-algo.h"
|
||||
|
||||
LIST_DEF(string, string_t, STRING_OPLIST)
|
||||
#define ASTR_OPLIST LIST_OPLIST(string, STRING_OPLIST)
|
||||
ALGO_DEF(astring, ASTR_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Let's create a variable named 'grow' which is a list of string_t
|
||||
M_LET (grow, ASTR_OPLIST)
|
||||
M_LET (tmpstr, STRING_OPLIST) { // And let's create a string_t
|
||||
|
||||
// add string elements to the array
|
||||
list_string_push_back (grow, STRING_CTE("AB"));
|
||||
string_printf(tmpstr, "%d", 12);
|
||||
list_string_push_back (grow, tmpstr);
|
||||
list_string_push_back (grow, STRING_CTE("CD"));
|
||||
|
||||
// get the chunk as a big string
|
||||
list_string_get_str (tmpstr, grow, false);
|
||||
|
||||
// print out
|
||||
printf("Number of elements = %lu\n", list_string_size(grow));
|
||||
printf("Final string = %s\n", string_get_cstr(tmpstr));
|
||||
|
||||
// Another way to print the list
|
||||
for M_EACH (item, grow, ASTR_OPLIST) {
|
||||
printf ("Item = ");
|
||||
string_fputs (stdout, *item);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
// Get the min and the max of the list
|
||||
string_t *p = astring_min(grow);
|
||||
printf ("Min string is %s\n", string_get_cstr(*p));
|
||||
p = astring_max(grow);
|
||||
printf ("Max string is %s\n", string_get_cstr(*p));
|
||||
|
||||
// We can even sort the list!
|
||||
astring_sort(grow);
|
||||
for M_EACH (item, grow, ASTR_OPLIST) {
|
||||
printf ("Sort Item = %s\n", string_get_cstr(*item) );
|
||||
}
|
||||
|
||||
// Split a string into a list.
|
||||
string_set_str(tmpstr, "HELLO;JOHN;HOW;ARE;YOU");
|
||||
astring_split(grow, tmpstr, ';');
|
||||
for M_EACH (item, grow, ASTR_OPLIST) {
|
||||
printf ("Split Item = %s\n", string_get_cstr(*item) );
|
||||
}
|
||||
|
||||
} // Everything is cleared after this point.
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#if 1 // Non macro version.
|
||||
|
||||
#include "m-dict.h"
|
||||
DICT_DEF2(m32, unsigned int, M_DEFAULT_OPLIST, char, M_DEFAULT_OPLIST)
|
||||
|
||||
int main(void) {
|
||||
dict_m32_t h;
|
||||
dict_m32_init(h); // h is init.
|
||||
dict_m32_set_at (h, 5, 10); // h[5] = 10
|
||||
char *k = dict_m32_get(h, 10); // k == NULL
|
||||
int is_missing = (k != NULL); // true
|
||||
assert (is_missing);
|
||||
dict_m32_remove(h, 5); // h is now empty
|
||||
dict_it_m32_t it; // iterate over all dictionnary
|
||||
for (dict_m32_it (it, h) ; !dict_m32_end_p (it); dict_m32_next(it)) {
|
||||
dict_pair_m32_t *item = dict_m32_ref(it);
|
||||
(*item)->value = 1; // Set its value to 1
|
||||
}
|
||||
dict_m32_clear(h); // h is cleared
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else // Use of M_LET & M_FOR macros (otherwise equivalent)
|
||||
|
||||
#include "m-dict.h"
|
||||
DICT_DEF2(m32, unsigned int, M_DEFAULT_OPLIST, char, M_DEFAULT_OPLIST)
|
||||
#define M32_OPLIST DICT_OPLIST(m32, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
int main(void) {
|
||||
M_LET(h, M32_OPLIST) { // h is init
|
||||
dict_m32_set_at (h, 5, 10); // h[5] = 10
|
||||
char *k = dict_m32_get(h, 10); // k == NULL
|
||||
int is_missing = (k != NULL); // true
|
||||
assert (is_missing);
|
||||
dict_m32_remove(h, 5); // h is now empty
|
||||
for M_EACH(item, h, M32_OPLIST) { // traverse each item
|
||||
(*item)->value = 1; // Set its value to 1
|
||||
}
|
||||
} // h is cleared
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* MLIB - ALGO module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_ALGO_H
|
||||
#define __M_ALGO_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
#define ALGO_DEF(name, cont_oplist) \
|
||||
ALGOI_DEF(name, M_GET_TYPE cont_oplist, cont_oplist, \
|
||||
M_GET_SUBTYPE cont_oplist, M_GET_OPLIST cont_oplist, M_GET_IT_TYPE cont_oplist)
|
||||
|
||||
#define ALGO_MAP(container, cont_oplist, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ALGOI_MAP(container, cont_oplist, __VA_ARGS__), \
|
||||
ALGOI_MAP_ARG(name, cont_oplist, __VA_ARGS__ ))
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
#define ALGOI_DEF(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
static inline void CAT(name, _find) (it_t it, container_t l, const type_t data) \
|
||||
{ \
|
||||
for (M_GET_IT_FIRST cont_oplist (it, l); \
|
||||
!M_GET_IT_END_P cont_oplist (it) ; \
|
||||
M_GET_IT_NEXT cont_oplist (it)) { \
|
||||
if (M_GET_EQUAL type_oplist (*M_GET_IT_CREF cont_oplist (it), data)) \
|
||||
return ; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline bool CAT(name, _contains) (container_t l, const type_t data) \
|
||||
{ \
|
||||
it_t it; \
|
||||
CAT(name,_find)(it, l, data); \
|
||||
return !M_GET_IT_END_P cont_oplist (it); \
|
||||
} \
|
||||
\
|
||||
static inline size_t CAT(name, _count) (container_t l, const type_t data) \
|
||||
{ \
|
||||
it_t it; \
|
||||
size_t count = 0; \
|
||||
for (M_GET_IT_FIRST cont_oplist (it, l); \
|
||||
!M_GET_IT_END_P cont_oplist (it) ; \
|
||||
M_GET_IT_NEXT cont_oplist (it)) { \
|
||||
if (M_GET_EQUAL type_oplist (*M_GET_IT_CREF cont_oplist (it), data)) \
|
||||
count++ ; \
|
||||
} \
|
||||
return count; \
|
||||
} \
|
||||
\
|
||||
static inline void CAT(name, _map) (container_t l, \
|
||||
void (*f)(type_t const) ) \
|
||||
{ \
|
||||
for M_EACH(item, l, cont_oplist) { \
|
||||
f(*item); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(CMP, type_oplist)( \
|
||||
static inline type_t *CAT(name, _min) (/*const*/ container_t l) \
|
||||
{ \
|
||||
type_t *min = NULL; \
|
||||
for M_EACH(cref, l, cont_oplist) { \
|
||||
if (min == NULL || \
|
||||
M_GET_CMP type_oplist (*min, *cref) > 0) \
|
||||
min = cref; \
|
||||
} \
|
||||
return min; \
|
||||
} \
|
||||
\
|
||||
static inline type_t *CAT(name, _max) (/*const*/ container_t l) \
|
||||
{ \
|
||||
type_t *max = NULL; \
|
||||
for M_EACH(cref, l, cont_oplist) { \
|
||||
if (max == NULL || \
|
||||
M_GET_CMP type_oplist (*max, *cref) < 0) \
|
||||
max = cref; \
|
||||
} \
|
||||
return max; \
|
||||
} \
|
||||
\
|
||||
static inline void CAT(name, _minmax) (type_t **min_p, type_t **max_p, \
|
||||
/*const*/ container_t l) \
|
||||
{ \
|
||||
type_t *min = NULL; \
|
||||
type_t *max = NULL; \
|
||||
for M_EACH(cref, l, cont_oplist) { \
|
||||
if (min == NULL || \
|
||||
M_GET_CMP type_oplist (*min, *cref) > 0) \
|
||||
min = cref; \
|
||||
if (max == NULL || \
|
||||
M_GET_CMP type_oplist (*max, *cref) < 0) \
|
||||
max = cref; \
|
||||
} \
|
||||
*min_p = min; \
|
||||
*max_p = max; \
|
||||
} \
|
||||
\
|
||||
/* Sort can be generated from 3 algorithms: */ \
|
||||
/* - a specialized version defined by the container */ \
|
||||
/* - an insertion sort (need 'previous' method) */ \
|
||||
/* - a selection sort */ \
|
||||
M_IF_METHOD(SORT, cont_oplist)( \
|
||||
/* optimized sort for container */ \
|
||||
static inline int CAT(name,_sort_cmp)(const type_t*a,const type_t*b) {\
|
||||
return M_GET_CMP type_oplist(*a, *b); \
|
||||
} \
|
||||
static inline void CAT(name, _sort)(container_t l) \
|
||||
{ \
|
||||
M_GET_SORT cont_oplist(l, CAT(name, _sort_cmp)); \
|
||||
} \
|
||||
, \
|
||||
M_IF_METHOD(IT_PREVIOUS, cont_oplist)( \
|
||||
/* generic insertion sort */ \
|
||||
static inline void CAT(name, _sort)(container_t l) \
|
||||
{ \
|
||||
it_t it1; \
|
||||
it_t it2; \
|
||||
it_t it21; \
|
||||
for(M_GET_IT_FIRST cont_oplist (it1, l); \
|
||||
!M_GET_IT_LAST_P cont_oplist (it1); \
|
||||
M_GET_IT_NEXT cont_oplist (it1)) { \
|
||||
type_t x; /* Do not use SET, as it is a MOVE operation */ \
|
||||
memcpy (&x, M_GET_IT_CREF cont_oplist (it1), sizeof (type_t)); \
|
||||
M_GET_IT_SET cont_oplist (it2, it1); \
|
||||
M_GET_IT_SET cont_oplist (it21, it1); \
|
||||
M_GET_IT_PREVIOUS cont_oplist (it2); \
|
||||
while (!M_GET_IT_END_P cont_oplist (it2) \
|
||||
&& M_GET_CMP type_oplist (*M_GET_IT_CREF cont_oplist (it2), \
|
||||
x) > 0) { \
|
||||
memcpy(M_GET_IT_REF cont_oplist (it21), \
|
||||
M_GET_IT_CREF cont_oplist (it2), sizeof (type_t) ); \
|
||||
M_GET_IT_SET cont_oplist (it21, it2); \
|
||||
M_GET_IT_PREVIOUS cont_oplist (it2); \
|
||||
} \
|
||||
memcpy(M_GET_IT_REF cont_oplist (it21), &x, sizeof (type_t) ); \
|
||||
} \
|
||||
} \
|
||||
, \
|
||||
/* generic selection sort */ \
|
||||
static inline void CAT(name, _sort)(container_t l) \
|
||||
{ \
|
||||
it_t it1; \
|
||||
it_t it2; \
|
||||
for(M_GET_IT_FIRST cont_oplist (it1, l); \
|
||||
!M_GET_IT_LAST_P cont_oplist (it1); \
|
||||
M_GET_IT_NEXT cont_oplist (it1)) { \
|
||||
it_t it_min; \
|
||||
M_GET_IT_SET cont_oplist (it_min, it1); \
|
||||
M_GET_IT_SET cont_oplist (it2, it1); \
|
||||
for(M_GET_IT_NEXT cont_oplist (it2) ; \
|
||||
!M_GET_IT_END_P cont_oplist (it2); \
|
||||
M_GET_IT_NEXT cont_oplist (it2)) { \
|
||||
if (M_GET_CMP type_oplist (*M_GET_IT_CREF cont_oplist (it2), \
|
||||
*M_GET_IT_CREF cont_oplist (it_min)) < 0) { \
|
||||
M_GET_IT_SET cont_oplist (it_min, it2); \
|
||||
} \
|
||||
} \
|
||||
if (M_GET_IT_EQUAL_P cont_oplist (it_min, it1) == false) { \
|
||||
type_t x; /* Do not use SET, as it is a MOVE operation */ \
|
||||
memcpy (&x, M_GET_IT_CREF cont_oplist (it1), sizeof (type_t)); \
|
||||
memcpy (M_GET_IT_REF cont_oplist (it1), \
|
||||
M_GET_IT_CREF cont_oplist (it_min), sizeof (type_t)); \
|
||||
memcpy (M_GET_IT_REF cont_oplist (it_min), &x, sizeof (type_t)); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
) /* IF IT_PREVIOUS METHOD */ \
|
||||
) /* IF SORT METHOD */ \
|
||||
,) /* IF CMP METHOD */ \
|
||||
\
|
||||
M_IF_METHOD(EXT_ALGO, type_oplist)( \
|
||||
M_GET_EXT_ALGO type_oplist (name, cont_oplist, type_oplist) \
|
||||
, ) \
|
||||
|
||||
//TODO: const_iterator & CM_EACH missing...
|
||||
//TODO: Algorithm missing
|
||||
// nth_element, ...
|
||||
|
||||
#define ALGOI_MAP(container, cont_oplist, func) \
|
||||
for M_EACH(item, l, cont_oplist) { \
|
||||
func(*item); \
|
||||
} \
|
||||
|
||||
#define ALGOI_MAP_ARG(container, cont_oplist, func, ...) \
|
||||
for M_EACH(item, l, cont_oplist) { \
|
||||
func(__VA_ARGS, *item); \
|
||||
} \
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,639 @@
|
||||
/*
|
||||
* MLIB - ARRAY module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_ARRAY_H
|
||||
#define __M_ARRAY_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define an array of a given type.
|
||||
USAGE: ARRAY_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define ARRAY_DEF(name, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ARRAYI_DEF2(name, __VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
ARRAYI_DEF2(name, __VA_ARGS__ ))
|
||||
|
||||
/* Define the oplist of an array of type.
|
||||
USAGE: ARRAY_OPLIST(name[, oplist of the type]) */
|
||||
#define ARRAY_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ARRAYI_OPLIST(__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
ARRAYI_OPLIST(__VA_ARGS__ ))
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
#define ARRAYI_OPLIST(name, oplist) \
|
||||
(INIT(CAT3(array_, name, _init)) \
|
||||
,INIT_SET(CAT3(array_, name, _init_set)) \
|
||||
,SET(CAT3(array_, name, _set)) \
|
||||
,CLEAR(CAT3(array_, name, _clear)) \
|
||||
,INIT_MOVE(CAT3(array_, name, _init_move)) \
|
||||
,MOVE(CAT3(array_, name, _move)) \
|
||||
,TYPE(CAT3(array_,name,_t)) \
|
||||
,SUBTYPE(CAT3(array_type_,name,_t)) \
|
||||
,IT_TYPE(CAT3(array_it_,name,_t)) \
|
||||
,IT_FIRST(CAT3(array_,name,_it)) \
|
||||
,IT_SET(CAT3(array_,name,_it_set)) \
|
||||
,IT_END_P(CAT3(array_,name,_end_p)) \
|
||||
,IT_LAST_P(CAT3(array_,name,_last_p)) \
|
||||
,IT_EQUAL_P(CAT3(array_,name,_it_equal_p)) \
|
||||
,IT_NEXT(CAT3(array_,name,_next)) \
|
||||
,IT_PREVIOUS(CAT3(array_,name,_previous)) \
|
||||
,IT_REF(CAT3(array_,name,_ref)) \
|
||||
,IT_CREF(CAT3(array_,name,_cref)) \
|
||||
,CLEAN(CAT3(array_,name,_clean)) \
|
||||
,PUSH(CAT3(array_,name,_push_back)) \
|
||||
,POP(CAT3(array_,name,_pop_back)) \
|
||||
,OPLIST(oplist) \
|
||||
,M_IF_METHOD(CMP, oplist)(SORT(CAT3(array_, name, _sort)),) \
|
||||
,M_IF_METHOD(GET_STR, oplist)(GET_STR(CAT3(array_, name, _get_str)),) \
|
||||
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(CAT3(array_, name, _out_str)),) \
|
||||
,M_IF_METHOD(IN_STR, oplist)(IN_STR(CAT3(array_, name, _in_str)),) \
|
||||
,M_IF_METHOD(EQUAL, oplist)(EQUAL(CAT3(array_, type, _equal_p)),) \
|
||||
)
|
||||
|
||||
// Compute alloc from size.
|
||||
#define ARRAYI_INC_ALLOC_SIZE(n) ((n) < 8 ? 16 : (n) * 2)
|
||||
|
||||
// Internal
|
||||
#define ARRAYI_DEF2(name, type, oplist) \
|
||||
typedef struct CAT3(array_, name, _s) { \
|
||||
size_t size, alloc; \
|
||||
type *ptr; \
|
||||
} CAT3(array_, name,_t)[1]; \
|
||||
\
|
||||
typedef union { \
|
||||
type *ptr; \
|
||||
const type *cptr; \
|
||||
} CAT3(array_union_, name,_t); \
|
||||
\
|
||||
typedef type CAT3(array_type_,name,_t); \
|
||||
\
|
||||
typedef struct CAT3(array_it_,name,_s) { \
|
||||
size_t index; \
|
||||
struct CAT3(array_, name, _s) *array; \
|
||||
} CAT3(array_it_,name,_t)[1]; \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(array_, name, _const_cast)(type *ptr) \
|
||||
{ \
|
||||
CAT3(array_union_, name,_t) u; \
|
||||
u.ptr = ptr; \
|
||||
return u.cptr; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _init)(CAT3(array_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL); \
|
||||
v->size = v->alloc = 0; \
|
||||
v->ptr = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _clean)(CAT3(array_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL && v->size <= v->alloc); \
|
||||
for(size_t i = 0; i < v->size; i++) \
|
||||
M_GET_CLEAR oplist(v->ptr[i]); \
|
||||
v->size = 0; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _clear)(CAT3(array_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL && v->size <= v->alloc); \
|
||||
CAT3(array_, name, _clean)(v); \
|
||||
M_MEMORY_FREE(v->ptr); \
|
||||
v->alloc = 0; \
|
||||
v->ptr = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _set)(CAT3(array_, name,_t) d, \
|
||||
const CAT3(array_, name,_t) s) \
|
||||
{ \
|
||||
assert (d != NULL && s != NULL \
|
||||
&& d->size <= d->alloc && s->size <= s->alloc); \
|
||||
if (d == s) return; \
|
||||
if (s->size > d->alloc) { \
|
||||
size_t alloc = ARRAYI_INC_ALLOC_SIZE(s->size); \
|
||||
type *ptr = M_MEMORY_REALLOC (type, d->ptr, alloc); \
|
||||
if (ptr == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (type) * alloc); \
|
||||
return ; \
|
||||
} \
|
||||
d->ptr = ptr; \
|
||||
d->alloc = alloc; \
|
||||
} \
|
||||
size_t i, step1 = M_MIN(s->size, d->size); \
|
||||
for(i = 0; i < step1; i++) \
|
||||
M_GET_SET oplist (d->ptr[i], s->ptr[i]); \
|
||||
for( ; i < s->size; i++) \
|
||||
M_GET_INIT_SET oplist (d->ptr[i], s->ptr[i]); \
|
||||
for( ; i < d->size; i++) \
|
||||
M_GET_CLEAR oplist (d->ptr[i]); \
|
||||
d->size = s->size; \
|
||||
assert (d->size <= d->alloc); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _init_set)(CAT3(array_, name,_t) d, \
|
||||
const CAT3(array_, name,_t) s) \
|
||||
{ \
|
||||
assert (d != s); \
|
||||
CAT3(array_, name, _init)(d); \
|
||||
CAT3(array_, name, _set)(d, s); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _init_move)(CAT3(array_, name,_t) d, \
|
||||
CAT3(array_, name,_t) s) \
|
||||
{ \
|
||||
assert (d != s); \
|
||||
d->size = s->size; \
|
||||
d->alloc = s->alloc; \
|
||||
d->ptr = s->ptr; \
|
||||
s->size = s->alloc = 0; \
|
||||
s->ptr = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _move)(CAT3(array_, name,_t) d, \
|
||||
CAT3(array_, name,_t) s) \
|
||||
{ \
|
||||
assert (d != s); \
|
||||
CAT3(array_, name, _clear)(d); \
|
||||
CAT3(array_, name, _init_move)(d, s); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _set_at)(CAT3(array_, name,_t) v, size_t i, type x) \
|
||||
{ \
|
||||
assert(v != NULL && i < v->size && v->ptr != NULL); \
|
||||
M_GET_SET oplist(v->ptr[i], x); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(array_, name, _back)(CAT3(array_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL && v->ptr != NULL); \
|
||||
return CAT3(array_, name, _const_cast)(&v->ptr[v->size-1]); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(array_, name, _push_raw)(CAT3(array_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL && v->size <= v->alloc); \
|
||||
if (v->size >= v->alloc) { \
|
||||
assert(v->size == v->alloc); \
|
||||
size_t alloc = ARRAYI_INC_ALLOC_SIZE(v->alloc); \
|
||||
assert (alloc > v->size); \
|
||||
type *ptr = M_MEMORY_REALLOC (type, v->ptr, alloc); \
|
||||
if (ptr == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (type) * alloc); \
|
||||
return NULL; \
|
||||
} \
|
||||
v->ptr = ptr; \
|
||||
v->alloc = alloc; \
|
||||
} \
|
||||
assert(v->ptr != NULL); \
|
||||
type *ret = &v->ptr[v->size]; \
|
||||
v->size++; \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _push_back)(CAT3(array_, name,_t) v, type const x) \
|
||||
{ \
|
||||
assert (v != NULL); \
|
||||
type *data = CAT3(array_, name, _push_raw)(v); \
|
||||
if (data == NULL) \
|
||||
return; \
|
||||
M_GET_INIT_SET oplist(*data, x); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(array_, name, _push_new)(CAT3(array_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL); \
|
||||
type *data = CAT3(array_, name, _push_raw)(v); \
|
||||
if (data == NULL) \
|
||||
return NULL; \
|
||||
M_GET_INIT oplist(*data); \
|
||||
return data; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _push_at)(CAT3(array_, name,_t) v, size_t key, type const x) \
|
||||
{ \
|
||||
assert (v != NULL && key <= v->size && v->size <= v->alloc); \
|
||||
if (v->size >= v->alloc) { \
|
||||
assert(v->size == v->alloc); \
|
||||
size_t alloc = ARRAYI_INC_ALLOC_SIZE(v->alloc); \
|
||||
assert (alloc > v->size); \
|
||||
type *ptr = M_MEMORY_REALLOC (type, v->ptr, alloc); \
|
||||
if (ptr == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (type) * alloc); \
|
||||
return; \
|
||||
} \
|
||||
v->ptr = ptr; \
|
||||
v->alloc = alloc; \
|
||||
} \
|
||||
assert(v->ptr != NULL); \
|
||||
memmove(&v->ptr[key+1], &v->ptr[key], (v->size-key)*sizeof(type)); \
|
||||
v->size++; \
|
||||
M_GET_INIT_SET oplist (v->ptr[key], x); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _resize)(CAT3(array_, name, _t) v, size_t size) \
|
||||
{ \
|
||||
assert (v != NULL && v->size <= v->alloc); \
|
||||
if (v->size > size) { \
|
||||
/* Decrease size of array */ \
|
||||
for(size_t i = size ; i < v->size; i++) \
|
||||
M_GET_CLEAR oplist(v->ptr[i]); \
|
||||
v->size = size; \
|
||||
} else if (v->size < size) { \
|
||||
/* Increase size of array */ \
|
||||
if (size > v->alloc) { \
|
||||
size_t alloc = size ; \
|
||||
type *ptr = M_MEMORY_REALLOC (type, v->ptr, alloc); \
|
||||
if (ptr == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (type) * alloc); \
|
||||
return; \
|
||||
} \
|
||||
v->ptr = ptr; \
|
||||
v->alloc = alloc; \
|
||||
} \
|
||||
for(size_t i = v->size ; i < size; i++) \
|
||||
M_GET_INIT oplist(v->ptr[i]); \
|
||||
v->size = size; \
|
||||
} \
|
||||
assert (v != NULL && v->size <= v->alloc); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _set_at2)(CAT3(array_, name,_t) v, size_t idx, type x) \
|
||||
{ \
|
||||
assert (v != NULL && v->size <= v->alloc); \
|
||||
size_t size = idx + 1; \
|
||||
if (v->size <= size) { \
|
||||
/* Increase size of array */ \
|
||||
if (size > v->alloc) { \
|
||||
size_t alloc = ARRAYI_INC_ALLOC_SIZE (size) ; \
|
||||
type *ptr = M_MEMORY_REALLOC (type, v->ptr, alloc); \
|
||||
if (ptr == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (type) * alloc); \
|
||||
return; \
|
||||
} \
|
||||
v->ptr = ptr; \
|
||||
v->alloc = alloc; \
|
||||
} \
|
||||
for(size_t i = v->size ; i < size; i++) \
|
||||
M_GET_INIT oplist(v->ptr[i]); \
|
||||
v->size = size; \
|
||||
} \
|
||||
M_GET_SET oplist(v->ptr[idx], x); \
|
||||
assert (v != NULL && v->size <= v->alloc); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _pop_back)(type *dest, CAT3(array_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL && v->size > 0 && v->ptr != NULL); \
|
||||
v->size--; \
|
||||
if (dest) \
|
||||
M_IF_METHOD(MOVE, oplist) ( \
|
||||
M_GET_MOVE oplist(*dest, v->ptr[v->size]); else \
|
||||
, \
|
||||
M_GET_SET oplist(*dest, v->ptr[v->size]); \
|
||||
) \
|
||||
M_GET_CLEAR oplist (v->ptr[v->size]); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(array_, name, _empty_p)(const CAT3(array_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL); \
|
||||
return v->size == 0; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
CAT3(array_, name, _size)(const CAT3(array_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL); \
|
||||
return v->size; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
CAT3(array_, name, _capacity)(const CAT3(array_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL); \
|
||||
return v->alloc; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _pop_at)(type *dest, CAT3(array_, name,_t) v, size_t i) \
|
||||
{ \
|
||||
assert(v != NULL && v->size > 0 && i < v->size && v->ptr != NULL); \
|
||||
if (dest) \
|
||||
M_IF_METHOD(MOVE, oplist) ( \
|
||||
M_GET_MOVE oplist(*dest, v->ptr[i]); else \
|
||||
, \
|
||||
M_GET_SET oplist (*dest, v->ptr[i]); \
|
||||
) \
|
||||
M_GET_CLEAR oplist (v->ptr[i]); \
|
||||
memmove(&v->ptr[i], &v->ptr[i+1], sizeof(type)*(v->size - i) ); \
|
||||
v->size--; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _insert_v)(CAT3(array_, name,_t) v, size_t i, size_t j) \
|
||||
{ \
|
||||
assert (v != NULL); \
|
||||
assert(i < v->size && j <= v->size && i < j); \
|
||||
size_t size = v->size + (j-i); \
|
||||
if (size > v->alloc) { \
|
||||
size_t alloc = ARRAYI_INC_ALLOC_SIZE (size) ; \
|
||||
type *ptr = M_MEMORY_REALLOC (type, v->ptr, alloc); \
|
||||
if (ptr == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (type) * alloc); \
|
||||
return; \
|
||||
} \
|
||||
v->ptr = ptr; \
|
||||
v->alloc = alloc; \
|
||||
} \
|
||||
memmove(&v->ptr[j], &v->ptr[i], sizeof(type)*(v->size - j) ); \
|
||||
for(size_t k = i ; k < j; k++) \
|
||||
M_GET_INIT oplist(v->ptr[i]); \
|
||||
v->size = size; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _remove_v)(CAT3(array_, name,_t) v, size_t i, size_t j) \
|
||||
{ \
|
||||
assert (v != NULL); \
|
||||
assert(i < v->size && j <= v->size && i < j && v->ptr != NULL); \
|
||||
for(size_t k = i ; k < j; k++) \
|
||||
M_GET_CLEAR oplist(v->ptr[k]); \
|
||||
memmove(&v->ptr[i], &v->ptr[j], sizeof(type)*(v->size - j) ); \
|
||||
v->size -= (j-i); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_,name, _remove)(CAT3(array_, name,_t) v, size_t i) \
|
||||
{ \
|
||||
CAT3(array_, name, _pop_at)(NULL, v, i); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _swap)(CAT3(array_, name,_t) v, size_t i, size_t j) \
|
||||
{ \
|
||||
assert (v != NULL); \
|
||||
assert(i < v->size && j < v->size && v->ptr != NULL); \
|
||||
type tmp; \
|
||||
M_IF_METHOD(INIT_MOVE, oplist) ( \
|
||||
M_GET_INIT_MOVE oplist (tmp, v->ptr[i]); \
|
||||
M_GET_INIT_MOVE oplist (v->ptr[i], v->ptr[j]); \
|
||||
M_GET_INIT_MOVE oplist (v->ptr[j], tmp); \
|
||||
, \
|
||||
M_GET_INIT_SET oplist (tmp, v->ptr[i]); \
|
||||
M_GET_SET oplist(v->ptr[i], v->ptr[j]); \
|
||||
M_GET_SET oplist(v->ptr[j], tmp); \
|
||||
M_GET_CLEAR oplist(tmp); \
|
||||
) /* IF INIT_MOVE method */ \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _shrink_to_fit)(CAT3(array_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL && v->size <= v->alloc); \
|
||||
v->ptr = M_MEMORY_REALLOC (type, v->ptr, v->size); \
|
||||
assert(v->ptr != NULL || v->size == 0); \
|
||||
v->alloc = v->size; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(array_, name, _get)(CAT3(array_, name,_t) v, size_t i) \
|
||||
{ \
|
||||
assert (v != NULL && i < v->size && v->ptr != NULL); \
|
||||
return &v->ptr[i]; \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(array_, name, _cget)(const CAT3(array_, name,_t) v, size_t i) \
|
||||
{ \
|
||||
assert(v != NULL && i < v->size && v->ptr != NULL); \
|
||||
return CAT3(array_, name, _const_cast)(&v->ptr[i]); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _it)(CAT3(array_it_,name,_t) it, \
|
||||
CAT3(array_, name, _t) v) \
|
||||
{ \
|
||||
assert (it != NULL && v != NULL); \
|
||||
it->index = 0; \
|
||||
it->array = v; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _it_set)(CAT3(array_it_,name,_t) it, \
|
||||
const CAT3(array_it_, name, _t) org) \
|
||||
{ \
|
||||
assert (it != NULL && org != NULL); \
|
||||
it->index = org->index; \
|
||||
it->array = org->array; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(array_, name, _end_p)(const CAT3(array_it_, name, _t) it) \
|
||||
{ \
|
||||
assert(it != NULL && it->array != NULL); \
|
||||
return (it->index) >= it->array->size; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(array_, name, _last_p)(const CAT3(array_it_, name, _t) it) \
|
||||
{ \
|
||||
assert(it != NULL && it->array != NULL); \
|
||||
/* Case i=0 & s=0 ==> true since unsigned type */ \
|
||||
return (it->index) >= it->array->size-1; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(array_, name, _it_equal_p)(const CAT3(array_it_, name,_t) it1, \
|
||||
const CAT3(array_it_, name,_t) it2) \
|
||||
{ \
|
||||
assert(it1 != NULL && it2 != NULL); \
|
||||
return it1->array == it2->array && it1->index == it2->index; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _next)(CAT3(array_it_,name,_t) it) \
|
||||
{ \
|
||||
assert(it != NULL && it->array != NULL); \
|
||||
it->index ++; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _previous)(CAT3(array_it_,name,_t) it) \
|
||||
{ \
|
||||
assert(it != NULL && it->array != NULL); \
|
||||
/* In the case index=0, it will be set to (unsigned) -1 \
|
||||
==> it will be greater than size ==> end_p will return true */ \
|
||||
it->index --; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(array_, name, _ref)(CAT3(array_it_, name,_t) it) \
|
||||
{ \
|
||||
assert(it != NULL); \
|
||||
return CAT3(array_, name, _get)(it->array, it->index); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(array_, name, _cref)(const CAT3(array_it_, name,_t) it) \
|
||||
{ \
|
||||
assert(it != NULL); \
|
||||
return CAT3(array_, name, _cget)(it->array, it->index); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(array_, name, _insert)(CAT3(array_it_, name,_t) it, type const x) \
|
||||
{ \
|
||||
assert(it != NULL); \
|
||||
CAT3(array_, name, _push_at)(it->array, it->index, x); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(CMP, oplist) \
|
||||
( \
|
||||
static inline void CAT3(array_, name, _sort)(CAT3(array_, name,_t) l, \
|
||||
int (*func_type) (const type *a, const type *b))\
|
||||
{ \
|
||||
/* Using qsort is more compact but slower than a full templated \
|
||||
version which can be twice faster */ \
|
||||
int (*func_void)(const void*, const void*); \
|
||||
/* There is no way to avoid the cast */ \
|
||||
func_void = (int (*)(const void*, const void*))func_type; \
|
||||
qsort (l->ptr, l->size, sizeof(type), func_void); \
|
||||
} \
|
||||
,) /* IF CMP oplist */ \
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
CAT3(array_, name, _get_str)(string_t str, CAT3(array_, name,_t) array, \
|
||||
bool append) \
|
||||
{ \
|
||||
assert (str != NULL && array != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
CAT3(array_it_, name, _t) it; \
|
||||
for (CAT3(array_, name, _it)(it, array) ; \
|
||||
!CAT3(array_, name, _end_p)(it); \
|
||||
CAT3(array_, name, _next)(it)){ \
|
||||
const type *item = CAT3(array_, name, _cref)(it); \
|
||||
M_GET_GET_STR oplist (str, *item, true); \
|
||||
if (!CAT3(array_, name, _last_p)(it)) \
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
} \
|
||||
, /* no str */ ) \
|
||||
\
|
||||
M_IF_METHOD(OUT_STR, oplist)( \
|
||||
static inline void \
|
||||
CAT3(array_, name, _out_str)(FILE *file, CAT3(array_, name,_t) array) \
|
||||
{ \
|
||||
assert (file != NULL && array != NULL); \
|
||||
fprintf (file, "["); \
|
||||
CAT3(array_it_, name, _t) it; \
|
||||
for (CAT3(array_, name, _it)(it, array) ; \
|
||||
!CAT3(array_, name, _end_p)(it); \
|
||||
CAT3(array_, name, _next)(it)){ \
|
||||
const type *item = CAT3(array_, name, _cref)(it); \
|
||||
M_GET_OUT_STR oplist (file, *item); \
|
||||
if (!CAT3(array_, name, _last_p)(it)) \
|
||||
fputc (M_GET_SEPARATOR oplist, file); \
|
||||
} \
|
||||
fprintf (file, "]"); \
|
||||
} \
|
||||
, /* no out_str */ ) \
|
||||
\
|
||||
M_IF_METHOD(IN_STR, oplist)( \
|
||||
static inline bool \
|
||||
CAT3(array_, name, _in_str)(CAT3(array_, name,_t) array, FILE *file) \
|
||||
{ \
|
||||
assert (file != NULL && array != NULL); \
|
||||
CAT3(array_, name,_clean)(array); \
|
||||
char c = fgetc(file); \
|
||||
if (c != '[') return false; \
|
||||
type item; \
|
||||
M_GET_INIT oplist (item); \
|
||||
do { \
|
||||
bool b = M_GET_IN_STR oplist (item, file); \
|
||||
if (!b) { M_GET_CLEAR oplist (item); return false; } \
|
||||
CAT3(array_, name, _push_back)(array, item); \
|
||||
c = fgetc(file); \
|
||||
} while (c == M_GET_SEPARATOR oplist && !feof(file) && !ferror(file)); \
|
||||
M_GET_CLEAR oplist (item); \
|
||||
return c == ']'; \
|
||||
} \
|
||||
, /* no in_str */ ) \
|
||||
\
|
||||
M_IF_METHOD(EQUAL, oplist)( \
|
||||
static inline bool \
|
||||
CAT3(array_, name, _equal_p)(CAT3(array_, name,_t) array1, \
|
||||
CAT3(array_, name,_t) array2) \
|
||||
{ \
|
||||
assert (array1 != NULL && array2 != NULL); \
|
||||
CAT3(array_it_, name, _t) it1; \
|
||||
CAT3(array_it_, name, _t) it2; \
|
||||
CAT3(array_, name, _it)(it1, array1); \
|
||||
CAT3(array_, name, _it)(it2, array2); \
|
||||
while (!CAT3(array_, name, _end_p)(it1) \
|
||||
&&!CAT3(array_, name, _end_p)(it2)) { \
|
||||
const type *item1 = CAT3(array_, name, _cref)(it1); \
|
||||
const type *item2 = CAT3(array_, name, _cref)(it2); \
|
||||
bool b = M_GET_EQUAL oplist (*item1, *item2); \
|
||||
if (!b) return false; \
|
||||
CAT3(array_, name, _next)(it1); \
|
||||
CAT3(array_, name, _next)(it2); \
|
||||
} \
|
||||
return CAT3(array_, name, _end_p)(it1) \
|
||||
&& CAT3(array_, name, _end_p)(it2); \
|
||||
} \
|
||||
, /* no equal */ ) \
|
||||
\
|
||||
|
||||
// TODO: Conditional HASH if HASH is present
|
||||
// TODO: 'remove' interface is different in list & array ==> erase for iterator & pop for size_t
|
||||
|
||||
#endif
|
||||
+382
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* MLIB - BITSET module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_BITSET_H
|
||||
#define __M_BITSET_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
typedef struct bitset_s {
|
||||
size_t size; // Size is the number of bits
|
||||
size_t alloc; // Alloc is the number of allocated bytes
|
||||
unsigned char *ptr;
|
||||
} bitset_t[1];
|
||||
|
||||
typedef struct bitset_it_s {
|
||||
size_t index;
|
||||
struct bitset_s *set;
|
||||
} bitset_it_t[1];
|
||||
|
||||
// Compute alloc from size.
|
||||
#define BITSETI_INC_ALLOC_SIZE(n) ((n) < 8 ? 16 : (n) * 2)
|
||||
#define BITSETI_TO_ALLOC(n) (((n) + CHAR_BIT - 1) / CHAR_BIT)
|
||||
#define BITSETI_FROM_ALLOC(n) ((n) * CHAR_BIT)
|
||||
|
||||
#define BITSETI_CONTRACT(t) \
|
||||
assert (t != NULL); \
|
||||
assert (t->size <= BITSETI_FROM_ALLOC (t->alloc)); \
|
||||
assert (t->size == 0 || t->ptr != NULL);
|
||||
|
||||
static inline void
|
||||
bitset_init(bitset_t t)
|
||||
{
|
||||
assert (t != NULL);
|
||||
assert (M_POWEROF2_P(CHAR_BIT));
|
||||
t->size = t->alloc = 0;
|
||||
t->ptr = NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_clean(bitset_t t)
|
||||
{
|
||||
BITSETI_CONTRACT(t);
|
||||
t->size = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_clear(bitset_t t)
|
||||
{
|
||||
bitset_clean(t);
|
||||
M_MEMORY_FREE(t->ptr);
|
||||
t->alloc = 0;
|
||||
t->ptr = NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_set(bitset_t d, const bitset_t s)
|
||||
{
|
||||
BITSETI_CONTRACT(d);
|
||||
BITSETI_CONTRACT(s);
|
||||
if (d == s) return;
|
||||
const size_t needAlloc = BITSETI_TO_ALLOC (s->size);
|
||||
if (s->size > BITSETI_FROM_ALLOC (d->alloc)) {
|
||||
unsigned char *ptr = M_MEMORY_REALLOC (unsigned char, d->ptr, needAlloc);
|
||||
if (ptr == NULL) {
|
||||
M_MEMORY_FULL(needAlloc);
|
||||
return ;
|
||||
}
|
||||
d->ptr = ptr;
|
||||
d->alloc = needAlloc;
|
||||
}
|
||||
memcpy (d->ptr, s->ptr, needAlloc);
|
||||
d->size = s->size;
|
||||
BITSETI_CONTRACT(d);
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_init_set(bitset_t d, const bitset_t s)
|
||||
{
|
||||
assert (d != s);
|
||||
bitset_init(d);
|
||||
bitset_set(d, s);
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_init_move(bitset_t d, bitset_t s)
|
||||
{
|
||||
BITSETI_CONTRACT(s);
|
||||
d->size = s->size;
|
||||
d->alloc = s->alloc;
|
||||
d->ptr = s->ptr;
|
||||
s->alloc = 0;
|
||||
s->ptr = NULL;
|
||||
BITSETI_CONTRACT(d);
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_move(bitset_t d, bitset_t s)
|
||||
{
|
||||
bitset_clear(d);
|
||||
bitset_init_move (d, s);
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_set_at(bitset_t v, size_t i, bool x)
|
||||
{
|
||||
BITSETI_CONTRACT(v);
|
||||
assert (i < v->size && v->ptr != NULL);
|
||||
size_t offset = i / CHAR_BIT;
|
||||
size_t index = i % CHAR_BIT;
|
||||
if (x == true){
|
||||
v->ptr[offset] |= 1<<index;
|
||||
} else {
|
||||
v->ptr[offset] &= ~(1<<index);
|
||||
}
|
||||
BITSETI_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_push_back (bitset_t v, bool x)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
if (v->size >= BITSETI_FROM_ALLOC (v->alloc)) {
|
||||
const size_t needAlloc = BITSETI_INC_ALLOC_SIZE(v->alloc);
|
||||
unsigned char *ptr = M_MEMORY_REALLOC (unsigned char, v->ptr, needAlloc);
|
||||
if (ptr == NULL) {
|
||||
M_MEMORY_FULL(needAlloc);
|
||||
return;
|
||||
}
|
||||
v->ptr = ptr;
|
||||
v->alloc = needAlloc;
|
||||
}
|
||||
assert(v->ptr != NULL);
|
||||
v->size ++;
|
||||
bitset_set_at (v, v->size - 1, x);
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_resize (bitset_t v, size_t size)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
size_t oldbytes = BITSETI_TO_ALLOC (v->size);
|
||||
size_t newbytes = BITSETI_TO_ALLOC (size);
|
||||
if (oldbytes != newbytes) {
|
||||
unsigned char *ptr = M_MEMORY_REALLOC (unsigned char, v->ptr, newbytes);
|
||||
if (ptr == NULL) {
|
||||
M_MEMORY_FULL(newbytes);
|
||||
return;
|
||||
}
|
||||
v->ptr = ptr;
|
||||
v->alloc = newbytes;
|
||||
}
|
||||
v->size = size;
|
||||
BITSETI_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitset_get(const bitset_t v, size_t i)
|
||||
{
|
||||
BITSETI_CONTRACT(v);
|
||||
assert (v->ptr != NULL && i < v->size);
|
||||
size_t offset = i / CHAR_BIT;
|
||||
size_t index = i % CHAR_BIT;
|
||||
return ( v->ptr[offset] & (1 << index) ) != 0;
|
||||
}
|
||||
#define bitset_cget bitset_get
|
||||
|
||||
static inline void
|
||||
bitset_pop_back(bool *dest, bitset_t v)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
assert (v->size > 0);
|
||||
if (dest) {
|
||||
*dest = bitset_get (v, v->size - 1);
|
||||
}
|
||||
v->size--;
|
||||
BITSETI_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitset_back(bitset_t v)
|
||||
{
|
||||
assert(v->size > 0);
|
||||
return bitset_get(v, v->size-1);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitset_empty_p(bitset_t v)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
return v->size == 0;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
bitset_size(bitset_t v)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
return v->size;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
bitset_capacity(bitset_t v)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
return BITSETI_FROM_ALLOC (v->alloc);
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_swap (bitset_t v, size_t i, size_t j)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
assert (i < v->size && j < v->size);
|
||||
bool i_val = bitset_get(v, i);
|
||||
bool j_val = bitset_get(v, j);
|
||||
bitset_set_at (v, i, j_val);
|
||||
bitset_set_at (v, j, i_val);
|
||||
BITSETI_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline unsigned char
|
||||
bitseti_lshift(unsigned char ptr[], size_t n, unsigned char carry)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
unsigned char v = ptr[i];
|
||||
ptr[i] = (v << 1) | carry;
|
||||
carry = (v >> (CHAR_BIT-1) );
|
||||
}
|
||||
return carry;
|
||||
}
|
||||
|
||||
static inline unsigned char
|
||||
bitseti_rshift(unsigned char ptr[], size_t n, unsigned char carry)
|
||||
{
|
||||
for(size_t i = n - 1; i < n; i--)
|
||||
{
|
||||
unsigned char v = ptr[i];
|
||||
v = (v >> 1) | (carry << (CHAR_BIT-1) );
|
||||
carry = v & 1;
|
||||
}
|
||||
return carry;
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_push_at(bitset_t set, size_t key, bool value)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
// First push another value to extend the array to the right size
|
||||
bitset_push_back(set, true);
|
||||
assert (set->ptr != NULL && key < set->size);
|
||||
// Then shift it
|
||||
size_t offset = key / CHAR_BIT;
|
||||
size_t index = key % CHAR_BIT;
|
||||
// BEFORE: 76543210 FEDBCA98
|
||||
// if key=5 ==>
|
||||
// AFTER: 65X43210 EDBCA987 000000F
|
||||
unsigned char v = set->ptr[offset];
|
||||
unsigned char mask = (1<<index)-1;
|
||||
unsigned char carry = (v >> (CHAR_BIT-1) );
|
||||
v = (v & mask) | (value << index) | ((v & ~mask) << 1);
|
||||
set->ptr[offset] = v;
|
||||
size_t size = (set->size + CHAR_BIT - 1) / CHAR_BIT;
|
||||
v = bitseti_lshift(&set->ptr[offset+1], size - offset - 1, carry);
|
||||
BITSETI_CONTRACT (set);
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_pop_at(bool *dest, bitset_t set, size_t key)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
assert (set->ptr != NULL && key < set->size);
|
||||
if (dest) {
|
||||
*dest = bitset_get (set, key);
|
||||
}
|
||||
// Shift it
|
||||
size_t offset = key / CHAR_BIT;
|
||||
size_t index = key % CHAR_BIT;
|
||||
// BEFORE: 76543210 FEDBCA98
|
||||
// if key=5 ==>
|
||||
// AFTER: 8643210 XFEDBCA9
|
||||
size_t size = (set->size + CHAR_BIT - 1) / CHAR_BIT;
|
||||
unsigned char v, mask, carry;
|
||||
carry = bitseti_rshift(&set->ptr[offset+1], size - offset - 1, false);
|
||||
v = set->ptr[offset];
|
||||
mask = (1<<index)-1;
|
||||
v = (v & mask) | ((v>>1) & ~mask) | (carry << (CHAR_BIT-1)) ;
|
||||
set->ptr[offset] = v;
|
||||
// Decrease size
|
||||
set->size --;
|
||||
BITSETI_CONTRACT (set);
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_it(bitset_it_t it, bitset_t set)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
it->index = 0;
|
||||
it->set = set;
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_it_set(bitset_it_t it, const bitset_it_t itorg)
|
||||
{
|
||||
assert (it != NULL && itorg != NULL);
|
||||
it->index = itorg->index;
|
||||
it->set = itorg->set;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitset_end_p(const bitset_it_t it)
|
||||
{
|
||||
assert (it != NULL && it->set != NULL);
|
||||
return (it->index) >= (it->set->size);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitset_last_p(const bitset_it_t it)
|
||||
{
|
||||
assert (it != NULL && it->set != NULL);
|
||||
return (it->index) >= (it->set->size)-1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitset_it_equal_p(const bitset_it_t it1, const bitset_it_t it2)
|
||||
{
|
||||
assert (it1 != NULL && it2 != NULL);
|
||||
return it1->index == it2->index && it1->set == it2->set;
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_next(bitset_it_t it)
|
||||
{
|
||||
assert (it != NULL && it->set != NULL);
|
||||
it->index++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitset_previous(bitset_it_t it)
|
||||
{
|
||||
assert (it != NULL && it->set != NULL);
|
||||
it->index--;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitset_ref(const bitset_it_t it)
|
||||
{
|
||||
assert (it != NULL && it->set != NULL);
|
||||
return bitset_get(it->set, it->index);
|
||||
}
|
||||
#define bitset_cref bitset_ref
|
||||
|
||||
// TODO: stringify...
|
||||
// TODO: OPLIST
|
||||
// TODO: set_at2, insert_v, remove_v, shrink_to_fit,
|
||||
|
||||
#endif
|
||||
+244
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* MLIB - BUFFER & STACK interface
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_BUFFER_H
|
||||
#define __M_BUFFER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "m-core.h"
|
||||
#include "m-mutex.h"
|
||||
|
||||
typedef enum {
|
||||
BUFFER_QUEUE = 0, BUFFER_STACK = 1,
|
||||
BUFFER_BLOCKING = 0, BUFFER_UNBLOCKING = 2,
|
||||
BUFFER_THREAD_SAFE = 0, BUFFER_THREAD_UNSAFE = 4,
|
||||
BUFFER_PUSH_INIT_POP_MOVE = 8,
|
||||
BUFFER_PUSH_OVERWRITE = 16
|
||||
} buffer_policy_e;
|
||||
|
||||
#define BUFFER_DEF(name, type, m_size, ... ) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(BUFFERI_DEF2(name, type, m_size,__VA_ARGS__, ()), \
|
||||
BUFFERI_DEF2(name, type, m_size,__VA_ARGS__))
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
#define BUFFERI_IF_CTE_SIZE(m_size) M_IF(M_BOOL(m_size))
|
||||
#define BUFFERI_SIZE(m_size) BUFFERI_IF_CTE_SIZE(m_size) (m_size, v->size)
|
||||
|
||||
#define BUFFERI_DEF2(name, type, m_size, policy, oplist) \
|
||||
typedef struct CAT3(buffer_, name, _s) { \
|
||||
M_MUTEX_T mutex; \
|
||||
M_COND_T there_is_data; \
|
||||
M_COND_T there_is_room_for_data; \
|
||||
BUFFERI_IF_CTE_SIZE(m_size)( ,size_t size;) \
|
||||
size_t idx_prod, idx_cons, number; \
|
||||
type *data; \
|
||||
} CAT3(buffer_, name,_t)[1]; \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(buffer_, name, _init)(CAT3(buffer_, name,_t) v, size_t size) \
|
||||
{ \
|
||||
assert( size > 0); \
|
||||
BUFFERI_IF_CTE_SIZE(m_size)(assert(size == m_size), v->size = size); \
|
||||
v->idx_prod = v->idx_cons = v->number = 0; \
|
||||
if (((policy) & BUFFER_THREAD_UNSAFE) != BUFFER_THREAD_UNSAFE) { \
|
||||
M_MUTEX_INIT(v->mutex); \
|
||||
M_COND_INIT(v->there_is_data); \
|
||||
M_COND_INIT(v->there_is_room_for_data); \
|
||||
} else \
|
||||
assert(((policy)&BUFFER_UNBLOCKING) == BUFFER_UNBLOCKING); \
|
||||
v->data = M_MEMORY_REALLOC (type, NULL, BUFFERI_SIZE(m_size)); \
|
||||
if (v->data == NULL) { \
|
||||
M_MEMORY_FULL (BUFFERI_SIZE(m_size)*sizeof(type)); \
|
||||
return; \
|
||||
} \
|
||||
if (((policy) & BUFFER_PUSH_INIT_POP_MOVE) == 0) { \
|
||||
for(size_t i = 0; i < size; i++) \
|
||||
M_GET_INIT oplist(v->data[i]); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(bufferi_, name, _clear_obj)(CAT3(buffer_, name,_t) v) \
|
||||
{ \
|
||||
if (((policy)&BUFFER_PUSH_INIT_POP_MOVE) == 0) { \
|
||||
for(size_t i = 0; i < BUFFERI_SIZE(m_size); i++) \
|
||||
M_GET_CLEAR oplist(v->data[i]); \
|
||||
} else { \
|
||||
size_t i = ((policy)&BUFFER_STACK) != 0 ? 0 : v->idx_cons; \
|
||||
while (i != v->idx_prod) { \
|
||||
M_GET_CLEAR oplist(v->data[i]); \
|
||||
i++; \
|
||||
if (((policy)&BUFFER_STACK) == 0 && i >= BUFFERI_SIZE(m_size)) \
|
||||
i = 0; \
|
||||
} \
|
||||
} \
|
||||
v->idx_prod = v->idx_cons = v->number = 0; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(buffer_, name, _clear)(CAT3(buffer_, name,_t) v) \
|
||||
{ \
|
||||
int rc; \
|
||||
CAT3(bufferi_, name, _clear_obj)(v); \
|
||||
M_MEMORY_FREE (v->data); \
|
||||
v->data = NULL; \
|
||||
if (((policy) & BUFFER_THREAD_UNSAFE) != BUFFER_THREAD_UNSAFE) { \
|
||||
rc = M_MUTEX_CLEAR(v->mutex); \
|
||||
assert (rc == 0); \
|
||||
rc = M_COND_CLEAR(v->there_is_data); \
|
||||
assert (rc == 0); \
|
||||
rc = M_COND_CLEAR(v->there_is_room_for_data); \
|
||||
assert (rc == 0); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(buffer_, name, _clean)(CAT3(buffer_, name,_t) v) \
|
||||
{ \
|
||||
assert (v->number <= BUFFERI_SIZE(m_size)); \
|
||||
if (((policy) & BUFFER_THREAD_UNSAFE) != BUFFER_THREAD_UNSAFE) \
|
||||
M_MUTEX_LOCK(v->mutex); \
|
||||
if (((policy)&BUFFER_PUSH_INIT_POP_MOVE) != 0) \
|
||||
CAT3(bufferi_, name, _clear_obj)(v); \
|
||||
if (((policy) & BUFFER_THREAD_UNSAFE) != BUFFER_THREAD_UNSAFE) { \
|
||||
M_COND_SIGNAL(v->there_is_room_for_data); \
|
||||
M_MUTEX_UNLOCK(v->mutex); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(buffer_, name, _empty_p)(CAT3(buffer_, name,_t) v) \
|
||||
{ \
|
||||
assert(v->number <= BUFFERI_SIZE(m_size)); \
|
||||
return v->number == 0; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(buffer_, name, _full_p)(CAT3(buffer_, name,_t) v) \
|
||||
{ \
|
||||
assert(v->number <= BUFFERI_SIZE(m_size)); \
|
||||
return v->number == BUFFERI_SIZE(m_size); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(buffer_, name, _push)(CAT3(buffer_, name,_t) v, type const data) \
|
||||
{ \
|
||||
if (((policy) & BUFFER_THREAD_UNSAFE) != BUFFER_THREAD_UNSAFE) { \
|
||||
M_MUTEX_LOCK(v->mutex); \
|
||||
while (((policy)&BUFFER_PUSH_OVERWRITE) == 0 \
|
||||
&& CAT3(buffer_, name, _full_p)(v)) { \
|
||||
if (((policy) & BUFFER_UNBLOCKING) == BUFFER_UNBLOCKING) { \
|
||||
M_MUTEX_UNLOCK(v->mutex); \
|
||||
return false; \
|
||||
} \
|
||||
M_COND_WAIT(v->there_is_room_for_data, v->mutex); \
|
||||
} \
|
||||
} else if (((policy)&BUFFER_PUSH_OVERWRITE) == 0 \
|
||||
&& CAT3(buffer_, name, _full_p)(v)) \
|
||||
return false; \
|
||||
\
|
||||
if (((policy)&BUFFER_PUSH_OVERWRITE) != 0 \
|
||||
&& v->number == BUFFERI_SIZE(m_size) ) { \
|
||||
/* Let's clear the last element to overwrite it */ \
|
||||
if (((policy) & BUFFER_STACK) == 0) { \
|
||||
v->idx_prod = (v->idx_prod - 1) % BUFFERI_SIZE(m_size); \
|
||||
} else { \
|
||||
(v->idx_prod) --; \
|
||||
} \
|
||||
v->number --; \
|
||||
if (((policy) & BUFFER_PUSH_INIT_POP_MOVE) != 0) { \
|
||||
M_GET_CLEAR oplist(v->data[v->idx_prod]); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (((policy) & BUFFER_PUSH_INIT_POP_MOVE) == 0) { \
|
||||
M_GET_SET oplist(v->data[v->idx_prod], data); \
|
||||
} else { \
|
||||
M_GET_INIT_SET oplist(v->data[v->idx_prod], data); \
|
||||
} \
|
||||
if (((policy) & BUFFER_STACK) != BUFFER_STACK) { \
|
||||
v->idx_prod = (v->idx_prod +1) % BUFFERI_SIZE(m_size); \
|
||||
} else { \
|
||||
(v->idx_prod) ++; \
|
||||
} \
|
||||
v->number ++; \
|
||||
\
|
||||
if (((policy) & BUFFER_THREAD_UNSAFE) != BUFFER_THREAD_UNSAFE) { \
|
||||
M_COND_SIGNAL(v->there_is_data); \
|
||||
M_MUTEX_UNLOCK(v->mutex); \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(buffer_, name, _pop)(type *data, CAT3(buffer_, name,_t) v) \
|
||||
{ \
|
||||
if (((policy) & BUFFER_THREAD_UNSAFE) != BUFFER_THREAD_UNSAFE) { \
|
||||
M_MUTEX_LOCK(v->mutex); \
|
||||
while (CAT3(buffer_, name, _empty_p)(v)) { \
|
||||
if (((policy) & BUFFER_UNBLOCKING) == BUFFER_UNBLOCKING) { \
|
||||
M_MUTEX_UNLOCK(v->mutex); \
|
||||
return false; \
|
||||
} \
|
||||
M_COND_WAIT(v->there_is_data, v->mutex); \
|
||||
} \
|
||||
} else if (CAT3(buffer_, name, _empty_p)(v)) \
|
||||
return false; \
|
||||
\
|
||||
if (((policy) & BUFFER_STACK) != BUFFER_STACK) { \
|
||||
if (((policy) & BUFFER_PUSH_INIT_POP_MOVE ) == 0) { \
|
||||
M_GET_SET oplist (*data, v->data[v->idx_cons]); \
|
||||
} else { \
|
||||
M_GET_INIT_MOVE oplist (*data, v->data[v->idx_cons]); \
|
||||
} \
|
||||
v->idx_cons = (v->idx_cons +1) % BUFFERI_SIZE(m_size); \
|
||||
} else { \
|
||||
v->idx_prod --; \
|
||||
if (((policy) & BUFFER_PUSH_INIT_POP_MOVE ) == 0) { \
|
||||
M_GET_SET oplist (*data, v->data[v->idx_prod]); \
|
||||
} else { \
|
||||
M_GET_INIT_MOVE oplist (*data, v->data[v->idx_prod]); \
|
||||
} \
|
||||
} \
|
||||
v->number --; \
|
||||
\
|
||||
if (((policy) & BUFFER_THREAD_UNSAFE) != BUFFER_THREAD_UNSAFE) { \
|
||||
M_COND_SIGNAL(v->there_is_room_for_data); \
|
||||
M_MUTEX_UNLOCK(v->mutex); \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
|
||||
// NOTE: SET & INIT_SET are deliberatly missing. TBC if it the right way.
|
||||
|
||||
// TODO: priority queue when it is the one with the huge priority which is taken out
|
||||
// TODO: merge queue waiting for all threads to finish producing one object to make it available to consummer (allow partial production by different threads)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,801 @@
|
||||
/*
|
||||
* MLIB - Extended Pre-processing macros module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_MACRO_H
|
||||
#define __M_MACRO_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
|
||||
//TODO: Prefix all macros with "M_" prefix.
|
||||
|
||||
/***************************************************************/
|
||||
/************************ Compiler Macro ***********************/
|
||||
/***************************************************************/
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
# define M_ASSUME(x) assert(x)
|
||||
#elif defined(__GNUC__) \
|
||||
&& (__GNUC__ * 100 + __GNUC_MINOR__) >= 480
|
||||
# define M_ASSUME(x) \
|
||||
(! __builtin_constant_p (!!(x) || !(x)) || (x) ? \
|
||||
(void) 0 : __builtin_unreachable())
|
||||
#elif defined(_MSC_VER)
|
||||
# define M_ASSUME(x) __assume(x)
|
||||
#else
|
||||
# define M_ASSUME(x) assert(x)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define M_LIKELY(cond) __builtin_expect(!!(cond), 1)
|
||||
# define M_UNLIKELY(cond) __builtin_expect(!!(cond), 0)
|
||||
#else
|
||||
# define M_LIKELY(cond) (cond)
|
||||
# define M_UNLIKELY(cond) (cond)
|
||||
#endif
|
||||
|
||||
|
||||
/***************************************************************/
|
||||
/****************** Preprocessing Times Macro ******************/
|
||||
/***************************************************************/
|
||||
|
||||
/* Maximum number of argument which can be handled by this header.
|
||||
Can be increased for future release of this header. */
|
||||
#define M_MAX_NB_ARGUMENT 26
|
||||
|
||||
/* Basic handling of concatenation of symbols:
|
||||
* CAT, CAT3, CAT4
|
||||
*/
|
||||
#define CAT0(a, ...) a ## __VA_ARGS__
|
||||
#define CAT(a, ...) CAT0(a, __VA_ARGS__)
|
||||
#define CAT3_0(a, b, ...) a ## b ## __VA_ARGS__
|
||||
#define CAT3(a, b, ...) CAT3_0(a ,b, __VA_ARGS__)
|
||||
#define CAT4_0(a, b, c, ...) a ## b ## c ## __VA_ARGS__
|
||||
#define CAT4(a, b, c, ...) CAT4_0(a ,b, c, __VA_ARGS__)
|
||||
|
||||
/* Increment the number given in argument (from [0..29[) */
|
||||
#define M_INC(x) CAT(M_INC_, x)
|
||||
#define M_INC_0 1
|
||||
#define M_INC_1 2
|
||||
#define M_INC_2 3
|
||||
#define M_INC_3 4
|
||||
#define M_INC_4 5
|
||||
#define M_INC_5 6
|
||||
#define M_INC_6 7
|
||||
#define M_INC_7 8
|
||||
#define M_INC_8 9
|
||||
#define M_INC_9 10
|
||||
#define M_INC_10 11
|
||||
#define M_INC_11 12
|
||||
#define M_INC_12 13
|
||||
#define M_INC_13 14
|
||||
#define M_INC_14 15
|
||||
#define M_INC_15 16
|
||||
#define M_INC_16 17
|
||||
#define M_INC_17 18
|
||||
#define M_INC_18 19
|
||||
#define M_INC_19 20
|
||||
#define M_INC_20 21
|
||||
#define M_INC_21 22
|
||||
#define M_INC_22 23
|
||||
#define M_INC_23 24
|
||||
#define M_INC_24 25
|
||||
#define M_INC_25 26
|
||||
#define M_INC_26 27
|
||||
#define M_INC_27 28
|
||||
#define M_INC_28 29
|
||||
#define M_INC_29 OVERFLOW
|
||||
|
||||
/* Decrement the number given in argument (from [0..29[) */
|
||||
#define M_DEC(x) CAT(M_DEC_, x)
|
||||
#define M_DEC_0 overflow
|
||||
#define M_DEC_1 0
|
||||
#define M_DEC_2 1
|
||||
#define M_DEC_3 2
|
||||
#define M_DEC_4 3
|
||||
#define M_DEC_5 4
|
||||
#define M_DEC_6 5
|
||||
#define M_DEC_7 6
|
||||
#define M_DEC_8 7
|
||||
#define M_DEC_9 8
|
||||
#define M_DEC_10 9
|
||||
#define M_DEC_11 10
|
||||
#define M_DEC_12 11
|
||||
#define M_DEC_13 12
|
||||
#define M_DEC_14 13
|
||||
#define M_DEC_15 14
|
||||
#define M_DEC_16 15
|
||||
#define M_DEC_17 16
|
||||
#define M_DEC_18 17
|
||||
#define M_DEC_19 18
|
||||
#define M_DEC_20 19
|
||||
#define M_DEC_21 20
|
||||
#define M_DEC_22 21
|
||||
#define M_DEC_23 22
|
||||
#define M_DEC_24 23
|
||||
#define M_DEC_25 24
|
||||
#define M_DEC_26 25
|
||||
#define M_DEC_27 26
|
||||
#define M_DEC_28 27
|
||||
#define M_DEC_29 28
|
||||
|
||||
/* Return the nth argument:
|
||||
M_RET_ARG1
|
||||
M_RET_ARG2
|
||||
M_RET_ARG3
|
||||
M_RET_ARG27
|
||||
*/
|
||||
#define M_RETI_ARG1(a, ...) a
|
||||
#define M_RET_ARG1(...) M_RETI_ARG1(__VA_ARGS__)
|
||||
|
||||
#define M_RETI_ARG2(a, b, ...) b
|
||||
#define M_RET_ARG2(...) M_RETI_ARG2(__VA_ARGS__)
|
||||
|
||||
#define M_RETI_ARG3(a, b, c, ...) c
|
||||
#define M_RET_ARG3(...) M_RETI_ARG3(__VA_ARGS__)
|
||||
|
||||
#define M_RETI_ARG27(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa, ...) aa
|
||||
#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__)
|
||||
|
||||
|
||||
/* Convert an integer or a symbol into 0 (if 0) or 1 (if not 0).
|
||||
1 if symbol unknown */
|
||||
#define M_TOBOOL_0 1, 0,
|
||||
#define M_BOOL(x) M_RET_ARG2(CAT(M_TOBOOL_, x), 1, useless)
|
||||
|
||||
/* Inverse 0 into 1 and 1 into 0 */
|
||||
#define M_INV_0 1
|
||||
#define M_INV_1 0
|
||||
#define M_INV(x) CAT(M_INV_, x)
|
||||
|
||||
/* Perform a AND between the inputs */
|
||||
#define M_AND_00 0
|
||||
#define M_AND_01 0
|
||||
#define M_AND_10 0
|
||||
#define M_AND_11 1
|
||||
#define M_AND(x,y) CAT3(M_AND_, x, y)
|
||||
|
||||
/* Perform a OR between the inputs */
|
||||
#define M_OR_00 0
|
||||
#define M_OR_01 1
|
||||
#define M_OR_10 1
|
||||
#define M_OR_11 1
|
||||
#define M_OR(x,y) CAT3(M_OR_, x, y)
|
||||
|
||||
/* M_IF Macro :
|
||||
M_IF(42)(Execute if true, execute if false)
|
||||
Example: M_IF(0)(true_action, false_action) --> false_action */
|
||||
#define M_IF_CAT(c) CAT(M_IF_, c)
|
||||
#define M_IF_0(true_macro, ...) __VA_ARGS__
|
||||
#define M_IF_1(true_macro, ...) true_macro
|
||||
#define M_IF(c) M_IF_CAT(M_BOOL(c))
|
||||
|
||||
/* Return 1 if comma inside the argument list, 0 otherwise */
|
||||
#define M_COMMA_P(...) M_RET_ARG27(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, useless)
|
||||
|
||||
/* Return 1 if the argument is 'empty', 0 otherwise.
|
||||
Handle: EMPTY_P(), EMPTY_P(x), EMPTY_P(()) and EMPTY_P(,) and EMPTY_P(f) with #define f() 2,3 */
|
||||
#define M_EMPTY_DETECT(...) 0, 1,
|
||||
#define M_EMPTY_P_C1(...) M_COMMA_P(M_EMPTY_DETECT __VA_ARGS__ () )
|
||||
#define M_EMPTY_P_C2(...) M_COMMA_P(M_EMPTY_DETECT __VA_ARGS__)
|
||||
#define M_EMPTY_P_C3(...) M_COMMA_P(__VA_ARGS__ () )
|
||||
#define M_EMPTY_P(...) M_AND(M_EMPTY_P_C1(__VA_ARGS__), M_INV(M_OR(M_OR(M_EMPTY_P_C2(__VA_ARGS__), M_COMMA_P(__VA_ARGS__)),M_EMPTY_P_C3(__VA_ARGS__))))
|
||||
|
||||
/* Generate a comma later in the next evaluation pass. */
|
||||
#define M_DEFERRED_COMMA ,
|
||||
|
||||
/* M_IF macro for empty arguments:
|
||||
M_IF_EMPTY(arguments)(action if empty, action if not empty) */
|
||||
#define M_IF_EMPTY(...) M_IF(M_EMPTY_P(__VA_ARGS__))
|
||||
|
||||
/* Return 1 if argument is "()" or "(x)" */
|
||||
#define M_PARENTHESIS_DETECT(...) 0, 1,
|
||||
#define M_PARENTHESIS_P(x) M_RET_ARG2(M_PARENTHESIS_DETECT x, 0, useless)
|
||||
|
||||
/* Necessary macros to handle recursivity */
|
||||
/* Delay the evaluation by one level or two or three or ... */
|
||||
/* The argument is a macro-function which has to be deferred */
|
||||
#define M_DELAY0()
|
||||
#define M_DELAY1(...) __VA_ARGS__ M_DELAY0 ()
|
||||
#define M_DELAY2(...) __VA_ARGS__ M_DELAY1 (M_DELAY0) ()
|
||||
#define M_DELAY3(...) __VA_ARGS__ M_DELAY2 (M_DELAY0) ()
|
||||
#define M_DELAY4(...) __VA_ARGS__ M_DELAY3 (M_DELAY0) ()
|
||||
#define M_DELAY5(...) __VA_ARGS__ M_DELAY4 (M_DELAY0) ()
|
||||
#define M_DELAY6(...) __VA_ARGS__ M_DELAY5 (M_DELAY0) ()
|
||||
#define M_DELAY7(...) __VA_ARGS__ M_DELAY6 (M_DELAY0) ()
|
||||
#define M_DELAY8(...) __VA_ARGS__ M_DELAY7 (M_DELAY0) ()
|
||||
#define M_DELAY9(...) __VA_ARGS__ M_DELAY8 (M_DELAY0) ()
|
||||
|
||||
/* Perform 3^5 evaluation */
|
||||
#define M_EVAL(...) M_EVAL1(M_EVAL1(M_EVAL1(__VA_ARGS__)))
|
||||
#define M_EVAL1(...) M_EVAL2(M_EVAL2(M_EVAL2(__VA_ARGS__)))
|
||||
#define M_EVAL2(...) M_EVAL3(M_EVAL3(M_EVAL3(__VA_ARGS__)))
|
||||
#define M_EVAL3(...) M_EVAL4(M_EVAL4(M_EVAL4(__VA_ARGS__)))
|
||||
#define M_EVAL4(...) M_EVAL0(M_EVAL0(M_EVAL0(__VA_ARGS__)))
|
||||
#define M_EVAL0(...) __VA_ARGS__
|
||||
|
||||
/* Apply Macro :
|
||||
It allows that a won't be evaluated until all arguments of 'a' have been already evaluated */
|
||||
#define M_APPLY(a, ...) a (__VA_ARGS__)
|
||||
|
||||
/* Apply 'func' to arg if 'arg' is not empty */
|
||||
/* Example: M_APPLY_FUNC(f, 2) ==> 'f(2)' and M_APPLY_FUNC(f, ) ==> '' */
|
||||
#define M_APPLY_FUNC(func, arg) \
|
||||
M_IF(M_INV(M_EMPTY_P(arg)))(func(arg),)
|
||||
|
||||
/* Apply 'func' to arg1,arg2 if 'arg2' is not empty */
|
||||
/* Example: M_APPLY_FUNC2(f, 2, 3) ==> 'f(2, 3)' and M_APPLY_FUNC2(f, 2, ) ==> '' */
|
||||
#define M_APPLY_FUNC2(func, arg1, arg2) \
|
||||
M_IF(M_INV(M_EMPTY_P(arg2)))(func(arg1, arg2),)
|
||||
|
||||
/* Map a macro to all given arguments (non recursive version) */
|
||||
/* Example: M_MAP(f,a, b, c) ==> f(a) f(b) f(c) */
|
||||
#define M_MAP_0(func, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, ...) \
|
||||
M_APPLY_FUNC(func, a) M_APPLY_FUNC(func, b) M_APPLY_FUNC(func, c) M_APPLY_FUNC(func, d) M_APPLY_FUNC(func, e) \
|
||||
M_APPLY_FUNC(func, f) M_APPLY_FUNC(func, g) M_APPLY_FUNC(func, h) M_APPLY_FUNC(func, i) M_APPLY_FUNC(func, j) \
|
||||
M_APPLY_FUNC(func, k) M_APPLY_FUNC(func, l) M_APPLY_FUNC(func, m) M_APPLY_FUNC(func, n) M_APPLY_FUNC(func, o) \
|
||||
M_APPLY_FUNC(func, p) M_APPLY_FUNC(func, q) M_APPLY_FUNC(func, r) M_APPLY_FUNC(func, s) M_APPLY_FUNC(func, t) \
|
||||
M_APPLY_FUNC(func, u) M_APPLY_FUNC(func, v) M_APPLY_FUNC(func, w) M_APPLY_FUNC(func, x) M_APPLY_FUNC(func, y) \
|
||||
M_APPLY_FUNC(func, z)
|
||||
#define M_MAP(f, ...) M_MAP_0(f, __VA_ARGS__, , , , , , , , , , , , , , , , , , , , , , , , , , )
|
||||
|
||||
/* Map a macro to all given arguments with one additional fixed data*/
|
||||
/* Example: M_MAP2(f,data,a, b, c) ==> f(data,a) f(data,b) f(data,c) */
|
||||
#define M_MAP2_0(func, data, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, ...) \
|
||||
M_APPLY_FUNC2(func, data, a) M_APPLY_FUNC2(func, data, b) M_APPLY_FUNC2(func, data, c) \
|
||||
M_APPLY_FUNC2(func, data, d) M_APPLY_FUNC2(func, data, e) M_APPLY_FUNC2(func, data, f) \
|
||||
M_APPLY_FUNC2(func, data, g) M_APPLY_FUNC2(func, data, h) M_APPLY_FUNC2(func, data, i) \
|
||||
M_APPLY_FUNC2(func, data, j) M_APPLY_FUNC2(func, data, k) M_APPLY_FUNC2(func, data, l) \
|
||||
M_APPLY_FUNC2(func, data, m) M_APPLY_FUNC2(func, data, n) M_APPLY_FUNC2(func, data, o) \
|
||||
M_APPLY_FUNC2(func, data, p) M_APPLY_FUNC2(func, data, q) M_APPLY_FUNC2(func, data, r) \
|
||||
M_APPLY_FUNC2(func, data, s) M_APPLY_FUNC2(func, data, t) M_APPLY_FUNC2(func, data, u) \
|
||||
M_APPLY_FUNC2(func, data, v) M_APPLY_FUNC2(func, data, w) M_APPLY_FUNC2(func, data, x) \
|
||||
M_APPLY_FUNC2(func, data, y) M_APPLY_FUNC2(func, data, z)
|
||||
#define M_MAP2(f, ...) M_MAP2_0(f, __VA_ARGS__, , , , , , , , , , , , , , , , , , , , , , , , , , , )
|
||||
|
||||
/* Duplicate of macros for GET_METHOD as it may be called in context where a M_MAP2 is in progress */
|
||||
#define M_APPLY_FUNC2B(func, arg1, arg2) \
|
||||
M_IF(M_INV(M_EMPTY_P(arg2)))(func(arg1, arg2),)
|
||||
#define M_MAP2B_0(func, data, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, ...) \
|
||||
M_APPLY_FUNC2B(func, data, a) M_APPLY_FUNC2B(func, data, b) M_APPLY_FUNC2B(func, data, c) \
|
||||
M_APPLY_FUNC2B(func, data, d) M_APPLY_FUNC2B(func, data, e) M_APPLY_FUNC2B(func, data, f) \
|
||||
M_APPLY_FUNC2B(func, data, g) M_APPLY_FUNC2B(func, data, h) M_APPLY_FUNC2B(func, data, i) \
|
||||
M_APPLY_FUNC2B(func, data, j) M_APPLY_FUNC2B(func, data, k) M_APPLY_FUNC2B(func, data, l) \
|
||||
M_APPLY_FUNC2B(func, data, m) M_APPLY_FUNC2B(func, data, n) M_APPLY_FUNC2B(func, data, o) \
|
||||
M_APPLY_FUNC2B(func, data, p) M_APPLY_FUNC2B(func, data, q) M_APPLY_FUNC2B(func, data, r) \
|
||||
M_APPLY_FUNC2B(func, data, s) M_APPLY_FUNC2B(func, data, t) M_APPLY_FUNC2B(func, data, u) \
|
||||
M_APPLY_FUNC2B(func, data, v) M_APPLY_FUNC2B(func, data, w) M_APPLY_FUNC2B(func, data, x) \
|
||||
M_APPLY_FUNC2B(func, data, y) M_APPLY_FUNC2B(func, data, z)
|
||||
#define M_MAP2B(f, ...) M_MAP2B_0(f, __VA_ARGS__, , , , , , , , , , , , , , , , , , , , , , , , , , , )
|
||||
|
||||
|
||||
/* Map a macro to all given pair of arguments (Using recursivity) */
|
||||
/* Example: M_MAP_PAIR(f, a, b, c, d) ==> f(a,b) f(c,d) */
|
||||
#define M_MAP_PAIR_L0_INDIRECT() M_MAP_PAIR_L0
|
||||
#define M_MAP_PAIR_L0(f, ...) M_IF_NARGS_EQ2(__VA_ARGS__)( f(__VA_ARGS__) , M_MAP_PAIR_L1(f, __VA_ARGS__))
|
||||
#define M_MAP_PAIR_L1(f, a, b, ...) f(a,b) M_DELAY3(M_MAP_PAIR_L0_INDIRECT) () (f, __VA_ARGS__)
|
||||
#define M_MAP_PAIR(f, ...) M_IF_EMPTY(__VA_ARGS__)( /* end */, M_EVAL(M_MAP_PAIR_L0(f, __VA_ARGS__)))
|
||||
|
||||
/* Map a macro to all given arguments and reduce all theses computation
|
||||
with another reduce macro (using recursivity) */
|
||||
/* Example: M_REDUCE(f, g, a, b, c) ==> g( f(a), g( f(b), f(c)) */
|
||||
#define M_REDUCE_L0_INDIRECT() M_REDUCE_L0
|
||||
#define M_REDUCE_L1(f, g, cur, a, ...) M_DELAY3(M_REDUCE_L0_INDIRECT) () (f, g, g(cur, f(a)), __VA_ARGS__)
|
||||
#define M_REDUCE_L0(f, g, cur, ...) M_IF_NARGS_EQ1(__VA_ARGS__)( g(cur, f(__VA_ARGS__)) , M_REDUCE_L1(f, g, cur, __VA_ARGS__))
|
||||
#define M_REDUCE1(f, g, a, ...) M_EVAL(M_REDUCE_L0(f, g, f(a), __VA_ARGS__))
|
||||
#define M_REDUCE(f, g, ...) M_IF_NARGS_EQ1(__VA_ARGS__)( f(__VA_ARGS__), M_REDUCE1(f, g, __VA_ARGS__))
|
||||
|
||||
/* Map a macro to all given arguments and reduce all theses computation
|
||||
with another reduce macro with an argument (non-recursive way - should be way faster):
|
||||
M_REDUCE2(f, g, data, a, b, c) ==> g( f(data,a), g( f(data, b), f(data, c))) */
|
||||
#define M_REDUCE2(f,g,d,...) \
|
||||
M_RET_ARG27(__VA_ARGS__, M_REDUCEI_26, M_REDUCEI_25, M_REDUCEI_24, \
|
||||
M_REDUCEI_23, M_REDUCEI_22, M_REDUCEI_21, M_REDUCEI_20, \
|
||||
M_REDUCEI_19, M_REDUCEI_18, M_REDUCEI_17, M_REDUCEI_16, \
|
||||
M_REDUCEI_15, M_REDUCEI_14, M_REDUCEI_13, M_REDUCEI_12, \
|
||||
M_REDUCEI_11, M_REDUCEI_10, M_REDUCEI_9, M_REDUCEI_8, \
|
||||
M_REDUCEI_7, M_REDUCEI_6, M_REDUCEI_5, M_REDUCEI_4, \
|
||||
M_REDUCEI_3, M_REDUCEI_2, M_REDUCEI_1, useless)(f,g,d,__VA_ARGS__)
|
||||
#define M_REDUCEI_1(f1,g1,d1,a) f1(d1, a)
|
||||
#define M_REDUCEI_2(f1,g1,d1,a,b) g1(f1(d1, a),f1(d1,b))
|
||||
#define M_REDUCEI_3(f1,g1,d1,a,b,c) g1(g1(f1(d1, a),f1(d1,b)),f1(d1,c))
|
||||
#define M_REDUCEI_4(f1,g1,d1,a,b,c,d) g1(g1(f1(d1, a),f1(d1,b)),g1(f1(d1,c),f1(d1,d)))
|
||||
#define M_REDUCEI_5(f1,g1,d1,a,b,c,d,e) g1(g1(g1(f1(d1, a),f1(d1,b)),g1(f1(d1,c),f1(d1,d))),f1(d1,e))
|
||||
#define M_REDUCEI_6(f1,g1,d1,a,b,c,d,e,f) g1(g1(g1(f1(d1, a),f1(d1,b)),f1(d1,c)),g1(g1(f1(d1,d),f1(d1,e)),f1(d1,f)))
|
||||
#define M_REDUCEI_7(f1,g1,d1,a,b,c,d,e,f,g) g1(M_REDUCEI_6(f1,g1,d1,a,b,c,d,e,f),f1(d1,g))
|
||||
#define M_REDUCEI_8(f1,g1,d1,a,b,c,d,e,f,g,h) g1(M_REDUCEI_4(f1,g1,d1,a,b,c,d),M_REDUCEI_4(f1,g1,d1,e,f,g,h))
|
||||
#define M_REDUCEI_9(f1,g1,d1,a,b,c,d,e,f,g,h,i) g1(M_REDUCEI_8(f1,g1,d1,a,b,c,d,e,f,g,h),f1(d1,i))
|
||||
#define M_REDUCEI_10(f1,g1,d1,a,b,c,d,e,f,g,h,i,j) g1(M_REDUCEI_5(f1,g1,d1,a,b,c,d,e),M_REDUCEI_5(f1,g1,d1,f,g,h,i,j))
|
||||
#define M_REDUCEI_11(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k) g1(M_REDUCEI_10(f1,g1,d1,a,b,c,d,e,f,g,h,i,j),f1(d1,k))
|
||||
#define M_REDUCEI_12(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l) g1(M_REDUCEI_6(f1,g1,d1,a,b,c,d,e,f),M_REDUCEI_6(f1,g1,d1,g,h,i,j,k,l))
|
||||
#define M_REDUCEI_13(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m) g1(M_REDUCEI_12(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l),f1(d1,m))
|
||||
#define M_REDUCEI_14(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n) g1(M_REDUCEI_7(f1,g1,d1,a,b,c,d,e,f,g),M_REDUCEI_7(f1,g1,d1,h,i,j,k,l,m,n))
|
||||
#define M_REDUCEI_15(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) g1(M_REDUCEI_14(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n),f1(d1,o))
|
||||
#define M_REDUCEI_16(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) g1(M_REDUCEI_8(f1,g1,d1,a,b,c,d,e,f,g,h),M_REDUCEI_8(f1,g1,d1,i,j,k,l,m,n,o,p))
|
||||
#define M_REDUCEI_17(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q) g1(M_REDUCEI_16(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p),f1(d1,q))
|
||||
#define M_REDUCEI_18(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r) g1(M_REDUCEI_9(f1,g1,d1,a,b,c,d,e,f,g,h,i),M_REDUCEI_9(f1,g1,d1,j,k,l,m,n,o,p,q,r))
|
||||
#define M_REDUCEI_19(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s) g1(M_REDUCEI_18(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r),f1(d1,s))
|
||||
#define M_REDUCEI_20(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t) g1(M_REDUCEI_10(f1,g1,d1,a,b,c,d,e,f,g,h,i,j),M_REDUCEI_9(f1,g1,d1,k,l,m,n,o,p,q,r,s,t))
|
||||
#define M_REDUCEI_21(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u) g1(M_REDUCEI_20(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t),f1(d1,u))
|
||||
#define M_REDUCEI_22(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v) g1(M_REDUCEI_11(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k),M_REDUCEI_9(f1,g1,d1,l,m,n,o,p,q,r,s,t,u,v))
|
||||
#define M_REDUCEI_23(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w) g1(M_REDUCEI_22(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v),f1(d1,w))
|
||||
#define M_REDUCEI_24(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x) g1(M_REDUCEI_11(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l),M_REDUCEI_11(f1,g1,d1,m,n,o,p,q,r,s,t,u,v,w,x))
|
||||
#define M_REDUCEI_25(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y) g1(M_REDUCEI_24(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x),f1(d1,y))
|
||||
#define M_REDUCEI_26(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z) g1(M_REDUCEI_12(f1,g1,d1,a,b,c,d,e,f,g,h,i,j,k,l,m),M_REDUCEI_12(f1,g1,d1,n,o,p,q,r,s,t,u,v,w,x,y,z))
|
||||
|
||||
|
||||
/* Sequence of numerical (using recursivity) */
|
||||
/* Example: M_SEQ(init,end, macro)==>macro(init), macro(init+1), ...macro(end) */
|
||||
#define M_SEQ_L0_INDIRECT() M_SEQ_L0
|
||||
#define M_SEQ_L0(current,end,f) M_IF(M_EQUAL(current, end))( f(current) , M_SEQ_L1(current, end, f))
|
||||
#define M_SEQ_L1(current,end,f) f(current) , M_DELAY3(M_SEQ_L0_INDIRECT) () (M_INC(current), end, f)
|
||||
#define M_SEQ(init,end,f) M_EVAL(M_SEQ_L0(init,end,f))
|
||||
|
||||
/* Sequence of numerical with data (using recursivity) */
|
||||
/* Example: M_SEQ2(init, end, macro, data)==>macro(data, init), macro(data, init+1), ...macro(data, end) */
|
||||
#define M_SEQ2_L0_INDIRECT() M_SEQ2_L0
|
||||
#define M_SEQ2_L0(current,end,f,d) M_IF(M_EQUAL(current, end))( f(d, current) , M_SEQ2_L1(current, end, f, d))
|
||||
#define M_SEQ2_L1(current,end,f,d) f(d,current) , M_DELAY3(M_SEQ2_L0_INDIRECT) () (M_INC(current), end, f, d)
|
||||
#define M_SEQ2(init,end,f,data) M_EVAL(M_SEQ2_L0(init,end,f,data))
|
||||
|
||||
/* Return the input (delay evaluation) */
|
||||
#define M_ID(...) __VA_ARGS__
|
||||
|
||||
/* M_NARGS: Return number of argument.
|
||||
(don't work for empty arg) */
|
||||
#define M_NARGS(...) \
|
||||
M_RET_ARG27(__VA_ARGS__, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, \
|
||||
15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, useless)
|
||||
|
||||
/* If the number of arguments is 1 */
|
||||
#define M_IF_NARGS_EQ1(...) M_IF(M_EQUAL(M_NARGS(__VA_ARGS__), 1))
|
||||
|
||||
/* If the number of arguments is 2 */
|
||||
#define M_IF_NARGS_EQ2(...) M_IF(M_EQUAL(M_NARGS(__VA_ARGS__), 2))
|
||||
|
||||
/* If NDEBUG macro is defined
|
||||
M_IF_DEBUG(code if NDEBUG is not defined)
|
||||
Note: not 100% robust */
|
||||
#define M_TEST_NDEBUG_P() CAT3(M_, NDEBUG, _TEST)
|
||||
#define M_NDEBUG_TEST 0
|
||||
#define M_IF_DEBUG(a) M_IF(M_TEST_NDEBUG_P())(,a)
|
||||
|
||||
/* NOTEQUAL(val1,val2) with val from [0 to 30[
|
||||
Return 1 or 0 if val1=val2
|
||||
*/
|
||||
#define M_NOTEQUAL_0_0 0
|
||||
#define M_NOTEQUAL_1_1 0
|
||||
#define M_NOTEQUAL_2_2 0
|
||||
#define M_NOTEQUAL_3_3 0
|
||||
#define M_NOTEQUAL_4_4 0
|
||||
#define M_NOTEQUAL_5_5 0
|
||||
#define M_NOTEQUAL_6_6 0
|
||||
#define M_NOTEQUAL_7_7 0
|
||||
#define M_NOTEQUAL_8_8 0
|
||||
#define M_NOTEQUAL_9_9 0
|
||||
#define M_NOTEQUAL_10_10 0
|
||||
#define M_NOTEQUAL_11_11 0
|
||||
#define M_NOTEQUAL_12_12 0
|
||||
#define M_NOTEQUAL_13_13 0
|
||||
#define M_NOTEQUAL_14_14 0
|
||||
#define M_NOTEQUAL_15_15 0
|
||||
#define M_NOTEQUAL_16_16 0
|
||||
#define M_NOTEQUAL_17_17 0
|
||||
#define M_NOTEQUAL_18_18 0
|
||||
#define M_NOTEQUAL_19_19 0
|
||||
#define M_NOTEQUAL_20_20 0
|
||||
#define M_NOTEQUAL_21_21 0
|
||||
#define M_NOTEQUAL_22_22 0
|
||||
#define M_NOTEQUAL_23_23 0
|
||||
#define M_NOTEQUAL_24_24 0
|
||||
#define M_NOTEQUAL_25_25 0
|
||||
#define M_NOTEQUAL_26_26 0
|
||||
#define M_NOTEQUAL_27_27 0
|
||||
#define M_NOTEQUAL_28_28 0
|
||||
#define M_NOTEQUAL_29_29 0
|
||||
#define M_NOTEQUAL(x,y) M_BOOL(CAT4(M_NOTEQUAL_, x, _, y))
|
||||
|
||||
/* ADD: Through recursivity.
|
||||
Example: ADD(4,5) --> 9 */
|
||||
#define M_ADD_L0_INDIRECT() M_ADD_L0
|
||||
#define M_ADD_L1(x,y) M_DELAY3(M_ADD_L0_INDIRECT) () (M_INC(x), M_DEC(y))
|
||||
#define M_ADD_L0(x,y) M_IF(M_BOOL(y)) (M_ADD_L1(x,y) , x)
|
||||
#define M_ADD(x,y) M_EVAL(M_ADD_L0(x,y))
|
||||
|
||||
/* SUB: Through recursivity
|
||||
Example: SUB(15,6) --> 11 */
|
||||
#define M_SUB_L0_INDIRECT() M_SUB_L0
|
||||
#define M_SUB_L1(x,y) M_DELAY3(M_SUB_L0_INDIRECT) () (M_DEC(x), M_DEC(y))
|
||||
#define M_SUB_L0(x,y) M_IF(M_BOOL(y)) (M_SUB_L1(x,y) , x)
|
||||
#define M_SUB(x,y) M_EVAL(M_SUB_L0(x,y))
|
||||
|
||||
/* EQUAL(val1,val2) with valN from [0 to 30[
|
||||
Return 1 if val1=val2 or 0
|
||||
Example: M_EQUAL(1,2) --> 0
|
||||
*/
|
||||
#define M_EQUAL(x,y) M_INV(M_NOTEQUAL(x,y))
|
||||
|
||||
/* Revert the list given as parameter
|
||||
Example: M_INVERT(a,b,c) --> (c,b,a) */
|
||||
/* Generated by:
|
||||
for i in $(seq 1 26) ; do printf "#define M_INVERT_%d(" $i ; for j in $(seq 1 $i) ; do printf "_%d" $j ; if test $i -ne $j ; then printf "," ; fi ; done; printf ") (" ; for j in $(seq $i -1 1) ; do printf "_%d" $j ; if test 1 -ne $j ; then printf "," ; fi ; done ; printf ")\n" ; done */
|
||||
#define M_INVERT_0() ()
|
||||
#define M_INVERT_1(_1) (_1)
|
||||
#define M_INVERT_2(_1,_2) (_2,_1)
|
||||
#define M_INVERT_3(_1,_2,_3) (_3,_2,_1)
|
||||
#define M_INVERT_4(_1,_2,_3,_4) (_4,_3,_2,_1)
|
||||
#define M_INVERT_5(_1,_2,_3,_4,_5) (_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_6(_1,_2,_3,_4,_5,_6) (_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_7(_1,_2,_3,_4,_5,_6,_7) (_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_8(_1,_2,_3,_4,_5,_6,_7,_8) (_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_9(_1,_2,_3,_4,_5,_6,_7,_8,_9) (_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_10(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10) (_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_11(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11) (_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_12(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12) (_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_13(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13) (_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_14(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14)\
|
||||
(_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_15(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15)\
|
||||
(_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_16(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16)\
|
||||
(_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_17(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17)\
|
||||
(_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_18(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18)\
|
||||
(_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_19(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19)\
|
||||
(_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_20(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20)\
|
||||
(_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_21(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21)\
|
||||
(_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_22(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22)\
|
||||
(_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_23(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23)\
|
||||
(_23,_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_24(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24)\
|
||||
(_24,_23,_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_25(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25)\
|
||||
(_25,_24,_23,_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT_26(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26)\
|
||||
(_26,_25,_24,_23,_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)
|
||||
#define M_INVERT(...) CAT(M_INVERT_, M_NARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
|
||||
/***************************************************************/
|
||||
/******************** Compile Times Macro **********************/
|
||||
/***************************************************************/
|
||||
|
||||
/* C11 MACROS */
|
||||
|
||||
/* Return the string format of a variable */
|
||||
#define M_PRINTF_FORMAT(x) \
|
||||
_Generic(((void)0,x), \
|
||||
char: "%c", \
|
||||
signed char: "%hhd", \
|
||||
unsigned char: "%hhu", \
|
||||
signed short: "%hd", \
|
||||
unsigned short: "%hu", \
|
||||
signed int: "%d", \
|
||||
unsigned int: "%u", \
|
||||
long int: "%ld", \
|
||||
unsigned long int: "%lu", \
|
||||
long long int: "%lld", \
|
||||
unsigned long long int: "%llu", \
|
||||
float: "%f", \
|
||||
double: "%f", \
|
||||
long double: "%Lf", \
|
||||
const char *: "%s", \
|
||||
char *: "%s", \
|
||||
const void *: "%p", \
|
||||
void *: "%p")
|
||||
|
||||
/* Print a C variable if it is a standard type to stdout.
|
||||
Note: final ';' is needed to be called within a M_MAP */
|
||||
#define M_PRINT_ARG(x) printf(M_PRINTF_FORMAT(x), x);
|
||||
|
||||
/* Print a C variable if it is a standard type to the given file 'f'
|
||||
Note: final ';' is needed to be called within a M_MAP2 */
|
||||
#define M_FPRINT_ARG(f, x) fprintf(f, M_PRINTF_FORMAT(x), x);
|
||||
|
||||
/* Generic PRINT macro: print all its inputs regardless of the type
|
||||
provided it is a generic "non-struct" type. */
|
||||
#define M_PRINT(...) do { M_MAP(M_PRINT_ARG, __VA_ARGS__) } while (0)
|
||||
|
||||
/* Generic FPRINT macro: print all its inputs regardless of the type
|
||||
provided it is a generic "non-struct" type into the file 'f'. */
|
||||
#define M_FPRINT(f,...) do { M_MAP2(M_FPRINT_ARG, f, __VA_ARGS__) } while (0)
|
||||
|
||||
/* Return the minimum between x and y (computed in compile time) */
|
||||
#define M_MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
/* Return the maximum between x and y (computed in compile time) */
|
||||
#define M_MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
/* Is the number a power of 2? (computed in compile time) */
|
||||
#define M_POWEROF2_P(n) (!((n)&((n)-1)))
|
||||
|
||||
|
||||
/************************************************************/
|
||||
/******************** METHODS handling **********************/
|
||||
/************************************************************/
|
||||
|
||||
/* List of supported methods */
|
||||
#define M_INIT_INIT(a) ,a,
|
||||
#define M_INIT_SET_INIT_SET(a) ,a,
|
||||
#define M_INIT_MOVE_INIT_MOVE(a) ,a,
|
||||
#define M_SET_SET(a) ,a,
|
||||
#define M_MOVE_MOVE(a) ,a,
|
||||
#define M_CLEAR_CLEAR(a) ,a,
|
||||
#define M_DEL_DEL(a) ,a,
|
||||
#define M_HASH_HASH(a) ,a,
|
||||
#define M_EQUAL_EQUAL(a) ,a,
|
||||
#define M_CMP_CMP(a) ,a,
|
||||
#define M_TYPE_TYPE(a) ,a,
|
||||
#define M_SUBTYPE_SUBTYPE(a) ,a,
|
||||
#define M_OPLIST_OPLIST(a) ,a,
|
||||
#define M_SORT_SORT(a) ,a,
|
||||
#define M_UPDATE_UPDATE(a) ,a,
|
||||
#define M_IT_TYPE_IT_TYPE(a) ,a,
|
||||
#define M_IT_FIRST_IT_FIRST(a) ,a,
|
||||
#define M_IT_LAST_IT_LAST(a) ,a,
|
||||
#define M_IT_SET_IT_SET(a) ,a,
|
||||
#define M_IT_END_P_IT_END_P(a) ,a,
|
||||
#define M_IT_LAST_P_IT_LAST_P(a) ,a,
|
||||
#define M_IT_EQUAL_P_IT_EQUAL_P(a) ,a,
|
||||
#define M_IT_NEXT_IT_NEXT(a) ,a,
|
||||
#define M_IT_PREVIOUS_IT_PREVIOUS(a) ,a,
|
||||
#define M_IT_REF_IT_REF(a) ,a,
|
||||
#define M_IT_CREF_IT_CREF(a) ,a,
|
||||
#define M_ADD_ADD(a) ,a,
|
||||
#define M_SUB_SUB(a) ,a,
|
||||
#define M_MUL_MUL(a) ,a,
|
||||
#define M_DIV_DIV(a) ,a,
|
||||
#define M_CLEAN_CLEAN(a) ,a,
|
||||
#define M_PUSH_PUSH(a) ,a,
|
||||
#define M_POP_POP(a) ,a,
|
||||
#define M_REVERSE_REVERSE(a) ,a,
|
||||
#define M_GET_STR_GET_STR(a) ,a,
|
||||
#define M_OUT_STR_OUT_STR(a) ,a,
|
||||
#define M_SET_STR_SET_STR(a) ,a,
|
||||
#define M_IN_STR_IN_STR(a) ,a,
|
||||
#define M_SEPARATOR_SEPARATOR(a) ,a,
|
||||
#define M_EXT_ALGO_EXT_ALGO(a) ,a,
|
||||
|
||||
/* From an oplist - an unorded list of methods : like "INIT(mpz_init),CLEAR(mpz_clear),SET(mpz_set)" -
|
||||
Return the given method in the oplist or the default method.
|
||||
Example:
|
||||
M_GET_METHOD(INIT, my_default, INIT(mpz_init),CLEAR(mpz_clear),SET(mpz_set)) --> mpz_init
|
||||
M_GET_METHOD(INIT, my_default, CLEAR(mpz_clear),SET(mpz_set)) --> my_default */
|
||||
#define M_GET_METHOD(method, method_default, ...) \
|
||||
M_RET_ARG2 (M_MAP2B(CAT, CAT3(M_, method, _), __VA_ARGS__), method_default,)
|
||||
|
||||
/* Get the given method */
|
||||
#define M_GET_INIT(...) M_GET_METHOD(INIT, M_INIT_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_INIT_SET(...) M_GET_METHOD(INIT_SET, M_SET_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_INIT_MOVE(...) M_GET_METHOD(INIT_MOVE, M_MOVE_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SET(...) M_GET_METHOD(SET, M_SET_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_MOVE(...) M_GET_METHOD(MOVE, M_MOVE_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_CLEAR(...) M_GET_METHOD(CLEAR, M_CLEAR_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_DEL(...) M_GET_METHOD(DEL, M_DEL_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_HASH(...) M_GET_METHOD(HASH, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_EQUAL(...) M_GET_METHOD(EQUAL, M_EQUAL_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_CMP(...) M_GET_METHOD(CMP, M_CMP_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_UPDATE(...) M_GET_METHOD(UPATE, M_MEMCPY_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_TYPE(...) M_GET_METHOD(TYPE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SUBTYPE(...) M_GET_METHOD(SUBTYPE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_OPLIST(...) M_GET_METHOD(OPLIST, (), __VA_ARGS__)
|
||||
#define M_GET_SORT(...) M_GET_METHOD(SORT, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_TYPE(...) M_GET_METHOD(IT_TYPE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_FIRST(...) M_GET_METHOD(IT_FIRST, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_LAST(...) M_GET_METHOD(IT_LAST, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_SET(...) M_GET_METHOD(IT_SET, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_END_P(...) M_GET_METHOD(IT_END_P, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_LAST_P(...) M_GET_METHOD(IT_LAST_P, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_EQUAL_P(...) M_GET_METHOD(IT_EQUAL_P, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_NEXT(...) M_GET_METHOD(IT_NEXT, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_PREVIOUS(...) M_GET_METHOD(IT_PREVIOUS, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_REF(...) M_GET_METHOD(IT_REF, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_CREF(...) M_GET_METHOD(IT_CREF, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_ADD(...) M_GET_METHOD(ADD, M_ADD_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SUB(...) M_GET_METHOD(SUB, M_SUB_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_MUL(...) M_GET_METHOD(MUL, M_MUL_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_DIV(...) M_GET_METHOD(DIV, M_DIV_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_CLEAN(...) M_GET_METHOD(CLEAN, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_PUSH(...) M_GET_METHOD(PUSH, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_POP(...) M_GET_METHOD(POP, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_REVERSE(...) M_GET_METHOD(REVERSE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_GET_STR(...) M_GET_METHOD(GET_STR, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_OUT_STR(...) M_GET_METHOD(OUT_STR, M_FPRINT_ARG, __VA_ARGS__)
|
||||
#define M_GET_IN_STR(...) M_GET_METHOD(IN_STR, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SEPARATOR(...) M_GET_METHOD(SEPARATOR, ',', __VA_ARGS__)
|
||||
#define M_GET_EXT_ALGO(...) M_GET_METHOD(EXT_ALGO, M_NO_EXT_ALGO, __VA_ARGS__)
|
||||
|
||||
/* Define the default method */
|
||||
#define M_INIT_DEFAULT(a) ((a) = 0)
|
||||
#define M_MEMSET_DEFAULT(a) (memset(&(a), 0, sizeof (a)))
|
||||
#define M_SET_DEFAULT(a,b) ((a) = (b))
|
||||
#define M_MOVE_DEFAULT(a,b) (M_MEMCPY_DEFAULT(a, b), M_MEMSET_DEFAULT(b))
|
||||
#define M_MEMCPY_DEFAULT(a,b) (memcpy(&(a), &(b), sizeof (a)))
|
||||
#define M_CLEAR_DEFAULT(a) (void)a
|
||||
#define M_DEL_DEFAULT(a) free(a)
|
||||
#define M_NO_DEFAULT(...) m_no_default_function
|
||||
#define M_EQUAL_DEFAULT(a,b) ((a) == (b))
|
||||
#define M_CMP_DEFAULT(a,b) ((a) < (b) ? -1 : (a) > (b))
|
||||
#define M_ADD_DEFAULT(a,b,c) ((a) = (b) + (c))
|
||||
#define M_SUB_DEFAULT(a,b,c) ((a) = (b) - (c))
|
||||
#define M_MUL_DEFAULT(a,b,c) ((a) = (b) * (c))
|
||||
#define M_DIV_DEFAULT(a,b,c) ((a) = (b) / (c))
|
||||
#define M_NO_EXT_ALGO(n,co,to)
|
||||
|
||||
/* Default hash: perform a hash of the memory pattern of the object */
|
||||
// TODO: Better hash function?
|
||||
static inline size_t
|
||||
m_core_hash(const void *ptr, size_t s)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char *) ptr;
|
||||
size_t hash = 0;
|
||||
for(size_t i = 0 ; i < s; i++) {
|
||||
unsigned int c = p[i];
|
||||
hash = hash * 31421 + c + 6297;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
#define M_HASH_DEFAULT(a) m_core_hash(&(a), sizeof (a))
|
||||
|
||||
#define M_DEFAULT_OPLIST \
|
||||
(INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \
|
||||
CLEAR(M_CLEAR_DEFAULT), EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \
|
||||
INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \
|
||||
HASH(M_HASH_DEFAULT) \
|
||||
/*ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), MUL(M_MUL_DEFAULT),*/ \
|
||||
/*DIV(M_DIV_DEFAULT)*/ )
|
||||
|
||||
/* From an oplist (...) return ... */
|
||||
#define M_OPLIST_FLAT(...) __VA_ARGS__
|
||||
|
||||
/* Concat two oplists in one. op1 will have higher priority to op2 */
|
||||
#define M_OPLIST_CAT(op1,op2) (M_OPLIST_FLAT op1, M_OPLIST_FLAT op2)
|
||||
|
||||
/* Appl an oplist */
|
||||
#define M_OPLIST_APPLY(a, oplist) a oplist
|
||||
|
||||
/* Test if a method is present in an oplist.
|
||||
Return 0 or 1 */
|
||||
#define M_TEST_METHOD_P(method, oplist) \
|
||||
M_BOOL(M_GET_METHOD (method, 0, M_OPLIST_FLAT oplist))
|
||||
|
||||
/* Perfom a preprocessing M_IF, if the method is present in the oplist.
|
||||
Example: M_IF_METHOD(HASH, oplist)(define function with HASH method, ) */
|
||||
#define M_IF_METHOD(method, oplist) M_IF(M_TEST_METHOD_P(method, oplist))
|
||||
|
||||
/* Perform a preprocessing M_IF if the method exists in both oplist.
|
||||
Example: M_IF_METHOD_BOTH(HASH, oplist1, oplist2) (define function with HASH method, ) */
|
||||
#define M_IF_METHOD_BOTH(method, oplist1, oplist2) \
|
||||
M_IF(M_AND(M_TEST_METHOD_P(method, oplist1), M_TEST_METHOD_P(method, oplist2)))
|
||||
|
||||
/* Perform a preprocessing M_IF if the method exists for all oplist.
|
||||
Example: M_IF_METHOD_ALL(HASH, oplist1, oplist2) (define function with HASH method, ) */
|
||||
#define M_IF_METHOD_ALL(method, ...) \
|
||||
M_IF(M_REDUCE2(M_TEST_METHOD_P, M_AND, method, __VA_ARGS__))
|
||||
|
||||
/* Define M_EACH macro allowing to iterate over a container
|
||||
First argument will be a created pointer to the underlying type.
|
||||
Example: for M_EACH(item, list, LIST_OPLIST) { action; } */
|
||||
#define M_EACH(item, container, oplist) \
|
||||
M_EACHI(item, container, oplist, CAT(local_iterator_, __LINE__), \
|
||||
CAT(local_cont_, __LINE__))
|
||||
|
||||
/* Internal for M_EACH */
|
||||
#define M_EACHI(item,container,oplist, iterator, cont) \
|
||||
(bool cont = true; cont; cont = false) \
|
||||
for(M_GET_SUBTYPE oplist *item; cont ; cont = false) \
|
||||
for(M_GET_IT_TYPE oplist iterator; cont ; cont = false) \
|
||||
for(M_GET_IT_FIRST oplist (iterator, container) ; \
|
||||
!M_GET_IT_END_P oplist (iterator) && (item = M_GET_IT_REF oplist (iterator), true) ; \
|
||||
M_GET_IT_NEXT oplist (iterator))
|
||||
|
||||
/* Define M_LET macro allowing to define, auto init & auto clear an object
|
||||
within the next bracket.
|
||||
Example:
|
||||
M_LET(a, STRING_OPLIST) { do something with a } or
|
||||
M_LET(a, b, c, STRING_OPLIST) { do something with a, b & c } */
|
||||
#define M_LET(...) \
|
||||
M_ID(M_LETI M_INVERT( __VA_ARGS__, CAT(local_cont_, __LINE__) ))
|
||||
|
||||
#define M_LETI(cont, oplist, ...) \
|
||||
for(bool cont = true; cont ; cont = false) \
|
||||
M_MAP2(M_LETI_SINGLE, (cont, oplist,), __VA_ARGS__)
|
||||
|
||||
#define M_LETI_SINGLE(data, name) \
|
||||
M_LETI_SINGLE2(M_RET_ARG1 data, M_RET_ARG2 data, name)
|
||||
|
||||
#define M_LETI_SINGLE2(cont, oplist, name) \
|
||||
for(M_GET_TYPE oplist name; \
|
||||
(M_GET_INIT oplist (name), cont); \
|
||||
(M_GET_CLEAR oplist (name), cont = false))
|
||||
|
||||
/* Check if 'n' is assignable to an object of type 'type'
|
||||
Return the object. */
|
||||
#define M_ASSIGN_CAST(type, n) \
|
||||
((type) { 0 } = (n))
|
||||
|
||||
|
||||
/* By putting this after a method, we transform the argument list
|
||||
so that the first argument becomes a pointer to the destination. */
|
||||
#define M_IPTR(...) ( & __VA_ARGS__ )
|
||||
|
||||
|
||||
/************************************************************/
|
||||
/********************* MEMORY handling **********************/
|
||||
/************************************************************/
|
||||
|
||||
#ifndef M_MEMORY_ALLOC
|
||||
#ifdef __cplusplus
|
||||
# include <cstdlib>
|
||||
# define M_MEMORY_ALLOC(type) ((type*)std::malloc (sizeof (type)))
|
||||
# define M_MEMORY_REALLOC(type, ptr, n) \
|
||||
((type*) std::realloc ((ptr), (n)*sizeof (type)))
|
||||
# define M_MEMORY_FREE(ptr) std::free(ptr)
|
||||
#else
|
||||
# include <stdlib.h>
|
||||
# define M_MEMORY_ALLOC(type) malloc (sizeof (type))
|
||||
# define M_MEMORY_REALLOC(type, ptr, n) realloc ((ptr), (n)*sizeof (type))
|
||||
# define M_MEMORY_FREE(ptr) free(ptr)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Basic ERROR handling macros.
|
||||
// Note: Can be overloaded by used code to:
|
||||
// * throw an exception if needed.
|
||||
// * set a global error variable and return
|
||||
// * abort
|
||||
#ifndef M_MEMORY_FULL
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#define M_MEMORY_FULL(size) do { \
|
||||
fprintf(stderr, "ERROR: Can not allocate memory (%lu bytes).\n", \
|
||||
(unsigned long) size); \
|
||||
abort(); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef M_INIT_FAILURE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#define M_INIT_FAILURE() do { \
|
||||
fprintf(stderr, "ERROR: Can not initialize data.\n"); \
|
||||
abort(); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef M_ASSERT_INIT
|
||||
#define M_ASSERT_INIT(expr) do { \
|
||||
if (!(expr)) { \
|
||||
fprintf(stderr, "ERROR: Can not initialize data: %s\n", #expr); \
|
||||
abort(); \
|
||||
} } while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,468 @@
|
||||
/*
|
||||
* MLIB - DICTIONARY Module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_DICT_H
|
||||
#define __M_DICT_H
|
||||
|
||||
#include "m-list.h"
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
#include "m-tuple.h"
|
||||
|
||||
/* Define a dictionnary with the key key_type to the value value_type. */
|
||||
#define DICT_DEF2(name, key_type, key_oplist, value_type, value_oplist) \
|
||||
TUPLE_DEF2(CAT(dict_pair_, name), (key, key_type, key_oplist), (value, value_type, value_oplist)) \
|
||||
LIST_DEF(CAT(dict_pair_, name), CAT3(dict_pair_,name,_t), TUPLE_OPLIST(CAT(dict_pair_, name), key_oplist, value_oplist)) \
|
||||
ARRAY_DEF(CAT(list_dict_pair_,name), CAT3(list_dict_pair_,name,_t), LIST_OPLIST(CAT(dict_pair_, name))) \
|
||||
\
|
||||
typedef struct CAT3(dict_, name, _s) { \
|
||||
size_t used, lower_limit, upper_limit; \
|
||||
CAT3(array_list_dict_pair_,name,_t) table; \
|
||||
} CAT3(dict_, name, _t)[1]; \
|
||||
\
|
||||
typedef struct CAT3(dict_it_, name, _s) { \
|
||||
CAT3(array_it_list_dict_pair_, name, _t) array_it; \
|
||||
CAT3(list_it_dict_pair_, name, _t) list_it; \
|
||||
} CAT3(dict_it_, name, _t)[1]; \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(dict_, name, _init)(CAT3(dict_,name,_t) map) \
|
||||
{ \
|
||||
map->used = 0; \
|
||||
CAT3(array_list_dict_pair_,name,_init)(map->table); \
|
||||
CAT3(array_list_dict_pair_,name,_resize)(map->table, DICTI_INITIAL_SIZE); \
|
||||
map->lower_limit = DICTI_LOWER_BOUND(DICTI_INITIAL_SIZE); \
|
||||
map->upper_limit = DICTI_UPPER_BOUND(DICTI_INITIAL_SIZE); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(dict_, name, _init_set)(CAT3(dict_,name,_t) map, \
|
||||
const CAT3(dict_,name,_t) org) \
|
||||
{ \
|
||||
DICTI_CONTRACT(name, org); \
|
||||
map->used = org->used; \
|
||||
map->lower_limit = org->lower_limit; \
|
||||
map->upper_limit = org->upper_limit; \
|
||||
CAT3(array_list_dict_pair_,name,_init_set)(map->table, org->table); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(dict_, name, _set)(CAT3(dict_,name,_t) map, \
|
||||
const CAT3(dict_,name,_t) org) \
|
||||
{ \
|
||||
DICTI_CONTRACT(name, map); \
|
||||
DICTI_CONTRACT(name, org); \
|
||||
map->used = org->used; \
|
||||
map->lower_limit = org->lower_limit; \
|
||||
map->upper_limit = org->upper_limit; \
|
||||
CAT3(array_list_dict_pair_,name,_set)(map->table, org->table); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(dict_,name,_clear)(CAT3(dict_,name,_t) map) \
|
||||
{ \
|
||||
CAT3(array_list_dict_pair_,name,_clear)(map->table); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(dict_, name, _init_move)(CAT3(dict_,name,_t) map, \
|
||||
CAT3(dict_,name,_t) org) \
|
||||
{ \
|
||||
DICTI_CONTRACT(name, org); \
|
||||
map->used = org->used; \
|
||||
map->lower_limit = org->lower_limit; \
|
||||
map->upper_limit = org->upper_limit; \
|
||||
CAT3(array_list_dict_pair_,name,_init_move)(map->table, org->table); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(dict_, name, _move)(CAT3(dict_,name,_t) map, \
|
||||
CAT3(dict_,name,_t) org) \
|
||||
{ \
|
||||
DICTI_CONTRACT(name, map); \
|
||||
DICTI_CONTRACT(name, org); \
|
||||
assert (map != org); \
|
||||
CAT3(dict_,name,_clear)(map); \
|
||||
CAT3(dict_,name,_init_move)(map, org); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(dict_,name,_clean)(CAT3(dict_,name,_t) map) \
|
||||
{ \
|
||||
CAT3(array_list_dict_pair_,name,_clean)(map->table); \
|
||||
CAT3(array_list_dict_pair_,name,_resize)(map->table, DICTI_INITIAL_SIZE); \
|
||||
map->lower_limit = DICTI_LOWER_BOUND(DICTI_INITIAL_SIZE); \
|
||||
map->upper_limit = DICTI_UPPER_BOUND(DICTI_INITIAL_SIZE); \
|
||||
map->used = 0; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
CAT3(dict_,name,_size)(const CAT3(dict_,name,_t) map) \
|
||||
{ \
|
||||
DICTI_CONTRACT(name, map); \
|
||||
return map->used; \
|
||||
} \
|
||||
\
|
||||
static inline value_type * \
|
||||
CAT3(dict_,name,_get)(const CAT3(dict_,name,_t) map, const key_type key) \
|
||||
{ \
|
||||
DICTI_CONTRACT(name, map); \
|
||||
size_t hash = M_GET_HASH key_oplist (key); \
|
||||
hash = hash & (CAT3(array_list_dict_pair_,name,_size)(map->table) - 1); \
|
||||
const CAT3(list_dict_pair_,name,_t) *list_ptr = \
|
||||
CAT3(array_list_dict_pair_,name,_cget)(map->table, hash); \
|
||||
CAT3(list_it_dict_pair_,name,_t) it; \
|
||||
for(CAT3(list_dict_pair_,name,_it)(it, *list_ptr); \
|
||||
!CAT3(list_dict_pair_,name,_end_p)(it); \
|
||||
CAT3(list_dict_pair_,name,_next)(it)) { \
|
||||
CAT3(dict_pair_,name,_t) *ref = CAT3(list_dict_pair_,name,_ref)(it); \
|
||||
if (M_GET_EQUAL key_oplist ((*ref)->key, key)) \
|
||||
return &(*ref)->value; \
|
||||
} \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(dicti_,name,_resize_up)(CAT3(dict_,name,_t) map) \
|
||||
{ \
|
||||
size_t old_size = CAT3(array_list_dict_pair_,name,_size)(map->table); \
|
||||
size_t new_size = old_size * 2; \
|
||||
/* Resize the dictionnary */ \
|
||||
CAT3(array_list_dict_pair_,name,_resize)(map->table, new_size); \
|
||||
/* Move the items to the new upper part */ \
|
||||
for(size_t i = 0; i < old_size; i++) { \
|
||||
CAT3(list_dict_pair_,name,_t) *list = \
|
||||
CAT3(array_list_dict_pair_,name,_get)(map->table, i); \
|
||||
if (CAT3(list_dict_pair_,name,_empty_p)(*list)) \
|
||||
continue; \
|
||||
CAT3(list_it_dict_pair_,name,_t) it; \
|
||||
CAT3(list_dict_pair_,name,_it)(it, *list); \
|
||||
while (!CAT3(list_dict_pair_,name,_end_p)(it)) { \
|
||||
CAT3(dict_pair_,name,_ptr) pair = *CAT3(list_dict_pair_,name,_ref)(it); \
|
||||
size_t hash = M_GET_HASH key_oplist (pair->key); \
|
||||
if ((hash & (new_size-1)) >= old_size) { \
|
||||
assert( (hash & (new_size-1)) == (i + old_size)); \
|
||||
CAT3(list_dict_pair_,name,_t) *new_list = \
|
||||
CAT3(array_list_dict_pair_,name,_get)(map->table, i + old_size); \
|
||||
CAT3(list_dict_pair_,name,_move_back)(*new_list, *list, it); \
|
||||
} else { \
|
||||
CAT3(list_dict_pair_,name,_next)(it); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
map->upper_limit = DICTI_UPPER_BOUND(new_size); \
|
||||
map->lower_limit = DICTI_LOWER_BOUND(new_size); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(dicti_,name,_resize_down)(CAT3(dict_,name,_t) map) \
|
||||
{ \
|
||||
assert (map != NULL); \
|
||||
size_t old_size = CAT3(array_list_dict_pair_,name,_size)(map->table); \
|
||||
assert ((old_size % 2) == 0); \
|
||||
size_t new_size = old_size / 2; \
|
||||
assert (new_size >= DICTI_INITIAL_SIZE); \
|
||||
/* Move all items to the lower part of the dictionnary */ \
|
||||
for(size_t i = new_size; i < old_size; i++) { \
|
||||
CAT3(list_dict_pair_,name,_t) *list = \
|
||||
CAT3(array_list_dict_pair_,name,_get)(map->table, i); \
|
||||
if (CAT3(list_dict_pair_,name,_empty_p)(*list)) \
|
||||
continue; \
|
||||
CAT3(list_it_dict_pair_,name,_t) it; \
|
||||
CAT3(list_dict_pair_,name,_it)(it, *list); \
|
||||
while (!CAT3(list_dict_pair_,name,_end_p)(it)) { \
|
||||
M_IF_DEBUG(CAT3(dict_pair_,name,_ptr) pair = *CAT3(list_dict_pair_,name,_ref)(it);) \
|
||||
M_IF_DEBUG(size_t hash = M_GET_HASH key_oplist (pair->key);) \
|
||||
assert ((hash & (old_size -1)) == i); \
|
||||
assert ((hash & (new_size -1)) == i - new_size); \
|
||||
CAT3(list_dict_pair_,name,_t) *new_list = \
|
||||
CAT3(array_list_dict_pair_,name,_get)(map->table, i - new_size); \
|
||||
CAT3(list_dict_pair_,name,_move_back)(*new_list, *list, it); \
|
||||
} \
|
||||
} \
|
||||
/* Resize the dictionary */ \
|
||||
CAT3(array_list_dict_pair_,name,_resize)(map->table, new_size); \
|
||||
map->upper_limit = DICTI_UPPER_BOUND(new_size); \
|
||||
map->lower_limit = DICTI_LOWER_BOUND(new_size); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(dict_,name,_set_at)(CAT3(dict_,name,_t) map, \
|
||||
const key_type key, const value_type value) \
|
||||
{ \
|
||||
DICTI_CONTRACT(name, map); \
|
||||
\
|
||||
size_t hash = M_GET_HASH key_oplist(key); \
|
||||
hash = hash & (CAT3(array_list_dict_pair_,name,_size)(map->table) - 1); \
|
||||
CAT3(list_dict_pair_,name,_t) *list_ptr = \
|
||||
CAT3(array_list_dict_pair_,name,_get)(map->table, hash); \
|
||||
CAT3(list_it_dict_pair_,name,_t) it; \
|
||||
for(CAT3(list_dict_pair_,name,_it)(it, *list_ptr); \
|
||||
!CAT3(list_dict_pair_,name,_end_p)(it); \
|
||||
CAT3(list_dict_pair_,name,_next)(it)) { \
|
||||
CAT3(dict_pair_,name,_ptr) ref = *CAT3(list_dict_pair_,name,_ref)(it); \
|
||||
if (M_GET_EQUAL key_oplist(ref->key, key)) { \
|
||||
M_GET_SET value_oplist(ref->value, value); \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
CAT3(dict_pair_,name,_init_set2)(*CAT3(list_dict_pair_,name,_push_raw)(*list_ptr), \
|
||||
key, value); \
|
||||
map->used ++; \
|
||||
if (map->used > map->upper_limit) \
|
||||
CAT3(dicti_,name,_resize_up)(map); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(dict_,name,_remove)(CAT3(dict_,name,_t) map, const key_type key) \
|
||||
{ \
|
||||
DICTI_CONTRACT(name, map); \
|
||||
\
|
||||
size_t hash = M_GET_HASH key_oplist(key); \
|
||||
hash = hash & (CAT3(array_list_dict_pair_,name,_size)(map->table) - 1); \
|
||||
CAT3(list_dict_pair_,name,_t) *list_ptr = \
|
||||
CAT3(array_list_dict_pair_,name,_get)(map->table, hash); \
|
||||
CAT3(list_it_dict_pair_,name,_t) it; \
|
||||
for(CAT3(list_dict_pair_,name,_it)(it, *list_ptr); \
|
||||
!CAT3(list_dict_pair_,name,_end_p)(it); \
|
||||
CAT3(list_dict_pair_,name,_next)(it)) { \
|
||||
CAT3(dict_pair_,name,_ptr) ref = *CAT3(list_dict_pair_,name,_ref)(it); \
|
||||
if (M_GET_EQUAL key_oplist(ref->key, key)) { \
|
||||
CAT3(list_dict_pair_,name,_remove)(*list_ptr, it); \
|
||||
map->used --; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
if (map->used < map->lower_limit) \
|
||||
CAT3(dicti_, name, _resize_down)(map); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(dict_, name, _it)(CAT3(dict_it_, name,_t) it, \
|
||||
CAT3(dict_, name,_t) d) \
|
||||
{ \
|
||||
CAT3(array_list_dict_pair_, name, _it)(it->array_it, d->table); \
|
||||
CAT3(list_dict_pair_,name,_t) *ref = \
|
||||
CAT3(array_list_dict_pair_, name, _ref)(it->array_it); \
|
||||
CAT3(list_dict_pair_, name, _it)(it->list_it, *ref); \
|
||||
while (CAT3(list_dict_pair_, name, _end_p)(it->list_it)) { \
|
||||
CAT3(array_list_dict_pair_, name, _next)(it->array_it); \
|
||||
if (CAT3(array_list_dict_pair_, name, _end_p)(it->array_it))break; \
|
||||
ref = CAT3(array_list_dict_pair_, name, _ref)(it->array_it); \
|
||||
CAT3(list_dict_pair_, name, _it)(it->list_it, *ref); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(dict_, name, _it_set)(CAT3(dict_it_, name,_t) it, \
|
||||
const CAT3(dict_it_, name,_t) ref) \
|
||||
{ \
|
||||
assert (it != NULL && ref != NULL); \
|
||||
CAT3(array_list_dict_pair_, name, _it_set)(it->array_it, \
|
||||
ref->array_it); \
|
||||
CAT3(list_dict_pair_, name, _it_set)(it->list_it, ref->list_it); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(dict_, name, _end_p)(const CAT3(dict_it_, name,_t) it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
return CAT3(list_dict_pair_, name, _end_p)(it->list_it); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(dict_, name, _next)(CAT3(dict_it_, name,_t) it) \
|
||||
{ \
|
||||
assert(it != NULL); \
|
||||
CAT3(list_dict_pair_, name, _next)(it->list_it); \
|
||||
CAT3(list_dict_pair_,name,_t) *ref; \
|
||||
while (CAT3(list_dict_pair_, name, _end_p)(it->list_it)) { \
|
||||
CAT3(array_list_dict_pair_, name, _next)(it->array_it); \
|
||||
if (CAT3(array_list_dict_pair_, name, _end_p)(it->array_it))break; \
|
||||
ref = CAT3(array_list_dict_pair_, name, _ref)(it->array_it); \
|
||||
CAT3(list_dict_pair_, name, _it)(it->list_it, *ref); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(dict_, name, _last_p)(const CAT3(dict_it_, name,_t) it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
CAT3(dict_it_, name,_t) it2; \
|
||||
CAT3(dict_, name,_it_set)(it2, it); \
|
||||
CAT3(dict_, name, _next)(it2); \
|
||||
return CAT3(dict_, name, _end_p)(it2); \
|
||||
} \
|
||||
\
|
||||
static inline CAT3(dict_pair_,name,_t) * \
|
||||
CAT3(dict_, name, _ref)(CAT3(dict_it_, name,_t) it) \
|
||||
{ \
|
||||
assert(it != NULL); \
|
||||
return CAT3(list_dict_pair_, name, _ref)(it->list_it); \
|
||||
} \
|
||||
\
|
||||
static inline const CAT3(dict_pair_,name,_t) * \
|
||||
CAT3(dict_, name, _cref)(const CAT3(dict_it_, name,_t) it) \
|
||||
{ \
|
||||
assert(it != NULL); \
|
||||
return CAT3(list_dict_pair_, name, _cref)(it->list_it); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(EQUAL, value_oplist)( \
|
||||
static inline bool \
|
||||
CAT3(dict_, name, _equal_p)(CAT3(dict_, name,_t) dict1, \
|
||||
CAT3(dict_, name,_t) dict2) \
|
||||
{ \
|
||||
assert (dict1 != NULL && dict2 != NULL); \
|
||||
/* NOTE: Key type has mandatory equal operator */ \
|
||||
return dict1->used == dict2-> used && \
|
||||
CAT3(array_list_dict_pair_, name, _equal_p)(dict1->table, \
|
||||
dict2->table); \
|
||||
} \
|
||||
, /* no value equal */ ) \
|
||||
\
|
||||
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \
|
||||
static inline void \
|
||||
CAT3(dict_, name, _get_str)(string_t str, \
|
||||
CAT3(dict_, name,_t) dict, \
|
||||
const bool append) \
|
||||
{ \
|
||||
assert (str != NULL && dict != NULL); \
|
||||
DICTI_CONTRACT(name, dict); \
|
||||
(append ? string_cat_str : string_set_str) (str, "{"); \
|
||||
CAT3(dict_it_, name, _t) it; \
|
||||
for (CAT3(dict_, name, _it)(it, dict) ; \
|
||||
!CAT3(dict_, name, _end_p)(it); \
|
||||
CAT3(dict_, name, _next)(it)){ \
|
||||
const CAT3(dict_pair_,name,_t) *item = \
|
||||
CAT3(dict_, name, _cref)(it); \
|
||||
M_GET_GET_STR key_oplist (str, (*item)->key, true); \
|
||||
string_push_back (str, ':'); \
|
||||
M_GET_GET_STR value_oplist (str, (*item)->value, true); \
|
||||
if (!CAT3(dict_, name, _last_p)(it)) \
|
||||
string_push_back (str, ','); \
|
||||
} \
|
||||
string_push_back (str, '}'); \
|
||||
} \
|
||||
, /* no GET_STR */ ) \
|
||||
\
|
||||
M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)( \
|
||||
static inline void \
|
||||
CAT3(dict_, name, _out_str)(FILE *file, \
|
||||
CAT3(dict_, name,_t) dict) \
|
||||
{ \
|
||||
assert (file != NULL && dict != NULL); \
|
||||
DICTI_CONTRACT(name, dict); \
|
||||
fputc ('{', file); \
|
||||
CAT3(dict_it_, name, _t) it; \
|
||||
for (CAT3(dict_, name, _it)(it, dict) ; \
|
||||
!CAT3(dict_, name, _end_p)(it); \
|
||||
CAT3(dict_, name, _next)(it)){ \
|
||||
const CAT3(dict_pair_,name,_t) *item = \
|
||||
CAT3(dict_, name, _cref)(it); \
|
||||
M_GET_OUT_STR key_oplist (file, (*item)->key); \
|
||||
fputc (':', file); \
|
||||
M_GET_OUT_STR value_oplist (file, (*item)->value); \
|
||||
if (!CAT3(dict_, name, _last_p)(it)) \
|
||||
fputc (',', file); \
|
||||
} \
|
||||
fputc ('}', file); \
|
||||
} \
|
||||
, /* no OUT_STR */ ) \
|
||||
\
|
||||
M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)( \
|
||||
static inline bool \
|
||||
CAT3(dict_, name, _in_str)(CAT3(dict_, name,_t) dict, FILE *file) \
|
||||
{ \
|
||||
assert (file != NULL && dict != NULL); \
|
||||
DICTI_CONTRACT(name, dict); \
|
||||
CAT3(dict_, name, _clean)(dict); \
|
||||
char c = fgetc(file); \
|
||||
if (c != '{') return false; \
|
||||
key_type key; \
|
||||
value_type value; \
|
||||
M_GET_INIT key_oplist (key); \
|
||||
M_GET_INIT value_oplist (value); \
|
||||
do { \
|
||||
bool b = M_GET_IN_STR key_oplist (key, file); \
|
||||
if (!b) { c = 0; break; } \
|
||||
c = fgetc(file); \
|
||||
if (c != ':') { c = 0; break; } \
|
||||
b = M_GET_IN_STR value_oplist (value, file); \
|
||||
if (!b) { c = 0; break; } \
|
||||
CAT3(dict_, name, _set_at)(dict, key, value); \
|
||||
c = fgetc(file); \
|
||||
} while (c == ',' && !feof(file) && !ferror(file)); \
|
||||
M_GET_CLEAR key_oplist (key); \
|
||||
M_GET_CLEAR value_oplist (value); \
|
||||
return c == '}'; \
|
||||
} \
|
||||
, /* no IN_STR */ ) \
|
||||
\
|
||||
|
||||
/* Define the oplist of a dictionnary.
|
||||
DICT_OPLIST(name[, oplist of the key type, oplist of the value type]) */
|
||||
#define DICT_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(DICTI_OPLIST(__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST ), \
|
||||
DICTI_OPLIST(__VA_ARGS__ ))
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Define the oplist of a dictionnary */
|
||||
#define DICTI_OPLIST(type, key_oplist, value_oplist) \
|
||||
(INIT(CAT3(dict_, type, _init)), \
|
||||
INIT_SET(CAT3(dict_, type, _init_set)), \
|
||||
SET(CAT3(dict_, type, _set)), \
|
||||
CLEAR(CAT3(dict_, type, _clear)), \
|
||||
INIT_MOVE(CAT3(dict_, type, _init_move)), \
|
||||
MOVE(CAT3(dict_, type, _move)), \
|
||||
TYPE(CAT3(dict_, type, _t)), \
|
||||
SUBTYPE(CAT3(dict_pair_,type,_t)), \
|
||||
IT_TYPE(CAT3(dict_it_,type,_t)), \
|
||||
IT_FIRST(CAT3(dict_,type,_it)), \
|
||||
IT_SET(CAT3(dict_, type, _it_set)), \
|
||||
IT_END_P(CAT3(dict_,type,_end_p)), \
|
||||
IT_LAST_P(CAT3(dict_,type,_last_p)), \
|
||||
IT_NEXT(CAT3(dict_,type,_next)), \
|
||||
IT_REF(CAT3(dict_,type,_ref)), \
|
||||
IT_CREF(CAT3(dict_,type,_cref)) \
|
||||
,M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)(GET_STR(CAT3(array_, type, _get_str)),) \
|
||||
,M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)(OUT_STR(CAT3(array_, type, _out_str)),) \
|
||||
,M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)(IN_STR(CAT3(array_, type, _in_str)),) \
|
||||
,M_IF_METHOD(EQUAL, value_oplist)(EQUAL(CAT3(dict_, type, _equal_p)),) \
|
||||
,KEY_OPLIST(key_oplist) \
|
||||
,VALUE_OPLIST(value_oplist) \
|
||||
)
|
||||
|
||||
#define DICTI_LOWER_BOUND(s) ((s) <= DICTI_INITIAL_SIZE ? 0 : (s) * 1 / 4)
|
||||
#define DICTI_UPPER_BOUND(s) ((s) * 2 / 3)
|
||||
#define DICTI_INITIAL_SIZE 16
|
||||
|
||||
#define DICTI_CONTRACT(name, map) do { \
|
||||
assert(map->used <= map->upper_limit); \
|
||||
assert(M_POWEROF2_P(CAT3(array_list_dict_pair_,name,_size)(map->table))); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
+336
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* MLIB - Intrusive List module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_I_LIST_H
|
||||
#define __M_I_LIST_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/* Interface to add to a structure to allow intrusive support.
|
||||
name: name of the intrusive list.
|
||||
type: name of the type of the structure (aka. struct test_s) - not used currently
|
||||
*/
|
||||
#define ILIST_INTERFACE(name, type) \
|
||||
struct CAT3(ilist_head_, name, _s) { \
|
||||
struct CAT3(ilist_head_, name, _s) *next; \
|
||||
struct CAT3(ilist_head_, name, _s) *prev; \
|
||||
} name
|
||||
|
||||
/* Define a list of a given type.
|
||||
LIST_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define ILIST_DEF(name, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ILISTI_DEF2(name, __VA_ARGS__, M_DEFAULT_OPLIST, ILISTI_CHECK_INSTANCE ), \
|
||||
ILISTI_DEF2(name, __VA_ARGS__, ILISTI_CHECK_INSTANCE ))
|
||||
|
||||
/* Define the oplist of an ilist of type */
|
||||
#define ILIST_OPLIST(name) \
|
||||
(INIT(CAT3(ilist_, name, _init)), \
|
||||
CLEAR(CAT3(ilist_, name, _clear)), \
|
||||
TYPE(CAT3(ilist_,name,_t)), \
|
||||
SUBTYPE(CAT3(ilist_type_,name,_t)), \
|
||||
IT_TYPE(CAT3(ilist_it_,name,_t)), \
|
||||
IT_FIRST(CAT3(ilist_,name,_it)), \
|
||||
IT_SET(CAT3(ilist_,name,_it_set)), \
|
||||
IT_END_P(CAT3(ilist_,name,_end_p)), \
|
||||
IT_LAST_P(CAT3(ilist_,name,_last_p)), \
|
||||
IT_EQUAL_P(CAT3(ilist_,name,_it_equal_p)), \
|
||||
IT_NEXT(CAT3(ilist_,name,_next)), \
|
||||
IT_REF(CAT3(ilist_,name,_ref)), \
|
||||
IT_CREF(CAT3(ilist_,name,_cref)), \
|
||||
PUSH(CAT3(ilist_,name,_push_back)), \
|
||||
POP(CAT3(ilist_,name,_pop_back)) \
|
||||
)
|
||||
//TODO: Add oplist as optional argument of ILIST_OPLIST
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
/* Check if there is only one instance on the list in debug mode.
|
||||
* It doesn't work with C++ (as global vars with the same name are not merged).
|
||||
* (Not sure if it is really mandatory, nor a good idea) */
|
||||
#if !defined(__cplusplus) && !defined (NDEBUG)
|
||||
# define ILISTI_CHECK_INSTANCE 1
|
||||
#else
|
||||
# define ILISTI_CHECK_INSTANCE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* From a pointer to a 'field_type' 'field' of a 'type'structure,
|
||||
* return pointer to the structure.
|
||||
* Note: Lot of cast. Can be unsafe.
|
||||
*/
|
||||
#define ILISTI_TYPE_FROM_FIELD(type, ptr, field_type, field) \
|
||||
( ( (void)((ptr) == (field_type*)(ptr))) , \
|
||||
((type *)(void*)( (char *)(ptr) - offsetof(type, field) )) )
|
||||
|
||||
#define ILISTI_DEF2(name, type, oplist, check_instance) \
|
||||
typedef struct CAT3(ilist_head_, name, _s) CAT3(ilist_, name, _t)[1]; \
|
||||
\
|
||||
typedef type CAT3(ilist_type_,name, _t); \
|
||||
\
|
||||
typedef struct CAT3(ilist_it_, name, _s) { \
|
||||
struct CAT3(ilist_head_, name, _s) *head; \
|
||||
struct CAT3(ilist_head_, name, _s) *previous; \
|
||||
struct CAT3(ilist_head_, name, _s) *current; \
|
||||
struct CAT3(ilist_head_, name, _s) *next; \
|
||||
} CAT3(ilist_it_, name, _t)[1]; \
|
||||
\
|
||||
typedef union { \
|
||||
type *ptr; \
|
||||
const type *cptr; \
|
||||
} CAT3(ilist_union_, name,_t); \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(ilist_, name, _const_cast)(type *ptr) \
|
||||
{ \
|
||||
CAT3(ilist_union_, name,_t) u; \
|
||||
u.ptr = ptr; \
|
||||
return u.cptr; \
|
||||
} \
|
||||
\
|
||||
M_IF(check_instance)(bool CAT3(ilist_instance_, name, _g);, ) \
|
||||
\
|
||||
static inline void CAT3(ilist_, name, _init)(CAT3(ilist_, name, _t) list) \
|
||||
{ \
|
||||
assert (list != NULL); \
|
||||
M_IF(check_instance)(assert (CAT3(ilist_instance_, name, _g) == false),); \
|
||||
M_IF(check_instance)(CAT3(ilist_instance_, name, _g) = true,); \
|
||||
list->next = list; \
|
||||
list->prev = list; \
|
||||
} \
|
||||
\
|
||||
static inline void CAT3(ilist_, name, _clean)(CAT3(ilist_, name, _t) list) \
|
||||
{ \
|
||||
assert (list != NULL); \
|
||||
list->next = list; \
|
||||
list->prev = list; \
|
||||
} \
|
||||
\
|
||||
static inline void CAT3(ilist_, name, _clear)(CAT3(ilist_, name, _t) list) \
|
||||
{ \
|
||||
M_IF(check_instance)(assert (CAT3(ilist_instance_, name, _g) == true),); \
|
||||
M_IF(check_instance)(CAT3(ilist_instance_, name, _g) = false,); \
|
||||
CAT3(ilist_, name, _clean)(list); \
|
||||
} \
|
||||
\
|
||||
static inline bool CAT3(ilist_, name, _empty_p)(const CAT3(ilist_, name, _t) list) \
|
||||
{ \
|
||||
return list->next == list; \
|
||||
} \
|
||||
\
|
||||
static inline size_t CAT3(ilist_, name, _size)(const CAT3(ilist_, name, _t) list) \
|
||||
{ \
|
||||
size_t s = 0; \
|
||||
for(const struct CAT3(ilist_head_, name, _s) *it = list->next ; \
|
||||
it != list; it = it->next) \
|
||||
s++; \
|
||||
return s; \
|
||||
} \
|
||||
\
|
||||
static inline void CAT3(ilist_, name, _push_back)(CAT3(ilist_, name, _t) list, \
|
||||
type *obj) \
|
||||
{ \
|
||||
assert (list != NULL && obj != NULL); \
|
||||
struct CAT3(ilist_head_, name, _s) *prev = list->prev; \
|
||||
list->prev = &obj->name; \
|
||||
obj->name.prev = prev; \
|
||||
obj->name.next = list; \
|
||||
prev->next = &obj->name; \
|
||||
} \
|
||||
\
|
||||
static inline void CAT3(ilist_, name, _push_front)(CAT3(ilist_, name, _t) list, \
|
||||
type *obj) \
|
||||
{ \
|
||||
assert (list != NULL && obj != NULL); \
|
||||
struct CAT3(ilist_head_, name, _s) *next = list->next; \
|
||||
list->next = &obj->name; \
|
||||
obj->name.next = next; \
|
||||
obj->name.prev = list; \
|
||||
next->prev = &obj->name; \
|
||||
} \
|
||||
\
|
||||
static inline void CAT3(ilist_, name, _push_after)(type *obj_it, \
|
||||
type *obj_ins) \
|
||||
{ \
|
||||
assert (obj_it != NULL && obj_ins != NULL); \
|
||||
struct CAT3(ilist_head_, name, _s) *next = obj_it->name.next; \
|
||||
obj_it->name.next = &obj_ins->name; \
|
||||
obj_ins->name.next = next; \
|
||||
obj_ins->name.prev = &obj_it->name; \
|
||||
next->prev = &obj_ins->name; \
|
||||
} \
|
||||
\
|
||||
static inline void CAT3(ilist_, name, _init_field)(type *obj) \
|
||||
{ \
|
||||
assert (obj != NULL); \
|
||||
obj->name.next = NULL; \
|
||||
obj->name.prev = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void CAT3(ilist_, name, _unlink)(type *obj) \
|
||||
{ \
|
||||
assert (obj != NULL); \
|
||||
struct CAT3(ilist_head_, name, _s) *next = obj->name.next; \
|
||||
struct CAT3(ilist_head_, name, _s) *prev = obj->name.prev; \
|
||||
next->prev = prev; \
|
||||
prev->next = next; \
|
||||
obj->name.next = NULL; \
|
||||
obj->name.prev = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(ilist_, name, _back)(const CAT3(ilist_, name,_t) list) \
|
||||
{ \
|
||||
assert(list != NULL && !CAT3(ilist_, name, _empty_p)(list)); \
|
||||
return ILISTI_TYPE_FROM_FIELD(type, list->prev, \
|
||||
struct CAT3(ilist_head_, name, _s), name); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(ilist_, name, _front)(const CAT3(ilist_, name,_t) list) \
|
||||
{ \
|
||||
assert(list != NULL && !CAT3(ilist_, name, _empty_p)(list)); \
|
||||
return ILISTI_TYPE_FROM_FIELD(type, list->next, \
|
||||
struct CAT3(ilist_head_, name, _s), name); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(ilist_, name, _it)(CAT3(ilist_it_, name,_t) it, \
|
||||
CAT3(ilist_, name,_t) list) \
|
||||
{ \
|
||||
assert (it != NULL && list != NULL); \
|
||||
assert (list->next != NULL && list->next->next != NULL); \
|
||||
it->head = list; \
|
||||
it->current = list->next; \
|
||||
it->next = list->next->next; \
|
||||
it->previous = list; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(ilist_, name, _it_set)(CAT3(ilist_it_, name,_t) it, \
|
||||
const CAT3(ilist_it_, name,_t) cit) \
|
||||
{ \
|
||||
assert (it != NULL && cit != NULL); \
|
||||
it->head = cit->head; \
|
||||
it->current = cit->current; \
|
||||
it->next = cit->next; \
|
||||
it->previous = cit->previous; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(ilist_, name, _end_p)(const CAT3(ilist_it_, name,_t) it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
return it->current == it->head; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(ilist_, name, _last_p)(const CAT3(ilist_it_, name,_t) it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
return it->next == it->head; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(ilist_, name, _next)(CAT3(ilist_it_, name,_t) it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
/* Can't set it->previous to it->current. \
|
||||
it->current may have been unlinked from the list */ \
|
||||
it->current = it->next; \
|
||||
assert (it->current != NULL); \
|
||||
it->next = it->current->next; \
|
||||
it->previous = it->current->prev; \
|
||||
assert (it->next != NULL && it->previous != NULL); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(ilist_, name, _previous)(CAT3(ilist_it_, name,_t) it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
/* Can't set it->next to it->current. \
|
||||
it->current may have been unlinked from the list */ \
|
||||
it->current = it->previous; \
|
||||
assert (it->current != NULL); \
|
||||
it->next = it->current->next; \
|
||||
it->previous = it->current->prev; \
|
||||
assert (it->next != NULL && it->previous != NULL); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(ilist_, name, _it_equal_p)(const CAT3(ilist_it_, name,_t) it1, \
|
||||
const CAT3(ilist_it_, name,_t) it2 ) \
|
||||
{ \
|
||||
assert (it1 != NULL && it2 != NULL); \
|
||||
/* No need to check for next & previous */ \
|
||||
return it1->head == it2->head && it1->current == it2->current; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(ilist_, name, _ref)(const CAT3(ilist_it_, name,_t) it) \
|
||||
{ \
|
||||
assert (it != NULL && it->current != NULL); \
|
||||
/* check if 'it' was not deleted */ \
|
||||
assert (it->current->next == it->next); \
|
||||
assert (it->current->prev == it->previous); \
|
||||
assert (!CAT3(ilist_, name, _end_p)(it)); \
|
||||
return ILISTI_TYPE_FROM_FIELD(type, it->current, \
|
||||
struct CAT3(ilist_head_, name, _s), name); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(ilist_, name, _cref)(const CAT3(ilist_it_, name,_t) it) \
|
||||
{ \
|
||||
type *ptr = CAT3(ilist_, name, _ref)(it); \
|
||||
return CAT3(ilist_, name, _const_cast)(ptr); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(ilist_, name, _pop_back)(CAT3(ilist_, name,_t) list) \
|
||||
{ \
|
||||
assert (!CAT3(ilist_, name, _empty_p)(list)); \
|
||||
type *obj = CAT3(ilist_, name, _back)(list); \
|
||||
list->prev = list->prev->prev; \
|
||||
list->prev->next = list; \
|
||||
return obj; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(ilist_, name, _pop_front)(CAT3(ilist_, name,_t) list) \
|
||||
{ \
|
||||
assert (!CAT3(ilist_, name, _empty_p)(list)); \
|
||||
type *obj = CAT3(ilist_, name, _front)(list); \
|
||||
list->next = list->next->next; \
|
||||
list->next->prev = list; \
|
||||
return obj; \
|
||||
} \
|
||||
|
||||
//TODO: C++ compatibility
|
||||
|
||||
#endif
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* MLIB - INTRUSIVE SHARED PTR Module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_SHARED_PTR__H
|
||||
#define __M_SHARED_PTR__H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
#define ISHARED_PTR_OPLIST(name) ( \
|
||||
INIT(M_INIT_DEFAULT), \
|
||||
CLEAR(CAT3(ishared_, name, _clear)), \
|
||||
SET(CAT3(ishared_, name, _set) M_IPTR), \
|
||||
INIT_SET(CAT3(ishared_, name, _init_set2) M_IPTR), \
|
||||
TYPE(CAT3(ishared_,name,_t)), \
|
||||
SUBTYPE(CAT3(ishared_type_,name,_t)), \
|
||||
)
|
||||
|
||||
/* Interface to add to a structure to allow intrusive support.
|
||||
name: name of the intrusive shared pointer.
|
||||
type: name of the type of the structure (aka. struct test_s) - not used currently */
|
||||
#define ISHARED_PTR_INTERFACE(name, type) \
|
||||
int CAT(name, _cpt)
|
||||
|
||||
|
||||
#define ISHARED_PTR_DEF(name, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ISHAREDI_PTR_DEF2(name, __VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
ISHAREDI_PTR_DEF2(name, __VA_ARGS__ ))
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
#define ISHAREDI_PTR_DEF2(name, type, oplist) \
|
||||
\
|
||||
typedef type *CAT3(ishared_,name,_t); \
|
||||
typedef type CAT3(ishared_type_,name,_t); \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(ishared_, name, _init)(type *ptr) \
|
||||
{ \
|
||||
if (ptr != NULL) \
|
||||
ptr->CAT(name, _cpt) = 1; \
|
||||
return ptr; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(ishared_, name, _init_set)(type *shared) \
|
||||
{ \
|
||||
if (shared != NULL) \
|
||||
atomic_fetch_add(&(shared->CAT(name, _cpt)), 1); \
|
||||
return shared; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(ishared_, name, _init_set2)(type ** ptr, type *shared) \
|
||||
{ \
|
||||
assert (ptr != NULL); \
|
||||
*ptr = CAT3(ishared_, name, _init_set)(shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(ishared_, name, _clear)(type *shared) \
|
||||
{ \
|
||||
if (shared != NULL) { \
|
||||
if (atomic_fetch_sub(&(shared->CAT(name, _cpt)), 1) == 1) { \
|
||||
M_GET_CLEAR oplist (*shared); \
|
||||
M_GET_DEL oplist (shared); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(ishared_, name, _release)(type *shared) \
|
||||
{ \
|
||||
CAT3(ishared_, name, _clear)(shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(ishared_, name, _set)(type ** ptr, type *shared) \
|
||||
{ \
|
||||
assert (ptr != NULL); \
|
||||
CAT3(ishared_, name, _clear)(*ptr); \
|
||||
*ptr = CAT3(ishared_, name, _init_set)(shared); \
|
||||
} \
|
||||
\
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,559 @@
|
||||
/*
|
||||
* MLIB - LIST module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_LIST_H
|
||||
#define __M_LIST_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define a list of a given type.
|
||||
USAGE: LIST_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define LIST_DEF(name, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(LISTI_DEF2(name, __VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
LISTI_DEF2(name, __VA_ARGS__ ))
|
||||
|
||||
/* Define the oplist of a list of type.
|
||||
USAGE: LIST_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define LIST_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(LISTI_OPLIST(__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
LISTI_OPLIST(__VA_ARGS__ ))
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
#define LISTI_OPLIST(name, oplist) \
|
||||
(INIT(CAT3(list_, name, _init)), \
|
||||
INIT_SET(CAT3(list_, name, _init_set)), \
|
||||
SET(CAT3(list_, name, _set)), \
|
||||
CLEAR(CAT3(list_, name, _clear)), \
|
||||
MOVE(CAT3(list_, name, _move)), \
|
||||
INIT_MOVE(CAT3(list_, name, _init_move)), \
|
||||
TYPE(CAT3(list_,name,_t)), \
|
||||
SUBTYPE(CAT3(list_type_,name,_t)), \
|
||||
IT_TYPE(CAT3(list_it_,name,_t)), \
|
||||
IT_FIRST(CAT3(list_,name,_it)), \
|
||||
IT_SET(CAT3(list_,name,_it_set)), \
|
||||
IT_END_P(CAT3(list_,name,_end_p)), \
|
||||
IT_EQUAL_P(CAT3(list_,name,_it_equal_p)), \
|
||||
IT_LAST_P(CAT3(list_,name,_last_p)), \
|
||||
IT_NEXT(CAT3(list_,name,_next)), \
|
||||
IT_REF(CAT3(list_,name,_ref)), \
|
||||
IT_CREF(CAT3(list_,name,_cref)), \
|
||||
CLEAN(CAT3(list_,name,_clean)), \
|
||||
PUSH(CAT3(list_,name,_push_back)), \
|
||||
POP(CAT3(list_,name,_pop_back)) \
|
||||
,REVERSE(CAT3(list_,name,_reverse)) \
|
||||
,OPLIST(oplist) \
|
||||
,M_IF_METHOD(GET_STR, oplist)(GET_STR(CAT3(list_, name, _get_str)),) \
|
||||
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(CAT3(list_, name, _out_str)),) \
|
||||
,M_IF_METHOD(IN_STR, oplist)(IN_STR(CAT3(list_, name, _in_str)),) \
|
||||
,M_IF_METHOD(EQUAL, oplist)(EQUAL(CAT3(list_, name, _equal_p)),) \
|
||||
)
|
||||
|
||||
#define LISTI_DEF2(name, type, oplist) \
|
||||
typedef struct CAT3(list_, name, _s) { \
|
||||
struct CAT3(list_, name, _s) *next; \
|
||||
type data; \
|
||||
} *CAT3(list_, name,_t)[1]; \
|
||||
\
|
||||
typedef struct CAT3(list_, name, _s) **CAT3(list_,name, _ptr); \
|
||||
\
|
||||
typedef const struct CAT3(list_, name, _s) *const*CAT3(list_,name, _srcptr);\
|
||||
\
|
||||
typedef type CAT3(list_type_,name, _t); \
|
||||
\
|
||||
typedef struct CAT3(list_it_, name, _s) { \
|
||||
struct CAT3(list_, name, _s) *previous; \
|
||||
CAT3(list_, name,_t) l; \
|
||||
} CAT3(list_it_, name,_t)[1]; \
|
||||
\
|
||||
typedef union { \
|
||||
type *ptr; \
|
||||
const type *cptr; \
|
||||
} CAT3(list_union_, name,_t); \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(list_, name, _const_cast)(type *ptr) \
|
||||
{ \
|
||||
CAT3(list_union_, name,_t) u; \
|
||||
u.ptr = ptr; \
|
||||
return u.cptr; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _init)(CAT3(list_, name,_t) v) \
|
||||
{ \
|
||||
assert( v != NULL); \
|
||||
*v = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _clean)(CAT3(list_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL); \
|
||||
struct CAT3(list_, name, _s) *it = *v; \
|
||||
while (it != NULL) { \
|
||||
struct CAT3(list_, name, _s) *next = it->next; \
|
||||
M_GET_CLEAR oplist(it->data); \
|
||||
M_MEMORY_FREE (it); \
|
||||
it = next; \
|
||||
} \
|
||||
*v = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _clear)(CAT3(list_, name,_t) v) \
|
||||
{ \
|
||||
CAT3(list_, name, _clean)(v); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(list_, name, _back)(const CAT3(list_, name,_t) v) \
|
||||
{ \
|
||||
assert(v != NULL && *v != NULL); \
|
||||
return CAT3(list_, name, _const_cast)(&((*v)->data)); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(list_, name, _push_raw)(CAT3(list_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL); \
|
||||
struct CAT3(list_, name, _s) *next; \
|
||||
next = M_MEMORY_ALLOC (struct CAT3(list_, name, _s)); \
|
||||
if (next == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (struct CAT3(list_, name, _s))); \
|
||||
return NULL; \
|
||||
} \
|
||||
type *ret = &next->data; \
|
||||
next->next = *v; \
|
||||
*v = next; \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _push_back)(CAT3(list_, name,_t) v, type const x) \
|
||||
{ \
|
||||
type *data = CAT3(list_, name, _push_raw)(v); \
|
||||
if (data == NULL) \
|
||||
return; \
|
||||
M_GET_INIT_SET oplist(*data, x); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(list_, name, _push_new)(CAT3(list_, name,_t) v) \
|
||||
{ \
|
||||
type *data = CAT3(list_, name, _push_raw)(v); \
|
||||
if (data == NULL) \
|
||||
return NULL; \
|
||||
M_GET_INIT oplist(*data); \
|
||||
return data; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _pop_back)(type *data, CAT3(list_, name,_t) v) \
|
||||
{ \
|
||||
assert(v != NULL && *v != NULL); \
|
||||
if (data != NULL) { \
|
||||
M_GET_SET oplist(*data, (*v)->data); \
|
||||
} \
|
||||
M_GET_CLEAR oplist((*v)->data); \
|
||||
struct CAT3(list_, name, _s) *tofree = *v; \
|
||||
*v = (*v)->next; \
|
||||
M_MEMORY_FREE (tofree); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(list_, name, _empty_p)(const CAT3(list_, name,_t) v) \
|
||||
{ \
|
||||
assert (v!= NULL); \
|
||||
return *v == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _swap)(CAT3(list_, name,_t) l, \
|
||||
CAT3(list_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL && l != NULL); \
|
||||
struct CAT3(list_, name, _s) *tmp = *l; \
|
||||
*l = *v; \
|
||||
*v = tmp; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _it)(CAT3(list_it_, name,_t) l, \
|
||||
const CAT3(list_, name,_t) v) \
|
||||
{ \
|
||||
assert (v != NULL && l[0].l != NULL); \
|
||||
l[0].l[0] = *v; \
|
||||
l[0].previous = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _it_set)(CAT3(list_it_, name,_t) it1, \
|
||||
const CAT3(list_it_, name,_t) it2) \
|
||||
{ \
|
||||
assert (it1 != NULL && it2 != NULL); \
|
||||
it1[0].l[0] = it2[0].l[0]; \
|
||||
it1[0].previous = it2[0].previous; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(list_, name, _end_p)(const CAT3(list_it_, name,_t) v) \
|
||||
{ \
|
||||
assert (v!= NULL); \
|
||||
return v[0].l[0] == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(list_, name, _last_p)(const CAT3(list_it_, name,_t) v) \
|
||||
{ \
|
||||
assert (v!= NULL); \
|
||||
return v[0].l[0] == NULL || v[0].l[0]->next == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _next)(CAT3(list_it_, name,_t) tail) \
|
||||
{ \
|
||||
assert(tail != NULL && tail[0].l[0] != NULL); \
|
||||
tail[0].previous = tail[0].l[0]; \
|
||||
tail[0].l[0] = tail[0].l[0]->next; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(list_, name, _it_equal_p)(const CAT3(list_it_, name,_t) it1, \
|
||||
const CAT3(list_it_, name,_t) it2) \
|
||||
{ \
|
||||
assert(it1 != NULL && it2 != NULL); \
|
||||
return it1[0].l[0] == it2[0].l[0]; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(list_, name, _ref)(CAT3(list_it_, name,_t) v) \
|
||||
{ \
|
||||
assert(v != NULL && v[0].l[0] != NULL); \
|
||||
return &(v[0].l[0]->data); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(list_, name, _cref)(const CAT3(list_it_, name,_t) v) \
|
||||
{ \
|
||||
assert(v != NULL && v[0].l[0] != NULL); \
|
||||
return CAT3(list_, name, _const_cast)(&(v[0].l[0]->data)); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
CAT3(list_, name, _size)(const CAT3(list_, name,_t) list) \
|
||||
{ \
|
||||
assert (list != NULL); \
|
||||
size_t size = 0; \
|
||||
/* FIXME: Store size field within the list to get faster? */ \
|
||||
struct CAT3(list_, name, _s) *it = *list; \
|
||||
while (it != NULL) { \
|
||||
size ++; \
|
||||
it = it->next; \
|
||||
} \
|
||||
return size; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(list_, name, _sublist_p)(const CAT3(list_, name,_t) list, \
|
||||
const CAT3(list_it_, name,_t) sublist) \
|
||||
{ \
|
||||
assert (list != NULL && sublist != NULL); \
|
||||
struct CAT3(list_, name, _s) *it = *list; \
|
||||
while (it != NULL) { \
|
||||
if (it == sublist[0].l[0]) return true; \
|
||||
it = it->next; \
|
||||
} \
|
||||
return (sublist[0].l[0] == NULL); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(list_, name, _get)(const CAT3(list_, name,_t) list, size_t i) \
|
||||
{ \
|
||||
assert (list != NULL); \
|
||||
struct CAT3(list_, name, _s) *it = *list; \
|
||||
/* FIXME: How to avoid the double iteration over the list? */ \
|
||||
size_t len = CAT3(list_,name,_size)(list); \
|
||||
assert (i < len); \
|
||||
size_t j = len-1; \
|
||||
while (it != NULL) { \
|
||||
if (i == j) return &it->data; \
|
||||
it = it->next; \
|
||||
j--; \
|
||||
} \
|
||||
assert(false); \
|
||||
return NULL; /* Can not be reached */ \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(list_, name, _cget)(const CAT3(list_, name,_t) l, size_t i) \
|
||||
{ \
|
||||
return CAT3(list_, name, _const_cast)(CAT3(list_, name, _get)(l,i)); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _insert)(CAT3(list_, name,_t) list, \
|
||||
CAT3(list_it_, name,_t) insertion_point, \
|
||||
type const x) \
|
||||
{ \
|
||||
assert (list != NULL && insertion_point != NULL); \
|
||||
assert(CAT3(list_, name, _sublist_p)(list, insertion_point)); \
|
||||
struct CAT3(list_, name, _s) *next; \
|
||||
next = M_MEMORY_ALLOC (struct CAT3(list_, name, _s)); \
|
||||
if (next == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (struct CAT3(list_, name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
M_GET_INIT_SET oplist(next->data, x); \
|
||||
/* FIXME: How to set an iterator to NULL? */ \
|
||||
if (insertion_point[0].l[0] == NULL) { \
|
||||
next->next = *list; \
|
||||
*list = next; \
|
||||
} else { \
|
||||
next->next = insertion_point[0].l[0]->next; \
|
||||
insertion_point[0].l[0]->next = next; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _remove)(CAT3(list_, name,_t) list, \
|
||||
CAT3(list_it_, name,_t) removing_point) \
|
||||
{ \
|
||||
assert (list != NULL && removing_point != NULL); \
|
||||
assert(removing_point[0].l[0] != NULL); \
|
||||
assert(CAT3(list_, name, _sublist_p)(list, removing_point)); \
|
||||
struct CAT3(list_, name, _s) *next = removing_point[0].l[0]->next; \
|
||||
if (removing_point->previous == NULL) { \
|
||||
*list = next; \
|
||||
} else { \
|
||||
removing_point->previous->next = next; \
|
||||
} \
|
||||
M_GET_CLEAR oplist(removing_point[0].l[0]->data); \
|
||||
M_MEMORY_FREE (removing_point[0].l[0]); \
|
||||
removing_point[0].l[0] = next; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _move_back)(CAT3(list_, name,_t) nv, \
|
||||
CAT3(list_, name,_t) ov, \
|
||||
CAT3(list_it_, name,_t) it) \
|
||||
{ \
|
||||
assert (nv != NULL && ov != NULL && it != NULL && nv != ov); \
|
||||
assert(it[0].l[0] != NULL); \
|
||||
assert(CAT3(list_, name, _sublist_p)(ov, it)); \
|
||||
/* Remove it from ov */ \
|
||||
struct CAT3(list_, name, _s) *next = it[0].l[0]->next; \
|
||||
struct CAT3(list_, name, _s) *current = it[0].l[0]; \
|
||||
if (it->previous == NULL) { \
|
||||
*ov = next; \
|
||||
} else { \
|
||||
it->previous->next = next; \
|
||||
} \
|
||||
/* Update it to next element */ \
|
||||
it[0].l[0] = next; \
|
||||
/* Move current in nv */ \
|
||||
current->next = *nv; \
|
||||
*nv = current; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _set)(CAT3(list_, name,_t) list, \
|
||||
const CAT3(list_, name,_t) org) \
|
||||
{ \
|
||||
assert (list != NULL && org != NULL); \
|
||||
struct CAT3(list_, name, _s) *next, *it_org; \
|
||||
struct CAT3(list_, name, _s) **update_list; \
|
||||
if (list == org) return; \
|
||||
/* TODO: Reuse memory of list */ \
|
||||
CAT3(list_, name, _clean)(list); \
|
||||
update_list = list; \
|
||||
it_org = *org; \
|
||||
while (it_org != NULL) { \
|
||||
next = M_MEMORY_ALLOC (struct CAT3(list_, name, _s)); \
|
||||
*update_list = next; \
|
||||
if (next == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (struct CAT3(list_, name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
update_list = &next->next; \
|
||||
M_GET_INIT_SET oplist(next->data, it_org->data); \
|
||||
it_org = it_org->next; \
|
||||
} \
|
||||
*update_list = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _init_set)(CAT3(list_, name,_t) list, \
|
||||
const CAT3(list_, name,_t) org) \
|
||||
{ \
|
||||
assert (list != NULL && org != NULL && list != org); \
|
||||
CAT3(list_, name, _init)(list); \
|
||||
CAT3(list_, name, _set)(list, org); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _init_move)(CAT3(list_, name,_t) list, \
|
||||
CAT3(list_, name,_t) org) \
|
||||
{ \
|
||||
assert (list != NULL && org != NULL && list != org); \
|
||||
*list = *org; \
|
||||
*org = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _move)(CAT3(list_, name,_t) list, \
|
||||
CAT3(list_, name,_t) org) \
|
||||
{ \
|
||||
assert (list != NULL && org != NULL && list != org); \
|
||||
CAT3(list_, name, _clear)(list); \
|
||||
CAT3(list_, name, _init_move)(list, org); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _slice)(CAT3(list_, name,_t) list1, \
|
||||
CAT3(list_, name,_t) list2) \
|
||||
{ \
|
||||
assert (list1 != NULL && list2 != NULL && list1 != list2); \
|
||||
struct CAT3(list_, name, _s) **update_list = list1; \
|
||||
struct CAT3(list_, name, _s) *it = *list1; \
|
||||
while (it != NULL) { \
|
||||
update_list = &it->next; \
|
||||
it = it->next; \
|
||||
} \
|
||||
*update_list = *list2; \
|
||||
*list2 = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(list_, name, _reverse)(CAT3(list_, name,_t) list) \
|
||||
{ \
|
||||
assert (list != NULL); \
|
||||
struct CAT3(list_, name, _s) *previous = NULL, *it = *list, *next; \
|
||||
while (it != NULL) { \
|
||||
next = it->next; \
|
||||
it->next = previous; \
|
||||
previous = it; \
|
||||
it = next; \
|
||||
} \
|
||||
*list = previous; \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
CAT3(list_, name, _get_str)(string_t str, const CAT3(list_, name,_t) list, \
|
||||
bool append) \
|
||||
{ \
|
||||
assert (str != NULL && list != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
CAT3(list_it_, name, _t) it; \
|
||||
for (CAT3(list_, name, _it)(it, list) ; \
|
||||
!CAT3(list_, name, _end_p)(it); \
|
||||
CAT3(list_, name, _next)(it)){ \
|
||||
const type *item = CAT3(list_, name, _cref)(it); \
|
||||
M_GET_GET_STR oplist (str, *item, true); \
|
||||
if (!CAT3(list_, name, _last_p)(it)) \
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
} \
|
||||
, /* no str */ ) \
|
||||
\
|
||||
M_IF_METHOD(OUT_STR, oplist)( \
|
||||
static inline void \
|
||||
CAT3(list_, name, _out_str)(FILE *file, const CAT3(list_, name,_t) list) \
|
||||
{ \
|
||||
assert (file != NULL && list != NULL); \
|
||||
fputc ('[', file); \
|
||||
CAT3(list_it_, name, _t) it; \
|
||||
for (CAT3(list_, name, _it)(it, list) ; \
|
||||
!CAT3(list_, name, _end_p)(it); \
|
||||
CAT3(list_, name, _next)(it)){ \
|
||||
const type *item = CAT3(list_, name, _cref)(it); \
|
||||
M_GET_OUT_STR oplist (file, *item); \
|
||||
if (!CAT3(list_, name, _last_p)(it)) \
|
||||
fputc (M_GET_SEPARATOR oplist, file); \
|
||||
} \
|
||||
fputc (']', file); \
|
||||
} \
|
||||
, /* no out_str */ ) \
|
||||
\
|
||||
M_IF_METHOD(IN_STR, oplist)( \
|
||||
static inline bool \
|
||||
CAT3(list_, name, _in_str)(CAT3(list_, name,_t) list, FILE *file) \
|
||||
{ \
|
||||
assert (file != NULL && list != NULL); \
|
||||
CAT3(list_, name,_clean)(list); \
|
||||
char c = fgetc(file); \
|
||||
if (c != '[') return false; \
|
||||
type item; \
|
||||
M_GET_INIT oplist (item); \
|
||||
do { \
|
||||
bool b = M_GET_IN_STR oplist (item, file); \
|
||||
if (!b) { c = 0; break; } \
|
||||
CAT3(list_, name, _push_back)(list, item); \
|
||||
c = fgetc(file); \
|
||||
} while (c == M_GET_SEPARATOR oplist && !feof(file) && !ferror(file)); \
|
||||
M_GET_CLEAR oplist (item); \
|
||||
CAT3(list_, name, _reverse)(list); \
|
||||
return c == ']'; \
|
||||
} \
|
||||
, /* no in_str */ ) \
|
||||
\
|
||||
M_IF_METHOD(EQUAL, oplist)( \
|
||||
static inline bool \
|
||||
CAT3(list_, name, _equal_p)(const CAT3(list_, name,_t) list1, \
|
||||
const CAT3(list_, name,_t) list2) \
|
||||
{ \
|
||||
assert (list1 != NULL && list2 != NULL); \
|
||||
CAT3(list_it_, name, _t) it1; \
|
||||
CAT3(list_it_, name, _t) it2; \
|
||||
if (list1 == list2) return true; \
|
||||
CAT3(list_, name, _it)(it1, list1); \
|
||||
CAT3(list_, name, _it)(it2, list2); \
|
||||
while (!CAT3(list_, name, _end_p)(it1) \
|
||||
&&!CAT3(list_, name, _end_p)(it2)) { \
|
||||
const type *item1 = CAT3(list_, name, _cref)(it1); \
|
||||
const type *item2 = CAT3(list_, name, _cref)(it2); \
|
||||
bool b = M_GET_EQUAL oplist (*item1, *item2); \
|
||||
if (!b) return false; \
|
||||
CAT3(list_, name, _next)(it1); \
|
||||
CAT3(list_, name, _next)(it2); \
|
||||
} \
|
||||
return CAT3(list_, name, _end_p)(it1) \
|
||||
&& CAT3(list_, name, _end_p)(it2); \
|
||||
} \
|
||||
, /* no equal */ ) \
|
||||
\
|
||||
|
||||
// TODO: Conditional HASH if HASH is present
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* MLIB - Slin Mutex & Thread wrapper
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_MUTEX_H
|
||||
#define __M_MUTEX_H
|
||||
|
||||
#include <assert.h>
|
||||
#include "m-core.h"
|
||||
|
||||
//TODO: static inline versions should be cleaner
|
||||
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \
|
||||
&& !defined(__STDC_NO_THREADS__)
|
||||
|
||||
/****************************** C11 version ********************************/
|
||||
|
||||
#include <threads.h>
|
||||
|
||||
#define M_MUTEX_T mtx_t
|
||||
#define M_MUTEX_INIT(_mutex) do { \
|
||||
int rc = mtx_init(&(_mutex), 0); \
|
||||
M_ASSERT_INIT (rc == 0); \
|
||||
} while (0)
|
||||
#define M_MUTEX_CLEAR(_mutex) mtx_destroy(&(_mutex))
|
||||
#define M_MUTEX_LOCK(_mutex) mtx_lock(&(_mutex))
|
||||
#define M_MUTEX_UNLOCK(_mutex) mtx_unlock(&(_mutex))
|
||||
|
||||
#define M_COND_T cnd_t
|
||||
#define M_COND_INIT(_cond) do { \
|
||||
int rc = cnd_init(&(_cond)); \
|
||||
M_ASSERT_INIT (rc == 0); \
|
||||
} while (0)
|
||||
#define M_COND_CLEAR(_cond) cnd_destroy(&(_cond))
|
||||
#define M_COND_SIGNAL(_cond) cnd_signal(&(_cond))
|
||||
#define M_COND_WAIT(_cond, _mutex) cnd_wait(&(_cond),&(_mutex))
|
||||
|
||||
#define M_THREAD_T thrd_t
|
||||
#define M_THREAD_CREATE(h, func, arg) do { \
|
||||
int rc = thrd_create(&(h), ((int)(*)(void*))func, arg); \
|
||||
M_ASSERT_INIT (rc == thrd_success); \
|
||||
} while (0)
|
||||
#define M_THREAD_JOIN(h) do { \
|
||||
int rc = thrd_join((h), NULL); \
|
||||
assert (rc == thrd_success); \
|
||||
} while (0)
|
||||
#define M_THREAD_EXIT(arg) thrd_exit(arg)
|
||||
|
||||
#elif defined(WIN32) || defined(_WIN32)
|
||||
|
||||
/****************************** WIN32 version ******************************/
|
||||
|
||||
#include <window.h>
|
||||
|
||||
#define M_MUTEX_T HANDLE
|
||||
#define M_MUTEX_INIT(_mutex) do { \
|
||||
(_mutex) = CreateMutex(NULL, FALSE, NULL); \
|
||||
M_ASSERT_INIT((_mutex) != NULL); \
|
||||
} while (0)
|
||||
#define M_MUTEX_CLEAR(_mutex) CloseHandle(_mutex)
|
||||
#define M_MUTEX_LOCK(_mutex) do { \
|
||||
DWORD dwWaitResult = WaitForSingleObject((_mutex), INFINITE); \
|
||||
assert (dwWaitResult == WAIT_OBJECT_0); \
|
||||
} while(0)
|
||||
#define M_MUTEX_TRYLOCK(m) (WaitForSingleObject((m), 0) == WAIT_OBJECT_0)
|
||||
#define M_MUTEX_UNLOCK(_mutex) ReleaseMutex(_mutex)
|
||||
|
||||
#define M_COND_T HANDLE
|
||||
#define M_COND_INIT(_cond) do { \
|
||||
(_cond) = = CreateEvent (NULL, FALSE, FALSE, NULL); \
|
||||
M_ASSERT_INIT ((_cond) != NULL); \
|
||||
} while (0)
|
||||
#define M_COND_CLEAR(_cond) CloseHandle(_cond)
|
||||
#define M_COND_SIGNAL(_cond) PulseEvent(_cond)
|
||||
#define M_COND_WAIT(_cond, _mutex) do { \
|
||||
DWORD dwWaitResult = SignalObjectAndWait((_mutex),(_cond),INFINITE,FALSE); \
|
||||
assert (dwWaitResult == WAIT_OBJECT_0); \
|
||||
dwWaitResult = WaitForSingleObject((_mutex), INFINITE); \
|
||||
assert (dwWaitResult == WAIT_OBJECT_0); \
|
||||
} while(0)
|
||||
|
||||
#define M_THREAD_T HANDLE
|
||||
#define M_THREAD_CREATE(h, func, arg) do { \
|
||||
(h) = CreateThread(NULL, 0, (unsigned int (*)(void*)) func, arg, \
|
||||
0, NULL); \
|
||||
M_ASSERT_INIT ((h) != NULL); \
|
||||
} while (0)
|
||||
#define M_THREAD_JOIN(h) do { \
|
||||
DWORD dwWaitResult = WaitForSingleObject((h), INFINITE); \
|
||||
assert (dwWaitResult == WAIT_OBJECT_0); \
|
||||
} while (0)
|
||||
#define M_THREAD_EXIT(arg) ExitThread(arg)
|
||||
|
||||
#else
|
||||
|
||||
/**************************** PTHREAD version ******************************/
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#define M_MUTEX_T pthread_mutex_t
|
||||
#define M_MUTEX_INIT(_mutex) do { \
|
||||
int _rc = pthread_mutex_init(&(_mutex), NULL); \
|
||||
M_ASSERT_INIT (_rc == 0); \
|
||||
} while (0)
|
||||
#define M_MUTEX_CLEAR(_mutex) pthread_mutex_destroy(&(_mutex))
|
||||
#define M_MUTEX_LOCK(_mutex) pthread_mutex_lock(&(_mutex))
|
||||
#define M_MUTEX_UNLOCK(_mutex) pthread_mutex_unlock(&(_mutex))
|
||||
|
||||
#define M_COND_T pthread_cond_t
|
||||
#define M_COND_INIT(_cond) do { \
|
||||
int _rc = pthread_cond_init(&(_cond), NULL); \
|
||||
M_ASSERT_INIT (_rc == 0); \
|
||||
} while (0)
|
||||
#define M_COND_CLEAR(_cond) pthread_cond_destroy(&(_cond))
|
||||
#define M_COND_SIGNAL(_cond) pthread_cond_signal(&(_cond))
|
||||
#define M_COND_WAIT(_cond, _mutex) pthread_cond_wait(&(_cond),&(_mutex))
|
||||
|
||||
#define M_THREAD_T pthread_t
|
||||
#define M_THREAD_CREATE(h, func, arg) do { \
|
||||
int _rc = pthread_create(&(h), NULL, (void*(*)(void*))func, arg); \
|
||||
M_ASSERT_INIT (_rc == 0); \
|
||||
} while (0)
|
||||
#define M_THREAD_JOIN(h) do { \
|
||||
int _rc = pthread_join((h), NULL); \
|
||||
assert (_rc == 0); \
|
||||
} while (0)
|
||||
#define M_THREAD_EXIT(arg) pthread_exit((void*)arg)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+753
@@ -0,0 +1,753 @@
|
||||
/*
|
||||
* MLIB - RED BLACK TREE module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_RBTREE_H
|
||||
#define __M_RBTREE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define a binary tree of a given type.
|
||||
USAGE: RBTREE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define RBTREE_DEF(name, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(RBTREEI_DEF2(name, __VA_ARGS__, M_DEFAULT_OPLIST, \
|
||||
CAT3(rbtree_, name, _t), struct CAT3(rbtree_node_, name, _s)), \
|
||||
RBTREEI_DEF2(name, __VA_ARGS__ , \
|
||||
CAT3(rbtree_, name, _t), struct CAT3(rbtree_node_, name, _s)))
|
||||
|
||||
/* Define the oplist of a rbtree of type.
|
||||
USAGE: RBTREE_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define RBTREE_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(RBTREEI_OPLIST(__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
RBTREEI_OPLIST(__VA_ARGS__ ))
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
#define RBTREEI_OPLIST(name, oplist) \
|
||||
(INIT(CAT3(rbtree_, name, _init)), \
|
||||
INIT_SET(CAT3(rbtree_, name, _init_set)), \
|
||||
SET(CAT3(rbtree_, name, _set)), \
|
||||
CLEAR(CAT3(rbtree_, name, _clear)), \
|
||||
INIT_MOVE(CAT3(rbtree_, name, _init_move)), \
|
||||
MOVE(CAT3(rbtree_, name, _move)), \
|
||||
TYPE(CAT3(rbtree_,name,_t)), \
|
||||
SUBTYPE(CAT3(rbtree_type_,name,_t)), \
|
||||
IT_TYPE(CAT3(rbtree_it_,name,_t)), \
|
||||
IT_FIRST(CAT3(rbtree_,name,_it)), \
|
||||
IT_SET(CAT3(rbtree_,name,_it_set)), \
|
||||
IT_END_P(CAT3(rbtree_,name,_end_p)), \
|
||||
IT_LAST_P(CAT3(rbtree_,name,_last_p)), \
|
||||
IT_EQUAL_P(CAT3(rbtree_,name,_it_equal_p)), \
|
||||
IT_NEXT(CAT3(rbtree_,name,_next)), \
|
||||
IT_REF(CAT3(rbtree_,name,_ref)), \
|
||||
IT_CREF(CAT3(rbtree_,name,_cref)), \
|
||||
CLEAN(CAT3(rbtree_,name,_clean)), \
|
||||
PUSH(CAT3(rbtree_,name,_push)), \
|
||||
POP(CAT3(rbtree_,name,_pop)) \
|
||||
GET_MIN(CAT3(rbtree_,name,_min)), \
|
||||
GET_MAX(CAT3(rbtree_,name,_max)) \
|
||||
)
|
||||
|
||||
/* Max depth of the binary tree
|
||||
It is twice the depth of a perfectly even tree with maximum elements.
|
||||
Max number of elements is max of size_t.
|
||||
A perfectly even tree is log2(max(size_t))<CHAR_BIT*sizeof(size_t)
|
||||
*/
|
||||
#define RBTREEI_MAX_STACK (2*CHAR_BIT*sizeof (size_t))
|
||||
|
||||
#define RBTREEI_SET_RED(x) ((x)->color = RBTREE_RED)
|
||||
#define RBTREEI_SET_BLACK(x) ((x)->color = RBTREE_BLACK)
|
||||
#define RBTREEI_IS_RED(x) ((x)->color == RBTREE_RED)
|
||||
#define RBTREEI_IS_BLACK(x) ((x)->color == RBTREE_BLACK)
|
||||
#define RBTREEI_COPY_COLOR(x,y) ((x)->color = (y)->color)
|
||||
|
||||
typedef enum {
|
||||
RBTREE_BLACK = 0, RBTREE_RED
|
||||
} rbtreei_color_e;
|
||||
|
||||
// General contact of a tree
|
||||
#define RBTREEI_CONTRACT(tree) \
|
||||
assert ((tree) != NULL); \
|
||||
assert ((tree)->node == NULL || RBTREEI_IS_BLACK((tree)->node)); \
|
||||
assert ((tree)->size != 0 || (tree)->node == NULL); \
|
||||
|
||||
// Contract of a node (doesn't check for equal depth in black)
|
||||
#define RBTREEI_CONTRACT_NODE(node) \
|
||||
assert((node) != NULL); \
|
||||
assert((node)->color == RBTREE_BLACK || (node)->color == RBTREE_RED); \
|
||||
assert((node)->color != RBTREE_RED \
|
||||
|| (((node)->child[0] == NULL || (node)->child[0]->color == RBTREE_BLACK) \
|
||||
&& ((node)->child[1] == NULL || (node)->child[1]->color == RBTREE_BLACK)))
|
||||
|
||||
#define RBTREEI_DEF2(name, type, oplist, tree_t, node_t) \
|
||||
\
|
||||
node_t { \
|
||||
node_t *child[2]; \
|
||||
type data; \
|
||||
rbtreei_color_e color; \
|
||||
}; \
|
||||
\
|
||||
typedef struct CAT3(rbtree_, name, _s) { \
|
||||
size_t size; \
|
||||
node_t *node; \
|
||||
} tree_t[1]; \
|
||||
\
|
||||
typedef struct { \
|
||||
node_t *stack[RBTREEI_MAX_STACK]; \
|
||||
char which[RBTREEI_MAX_STACK]; \
|
||||
unsigned int cpt; \
|
||||
} CAT3(rbtree_it_, name, _t)[1]; \
|
||||
\
|
||||
typedef type CAT3(rbtree_type_, name, _t); \
|
||||
\
|
||||
typedef union { \
|
||||
type *ptr; \
|
||||
const type *cptr; \
|
||||
} CAT3(rbtree_union_, name,_t); \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(rbtree_, name, _const_cast)(type *ptr) \
|
||||
{ \
|
||||
CAT3(rbtree_union_, name,_t) u; \
|
||||
u.ptr = ptr; \
|
||||
return u.cptr; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(rbtree_, name, _init)(tree_t tree) \
|
||||
{ \
|
||||
assert (tree != NULL); \
|
||||
tree->size = 0; \
|
||||
tree->node = NULL; \
|
||||
RBTREEI_CONTRACT(tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(rbtree_, name, _clear)(tree_t tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT(tree); \
|
||||
node_t *stack[RBTREEI_MAX_STACK]; \
|
||||
unsigned int cpt = 0; \
|
||||
if (tree->node == NULL) return; \
|
||||
stack[cpt++] = tree->node; \
|
||||
while (cpt > 0) { \
|
||||
node_t *n = stack[cpt-1]; \
|
||||
while (true) { \
|
||||
RBTREEI_CONTRACT_NODE(n); \
|
||||
if (n->child[0] != NULL) { \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
stack[cpt++] = n->child[0]; \
|
||||
n = n->child[0]; \
|
||||
stack[cpt-2]->child[0] = NULL; \
|
||||
} else if (n->child[1] != NULL) { \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
stack[cpt++] = n->child[1]; \
|
||||
n = n->child[1]; \
|
||||
stack[cpt-2]->child[1] = NULL; \
|
||||
} else \
|
||||
break; \
|
||||
} \
|
||||
assert (n == stack[cpt - 1]); \
|
||||
M_GET_CLEAR oplist (n->data); \
|
||||
M_MEMORY_FREE (n); \
|
||||
assert((stack[cpt-1] = NULL) == NULL); \
|
||||
cpt--; \
|
||||
} \
|
||||
tree->node = NULL; \
|
||||
tree->size = 0; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(rbtree_, name, _push)(tree_t tree, type const data) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT(tree); \
|
||||
node_t *tab[RBTREEI_MAX_STACK]; \
|
||||
char which[RBTREEI_MAX_STACK]; \
|
||||
unsigned int cpt = 0; \
|
||||
node_t *n = tree->node; \
|
||||
/* If nothing, create new node */ \
|
||||
if (n == NULL) { \
|
||||
n = M_MEMORY_ALLOC(node_t); \
|
||||
M_GET_INIT_SET oplist (n->data, data); \
|
||||
n->child[0] = n->child[1] = NULL; \
|
||||
RBTREEI_SET_BLACK (n); \
|
||||
tree->node = n; \
|
||||
assert(tree->size == 0); \
|
||||
tree->size = 1; \
|
||||
RBTREEI_CONTRACT(tree); \
|
||||
return; \
|
||||
} \
|
||||
/* Search for insertion point */ \
|
||||
tab[cpt] = n; \
|
||||
while (n != NULL) { \
|
||||
RBTREEI_CONTRACT_NODE(n); \
|
||||
int cmp = M_GET_CMP oplist (n->data, data); \
|
||||
if (cmp == 0) { \
|
||||
break; \
|
||||
} else if (cmp > 0) { \
|
||||
which[cpt++] = 0; \
|
||||
n = n->child[0]; \
|
||||
} else { \
|
||||
which[cpt++] = 1; \
|
||||
n = n->child[1]; \
|
||||
} \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
tab[cpt] = n; \
|
||||
} \
|
||||
/* If found, update the data (default is set) */ \
|
||||
if (n != NULL) { \
|
||||
M_GET_UPDATE oplist (n->data, data); \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
return; \
|
||||
} \
|
||||
/* Create new */ \
|
||||
n = M_MEMORY_ALLOC(node_t); \
|
||||
M_GET_INIT_SET oplist (n->data, data); \
|
||||
n->child[0] = n->child[1] = NULL; \
|
||||
RBTREEI_SET_RED (n); \
|
||||
assert (tab[cpt] == NULL); \
|
||||
tab[cpt] = n; \
|
||||
tree->size ++; \
|
||||
/* Add it in the tree */ \
|
||||
assert(tab[cpt-1]->child[0+which[cpt-1]] == NULL); \
|
||||
tab[cpt-1]->child[0+which[cpt-1]] = n; \
|
||||
/* Fix the tree */ \
|
||||
while (cpt >= 2 \
|
||||
&& RBTREEI_IS_RED(tab[cpt-1]) \
|
||||
&& tab[cpt-2]->child[1-which[cpt-2]] != NULL \
|
||||
&& RBTREEI_IS_RED(tab[cpt-2]->child[1-which[cpt-2]])) { \
|
||||
RBTREEI_SET_BLACK(tab[cpt-1]); \
|
||||
RBTREEI_SET_BLACK(tab[cpt-2]->child[1-which[cpt-2]]); \
|
||||
RBTREEI_SET_RED(tab[cpt-2]); \
|
||||
cpt-=2; \
|
||||
} \
|
||||
/* root is always black */ \
|
||||
RBTREEI_SET_BLACK(tab[0]); \
|
||||
if (cpt <= 1 || RBTREEI_IS_BLACK(tab[cpt-1])) { \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
return; \
|
||||
} \
|
||||
/* Read the grand-father, the father and the element */ \
|
||||
node_t *pp = tab[cpt-2]; \
|
||||
node_t *p = tab[cpt-1]; \
|
||||
node_t *x = tab[cpt]; \
|
||||
/* We need to do some rotations */ \
|
||||
if (which[cpt-2] == 0) { \
|
||||
/* The father is the left child of the grand-father */ \
|
||||
if (which[cpt-1] == 0) { \
|
||||
/* The child is the left child of its father */ \
|
||||
/* Right rotation: cpt is the new grand-father. \
|
||||
x is its left child, the grand-father is the right one */ \
|
||||
pp->child[0] = p->child[1]; \
|
||||
p->child[0] = x; \
|
||||
p->child[1] = pp; \
|
||||
RBTREEI_SET_BLACK(p); \
|
||||
RBTREEI_SET_RED(pp); \
|
||||
} else { \
|
||||
/* The child is the right child of its father */ \
|
||||
/* Left rotation */ \
|
||||
pp->child[0] = x->child[1]; \
|
||||
p->child[1] = x->child[0]; \
|
||||
x->child[0] = p; \
|
||||
x->child[1] = pp; \
|
||||
RBTREEI_SET_BLACK(x); \
|
||||
RBTREEI_SET_RED(p); \
|
||||
RBTREEI_SET_RED(pp); \
|
||||
p = x; \
|
||||
} \
|
||||
} else { \
|
||||
/* The father is the right child of the grand-father */ \
|
||||
if (which[cpt-1] == 0) { \
|
||||
/* The child is the left child of its father */ \
|
||||
pp->child[1] = x->child[0]; \
|
||||
p->child[0] = x->child[1]; \
|
||||
x->child[1] = p; \
|
||||
x->child[0] = pp; \
|
||||
RBTREEI_SET_BLACK(x); \
|
||||
RBTREEI_SET_RED(p); \
|
||||
RBTREEI_SET_RED(pp); \
|
||||
p = x; \
|
||||
} else { \
|
||||
/* The child is the right child of its father */ \
|
||||
pp->child[1] = p->child[0]; \
|
||||
p->child[1] = x; \
|
||||
p->child[0] = pp; \
|
||||
RBTREEI_SET_BLACK(p); \
|
||||
RBTREEI_SET_RED(pp); \
|
||||
} \
|
||||
} \
|
||||
/* Insert the new grand father */ \
|
||||
if (cpt == 2) { \
|
||||
tree->node = p; \
|
||||
} else { \
|
||||
tab[cpt-3]->child[(int) which[cpt-3]] = p; \
|
||||
} \
|
||||
/* Done */ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
CAT3(rbtree_, name, _size)(const tree_t tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
return tree->size; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(rbtreei_, name, _it)(CAT3(rbtree_it_, name,_t) it, \
|
||||
const CAT3(rbtree_, name,_t) tree, int child) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
assert (it != NULL); \
|
||||
unsigned int cpt = 0; \
|
||||
if (tree->node != NULL) { \
|
||||
it->which[cpt] = child; \
|
||||
node_t *n = it->stack[cpt++] = tree->node; \
|
||||
while (n->child[child] != NULL) { \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
n = n->child[child]; \
|
||||
it->which[cpt] = child; \
|
||||
it->stack[cpt++] = n; \
|
||||
} \
|
||||
assert (n == it->stack[cpt - 1]); \
|
||||
} \
|
||||
it->cpt = cpt; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(rbtree_, name, _it)(CAT3(rbtree_it_, name,_t) it, \
|
||||
const CAT3(rbtree_, name,_t) tree) \
|
||||
{ \
|
||||
CAT3(rbtreei_, name, _it)(it, tree, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(rbtree_, name, _it_last)(CAT3(rbtree_it_, name,_t) it, \
|
||||
const CAT3(rbtree_, name,_t) tree) \
|
||||
{ \
|
||||
CAT3(rbtreei_, name, _it)(it, tree, 1); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(rbtree_, name, _end_p)(const CAT3(rbtree_it_, name,_t) it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
return it->cpt == 0; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(rbtreei_, name, _next)(CAT3(rbtree_it_, name,_t) it, int child) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
assert (child == 0 || child == 1); \
|
||||
unsigned int cpt = it->cpt - 1; \
|
||||
node_t *n = it->stack[cpt]; \
|
||||
const int right = 1 ^ child; \
|
||||
if (n->child[right] != NULL && it->which[cpt] == child) { \
|
||||
/* Going right */ \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
n = n->child[right]; \
|
||||
it->which[cpt++] = right; \
|
||||
it->stack[cpt] = n; \
|
||||
it->which[cpt++] = child; \
|
||||
/* Going left */ \
|
||||
while (n->child[child] != NULL) { \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
n = n->child[child]; \
|
||||
it->which[cpt] = child; \
|
||||
it->stack[cpt++] = n; \
|
||||
} \
|
||||
assert (n == it->stack[cpt - 1]); \
|
||||
} else { \
|
||||
/* Going up */ \
|
||||
while (cpt > 0 && it->which[cpt-1] == right) cpt--; \
|
||||
} \
|
||||
it->cpt = cpt; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(rbtree_, name, _next)(CAT3(rbtree_it_, name,_t) it) \
|
||||
{ \
|
||||
CAT3(rbtreei_, name, _next)(it, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(rbtree_, name, _previous)(CAT3(rbtree_it_, name,_t) it) \
|
||||
{ \
|
||||
CAT3(rbtreei_, name, _next)(it, 1); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(rbtree_, name, _ref)(const CAT3(rbtree_it_, name,_t) it) \
|
||||
{ \
|
||||
assert(it != NULL && it->cpt > 0); \
|
||||
return &(it->stack[it->cpt-1]->data); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(rbtree_, name, _cref)(const CAT3(rbtree_it_, name,_t) it) \
|
||||
{ \
|
||||
return CAT3(rbtree_, name, _const_cast)(CAT3(rbtree_, name, _ref)(it)); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(rbtree_, name, _it_equal_p)(const CAT3(rbtree_it_, name,_t) it1, \
|
||||
const CAT3(rbtree_it_, name,_t) it2) \
|
||||
{ \
|
||||
return it1->cpt == it2->cpt \
|
||||
&& it1->stack[it1->cpt-1] == it2->stack[it2->cpt-1]; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(rbtree_, name, _min)(const CAT3(rbtree_, name,_t) tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
node_t *n = tree->node; \
|
||||
if (n == NULL) return NULL; \
|
||||
while (n->child[0] != NULL) { \
|
||||
RBTREEI_CONTRACT_NODE (n); \
|
||||
n = n->child[0]; \
|
||||
} \
|
||||
return &n->data; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(rbtree_, name, _max)(const CAT3(rbtree_, name,_t) tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
node_t *n = tree->node; \
|
||||
if (n == NULL) return NULL; \
|
||||
while (n->child[1] != NULL) { \
|
||||
RBTREEI_CONTRACT_NODE (n); \
|
||||
n = n->child[1]; \
|
||||
} \
|
||||
return &n->data; \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(rbtree_, name, _cmin)(const CAT3(rbtree_, name,_t) tree) \
|
||||
{ \
|
||||
return CAT3(rbtree_, name, _const_cast)(CAT3(rbtree_, name, _min)(tree)); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(rbtree_, name, _cmax)(const CAT3(rbtree_, name,_t) tree) \
|
||||
{ \
|
||||
return CAT3(rbtree_, name, _const_cast)(CAT3(rbtree_, name, _max)(tree)); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(rbtree_, name, _get)(const tree_t tree, type const data) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
node_t *n = tree->node; \
|
||||
while (n != NULL) { \
|
||||
RBTREEI_CONTRACT_NODE (n); \
|
||||
int cmp = M_GET_CMP oplist (n->data, data); \
|
||||
if (cmp == 0) { \
|
||||
return &n->data; \
|
||||
} else if (cmp > 0) { \
|
||||
n = n->child[0]; \
|
||||
} else { \
|
||||
n = n->child[1]; \
|
||||
} \
|
||||
} \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(rbtree_, name, _cget)(const CAT3(rbtree_, name,_t) tree, \
|
||||
type const data) \
|
||||
{ \
|
||||
return CAT3(rbtree_, name, _const_cast)(CAT3(rbtree_, name, _get)(tree, data)); \
|
||||
} \
|
||||
\
|
||||
static inline node_t * \
|
||||
CAT3(rbtreei_,name,_copyn)(const node_t *o) \
|
||||
{ \
|
||||
if (o == NULL) return NULL; \
|
||||
node_t *n = M_MEMORY_ALLOC(node_t); \
|
||||
M_GET_INIT_SET oplist (n->data, o->data); \
|
||||
n->child[0] = CAT3(rbtreei_,name,_copyn)(o->child[0]); \
|
||||
n->child[1] = CAT3(rbtreei_,name,_copyn)(o->child[1]); \
|
||||
RBTREEI_COPY_COLOR (n, o); \
|
||||
return n; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(rbtree_, name, _init_set)(tree_t tree, const tree_t ref) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (ref); \
|
||||
assert (tree != NULL && tree != ref); \
|
||||
tree->size = ref->size; \
|
||||
tree->node = CAT3(rbtreei_,name,_copyn)(ref->node); \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(rbtree_, name, _set)(tree_t tree, const tree_t ref) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
RBTREEI_CONTRACT (ref); \
|
||||
if (tree == ref) return; \
|
||||
CAT3(rbtree_,name,_clear)(tree); \
|
||||
CAT3(rbtree_,name,_init_set)(tree, ref); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(rbtree_, name, _init_move)(tree_t tree, tree_t ref) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (ref); \
|
||||
assert (tree != NULL && tree != ref); \
|
||||
tree->size = ref->size; \
|
||||
tree->node = ref->node; \
|
||||
ref->node = NULL; \
|
||||
ref->size = 0; \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(rbtree_, name, _move)(tree_t tree, tree_t ref) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
RBTREEI_CONTRACT (ref); \
|
||||
assert (tree != ref); \
|
||||
CAT3(rbtree_,name,_clear)(tree); \
|
||||
CAT3(rbtree_,name,_init_move)(tree, ref); \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(rbtree_, name, _empty_p)(const tree_t tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
return tree->size == 0; \
|
||||
} \
|
||||
\
|
||||
static inline rbtreei_color_e \
|
||||
CAT3(rbtreei_, name, _get_color)(const node_t *n) \
|
||||
{ \
|
||||
return (n == NULL) ? RBTREE_BLACK : n->color; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(rbtreei_, name, _set_color)(node_t *n, rbtreei_color_e c) \
|
||||
{ \
|
||||
if (n != NULL) n->color = c; \
|
||||
} \
|
||||
\
|
||||
static inline node_t * \
|
||||
CAT3(rbtreei_, name, _rotate)(node_t *pp, node_t *ppp, const bool right) \
|
||||
{ \
|
||||
assert (pp != NULL && ppp != NULL); \
|
||||
bool left = !right; \
|
||||
node_t *p = pp->child[right]; \
|
||||
assert (p != NULL); \
|
||||
pp->child[right] = p->child[left]; \
|
||||
p->child[left] = pp; \
|
||||
/* Fix grandparent with new parent */ \
|
||||
assert(ppp->child[0] == pp || ppp->child[1] == pp); \
|
||||
ppp->child[(ppp->child[0] != pp)] = p; \
|
||||
return p; \
|
||||
} \
|
||||
\
|
||||
static size_t \
|
||||
CAT3(rbtreei_,name,_depth)(const node_t *n) \
|
||||
{ \
|
||||
if (n == NULL) return 1; \
|
||||
return (n->color == RBTREE_BLACK) \
|
||||
+ CAT3(rbtreei_,name,_depth)(n->child[0]); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(rbtree_, name, _pop)(type *data_ptr, tree_t tree, type const key) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
node_t *tab[RBTREEI_MAX_STACK]; \
|
||||
unsigned char which[RBTREEI_MAX_STACK]; \
|
||||
unsigned int cpt = 0; \
|
||||
node_t *n = tree->node; \
|
||||
which[0] = 0; \
|
||||
tab[cpt++] = (node_t*) &tree->node; /* hug! */ \
|
||||
/* Search for the deletion point */ \
|
||||
tab[cpt] = n; \
|
||||
while (n != NULL) { \
|
||||
RBTREEI_CONTRACT_NODE (n); \
|
||||
assert(CAT3(rbtreei_,name,_depth)(n->child[0]) \
|
||||
== CAT3(rbtreei_,name,_depth)(n->child[1])); \
|
||||
int cmp = M_GET_CMP oplist (n->data, key); \
|
||||
if (cmp == 0) { \
|
||||
break; \
|
||||
} \
|
||||
int i = (cmp < 0); \
|
||||
which[cpt++] = i; \
|
||||
n = n->child[i]; \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
tab[cpt] = n; \
|
||||
} \
|
||||
assert (tab[cpt] == n); \
|
||||
/* If not found, fail */ \
|
||||
if (n == NULL) { \
|
||||
return false; \
|
||||
} \
|
||||
unsigned int cpt_n = cpt; \
|
||||
node_t *v = n; /* the replacement node */ \
|
||||
node_t *u; /* the deleted node */ \
|
||||
rbtreei_color_e v_color = v->color; \
|
||||
/* Classical removal of a node from a binary tree */ \
|
||||
if (v->child[0] != NULL && v->child[1] != NULL) { \
|
||||
/* node has 2 child. */ \
|
||||
/* Get the element right next to the deleted one */ \
|
||||
v = v->child[1]; \
|
||||
which[cpt++] = 1; \
|
||||
tab[cpt] = v; \
|
||||
while (v != NULL) { \
|
||||
/* Always left node */ \
|
||||
RBTREEI_CONTRACT_NODE (v); \
|
||||
assert(CAT3(rbtreei_,name,_depth)(v->child[0]) \
|
||||
== CAT3(rbtreei_,name,_depth)(v->child[1])); \
|
||||
which[cpt++] = 0; \
|
||||
v = v->child[0]; \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
tab[cpt] = v; \
|
||||
} \
|
||||
/* Pop the last element to get the last non-null element */ \
|
||||
v = tab[--cpt]; \
|
||||
assert (v != NULL); \
|
||||
u = v->child[1]; \
|
||||
/* Replace 'v' by 'u' in the tree */ \
|
||||
assert(tab[cpt-1]->child[which[cpt-1]] == v); \
|
||||
tab[cpt-1]->child[which[cpt-1]] = u; \
|
||||
/* Replace 'n' by 'v' in the tree */ \
|
||||
assert(tab[cpt_n-1] != NULL); \
|
||||
assert(tab[cpt_n-1]->child[which[cpt_n-1]] == n); \
|
||||
tab[cpt_n-1]->child[which[cpt_n-1]] = v; \
|
||||
v->child[0] = n->child[0]; \
|
||||
v->child[1] = n->child[1]; \
|
||||
v_color = v->color; \
|
||||
v->color = n->color; \
|
||||
tab[cpt_n] = v; \
|
||||
/* For the algorithm, 'u' is now the deleted node */ \
|
||||
} else { \
|
||||
/* 1 or no child to the node. Replace the element */ \
|
||||
v = n; \
|
||||
u = v->child[(n->child[0] == NULL)]; \
|
||||
assert (cpt_n >= 1 && tab[cpt_n-1]->child[which[cpt_n-1]] == n); \
|
||||
assert (n->child[(n->child[0] != NULL)] == NULL); \
|
||||
tab[cpt_n-1]->child[which[cpt_n-1]] = u; \
|
||||
/* in all cases, this node shall be set to black */ \
|
||||
} \
|
||||
\
|
||||
/* Rebalance from child to root */ \
|
||||
if (v_color == RBTREE_BLACK \
|
||||
&& CAT3(rbtreei_,name,_get_color)(u) == RBTREE_BLACK) { \
|
||||
/* tab[0] is NULL, tab[1] is root, u is double black */ \
|
||||
node_t *p = u, *s; \
|
||||
while (cpt >= 2) { \
|
||||
p = tab[--cpt]; \
|
||||
bool nbChild = which[cpt]; \
|
||||
assert (p != NULL && u == p->child[nbChild]); \
|
||||
s = p->child[!nbChild]; \
|
||||
/* if sibling is red, perform a rotation to move sibling up */ \
|
||||
if (CAT3(rbtreei_,name,_get_color)(s) == RBTREE_RED) { \
|
||||
p = CAT3(rbtreei_,name,_rotate) (p, tab[cpt-1], !nbChild); \
|
||||
p->color = RBTREE_BLACK; /* was sibling */ \
|
||||
tab[cpt] = p; \
|
||||
which[cpt++] = nbChild; \
|
||||
p = p->child[nbChild]; /* was parent */ \
|
||||
assert (p != NULL); \
|
||||
p->color = RBTREE_RED; \
|
||||
s = p->child[!nbChild]; \
|
||||
assert (CAT3(rbtreei_,name,_get_color)(s) == RBTREE_BLACK); \
|
||||
} \
|
||||
assert (p != NULL && u == p->child[nbChild]); \
|
||||
/* if both childreen of s are black */ \
|
||||
/* perform recoloring and recur on parent if black */ \
|
||||
if (s != NULL \
|
||||
&& CAT3(rbtreei_,name,_get_color)(s->child[0])== RBTREE_BLACK \
|
||||
&& CAT3(rbtreei_,name,_get_color)(s->child[1])== RBTREE_BLACK) { \
|
||||
assert(CAT3(rbtreei_,name,_depth)(s->child[0]) == CAT3(rbtreei_,name,_depth)(s->child[1])); \
|
||||
s->color = RBTREE_RED; \
|
||||
if (p->color == RBTREE_RED) { \
|
||||
p->color = RBTREE_BLACK; \
|
||||
RBTREEI_CONTRACT_NODE(p); \
|
||||
assert(CAT3(rbtreei_,name,_depth)(p->child[0]) == CAT3(rbtreei_,name,_depth)(p->child[1])); \
|
||||
break; \
|
||||
} \
|
||||
u = p; \
|
||||
} else { \
|
||||
assert (s != NULL); \
|
||||
/* at least one child of 's' is red */ \
|
||||
/* perform rotation(s) */ \
|
||||
bool childIsRight = CAT3(rbtreei_,name,_get_color)(s->child[1])== RBTREE_RED; \
|
||||
rbtreei_color_e p_color = p->color; \
|
||||
if (childIsRight != nbChild) { \
|
||||
/* left-left or right-right case */ \
|
||||
p = CAT3(rbtreei_,name,_rotate) (p, tab[cpt-1], childIsRight); \
|
||||
} else { \
|
||||
s = CAT3(rbtreei_,name,_rotate) (s, p, childIsRight); \
|
||||
p = CAT3(rbtreei_,name,_rotate) (p, tab[cpt-1], !nbChild); \
|
||||
} \
|
||||
p->color = p_color; \
|
||||
assert(p->child[0] != NULL && p->child[1] != NULL); \
|
||||
p->child[0]->color = RBTREE_BLACK; \
|
||||
p->child[1]->color = RBTREE_BLACK; \
|
||||
RBTREEI_CONTRACT_NODE(p); \
|
||||
assert(CAT3(rbtreei_,name,_depth)(p->child[0]) == CAT3(rbtreei_,name,_depth)(p->child[1])); \
|
||||
break; \
|
||||
} \
|
||||
} /* while */ \
|
||||
if (cpt == 1 /* root has been reached? */ ) { \
|
||||
CAT3(rbtreei_,name,_set_color)(p, RBTREE_BLACK); \
|
||||
assert (tree->node == p); \
|
||||
} \
|
||||
} else { \
|
||||
CAT3(rbtreei_,name,_set_color)(u, RBTREE_BLACK); \
|
||||
} \
|
||||
assert (tree->node == NULL || tree->node->color == RBTREE_BLACK); \
|
||||
/* delete it */ \
|
||||
if (data_ptr != NULL) \
|
||||
M_GET_SET oplist (*data_ptr, n->data); \
|
||||
M_GET_CLEAR oplist (n->data); \
|
||||
M_MEMORY_FREE (n); \
|
||||
tree->size --; \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
return true; \
|
||||
}
|
||||
|
||||
|
||||
// TODO: missing specialized iterator functions (it_from, it_to)
|
||||
// TODO: _get_str, _in_str, _out_str: how to print them?
|
||||
// TODO: specialized _sort shall do nothing, but shall check the requested order. How ?
|
||||
|
||||
|
||||
#endif
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
#ifndef M_CLASS_CPT
|
||||
|
||||
// TODO: Integrate default case with dynamic polymorphisme
|
||||
// TODO: WIP...
|
||||
|
||||
// Global counter
|
||||
#define M_CLASS_CPT 0
|
||||
|
||||
// In case
|
||||
#define M_REGISTER_TYPE "m-register.h"
|
||||
|
||||
// TODO: Iterator shall also be considered as key
|
||||
#define M_METHOD_EXPAND(method, id) \
|
||||
CAT3(CLASS_,id,_TYPE)*: CAT3(CLASS_,id,_DEFINITION).method, \
|
||||
const CAT3(CLASS_,id,_TYPE)*: CAT3(CLASS_,id,_DEFINITION).method
|
||||
|
||||
// TODO: How to define Default method if there is no registered method?
|
||||
// the current way may produce syntaxically invalid C due to macro expanding to
|
||||
// wrong term...
|
||||
#define M_CALL_METHOD(method, def, ...) \
|
||||
_Generic(&(M_RET_ARG1(__VA_ARGS__, )), \
|
||||
M_SEQ2(0,DEC(CLASS_CPT),M_METHOD_EXPAND, method))(__VA_ARGS__) \
|
||||
|
||||
#define M_CALL_METHOD2(method, def, ...) \
|
||||
_Generic(&(M_RET_ARG2(__VA_ARGS__, )), \
|
||||
M_SEQ2(0,DEC(CLASS_CPT),M_METHOD_EXPAND, method))(__VA_ARGS__) \
|
||||
|
||||
#define M_CLASS_DEFINE_FIELD(a) M_APPLY(M_CLASS_DEFINE_FIELD0 , CAT(M_PROTO_TUPLE_, a))
|
||||
#define M_CLASS_M_GET_FUNCPTR(a) M_APPLY(M_CLASS_M_GET_FUNCPTR0, CAT(M_PROTO_TUPLE_, a))
|
||||
#define M_CLASS_DEFINE_TYPE(a) M_APPLY(M_CLASS_DEFINE_TYPE0 , CAT(M_PROTO_TUPLE_, a))
|
||||
#define M_CLASS_DEFINE_FIELD0(a, b) M_IF(M_BOOL(CAT(M_PROTO_ISMETHOD_, a)))(CAT(M_PROTO_METHOD_, a)(TYPE, a);,/*nothing*/)
|
||||
#define M_CLASS_M_GET_FUNCPTR0(a,b) M_IF(M_BOOL(CAT(M_PROTO_ISMETHOD_, a)))(.a = b M_DEFERRED_COMMA, /*nothing*/)
|
||||
#define M_CLASS_DEFINE_TYPE0(a, b) M_IF(M_BOOL(CAT(M_PROTO_ISMETHOD_, a)))(/*nothing*/, typedef b CAT(TYPE_, a);)
|
||||
|
||||
/* Define basic supported methods and types */
|
||||
#define M_PROTO_TUPLE_INIT(value) INIT, value
|
||||
#define M_PROTO_TUPLE_INIT_SET(value) INIT_SET, value
|
||||
#define M_PROTO_TUPLE_SET(value) SET, value
|
||||
#define M_PROTO_TUPLE_CLEAR(value) CLEAR, value
|
||||
#define M_PROTO_TUPLE_EQUAL(value) EQUAL, value
|
||||
#define M_PROTO_TUPLE_IT_TYPE(value) IT_TYPE, value
|
||||
#define M_PROTO_TUPLE_PUSH(value) PUSH, value
|
||||
#define M_PROTO_TUPLE_POP(value) POP, value
|
||||
#define M_PROTO_TUPLE_PRINT(value) PRINT, value
|
||||
#define M_PROTO_TUPLE_TOSTR(value) TOSTR, value
|
||||
|
||||
// Define methods
|
||||
#define M_PROTO_METHOD_INIT(type, alias) void (*alias)(type)
|
||||
#define M_PROTO_METHOD_INIT_SET(type, alias) void (*alias)(type, const type)
|
||||
#define M_PROTO_METHOD_SET(type, alias) void (*alias)(type, const type)
|
||||
#define M_PROTO_METHOD_CLEAR(type, alias) void (*alias)(type)
|
||||
#define M_PROTO_METHOD_EQUAL(type, alias) bool (*alias)(const type, const type)
|
||||
#define M_PROTO_METHOD_PUSH(type, alias) void (*alias)(type, const CAT(type, _TYPE))
|
||||
#define M_PROTO_METHOD_POP(type, alias) void (*alias)(CAT(type, _TYPE)*, type)
|
||||
#define M_PROTO_METHOD_PRINT(type, alias) void (*alias)(const type)
|
||||
#define M_PROTO_METHOD_TOSTR(type, alias) void (*alias)(string_t, const type)
|
||||
|
||||
// Define types
|
||||
#define M_PROTO_ISMETHOD_IT_TYPE 0
|
||||
#define M_PROTO_ISMETHOD_TYPE 0
|
||||
|
||||
#define INIT_DEFLIST \
|
||||
char: "%c", \
|
||||
signed char: "%hhd", \
|
||||
unsigned char: "%hhu", \
|
||||
signed short: "%hd", \
|
||||
unsigned short: "%hu", \
|
||||
signed int: "%d", \
|
||||
unsigned int: "%u", \
|
||||
long int: "%ld", \
|
||||
unsigned long int: "%lu", \
|
||||
long long int: "%lld", \
|
||||
unsigned long long int: "%llu", \
|
||||
float: "%f", \
|
||||
double: "%f", \
|
||||
long double: "%Lf", \
|
||||
const char *: "%s", \
|
||||
char *: "%s", \
|
||||
const void *: "%p", \
|
||||
void *: "%p"
|
||||
|
||||
#define new(type) ({type *tmp = malloc(sizeof (type)); init(*tmp); tmp; })
|
||||
#define init(...) M_CALL_METHOD(INIT, M_INIT_DEFAULT, __VA_ARGS__)
|
||||
#define init_set(...) M_CALL_METHOD(INIT_SET, M_SET_DEFAULT, __VA_ARGS__)
|
||||
#define set(...) M_CALL_METHOD(SET, M_SET_DEFAULT, __VA_ARGS__)
|
||||
#define clear(...) M_CALL_METHOD(CLEAR, M_CLEAR_DEFAULT, __VA_ARGS__)
|
||||
#define delete(obj) (clear(*obj), free(obj))
|
||||
#define equal(...) M_CALL_METHOD(EQUAL, M_EQUAL_DEFAULT, __VA_ARGS__)
|
||||
#define push(...) M_CALL_METHOD(PUSH, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define pop(...) M_CALL_METHOD2(POP, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define print_arg(...) M_CALL_METHOD(PRINT, M_PRINT_ARG, __VA_ARGS__) ;
|
||||
#define print(...) do { M_MAP(print_arg, __VA_ARGS__) } while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TYPE
|
||||
|
||||
#ifndef OPLIST
|
||||
# error "OPLIST macro not defined."
|
||||
#endif
|
||||
|
||||
/* Do the stuff */
|
||||
#if CLASS_CPT == 0
|
||||
|
||||
typedef TYPE CLASS_0_TYPE;
|
||||
M_MAP(M_CLASS_DEFINE_TYPE, M_OPLIST_APPLY(M_OPLIST_FLAT, OPLIST))
|
||||
static const struct {
|
||||
M_MAP(M_CLASS_DEFINE_FIELD, M_OPLIST_APPLY(M_OPLIST_FLAT, OPLIST))
|
||||
} CLASS_0_DEFINITION = {
|
||||
M_MAP(M_CLASS_M_GET_FUNCPTR, M_OPLIST_APPLY(M_OPLIST_FLAT, OPLIST))
|
||||
};
|
||||
# undef TYPE
|
||||
# undef OPLIST
|
||||
# undef CLASS_CPT
|
||||
# define CLASS_CPT 1
|
||||
|
||||
#elif CLASS_CPT == 1
|
||||
|
||||
typedef TYPE CLASS_1_TYPE;
|
||||
M_MAP(M_CLASS_DEFINE_TYPE, M_OPLIST_APPLY(M_OPLIST_FLAT, OPLIST))
|
||||
static const struct {
|
||||
M_MAP(M_CLASS_DEFINE_FIELD, M_OPLIST_APPLY(M_OPLIST_FLAT, OPLIST))
|
||||
} CLASS_1_DEFINITION = {
|
||||
M_MAP(M_CLASS_M_GET_FUNCPTR, M_OPLIST_APPLY(M_OPLIST_FLAT, OPLIST))
|
||||
};
|
||||
# undef TYPE
|
||||
# undef OPLIST
|
||||
# undef CLASS_CPT
|
||||
# define CLASS_CPT 2
|
||||
|
||||
#elif CLASS_CPT == 2
|
||||
|
||||
typedef TYPE CLASS_2_TYPE;
|
||||
M_MAP(M_CLASS_DEFINE_TYPE, M_OPLIST_APPLY(M_OPLIST_FLAT, OPLIST))
|
||||
static const struct {
|
||||
M_MAP(M_CLASS_DEFINE_FIELD, M_OPLIST_APPLY(M_OPLIST_FLAT, OPLIST))
|
||||
} CLASS_2_DEFINITION = {
|
||||
M_MAP(M_CLASS_M_GET_FUNCPTR, M_OPLIST_APPLY(M_OPLIST_FLAT, OPLIST))
|
||||
};
|
||||
# undef TYPE
|
||||
# undef OPLIST
|
||||
# undef CLASS_CPT
|
||||
# define CLASS_CPT 3
|
||||
|
||||
#else
|
||||
# error "Out of scope"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* MLIB - SHARED PTR Module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_SHARED_PTR__H
|
||||
#define __M_SHARED_PTR__H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
#define SHARED_PTR_OPLIST(name) ( \
|
||||
INIT(CAT3(shared_, name, _init)), \
|
||||
CLEAR(CAT3(shared_, name, _clear)), \
|
||||
INIT_SET(CAT3(shared_, name, _init_set)), \
|
||||
SET(CAT3(shared_, name, _set)) \
|
||||
INIT_MOVE(CAT3(shared_, name, _init_move)), \
|
||||
MOVE(CAT3(shared_, name, _move)) \
|
||||
)
|
||||
|
||||
#define SHARED_PTR_DEF(name, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(SHAREDI_PTR_DEF2(name, __VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
SHAREDI_PTR_DEF2(name, __VA_ARGS__ ))
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
#define SHAREDI_PTR_DEF2(name, type, oplist) \
|
||||
typedef struct CAT3(shared_, name, _s){ \
|
||||
int cpt; \
|
||||
type *data; \
|
||||
} *CAT3(shared_, name, _t)[1]; \
|
||||
\
|
||||
typedef union { \
|
||||
type *ptr; \
|
||||
const type *cptr; \
|
||||
} CAT3(shared_union_, name,_t); \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(shared_, name, _const_cast)(type *ptr) \
|
||||
{ \
|
||||
CAT3(shared_union_, name,_t) u; \
|
||||
u.ptr = ptr; \
|
||||
return u.cptr; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(shared_, name, _init)(CAT3(shared_, name, _t) shared) \
|
||||
{ \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(shared_, name, _init2)(CAT3(shared_, name, _t) shared, type *data) \
|
||||
{ \
|
||||
struct CAT3(shared_, name, _s) *ptr; \
|
||||
if (data == NULL) { \
|
||||
*shared = NULL; \
|
||||
return; \
|
||||
} \
|
||||
ptr = M_MEMORY_ALLOC (struct CAT3(shared_, name, _s)); \
|
||||
if (ptr == NULL) \
|
||||
M_MEMORY_FULL(sizeof(struct CAT3(shared_, name, _s))); \
|
||||
ptr->cpt = 1; \
|
||||
ptr->data = data; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
CAT3(shared_, name, _NULL_p)(const CAT3(shared_, name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
return *shared == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(shared_, name, _init_set)(CAT3(shared_, name, _t) dest, \
|
||||
const CAT3(shared_, name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
assert (dest != shared); \
|
||||
*dest = *shared; \
|
||||
if (*dest != NULL) \
|
||||
atomic_fetch_add(&((*dest)->cpt), 1); \
|
||||
SHAREDI_CONTRACT(dest); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(shared_, name, _release)(CAT3(shared_, name, _t) dest) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest); \
|
||||
if (*dest != NULL) { \
|
||||
if (atomic_fetch_sub(&((*dest)->cpt), 1) == 1) { \
|
||||
M_GET_CLEAR oplist (*(*dest)->data); \
|
||||
M_GET_DEL oplist ((*dest)->data); \
|
||||
M_MEMORY_FREE (*dest); \
|
||||
} \
|
||||
*dest = NULL; \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(shared_, name, _clear)(CAT3(shared_, name, _t) dest) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest); \
|
||||
CAT3(shared_, name, _release)(dest); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(shared_, name, _set)(CAT3(shared_, name, _t) dest, \
|
||||
const CAT3(shared_, name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest); \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
CAT3(shared_, name, _release)(dest); \
|
||||
CAT3(shared_, name, _init_set)(dest, shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(shared_, name, _init_move)(CAT3(shared_, name, _t) dest, \
|
||||
CAT3(shared_, name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
assert (dest != NULL && dest != shared); \
|
||||
*dest = *shared; \
|
||||
*shared = NULL; \
|
||||
SHAREDI_CONTRACT(dest); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
CAT3(shared_, name, _move)(CAT3(shared_, name, _t) dest, \
|
||||
CAT3(shared_, name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest); \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
assert (dest != shared); \
|
||||
CAT3(shared_, name, _clear)(dest); \
|
||||
CAT3(shared_, name, _init_move)(dest, shared); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
CAT3(shared_, name, _cref)(const CAT3(shared_, name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
return CAT3(shared_, name, _const_cast) ((*shared)->data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
CAT3(shared_, name, _ref)(CAT3(shared_, name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
return (*shared)->data; \
|
||||
} \
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
#define SHAREDI_CONTRACT(shared) do { \
|
||||
assert(shared != NULL); \
|
||||
assert(*shared == NULL || (*shared)->cpt >= 1); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* MLIB - SNAPSHOT Module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_SNAPSHOT
|
||||
#define __M_SNAPSHOT
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/* Public interface of a snapshot */
|
||||
#define SNAPSHOT_DEF(name, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(SNAPSHOTI_DEF2(name, __VA_ARGS__, () ), \
|
||||
SNAPSHOTI_DEF2(name, __VA_ARGS__ ))
|
||||
|
||||
/* Define the oplist of a snapshot */
|
||||
#define SNAPSHOT_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(SNAPSHOTI_OPLIST(__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
SNAPSHOTI_OPLIST(__VA_ARGS__ ))
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Define the oplist of a snapshot */
|
||||
#define SNAPSHOTI_OPLIST(type, oplist) \
|
||||
(INIT(CAT3(snapshot_, type, _init)), \
|
||||
INIT_SET(CAT3(snapshot_, type, _init_set)), \
|
||||
SET(CAT3(snapshot_, type, _set)), \
|
||||
CLEAR(CAT3(snapshot_, type, _clear)), \
|
||||
TYPE(CAT3(snapshot_, type, _t)), \
|
||||
SUBTYPE(CAT3(snapshot_type_, name, _t)) \
|
||||
,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(CAT3(snapshot_, name, _init_move)),) \
|
||||
,M_IF_METHOD(MOVE, oplist)(MOVE(CAT3(snapshot_, name, _move)),) \
|
||||
)
|
||||
|
||||
#define SNAPSHOTI_FLAG(r, w, f, b) \
|
||||
( ( (r) << 4) | ((w) << 2) | ((f)) | ((b) << 6))
|
||||
#define SNAPSHOTI_R(flags) \
|
||||
(((flags) >> 4) & 0x03u)
|
||||
#define SNAPSHOTI_W(flags) \
|
||||
(((flags) >> 2) & 0x03u)
|
||||
#define SNAPSHOTI_F(flags) \
|
||||
(((flags) >> 0) & 0x03u)
|
||||
#define SNAPSHOTI_B(flags) \
|
||||
(((flags) >> 6) & 0x01u)
|
||||
|
||||
#define SNAPSHOTI_FLAGS_CONTRACT(flags) \
|
||||
assert(SNAPSHOTI_R(flags) != SNAPSHOTI_W(flags) \
|
||||
&& SNAPSHOTI_R(flags) != SNAPSHOTI_F(flags) \
|
||||
&& SNAPSHOTI_W(flags) != SNAPSHOTI_F(flags))
|
||||
#define SNAPSHOTI_CONTRACT(snap) do { \
|
||||
assert((snap) != NULL); \
|
||||
SNAPSHOTI_FLAGS_CONTRACT((snap)->flags); \
|
||||
} while (0)
|
||||
|
||||
#define SNAPSHOTI_DEF2(name, type, oplist) \
|
||||
typedef struct CAT3(snapshot_, name, _s) { \
|
||||
type data[3]; \
|
||||
atomic_uint_fast8_t flags; \
|
||||
} CAT3(snapshot_, name, _t)[1]; \
|
||||
typedef type CAT3(snapshot_type_, name, _t); \
|
||||
\
|
||||
static inline void CAT3(snapshot_, name, _init)(CAT3(snapshot_, name, _t) snap) \
|
||||
{ \
|
||||
assert(snap != NULL); \
|
||||
for(int i = 0; i < 3; i++) { \
|
||||
M_GET_INIT oplist(snap->data[i]); \
|
||||
} \
|
||||
snap->flags = ATOMIC_VAR_INIT (SNAPSHOTI_FLAG(0, 1, 2, 0)); \
|
||||
} \
|
||||
\
|
||||
static inline void CAT3(snapshot_, name, _clear)(CAT3(snapshot_, name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
for(int i = 0; i < 3; i++) { \
|
||||
M_GET_CLEAR oplist(snap->data[i]); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void CAT3(snapshot_, name, _init_set)(CAT3(snapshot_, name, _t) snap, \
|
||||
const CAT3(snapshot_, name, _t) org) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(org); \
|
||||
assert(snap != NULL && snap != org); \
|
||||
for(int i = 0; i < 3; i++) { \
|
||||
M_GET_INIT_SET oplist(snap->data[i], org->data[i]); \
|
||||
} \
|
||||
snap->flags = org->flags; \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
static inline void CAT3(snapshot_, name, _set)(CAT3(snapshot_, name, _t) snap, \
|
||||
const CAT3(snapshot_, name, _t) org) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
SNAPSHOTI_CONTRACT(org); \
|
||||
for(int i = 0; i < 3; i++) { \
|
||||
M_GET_SET oplist(snap->data[i], org->data[i]); \
|
||||
} \
|
||||
snap->flags = org->flags; \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT_MOVE, oplist)( \
|
||||
static inline void CAT3(snapshot_, name, _init_move)(CAT3(snapshot_, name, _t) snap, \
|
||||
CAT3(snapshot_, name, _t) org) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(org); \
|
||||
assert(snap != NULL && snap != org); \
|
||||
for(int i = 0; i < 3; i++) { \
|
||||
M_GET_INIT_MOVE oplist(snap->data[i], org->data[i]); \
|
||||
} \
|
||||
snap->flags = org->flags; \
|
||||
org->flags = 0; \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
} \
|
||||
,) /* IF_METHOD (INIT_MOVE) */ \
|
||||
\
|
||||
M_IF_METHOD(MOVE, oplist)( \
|
||||
static inline void CAT3(snapshot_, name, _move)(CAT3(snapshot_, name, _t) snap, \
|
||||
CAT3(snapshot_, name, _t) org) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
SNAPSHOTI_CONTRACT(org); \
|
||||
assert(snap != org); \
|
||||
for(int i = 0; i < 3; i++) { \
|
||||
M_GET_MOVE oplist(snap->data[i], org->data[i]); \
|
||||
} \
|
||||
snap->flags = org->flags; \
|
||||
org->flags = 0; \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
} \
|
||||
,) /* IF_METHOD (MOVE) */ \
|
||||
\
|
||||
static inline type *CAT3(snapshot_, name, _take)(CAT3(snapshot_, name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
uint_fast8_t nextFlags, origFlags = atomic_load(&snap->flags); \
|
||||
do { \
|
||||
nextFlags = SNAPSHOTI_FLAG(SNAPSHOTI_R(origFlags), \
|
||||
SNAPSHOTI_F(origFlags), \
|
||||
SNAPSHOTI_W(origFlags), 1); \
|
||||
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
||||
nextFlags)); \
|
||||
return &snap->data[SNAPSHOTI_W(nextFlags)]; \
|
||||
} \
|
||||
\
|
||||
static inline const type *CAT3(snapshot_, name, _look)(const CAT3(snapshot_, name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
uint_fast8_t nextFlags, origFlags = atomic_load(&snap->flags); \
|
||||
do { \
|
||||
if (!SNAPSHOTI_B(origFlags)) \
|
||||
break; \
|
||||
nextFlags = SNAPSHOTI_FLAG(SNAPSHOTI_F(origFlags), \
|
||||
SNAPSHOTI_W(origFlags), \
|
||||
SNAPSHOTI_R(origFlags), 0); \
|
||||
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
||||
nextFlags)); \
|
||||
return &snap->data[SNAPSHOTI_R(snap->flags)]; \
|
||||
} \
|
||||
\
|
||||
static inline type *CAT3(snapshot_, name, _get_produced)(CAT3(snapshot_, name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
return &snap->data[SNAPSHOTI_W(snap->flags)]; \
|
||||
} \
|
||||
\
|
||||
static inline const type *CAT3(snapshot_, name, _get_consummed)(const CAT3(snapshot_, name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
return &snap->data[SNAPSHOTI_R(snap->flags)]; \
|
||||
} \
|
||||
|
||||
|
||||
#endif
|
||||
+685
@@ -0,0 +1,685 @@
|
||||
/*
|
||||
* MLIB - Dynamic Size String Module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_STRING_H
|
||||
#define __M_STRING_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
// This macro defines the contract of a string.
|
||||
// Note: A ==> B is represented as not(A) or B
|
||||
#define STRING_CONTRACT(v) \
|
||||
M_ASSUME (v != NULL); \
|
||||
M_ASSUME (v->ptr != NULL || (v->size == 0 && v->alloc == 0)); \
|
||||
M_ASSUME (v->ptr == NULL || strlen(v->ptr) == v->size); \
|
||||
M_ASSUME (v->ptr == NULL || v->ptr[v->size] == 0); \
|
||||
M_ASSUME (v->ptr == NULL || v->size < v->alloc);
|
||||
|
||||
|
||||
/********************************** EXTERNAL ************************************/
|
||||
|
||||
#define STRING_FAILURE ((size_t)-1)
|
||||
|
||||
typedef struct string_s {
|
||||
size_t size, alloc;
|
||||
char *ptr;
|
||||
} string_t[1];
|
||||
|
||||
typedef enum {
|
||||
STRING_READ_LINE = 0, STRING_READ_PURE_LINE = 1, STRING_READ_FILE = 2
|
||||
} string_fgets_t;
|
||||
|
||||
static inline void
|
||||
string_init(string_t v)
|
||||
{
|
||||
v->size = v->alloc = 0;
|
||||
v->ptr = NULL;
|
||||
STRING_CONTRACT(v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_clear(string_t v)
|
||||
{
|
||||
STRING_CONTRACT(v);
|
||||
M_MEMORY_FREE(v->ptr);
|
||||
v->size = v->alloc = 0;
|
||||
v->ptr = NULL;
|
||||
}
|
||||
|
||||
static inline void string_clear2(string_t *v) { string_clear(*v); }
|
||||
|
||||
static inline char *
|
||||
string_clear_get_str(string_t v)
|
||||
{
|
||||
STRING_CONTRACT(v);
|
||||
char *p = v->ptr;
|
||||
v->size = v->alloc = 0;
|
||||
v->ptr = NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_clean(string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
v->size = 0;
|
||||
if (M_LIKELY (v->ptr))
|
||||
v->ptr[0] = 0;
|
||||
STRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
string_get_length(const string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
return v->size;
|
||||
}
|
||||
|
||||
static inline char
|
||||
string_get_char(const string_t v, size_t index)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
M_ASSUME( index < v->size);
|
||||
return v->ptr[index];
|
||||
}
|
||||
|
||||
static inline bool
|
||||
string_empty_p(const string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
return v->size == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
stringi_fit2size (string_t v, size_t size)
|
||||
{
|
||||
// Note: this function may be called in context where the contract
|
||||
// is not fullfilled.
|
||||
if (size > v->alloc) {
|
||||
size_t alloc = size < 16 ? 16 : (size + size / 2);
|
||||
char *ptr = M_MEMORY_REALLOC (char, v->ptr, alloc);
|
||||
if (ptr == NULL) {
|
||||
M_MEMORY_FULL(sizeof (char) * alloc);
|
||||
return;
|
||||
}
|
||||
v->ptr = ptr;
|
||||
v->alloc = alloc;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_shrink2fit(string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
char *ptr = M_MEMORY_REALLOC (char, v->ptr, v->size+1);
|
||||
M_ASSUME (ptr != NULL);
|
||||
v->ptr = ptr; // Can be != ptr if v->ptr was NULL before.
|
||||
v->alloc = v->size+1;
|
||||
STRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_set_str(string_t v, const char str[])
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
M_ASSUME(str != NULL);
|
||||
size_t size = strlen(str);
|
||||
stringi_fit2size(v, size+1);
|
||||
memcpy(v->ptr, str, size+1);
|
||||
v->size = size;
|
||||
STRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_set_strn(string_t v, const char str[], size_t n)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
M_ASSUME(str != NULL);
|
||||
size_t size = M_MIN (strlen(str), n);
|
||||
stringi_fit2size(v, size+1);
|
||||
memcpy(v->ptr, str, size);
|
||||
v->ptr[size] = 0;
|
||||
v->size = size;
|
||||
STRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline const char*
|
||||
string_get_cstr(const string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
return M_UNLIKELY (v->ptr == NULL) ? "" : v->ptr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_set (string_t v1, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v2);
|
||||
string_set_str (v1, string_get_cstr(v2));
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_init_set(string_t v1, const string_t v2)
|
||||
{
|
||||
string_init(v1);
|
||||
string_set(v1,v2);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_init_set_str(string_t v1, const char str[])
|
||||
{
|
||||
string_init(v1);
|
||||
string_set_str(v1, str);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_init_move(string_t v1, string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v2);
|
||||
v1->size = v2->size;
|
||||
v1->alloc = v2->alloc;
|
||||
v1->ptr = v2->ptr;
|
||||
v2->alloc = 0;
|
||||
v2->ptr = NULL;
|
||||
STRING_CONTRACT (v1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_move(string_t v1, string_t v2)
|
||||
{
|
||||
string_clear(v1);
|
||||
string_init_move(v1,v2);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_push_back (string_t v, char c)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
stringi_fit2size(v, v->size+2);
|
||||
v->ptr[v->size++] = c;
|
||||
v->ptr[v->size] = 0;
|
||||
STRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_cat_str(string_t v, const char str[])
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
size_t size = strlen(str);
|
||||
stringi_fit2size(v, v->size + size + 1);
|
||||
memcpy(&v->ptr[v->size], str, size + 1);
|
||||
v->size += size;
|
||||
STRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_cat(string_t v, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v2);
|
||||
string_cat_str(v, string_get_cstr(v2));
|
||||
}
|
||||
|
||||
static inline int
|
||||
string_cmp_str(const string_t v1, const char str[])
|
||||
{
|
||||
STRING_CONTRACT (v1);
|
||||
return strcmp(string_get_cstr(v1), str);
|
||||
}
|
||||
|
||||
static inline int
|
||||
string_cmp(const string_t v1, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v1);
|
||||
STRING_CONTRACT (v2);
|
||||
return strcmp(string_get_cstr(v1), string_get_cstr(v2));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
string_equal_str_p(const string_t v1, const char str[])
|
||||
{
|
||||
STRING_CONTRACT(v1);
|
||||
M_ASSUME (str != NULL);
|
||||
return string_cmp_str(v1, str) == 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
string_equal_p(const string_t v1, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT(v1);
|
||||
STRING_CONTRACT(v2);
|
||||
return v1->size == v2->size && string_cmp(v1, v2) == 0;
|
||||
}
|
||||
|
||||
// Note: doesn't work with UTF-8 strings...
|
||||
static inline int
|
||||
string_cmpi(const string_t v1, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v1);
|
||||
STRING_CONTRACT (v2);
|
||||
// strcasecmp is POSIX
|
||||
const char *p1 = string_get_cstr(v1), *p2 = string_get_cstr(v2);
|
||||
int c1, c2;
|
||||
do {
|
||||
// To avoid locale without 1 per 1 mapping.
|
||||
c1 = tolower((unsigned char) toupper((unsigned char) *p1++));
|
||||
c2 = tolower((unsigned char) toupper((unsigned char) *p2++));
|
||||
} while (c1 == c2 && c1 != 0);
|
||||
return c1 - c2;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
string_search_char (const string_t v, char c)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
const char *p = (const char*) strchr(string_get_cstr(v), c);
|
||||
return p == NULL ? STRING_FAILURE : (size_t) (p-string_get_cstr(v));
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
string_search_rchar (const string_t v, char c)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
const char *p = (const char*) strrchr(string_get_cstr(v), c);
|
||||
return p == NULL ? STRING_FAILURE : (size_t) (p-string_get_cstr(v));
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
string_search_str (const string_t v, const char str[])
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
const char *p = (const char*) strstr(string_get_cstr(v), str);
|
||||
return p == NULL ? STRING_FAILURE : (size_t) (p-string_get_cstr(v));
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
string_search_string (const string_t v1, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v2);
|
||||
return string_search_str(v1, string_get_cstr(v2));
|
||||
}
|
||||
|
||||
static inline int
|
||||
string_strcoll_str(const string_t v, const char str[])
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
return strcoll(string_get_cstr(v), str);
|
||||
}
|
||||
|
||||
static inline int
|
||||
string_strcoll (const string_t v1, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v2);
|
||||
return string_strcoll_str(v1, string_get_cstr(v2));
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
string_spn(const string_t v1, const char accept[])
|
||||
{
|
||||
STRING_CONTRACT (v1);
|
||||
M_ASSUME (accept != NULL);
|
||||
return strspn(string_get_cstr(v1), accept);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
string_cspn(const string_t v1, const char accept[])
|
||||
{
|
||||
STRING_CONTRACT (v1);
|
||||
M_ASSUME (accept != NULL);
|
||||
return strcspn(string_get_cstr(v1), accept);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_left(string_t v, size_t index)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
if (index >= v->size)
|
||||
return;
|
||||
M_ASSUME (v->ptr != NULL);
|
||||
v->ptr[index] = 0;
|
||||
v->size = index;
|
||||
STRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
// Note: this is an index, not the size to keep from the right !
|
||||
static inline void
|
||||
string_right(string_t v, size_t index)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
if (index >= v->size) {
|
||||
if (v->ptr != NULL) {
|
||||
v->ptr[0] = 0;
|
||||
v->size = 0;
|
||||
}
|
||||
STRING_CONTRACT (v);
|
||||
return;
|
||||
}
|
||||
M_ASSUME (v->ptr != NULL);
|
||||
size_t s2 = v->size - index;
|
||||
memmove (&v->ptr[0], &v->ptr[index], s2+1);
|
||||
v->size = s2;
|
||||
STRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_mid (string_t v, size_t index, size_t size)
|
||||
{
|
||||
string_right(v, index);
|
||||
string_left(v, size);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
string_replace_str (string_t v, const char str1[], const char str2[])
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
M_ASSUME (str1 != NULL && str2 != NULL);
|
||||
size_t i = string_search_str(v, str1);
|
||||
if (i != STRING_FAILURE) {
|
||||
size_t str1_l = strlen(str1);
|
||||
size_t str2_l = strlen(str2);
|
||||
stringi_fit2size (v, v->size + str2_l - str1_l + 1);
|
||||
if (str1_l != str2_l)
|
||||
memmove(&v->ptr[i+str2_l], &v->ptr[i+str1_l], v->size - i - str1_l + 1);
|
||||
memcpy (&v->ptr[i], str2, str2_l);
|
||||
v->size += str2_l - str1_l;
|
||||
STRING_CONTRACT (v);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
string_replace_string (string_t v, const string_t v1, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRING_CONTRACT (v1);
|
||||
STRING_CONTRACT (v2);
|
||||
return string_replace_str(v, string_get_cstr(v1), string_get_cstr(v2));
|
||||
}
|
||||
|
||||
static inline int
|
||||
string_printf (string_t v, const char format[], ...)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
va_list args;
|
||||
int size;
|
||||
va_start (args, format);
|
||||
size = vsnprintf (v->ptr, v->alloc, format, args);
|
||||
if (size > 0 && ((size_t) size+1 >= v->alloc) ) {
|
||||
// We have to realloc our string to fit the needed size
|
||||
stringi_fit2size (v, (size_t) size + 1);
|
||||
// and redo the parsing.
|
||||
va_end (args);
|
||||
va_start (args, format);
|
||||
size = vsnprintf (v->ptr, v->alloc, format, args);
|
||||
}
|
||||
if (size >= 0) {
|
||||
v->size = (size_t) size;
|
||||
}
|
||||
va_end (args);
|
||||
STRING_CONTRACT (v);
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline int
|
||||
string_cat_printf (string_t v, const char format[], ...)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
va_list args;
|
||||
int size;
|
||||
va_start (args, format);
|
||||
size = vsnprintf (&v->ptr[v->size], v->alloc - v->size, format, args);
|
||||
if (size > 0 && (v->size+(size_t)size+1 >= v->alloc) ) {
|
||||
// We have to realloc our string to fit the needed size
|
||||
stringi_fit2size (v, v->size + (size_t) size + 1);
|
||||
// and redo the parsing.
|
||||
va_end (args);
|
||||
va_start (args, format);
|
||||
size = vsnprintf (&v->ptr[v->size], v->alloc - v->size, format, args);
|
||||
}
|
||||
if (size >= 0) {
|
||||
v->size += (size_t) size;
|
||||
}
|
||||
va_end (args);
|
||||
STRING_CONTRACT (v);
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_fgets(string_t v, FILE *f, string_fgets_t arg)
|
||||
{
|
||||
STRING_CONTRACT(v);
|
||||
stringi_fit2size (v, 100);
|
||||
M_ASSUME(v->ptr != NULL);
|
||||
v->size = 0;
|
||||
v->ptr[0] = 0;
|
||||
while (!feof (f) && !ferror(f)) {
|
||||
fgets(&v->ptr[v->size], v->alloc - v->size, f);
|
||||
char *p = strchr(&v->ptr[v->size], '\n');
|
||||
v->size += strlen(&v->ptr[v->size]);
|
||||
STRING_CONTRACT(v);
|
||||
if (arg != STRING_READ_FILE && p != NULL) {
|
||||
if (arg == STRING_READ_PURE_LINE) {
|
||||
*p = 0;
|
||||
v->size --;
|
||||
}
|
||||
STRING_CONTRACT(v);
|
||||
return;
|
||||
} else if (p == NULL)
|
||||
stringi_fit2size (v, v->alloc + v->alloc/2);
|
||||
}
|
||||
STRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_fputs(FILE *f, const string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
fputs(string_get_cstr(v), f);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
string_start_with_str_p(const string_t v, const char *str)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
M_ASSUME (str != NULL);
|
||||
const char *v_str = string_get_cstr(v);
|
||||
while (*str){
|
||||
if (*str != *v_str)
|
||||
return false;
|
||||
str++;
|
||||
v_str++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
string_start_with_string_p(const string_t v, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v2);
|
||||
return string_start_with_str_p (v, string_get_cstr(v2));
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
string_hash(const string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
const char *p = string_get_cstr(v);
|
||||
size_t hash = 0;
|
||||
char c;
|
||||
do {
|
||||
c = *p++;
|
||||
hash = hash * 31421 + (unsigned int) c + 6297;
|
||||
} while (c != 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_strim(string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
char *b = v->ptr;
|
||||
size_t size = v->size;
|
||||
while (size > 0 && (b[size-1] == ' ' || b[size-1] == '\n' || b[size-1] == '\r' || b[size-1] == '\t'))
|
||||
size --;
|
||||
if (size == 0) {
|
||||
v->ptr[0] = 0;
|
||||
v->size = size;
|
||||
return;
|
||||
}
|
||||
while (*b == ' ' || *b == '\n' || *b == '\r' || *b == '\t')
|
||||
b++;
|
||||
M_ASSUME (b >= v->ptr && size >= (size_t) (b - v->ptr) );
|
||||
size -= (b - v->ptr);
|
||||
memmove (v->ptr, b, size);
|
||||
v->ptr[size] = 0;
|
||||
v->size = size;
|
||||
STRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* I/O */
|
||||
static inline void
|
||||
string_get_str(string_t v, const string_t v2, bool append)
|
||||
{
|
||||
/* Output: "string" with quote around
|
||||
Replace " by \" within the string */
|
||||
STRING_CONTRACT(v2);
|
||||
STRING_CONTRACT(v);
|
||||
M_ASSUME (v != v2); // Limitation
|
||||
if(append==false) v->size = 0;
|
||||
size_t targetSize = v->size + v2->size + 3;
|
||||
stringi_fit2size(v, targetSize);
|
||||
v->ptr[v->size ++] = '"';
|
||||
for(size_t i = 0 ; i < v2->size; i++) {
|
||||
const char c = v2->ptr[i];
|
||||
if (c == '"') {
|
||||
targetSize ++ ;
|
||||
stringi_fit2size(v, targetSize);
|
||||
v->ptr[v->size ++] = '\\';
|
||||
}
|
||||
v->ptr[v->size ++] = c;
|
||||
}
|
||||
v->ptr[v->size ++] = '"';
|
||||
v->ptr[v->size] = 0;
|
||||
M_ASSUME (v->size <= targetSize);
|
||||
STRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_out_str(FILE *f, const string_t v)
|
||||
{
|
||||
/* Output: "string" with quote around
|
||||
Replace " by \" within the string */
|
||||
STRING_CONTRACT(v);
|
||||
M_ASSUME (f != NULL);
|
||||
fputc('"', f);
|
||||
for(size_t i = 0 ; i < v->size; i++) {
|
||||
const char c = v->ptr[i];
|
||||
if (c == '"') {
|
||||
fputc('\\', f);
|
||||
}
|
||||
fputc(c, f);
|
||||
}
|
||||
fputc('"', f);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
string_in_str(string_t v, FILE *f)
|
||||
{
|
||||
STRING_CONTRACT(v);
|
||||
M_ASSUME (f != NULL);
|
||||
char c = fgetc(f);
|
||||
if (c != '"') return false;
|
||||
string_clean(v);
|
||||
c = fgetc(f);
|
||||
while (c != '"' && !feof(f) && !ferror(f)) {
|
||||
if (c == '\\') {
|
||||
c = getc(f);
|
||||
if (c != '"') string_push_back (v, '\\');
|
||||
}
|
||||
string_push_back (v, c);
|
||||
c = fgetc(f);
|
||||
}
|
||||
return c == '"';
|
||||
}
|
||||
|
||||
#define STRING_SPLIT(name, oplist, type_oplist) \
|
||||
static inline void CAT(name, _split)(M_GET_TYPE oplist cont, \
|
||||
const string_t str, const char sep) \
|
||||
{ \
|
||||
size_t begin = 0; \
|
||||
string_t tmp; \
|
||||
string_init(tmp); \
|
||||
M_GET_CLEAN oplist (cont); \
|
||||
for(size_t i = 0 ; i < string_get_length(str); i++) { \
|
||||
char c = string_get_char(str, i); \
|
||||
if (c == sep) { \
|
||||
string_set_strn(tmp, &str->ptr[begin], i - begin); \
|
||||
M_GET_PUSH oplist (cont, tmp); \
|
||||
begin = i + 1; \
|
||||
} \
|
||||
} \
|
||||
string_set_strn(tmp, &str->ptr[begin], string_get_length(str) - begin); \
|
||||
M_GET_PUSH oplist (cont, tmp); \
|
||||
/* HACK: if method reverse is defined, it is likely that we have */ \
|
||||
/* inserted the items in the wrong order (aka for a list) */ \
|
||||
M_IF_METHOD(REVERSE, oplist) (M_GET_REVERSE oplist (cont);, ) \
|
||||
string_clear(tmp); \
|
||||
} \
|
||||
|
||||
/* Use of Compound Literals to init a constant string */
|
||||
#define STRING_CTE(s) \
|
||||
((const string_t){{.size = sizeof(s)-1, .alloc = sizeof(s), \
|
||||
.ptr = s}})
|
||||
|
||||
#define STRING_INIT_PRINTF(v, format, ...) do { \
|
||||
string_init (v); \
|
||||
string_printf (v, format, __VA_ARGS__) ; \
|
||||
} while (0)
|
||||
|
||||
#define STRING_DECL_INIT(v) \
|
||||
string_t v __attribute__((cleanup(string_clear2))) = {{ 0, 0, NULL}}
|
||||
|
||||
#define STRING_DECL_INIT_PRINTF(v, format, ...) \
|
||||
STRING_DECL_INIT(v); \
|
||||
string_printf (v, format, __VA_ARGS__)
|
||||
|
||||
#define STRING_OPLIST \
|
||||
(INIT(string_init),INIT_SET(string_init_set), SET(string_set), \
|
||||
INIT_MOVE(string_init_move), MOVE(string_move), \
|
||||
CLEAR(string_clear), HASH(string_hash), EQUAL(string_equal_p), \
|
||||
CMP(string_cmp), TYPE(string_t), GET_STR(string_get_str), \
|
||||
OUT_STR(string_out_str), IN_STR(string_in_str), \
|
||||
EXT_ALGO(STRING_SPLIT) \
|
||||
)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_TUPLE_H
|
||||
#define __M_TUPLE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
#define TUPLE_GET_FIELD(f,t,o) f
|
||||
#define TUPLE_GET_TYPE(f,t,o) t
|
||||
#define TUPLE_GET_INIT(f,t,o) M_GET_INIT o
|
||||
#define TUPLE_GET_INIT_SET(f,t,o) M_GET_INIT_SET o
|
||||
#define TUPLE_GET_INIT_MOVE(f,t,o) M_GET_INIT_MOVE o
|
||||
#define TUPLE_GET_MOVE(f,t,o) M_GET_MOVE o
|
||||
#define TUPLE_GET_SET(f,t,o) M_GET_SET o
|
||||
#define TUPLE_GET_CLEAR(f,t,o) M_GET_CLEAR o
|
||||
#define TUPLE_GET_CMP(f,t,o) M_GET_CMP o
|
||||
#define TUPLE_GET_HASH(f,t,o) M_GET_HASH o
|
||||
#define TUPLE_GET_EQUAL(f,t,o) M_GET_EQUAL o
|
||||
#define TUPLE_GET_STR(f,t,o) M_GET_GET_STR o
|
||||
#define TUPLE_GET_OUT_STR(f,t,o) M_GET_OUT_STR o
|
||||
#define TUPLE_GET_IN_STR(f,t,o) M_GET_IN_STR o
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_TYPE(name, ...) \
|
||||
typedef struct CAT(name, _s) { \
|
||||
M_MAP(TUPLE_DEFINE_RECUR_TYPE_ELE , __VA_ARGS__) \
|
||||
} CAT(name,_t)[1]; \
|
||||
typedef struct CAT(name, _s) *CAT(name, _ptr); \
|
||||
typedef const struct CAT(name, _s) *CAT(name, _srcptr);
|
||||
#define TUPLE_DEFINE_RECUR_TYPE_ELE(a) \
|
||||
TUPLE_GET_TYPE a TUPLE_GET_FIELD a ;
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_INIT(name, ...) \
|
||||
static inline void CAT(name, _init)(CAT(name,_t) my) { \
|
||||
M_MAP(TUPLE_DEFINE_INIT_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_INIT_FUNC(a) \
|
||||
TUPLE_GET_INIT a ( my -> TUPLE_GET_FIELD a );
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_INIT_SET(name, ...) \
|
||||
static inline void CAT(name, _init_set)(CAT(name,_t) my , CAT(name,_t) const org) { \
|
||||
M_MAP(TUPLE_DEFINE_INIT_SET_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_INIT_SET_FUNC(a) \
|
||||
TUPLE_GET_INIT_SET a ( my -> TUPLE_GET_FIELD a , org -> TUPLE_GET_FIELD a );
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_INIT_SET2(name, ...) \
|
||||
static inline void CAT(name, _init_set2)(CAT(name,_t) my \
|
||||
M_MAP(TUPLE_DEFINE_INIT_SET2_PROTO, __VA_ARGS__) \
|
||||
) { \
|
||||
M_MAP(TUPLE_DEFINE_INIT_SET2_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_INIT_SET2_PROTO(a) \
|
||||
, TUPLE_GET_TYPE a const TUPLE_GET_FIELD a
|
||||
#define TUPLE_DEFINE_INIT_SET2_FUNC(a) \
|
||||
TUPLE_GET_INIT_SET a ( my -> TUPLE_GET_FIELD a , TUPLE_GET_FIELD a );
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_SET(name, ...) \
|
||||
static inline void CAT(name, _set)(CAT(name,_t) my , \
|
||||
CAT(name,_t) const org) { \
|
||||
M_MAP(TUPLE_DEFINE_SET_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_SET_FUNC(a) \
|
||||
TUPLE_GET_SET a ( my -> TUPLE_GET_FIELD a , org -> TUPLE_GET_FIELD a );
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_CLEAR(name, ...) \
|
||||
static inline void CAT(name, _clear)(CAT(name,_t) my) { \
|
||||
M_MAP(TUPLE_DEFINE_CLEAR_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_CLEAR_FUNC(a) \
|
||||
TUPLE_GET_CLEAR a ( my -> TUPLE_GET_FIELD a );
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_GETTER(name, ...) \
|
||||
M_MAP2(TUPLE_DEFINE_GETTER_PROTO, name, __VA_ARGS__)
|
||||
#define TUPLE_DEFINE_GETTER_PROTO(name, a) \
|
||||
static inline TUPLE_GET_TYPE a const * CAT3(name, _get_, TUPLE_GET_FIELD a) \
|
||||
(CAT(name,_t) const my) { \
|
||||
return (TUPLE_GET_TYPE a const * ) &(my->TUPLE_GET_FIELD a);}
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_SETTER(name, ...) \
|
||||
M_MAP2(TUPLE_DEFINE_SETTER_PROTO, name, __VA_ARGS__)
|
||||
#define TUPLE_DEFINE_SETTER_PROTO(name, a) \
|
||||
static inline void CAT3(name, _set_, TUPLE_GET_FIELD a) \
|
||||
(CAT(name,_t) my, TUPLE_GET_TYPE a TUPLE_GET_FIELD a) { \
|
||||
TUPLE_GET_SET a (my ->TUPLE_GET_FIELD a, TUPLE_GET_FIELD a);}
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_CMP(name, ...) \
|
||||
static inline int CAT(name, _cmp)(CAT(name,_t) const e1 , \
|
||||
CAT(name,_t) const e2) { \
|
||||
int i; \
|
||||
M_MAP(TUPLE_DEFINE_CMP_FUNC , __VA_ARGS__) \
|
||||
return 0; \
|
||||
}
|
||||
#define TUPLE_DEFINE_CMP_FUNC(a) \
|
||||
i = TUPLE_GET_CMP a ( e1 -> TUPLE_GET_FIELD a , e2 -> TUPLE_GET_FIELD a );\
|
||||
if (i != 0) return i;
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_EQUAL(name, ...) \
|
||||
static inline bool CAT(name, _equal_p)(CAT(name,_t) const e1 , \
|
||||
CAT(name,_t) const e2) { \
|
||||
bool b; \
|
||||
M_MAP(TUPLE_DEFINE_EQUAL_FUNC , __VA_ARGS__) \
|
||||
return true; \
|
||||
}
|
||||
#define TUPLE_DEFINE_EQUAL_FUNC(a) \
|
||||
b = TUPLE_GET_EQUAL a ( e1 -> TUPLE_GET_FIELD a , e2 -> TUPLE_GET_FIELD a ); \
|
||||
if (!b) return false;
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_HASH(name, ...) \
|
||||
static inline unsigned long CAT(name, _hash)(CAT(name,_t) const e1) { \
|
||||
unsigned long hash = 0; \
|
||||
M_MAP(TUPLE_DEFINE_HASH_FUNC , __VA_ARGS__) \
|
||||
return hash; \
|
||||
}
|
||||
#define TUPLE_DEFINE_HASH_FUNC(a) \
|
||||
hash = hash * 31421ul + TUPLE_GET_HASH a ( e1 -> TUPLE_GET_FIELD a);
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_GET_STR(name, ...) \
|
||||
static inline void CAT(name, _get_str)(string_t str, \
|
||||
CAT(name,_t) const el, \
|
||||
bool append) { \
|
||||
bool comma = false; \
|
||||
assert (str != NULL && el != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "("); \
|
||||
M_MAP(TUPLE_DEFINE_GET_STR_FUNC , __VA_ARGS__) \
|
||||
string_push_back (str, ')'); \
|
||||
}
|
||||
#define TUPLE_DEFINE_GET_STR_FUNC(a) \
|
||||
if (comma) string_push_back (str, ','); \
|
||||
comma = true; \
|
||||
TUPLE_GET_STR a (str, el -> TUPLE_GET_FIELD a, true); \
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_OUT_STR(name, ...) \
|
||||
static inline void CAT(name, _out_str)(FILE *f, \
|
||||
CAT(name,_t) const el) { \
|
||||
bool comma = false; \
|
||||
assert (f != NULL && el != NULL); \
|
||||
fputc('(', f); \
|
||||
M_MAP(TUPLE_DEFINE_OUT_STR_FUNC , __VA_ARGS__) \
|
||||
fputc (')', f); \
|
||||
}
|
||||
#define TUPLE_DEFINE_OUT_STR_FUNC(a) \
|
||||
if (comma) fputc (',', f); \
|
||||
comma = true; \
|
||||
TUPLE_GET_OUT_STR a (f, el -> TUPLE_GET_FIELD a); \
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_IN_STR(name, ...) \
|
||||
static inline bool CAT(name, _in_str)(CAT(name,_t) el, FILE *f) { \
|
||||
bool comma = false; \
|
||||
assert (f != NULL && el != NULL); \
|
||||
char c = fgetc(f); \
|
||||
if (c != '(') return false; \
|
||||
M_MAP(TUPLE_DEFINE_IN_STR_FUNC , __VA_ARGS__) \
|
||||
c = fgetc(f); \
|
||||
return (c == ')'); \
|
||||
}
|
||||
#define TUPLE_DEFINE_IN_STR_FUNC(a) \
|
||||
if (comma) { \
|
||||
c = fgetc (f); \
|
||||
if (c != ',' || feof(f) || ferror(f)) return false; \
|
||||
} \
|
||||
comma = true; \
|
||||
if (TUPLE_GET_IN_STR a (el -> TUPLE_GET_FIELD a, f) == false) \
|
||||
return false ; \
|
||||
|
||||
#define TUPLE_DEFINE_INIT_MOVE(name, ...) \
|
||||
static inline void CAT(name, _init_move)(CAT(name,_t) el, CAT(name,_t) org) { \
|
||||
M_MAP(TUPLE_DEFINE_INIT_MOVE_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_INIT_MOVE_FUNC(a) \
|
||||
TUPLE_GET_INIT_MOVE a (el -> TUPLE_GET_FIELD a, org -> TUPLE_GET_FIELD a);
|
||||
|
||||
#define TUPLE_DEFINE_MOVE(name, ...) \
|
||||
static inline void CAT(name, _move)(CAT(name,_t) el, CAT(name,_t) org) { \
|
||||
M_MAP(TUPLE_DEFINE_MOVE_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_MOVE_FUNC(a) \
|
||||
TUPLE_GET_MOVE a (el -> TUPLE_GET_FIELD a, org -> TUPLE_GET_FIELD a);
|
||||
|
||||
|
||||
/* Macros for testing for method presence */
|
||||
#define TUPLE_TEST_METHOD2_P(method, f, t, op) \
|
||||
M_TEST_METHOD_P(method, op)
|
||||
#define TUPLE_TEST_METHOD_P(method, trio) \
|
||||
M_APPLY(TUPLE_TEST_METHOD2_P, method, M_OPLIST_FLAT trio)
|
||||
|
||||
#define TUPLE_ALL_CMP(...) \
|
||||
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, CMP, __VA_ARGS__)
|
||||
#define TUPLE_ALL_EQUAL(...) \
|
||||
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, EQUAL, __VA_ARGS__)
|
||||
#define TUPLE_ALL_HASH(...) \
|
||||
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, HASH, __VA_ARGS__)
|
||||
#define TUPLE_ALL_GET_STR(...) \
|
||||
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, GET_STR, __VA_ARGS__)
|
||||
#define TUPLE_ALL_OUT_STR(...) \
|
||||
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, OUT_STR, __VA_ARGS__)
|
||||
#define TUPLE_ALL_IN_STR(...) \
|
||||
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, IN_STR, __VA_ARGS__)
|
||||
#define TUPLE_ALL_INIT_MOVE(...) \
|
||||
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, INIT_MOVE, __VA_ARGS__)
|
||||
#define TUPLE_ALL_MOVE(...) \
|
||||
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, MOVE, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_OPLIST(name, ...) \
|
||||
(INIT(CAT(name,_init)), \
|
||||
INIT_SET(CAT(name, _init_set)), \
|
||||
SET(CAT(name,_set)), \
|
||||
CLEAR(CAT(name, _clear)), \
|
||||
TYPE(CAT(name,_t)), \
|
||||
M_IF_METHOD_ALL(CMP, __VA_ARGS__)(CMP(CAT(name, _cmp)),), \
|
||||
M_IF_METHOD_ALL(HASH, __VA_ARGS__)(HASH(CAT(name, _hash)),), \
|
||||
M_IF_METHOD_ALL(EQUAL, __VA_ARGS__)(EQUAL(CAT(name, _equal_p)),), \
|
||||
)
|
||||
|
||||
/********************** External interface *************************/
|
||||
|
||||
#define TUPLE_DEF2(name, ...) \
|
||||
TUPLE_DEFINE_TYPE(name, __VA_ARGS__) \
|
||||
TUPLE_DEFINE_INIT(name, __VA_ARGS__) \
|
||||
TUPLE_DEFINE_INIT_SET(name, __VA_ARGS__) \
|
||||
TUPLE_DEFINE_INIT_SET2(name, __VA_ARGS__) \
|
||||
TUPLE_DEFINE_SET(name, __VA_ARGS__) \
|
||||
TUPLE_DEFINE_CLEAR(name, __VA_ARGS__) \
|
||||
TUPLE_DEFINE_GETTER(name, __VA_ARGS__) \
|
||||
TUPLE_DEFINE_SETTER(name, __VA_ARGS__) \
|
||||
M_IF(TUPLE_ALL_CMP(__VA_ARGS__)) \
|
||||
(TUPLE_DEFINE_CMP(name, __VA_ARGS__),) \
|
||||
M_IF(TUPLE_ALL_HASH(__VA_ARGS__)) \
|
||||
(TUPLE_DEFINE_HASH(name, __VA_ARGS__),) \
|
||||
M_IF(TUPLE_ALL_EQUAL(__VA_ARGS__)) \
|
||||
(TUPLE_DEFINE_EQUAL(name, __VA_ARGS__),) \
|
||||
M_IF(TUPLE_ALL_GET_STR(__VA_ARGS__)) \
|
||||
(TUPLE_DEFINE_GET_STR(name, __VA_ARGS__),) \
|
||||
M_IF(TUPLE_ALL_OUT_STR(__VA_ARGS__)) \
|
||||
(TUPLE_DEFINE_OUT_STR(name, __VA_ARGS__),) \
|
||||
M_IF(TUPLE_ALL_IN_STR(__VA_ARGS__)) \
|
||||
(TUPLE_DEFINE_IN_STR(name, __VA_ARGS__),) \
|
||||
M_IF(TUPLE_ALL_INIT_MOVE(__VA_ARGS__)) \
|
||||
(TUPLE_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \
|
||||
M_IF(TUPLE_ALL_MOVE(__VA_ARGS__)) \
|
||||
(TUPLE_DEFINE_MOVE(name, __VA_ARGS__),)
|
||||
|
||||
/* Define the oplist of a tuple.
|
||||
TYPLE_OPLIST(name[, oplist of the first type, ...]) */
|
||||
#define TUPLE_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(TUPLEI_OPLIST(__VA_ARGS__, () ), \
|
||||
TUPLEI_OPLIST(__VA_ARGS__ ))
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
CC=gcc -std=c99
|
||||
CFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function
|
||||
CPPFLAGS=-I..
|
||||
RM=rm -f
|
||||
VALGRIND=
|
||||
EXE=./a.exe
|
||||
|
||||
all:
|
||||
@echo "Nothing to be done."
|
||||
|
||||
check: core array list i-list string buffer shared tuple snapshot algo dict rbtree
|
||||
|
||||
valgrind:
|
||||
make check VALGRIND=valgrind
|
||||
|
||||
core:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(COVERAGE_CFLAGS) test-mcore.c -lgmp -o $(EXE) && $(VALGRIND) $(EXE)
|
||||
|
||||
array:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(COVERAGE_CFLAGS) test-marray.c -lgmp -o $(EXE) && $(VALGRIND) $(EXE)
|
||||
|
||||
list:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(COVERAGE_CFLAGS) test-mlist.c -lgmp -o $(EXE) && $(VALGRIND) $(EXE)
|
||||
|
||||
i-list:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(COVERAGE_CFLAGS) test-milist.c -lgmp -o $(EXE) && $(VALGRIND) $(EXE)
|
||||
|
||||
string:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(COVERAGE_CFLAGS) test-mstring.c -lgmp -o $(EXE) && $(VALGRIND) $(EXE)
|
||||
|
||||
buffer:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(COVERAGE_CFLAGS) test-mbuffer.c -lpthread -o $(EXE) && $(VALGRIND) $(EXE)
|
||||
|
||||
shared:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(COVERAGE_CFLAGS) test-mshared.c -lpthread -o $(EXE) && $(VALGRIND) $(EXE)
|
||||
|
||||
algo:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(COVERAGE_CFLAGS) test-malgo.c -lgmp -o $(EXE) && $(VALGRIND) $(EXE)
|
||||
|
||||
tuple:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(COVERAGE_CFLAGS) test-mtuple.c -lgmp -o $(EXE) && $(VALGRIND) $(EXE)
|
||||
|
||||
snapshot:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(COVERAGE_CFLAGS) test-msnapshot.c -lgmp -o $(EXE) && $(VALGRIND) $(EXE)
|
||||
|
||||
dict:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(COVERAGE_CFLAGS) test-mdict.c -lgmp -o $(EXE) && $(VALGRIND) $(EXE)
|
||||
|
||||
rbtree:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(COVERAGE_CFLAGS) test-mrbtree.c -lgmp -o $(EXE) && $(VALGRIND) $(EXE)
|
||||
|
||||
bitset:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(COVERAGE_CFLAGS) test-mbitset.c -lgmp -o $(EXE) && $(VALGRIND) $(EXE)
|
||||
|
||||
gene-list:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS)-O3 -DNDEBUG -S tgen-mlist.c && less tgen-mlist.s
|
||||
|
||||
gene-array:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS)-O3 -DNDEBUG -S tgen-marray.c && less tgen-marray.s
|
||||
|
||||
clean:
|
||||
$(RM) $(EXE) *.s *~ *.o ./a.dat
|
||||
$(RM) -r coverage *.gcda *.gcno all.info test.tar README.html
|
||||
@@ -0,0 +1,18 @@
|
||||
hello:salut
|
||||
README:lisez-moi
|
||||
dictionary:dictionnaire
|
||||
vector:vecteur
|
||||
list:liste
|
||||
buffer:tableau
|
||||
circular:circulaire
|
||||
gnu:gnu is not unix
|
||||
README:LISEZ-MOI
|
||||
file:fichier
|
||||
string:chaine de caractere
|
||||
reference:reference
|
||||
const:constante
|
||||
error:erreur
|
||||
char:caractere
|
||||
key:cle
|
||||
value:valeur
|
||||
print:afficher
|
||||
@@ -0,0 +1,77 @@
|
||||
#include "m-list.h"
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
#include "m-algo.h"
|
||||
|
||||
ARRAY_DEF(int, int)
|
||||
|
||||
ALGO_DEF(algo_array, ARRAY_OPLIST(int))
|
||||
|
||||
LIST_DEF(int, int)
|
||||
|
||||
ALGO_DEF(algo_list, LIST_OPLIST(int))
|
||||
|
||||
LIST_DEF(string, string_t, STRING_OPLIST)
|
||||
|
||||
ALGO_DEF(algo_string, LIST_OPLIST(string, STRING_OPLIST))
|
||||
|
||||
static void test_list(void)
|
||||
{
|
||||
list_int_t l;
|
||||
list_int_init(l);
|
||||
for(int i = 0; i < 100; i++)
|
||||
list_int_push_back (l, i);
|
||||
assert( algo_list_contains(l, 62) == true);
|
||||
assert( algo_list_contains(l, -1) == false);
|
||||
|
||||
assert( algo_list_count(l, 1) == 1);
|
||||
list_int_push_back (l, 17);
|
||||
assert( algo_list_count(l, 17) == 2);
|
||||
assert( algo_list_count(l, -1) == 0);
|
||||
|
||||
list_int_clear(l);
|
||||
}
|
||||
|
||||
static void test_array(void)
|
||||
{
|
||||
array_int_t l;
|
||||
array_int_init(l);
|
||||
for(int i = 0; i < 100; i++)
|
||||
array_int_push_back (l, i);
|
||||
assert( algo_array_contains(l, 62) == true);
|
||||
assert( algo_array_contains(l, -1) == false);
|
||||
|
||||
assert( algo_array_count(l, 1) == 1);
|
||||
array_int_push_back (l, 17);
|
||||
assert( algo_array_count(l, 17) == 2);
|
||||
assert( algo_array_count(l, -1) == 0);
|
||||
|
||||
array_int_clear(l);
|
||||
}
|
||||
|
||||
static void test_string(void)
|
||||
{
|
||||
list_string_t l;
|
||||
list_string_init(l);
|
||||
string_t s;
|
||||
string_init_set_str(s, "Hello, World, John");
|
||||
algo_string_split(l, s, ',');
|
||||
list_string_pop_back (&s, l);
|
||||
assert (string_equal_str_p(s, "Hello"));
|
||||
list_string_pop_back (&s, l);
|
||||
assert (string_equal_str_p(s, " World"));
|
||||
list_string_pop_back (&s, l);
|
||||
assert (string_equal_str_p(s, " John"));
|
||||
assert (list_string_empty_p(l));
|
||||
string_clear(s);
|
||||
|
||||
list_string_clear(l);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_list();
|
||||
test_array();
|
||||
test_string();
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <gmp.h>
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF(uint, unsigned int)
|
||||
#define ARRAY_UINT_OPLIST ARRAY_OPLIST(uint)
|
||||
|
||||
static void my_mpz_out_str(FILE *f, const mpz_t z)
|
||||
{
|
||||
mpz_out_str (f, 10, z);
|
||||
}
|
||||
|
||||
static bool my_mpz_in_str(mpz_t z, FILE *f)
|
||||
{
|
||||
return mpz_inp_str (z, f, 10) > 0;
|
||||
}
|
||||
|
||||
static bool my_mpz_equal_p(const mpz_t z1, const mpz_t z2)
|
||||
{
|
||||
return mpz_cmp (z1, z2) == 0;
|
||||
}
|
||||
|
||||
#include "m-string.h"
|
||||
static void my_mpz_str(string_t str, const mpz_t z, bool append)
|
||||
{
|
||||
char *s = mpz_get_str(NULL, 10, z);
|
||||
assert (s != NULL);
|
||||
if (append) string_cat_str (str, s);
|
||||
else string_set_str (str, s);
|
||||
free(s);
|
||||
}
|
||||
|
||||
ARRAY_DEF(mpz, mpz_t,
|
||||
(INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), \
|
||||
OUT_STR(my_mpz_out_str), IN_STR(my_mpz_in_str), EQUAL(my_mpz_equal_p), \
|
||||
GET_STR(my_mpz_str) ))
|
||||
|
||||
static void test_uint(void)
|
||||
{
|
||||
array_uint_t v;
|
||||
array_uint_init(v);
|
||||
|
||||
assert (array_uint_empty_p(v) == true);
|
||||
|
||||
array_uint_push_back(v, 2);
|
||||
assert (array_uint_empty_p(v) == false);
|
||||
unsigned int x;
|
||||
array_uint_pop_back(&x, v);
|
||||
assert( x == 2);
|
||||
|
||||
for(unsigned int i = 0; i < 100; i++)
|
||||
array_uint_push_back(v, i);
|
||||
|
||||
unsigned int s = 0;
|
||||
for(size_t i = 0; i < array_uint_size(v) ; i++)
|
||||
s += *array_uint_cget(v, i);
|
||||
assert( s == 100 * 99 /2);
|
||||
|
||||
s = 0;
|
||||
for M_EACH(item, v, ARRAY_UINT_OPLIST) {
|
||||
s += *item;
|
||||
}
|
||||
assert( s == 100 * 99 /2);
|
||||
|
||||
array_uint_pop_at (NULL, v, 0);
|
||||
assert(array_uint_size(v) == 99);
|
||||
s= 0;
|
||||
for(size_t i = 0; i < array_uint_size(v) ; i++)
|
||||
s += *array_uint_cget(v, i);
|
||||
assert( s == 100 * 99 /2);
|
||||
|
||||
unsigned int *p = array_uint_get(v, 1);
|
||||
*p += 999;
|
||||
s= 0;
|
||||
for(size_t i = 0; i < array_uint_size(v) ; i++)
|
||||
s += *array_uint_cget(v, i);
|
||||
assert( s == 100 * 99 /2 + 999);
|
||||
|
||||
array_uint_swap(v, 2, 3);
|
||||
assert(*array_uint_cget(v, 2) == 4);
|
||||
assert(*array_uint_cget(v, 3) == 3);
|
||||
|
||||
array_uint_shrink_to_fit(v);
|
||||
assert(array_uint_capacity(v) == array_uint_size(v));
|
||||
|
||||
const unsigned int *src = array_uint_cget(v, 4);
|
||||
assert (*src == 5);
|
||||
|
||||
array_uint_remove_v(v, 1, array_uint_size(v) -1);
|
||||
assert(array_uint_size(v) == 2);
|
||||
assert(*array_uint_cget(v, 0) == 1);
|
||||
assert(*array_uint_cget(v, 1) == 99);
|
||||
|
||||
for(unsigned int i = 3; i < 100; i++)
|
||||
array_uint_push_back(v, i);
|
||||
|
||||
array_uint_resize(v, 10);
|
||||
assert(array_uint_size(v) == 10);
|
||||
assert(*array_uint_cget(v, 9) == 10);
|
||||
array_uint_resize(v, 1000);
|
||||
assert(array_uint_size(v) == 1000);
|
||||
assert(*array_uint_cget(v, 999) == 0);
|
||||
|
||||
array_uint_t v2;
|
||||
array_uint_init_set(v2,v);
|
||||
array_uint_clear(v);
|
||||
assert(array_uint_size(v2) == 1000);
|
||||
assert(*array_uint_cget(v2, 999) == 0);
|
||||
array_uint_push_at (v2, 0, 1742);
|
||||
assert (array_uint_size(v2) == 1001);
|
||||
assert(*array_uint_cget(v2, 0) == 1742);
|
||||
assert(*array_uint_cget(v2, 1000) == 0);
|
||||
|
||||
array_uint_insert_v (v2, 500, 504);
|
||||
assert (array_uint_size(v2) == 1005);
|
||||
assert(*array_uint_cget(v2, 0) == 1742);
|
||||
assert(*array_uint_cget(v2, 500) == 0);
|
||||
assert(array_uint_size(v2) == 1005);
|
||||
assert(*array_uint_cget(v2, 1004) == 0);
|
||||
|
||||
array_uint_clear(v2);
|
||||
}
|
||||
|
||||
static void test_mpz(void)
|
||||
{
|
||||
array_mpz_t array1, array2;
|
||||
mpz_t z;
|
||||
|
||||
array_mpz_init (array1);
|
||||
array_mpz_init (array2);
|
||||
mpz_init (z);
|
||||
|
||||
for(int n = 0; n < 1000; n++) {
|
||||
mpz_set_ui (z, n);
|
||||
array_mpz_push_back (array1, z);
|
||||
}
|
||||
|
||||
FILE *f = fopen ("a.dat", "wt");
|
||||
if (!f) abort();
|
||||
array_mpz_out_str(f, array1);
|
||||
fclose (f);
|
||||
|
||||
f = fopen ("a.dat", "rt");
|
||||
if (!f) abort();
|
||||
bool b = array_mpz_in_str (array2, f);
|
||||
assert (b == true);
|
||||
assert (array_mpz_equal_p (array1, array2));
|
||||
fclose(f);
|
||||
|
||||
array_mpz_clean(array1);
|
||||
|
||||
M_LET(str, STRING_OPLIST) {
|
||||
array_mpz_get_str(str, array1, false);
|
||||
assert (string_cmp_str (str, "[]") == 0);
|
||||
mpz_set_ui (z, 17);
|
||||
array_mpz_push_back (array1, z);
|
||||
array_mpz_get_str(str, array1, false);
|
||||
assert (string_cmp_str (str, "[17]") == 0);
|
||||
mpz_set_ui (z, 42);
|
||||
array_mpz_push_back (array1, z);
|
||||
array_mpz_get_str(str, array1, true);
|
||||
assert (string_cmp_str (str, "[17][17,42]") == 0);
|
||||
// NOTE: Not the same order than list...
|
||||
}
|
||||
|
||||
mpz_clear (z);
|
||||
array_mpz_clear(array2);
|
||||
array_mpz_clear(array1);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_uint();
|
||||
test_mpz();
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m-bitset.h"
|
||||
|
||||
static void test1(void)
|
||||
{
|
||||
bitset_t set;
|
||||
|
||||
bitset_init(set);
|
||||
for(int i = 0; i < 100; i ++) {
|
||||
bitset_push_back(set, i%2);
|
||||
assert (bitset_back(set) == (i%2));
|
||||
}
|
||||
for(int i = 0; i < 100; i ++) {
|
||||
assert (bitset_get(set, i) == (i%2));
|
||||
}
|
||||
assert(bitset_size(set) == 100);
|
||||
assert(bitset_empty_p(set) == false);
|
||||
|
||||
bitset_t set2;
|
||||
bitset_init_set(set2, set);
|
||||
|
||||
bitset_clean(set);
|
||||
assert(bitset_size(set) == 0);
|
||||
assert(bitset_empty_p(set) == true);
|
||||
|
||||
assert(bitset_size(set2) == 100);
|
||||
assert(bitset_empty_p(set2) == false);
|
||||
bitset_resize(set2, 50);
|
||||
assert(bitset_size(set2) == 50);
|
||||
assert(bitset_empty_p(set2) == false);
|
||||
for(int i = 0; i < 50; i ++) {
|
||||
assert (bitset_get(set2, i) == (i%2));
|
||||
}
|
||||
|
||||
// Push from 0
|
||||
bitset_push_at(set2, 0, 1);
|
||||
assert (bitset_get(set2, 0) == 1);
|
||||
for(int i = 1; i < 51; i ++) {
|
||||
assert (bitset_get(set2, i) == ((i-1)%2));
|
||||
}
|
||||
// Push from not aligned bit
|
||||
bitset_push_at(set2, 9, 1);
|
||||
for(int i = 1; i < 9; i ++) {
|
||||
assert (bitset_get(set2, i) == ((i-1)%2));
|
||||
}
|
||||
assert (bitset_get(set2, 9) == 1);
|
||||
for(int i = 10; i < 52; i ++) {
|
||||
assert (bitset_get(set2, i) == ((i)%2));
|
||||
}
|
||||
|
||||
bool b;
|
||||
bitset_pop_back(NULL, set2);
|
||||
bitset_pop_back(&b, set2);
|
||||
assert(b == false);
|
||||
assert(bitset_size(set2) == 50);
|
||||
|
||||
for(int i = 0; i < 200; i++)
|
||||
bitset_push_back(set, (i%2));
|
||||
bitset_pop_at(&b, set, 0);
|
||||
assert (b == false);
|
||||
assert (bitset_size(set) == 199);
|
||||
bitset_pop_at(&b, set, 0);
|
||||
assert (b == true);
|
||||
assert (bitset_size(set) == 198);
|
||||
bitset_pop_at(&b, set, 9);
|
||||
assert (b == true);
|
||||
assert (bitset_size(set) == 197);
|
||||
bitset_pop_at(&b, set, 9);
|
||||
assert (b == false);
|
||||
assert (bitset_size(set) == 196);
|
||||
|
||||
bitset_clean(set);
|
||||
for(int i = 0; i < 200; i++)
|
||||
bitset_push_back(set, (i*17547854547UL)&1) ;
|
||||
bitset_it_t it;
|
||||
int n = 0;
|
||||
for(bitset_it(it, set); ! bitset_end_p(it); bitset_next(it)) {
|
||||
bool v = (n*17547854547UL)&1;
|
||||
bool c = bitset_ref(it);
|
||||
assert (v == c);
|
||||
n++;
|
||||
}
|
||||
|
||||
bitset_clear(set);
|
||||
bitset_clear(set2);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test1();
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "m-buffer.h"
|
||||
|
||||
// Define a fixed queue of unsigned int
|
||||
BUFFER_DEF(uint, unsigned int, 10, BUFFER_QUEUE|BUFFER_BLOCKING)
|
||||
|
||||
// Define a variable stack of float
|
||||
BUFFER_DEF(floats, float, 0, BUFFER_STACK|BUFFER_BLOCKING)
|
||||
|
||||
// Define a fixed stack of char
|
||||
BUFFER_DEF(char, char, 10, BUFFER_STACK|BUFFER_UNBLOCKING)
|
||||
|
||||
// Define a fixed queue of long long
|
||||
BUFFER_DEF(llong, long long, 16, BUFFER_QUEUE|BUFFER_THREAD_UNSAFE|BUFFER_UNBLOCKING)
|
||||
|
||||
#include <gmp.h>
|
||||
BUFFER_DEF(mpz, mpz_t, 32, BUFFER_QUEUE, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear)))
|
||||
|
||||
buffer_uint_t g_buff;
|
||||
|
||||
static void *conso(void *arg)
|
||||
{
|
||||
unsigned int j;
|
||||
assert (arg == NULL);
|
||||
for(int i = 0; i < 1000;i++) {
|
||||
buffer_uint_pop(&j, g_buff);
|
||||
assert (j < 1000);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *prod(void *arg)
|
||||
{
|
||||
assert (arg == NULL);
|
||||
for(unsigned int i = 0; i < 1000;i++)
|
||||
buffer_uint_push(g_buff, i);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void test_global(void)
|
||||
{
|
||||
M_THREAD_T idx_p[100];
|
||||
M_THREAD_T idx_c[100];
|
||||
|
||||
buffer_uint_init(g_buff, 10);
|
||||
|
||||
for(int i = 0; i < 100; i++) {
|
||||
M_THREAD_CREATE (idx_p[i], conso, NULL);
|
||||
M_THREAD_CREATE (idx_c[i], prod, NULL);
|
||||
}
|
||||
for(int i = 0; i < 100;i++) {
|
||||
M_THREAD_JOIN(idx_p[i]);
|
||||
M_THREAD_JOIN(idx_c[i]);
|
||||
}
|
||||
|
||||
buffer_uint_clear(g_buff);
|
||||
}
|
||||
|
||||
static void test_stack(void)
|
||||
{
|
||||
buffer_floats_t buff;
|
||||
buffer_floats_init(buff, 100);
|
||||
for(unsigned int i = 0; i < 100; i++) {
|
||||
float f = i;
|
||||
buffer_floats_push(buff, f);
|
||||
assert (buffer_floats_empty_p(buff) == false);
|
||||
}
|
||||
assert (buffer_floats_full_p(buff) == true);
|
||||
for(unsigned int i = 0; i < 100; i++) {
|
||||
float j;
|
||||
buffer_floats_pop(&j, buff);
|
||||
assert(j == 99-i);
|
||||
assert (buffer_floats_full_p(buff) == false);
|
||||
}
|
||||
assert (buffer_floats_empty_p(buff) == true);
|
||||
buffer_floats_clear(buff);
|
||||
}
|
||||
|
||||
static void test_stack2(void)
|
||||
{
|
||||
buffer_char_t buff;
|
||||
bool b;
|
||||
char c;
|
||||
buffer_char_init(buff, 10);
|
||||
for(int i = 0; i < 10; i++) {
|
||||
c = i;
|
||||
b = buffer_char_push(buff, c);
|
||||
assert (b == true);
|
||||
assert (buffer_char_empty_p(buff) == false);
|
||||
}
|
||||
b = buffer_char_push(buff, c);
|
||||
assert (b == false);
|
||||
assert (buffer_char_full_p(buff) == true);
|
||||
for(int i = 0; i < 10; i++) {
|
||||
buffer_char_pop(&c, buff);
|
||||
assert(c == 9-i);
|
||||
assert (buffer_char_full_p(buff) == false);
|
||||
}
|
||||
b = buffer_char_pop(&c, buff);
|
||||
assert (b == false);
|
||||
assert (buffer_char_empty_p(buff) == true);
|
||||
buffer_char_clear(buff);
|
||||
}
|
||||
|
||||
static void test_no_thread(void)
|
||||
{
|
||||
buffer_llong_t buff;
|
||||
bool b;
|
||||
long long c;
|
||||
buffer_llong_init(buff, 16);
|
||||
for(int i = 0; i < 16; i++) {
|
||||
c = i;
|
||||
b = buffer_llong_push(buff, c);
|
||||
assert (b == true);
|
||||
assert (buffer_llong_empty_p(buff) == false);
|
||||
}
|
||||
b = buffer_llong_push(buff, c);
|
||||
assert (b == false);
|
||||
assert (buffer_llong_full_p(buff) == true);
|
||||
for(int i = 0; i < 16; i++) {
|
||||
buffer_llong_pop(&c, buff);
|
||||
assert(c == i);
|
||||
assert (buffer_llong_full_p(buff) == false);
|
||||
}
|
||||
b = buffer_llong_pop(&c, buff);
|
||||
assert (b == false);
|
||||
assert (buffer_llong_empty_p(buff) == true);
|
||||
buffer_llong_clear(buff);
|
||||
}
|
||||
|
||||
/* Test intrusive shared pointer + buffer */
|
||||
#include "m-i-shared.h"
|
||||
// Tiny test structure
|
||||
typedef struct test_s {
|
||||
char buffer[52];
|
||||
char bigbuffer[1000000];
|
||||
ISHARED_PTR_INTERFACE(itest, struct test_s);
|
||||
} test_t;
|
||||
|
||||
static void test_init(test_t *p) { memset(p->buffer, 0x00, 52); }
|
||||
static void test_clear(test_t *p) { memset(p->buffer, 0xFF, 52); }
|
||||
ISHARED_PTR_DEF(itest, test_t,
|
||||
(INIT(test_init M_IPTR), CLEAR(test_clear M_IPTR), DEL(free)))
|
||||
static test_t *test_new(void)
|
||||
{
|
||||
test_t *p = malloc (sizeof (test_t));
|
||||
assert (p != NULL);
|
||||
test_init (p);
|
||||
return ishared_itest_init(p);
|
||||
}
|
||||
BUFFER_DEF(itest, test_t *, 16, BUFFER_PUSH_INIT_POP_MOVE,
|
||||
ISHARED_PTR_OPLIST(itest))
|
||||
static buffer_itest_t comm1;
|
||||
static buffer_itest_t comm2;
|
||||
|
||||
static void *test_conso1(void *arg)
|
||||
{
|
||||
test_t *p;
|
||||
assert (arg == NULL);
|
||||
for(int i = 0; i < 10;i++) {
|
||||
buffer_itest_pop(&p, comm1);
|
||||
for(int j = 0; j < 52; j++)
|
||||
assert (p->buffer[j] == (char) ((j * j * 17) + j * 42 + 1));
|
||||
ishared_itest_release(p);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
static void *test_conso2(void *arg)
|
||||
{
|
||||
test_t *p;
|
||||
assert (arg == NULL);
|
||||
for(int i = 0; i < 10;i++) {
|
||||
buffer_itest_pop(&p, comm2);
|
||||
for(int j = 0; j < 52; j++)
|
||||
assert (p->buffer[j] == (char) ((j * j * 17) + j * 42 + 1));
|
||||
ishared_itest_release(p);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
static void *test_prod(void *arg)
|
||||
{
|
||||
assert (arg == NULL);
|
||||
for(unsigned int i = 0; i < 10;i++) {
|
||||
test_t *p = test_new();
|
||||
for(int j = 0; j < 52; j++)
|
||||
p->buffer[j] = (j * j * 17) + j * 42 + 1;
|
||||
buffer_itest_push(comm1, p);
|
||||
buffer_itest_push(comm2, p);
|
||||
ishared_itest_release(p);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void test_global_ishared(void)
|
||||
{
|
||||
M_THREAD_T idx_p[100];
|
||||
M_THREAD_T idx_c1[100];
|
||||
M_THREAD_T idx_c2[100];
|
||||
|
||||
buffer_itest_init(comm1, 16);
|
||||
buffer_itest_init(comm2, 16);
|
||||
|
||||
for(int i = 0; i < 100; i++) {
|
||||
M_THREAD_CREATE (idx_c1[i], test_conso1, NULL);
|
||||
M_THREAD_CREATE (idx_c2[i], test_conso2, NULL);
|
||||
M_THREAD_CREATE (idx_p[i], test_prod, NULL);
|
||||
}
|
||||
for(int i = 0; i < 100;i++) {
|
||||
M_THREAD_JOIN(idx_p[i]);
|
||||
M_THREAD_JOIN(idx_c1[i]);
|
||||
M_THREAD_JOIN(idx_c2[i]);
|
||||
}
|
||||
|
||||
buffer_itest_clear(comm1);
|
||||
buffer_itest_clear(comm2);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned int x, y;
|
||||
buffer_uint_t v;
|
||||
buffer_uint_init(v, 10);
|
||||
|
||||
assert (buffer_uint_empty_p(v) == true);
|
||||
assert (buffer_uint_full_p(v) == false);
|
||||
|
||||
x = 10;
|
||||
buffer_uint_push (v, x);
|
||||
|
||||
assert (buffer_uint_empty_p(v) == false);
|
||||
assert (buffer_uint_full_p(v) == false);
|
||||
|
||||
buffer_uint_pop (&y, v);
|
||||
|
||||
assert (buffer_uint_empty_p(v) == true);
|
||||
assert (buffer_uint_full_p(v) == false);
|
||||
assert (y == 10);
|
||||
|
||||
buffer_uint_clear(v);
|
||||
|
||||
test_global();
|
||||
test_stack();
|
||||
test_stack2();
|
||||
test_no_thread();
|
||||
test_global_ishared();
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include "m-core.h"
|
||||
|
||||
static void test_cat(void)
|
||||
{
|
||||
#define AandB true
|
||||
#define AandBandC true
|
||||
assert (CAT(A,andB));
|
||||
assert (CAT3(A,and,B));
|
||||
assert (CAT4(A,and,B,andC));
|
||||
}
|
||||
|
||||
static void test_power2(void)
|
||||
{
|
||||
assert (M_POWEROF2_P(1));
|
||||
assert (M_POWEROF2_P(2));
|
||||
assert (!M_POWEROF2_P(3));
|
||||
assert (M_POWEROF2_P(4));
|
||||
assert (!M_POWEROF2_P(5));
|
||||
assert (!M_POWEROF2_P(6));
|
||||
assert (!M_POWEROF2_P(7));
|
||||
assert (M_POWEROF2_P(8));
|
||||
}
|
||||
|
||||
static void test_incdec(void)
|
||||
{
|
||||
assert (M_INC(0) == 1);
|
||||
assert (M_INC(1) == 2);
|
||||
assert (M_INC(2) == 3);
|
||||
assert (M_INC(3) == 4);
|
||||
assert (M_INC(4) == 5);
|
||||
assert (M_INC(5) == 6);
|
||||
assert (M_INC(6) == 7);
|
||||
assert (M_INC(7) == 8);
|
||||
assert (M_INC(8) == 9);
|
||||
assert (M_INC(9) == 10);
|
||||
assert (M_INC(10) == 11);
|
||||
assert (M_INC(11) == 12);
|
||||
assert (M_INC(12) == 13);
|
||||
assert (M_INC(13) == 14);
|
||||
assert (M_INC(14) == 15);
|
||||
assert (M_INC(15) == 16);
|
||||
assert (M_INC(16) == 17);
|
||||
assert (M_INC(17) == 18);
|
||||
assert (M_INC(18) == 19);
|
||||
assert (M_INC(19) == 20);
|
||||
assert (M_INC(20) == 21);
|
||||
assert (M_INC(21) == 22);
|
||||
assert (M_INC(22) == 23);
|
||||
assert (M_INC(23) == 24);
|
||||
assert (M_INC(24) == 25);
|
||||
assert (M_INC(25) == 26);
|
||||
assert (M_INC(26) == 27);
|
||||
assert (M_INC(27) == 28);
|
||||
assert (M_INC(28) == 29);
|
||||
|
||||
assert ((0) == M_DEC(1));
|
||||
assert ((1) == M_DEC(2));
|
||||
assert ((2) == M_DEC(3));
|
||||
assert ((3) == M_DEC(4));
|
||||
assert ((4) == M_DEC(5));
|
||||
assert ((5) == M_DEC(6));
|
||||
assert ((6) == M_DEC(7));
|
||||
assert ((7) == M_DEC(8));
|
||||
assert ((8) == M_DEC(9));
|
||||
assert ((9) == M_DEC(10));
|
||||
assert ((10) == M_DEC(11));
|
||||
assert ((11) == M_DEC(12));
|
||||
assert ((12) == M_DEC(13));
|
||||
assert ((13) == M_DEC(14));
|
||||
assert ((14) == M_DEC(15));
|
||||
assert ((15) == M_DEC(16));
|
||||
assert ((16) == M_DEC(17));
|
||||
assert ((17) == M_DEC(18));
|
||||
assert ((18) == M_DEC(19));
|
||||
assert ((19) == M_DEC(20));
|
||||
assert ((20) == M_DEC(21));
|
||||
assert ((21) == M_DEC(22));
|
||||
assert ((22) == M_DEC(23));
|
||||
assert ((23) == M_DEC(24));
|
||||
assert ((24) == M_DEC(25));
|
||||
assert ((25) == M_DEC(26));
|
||||
assert ((26) == M_DEC(27));
|
||||
assert ((27) == M_DEC(28));
|
||||
assert ((28) == M_DEC(29));
|
||||
|
||||
assert( M_ADD(2,5) == M_SUB(10,3));
|
||||
assert( M_ADD(5,15) == M_SUB(25,5));
|
||||
}
|
||||
|
||||
static void test_return(void)
|
||||
{
|
||||
assert (M_RET_ARG1(1, 0));
|
||||
assert (M_RET_ARG2(0, 1, 0));
|
||||
assert (M_RET_ARG3(0, 0, 1, 0));
|
||||
assert (M_RET_ARG27(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0));
|
||||
}
|
||||
|
||||
static void test_invert(void)
|
||||
{
|
||||
assert (M_RET_ARG1 M_INVERT(0,1));
|
||||
assert (M_RET_ARG1 M_INVERT(0,0,1));
|
||||
assert (M_RET_ARG1 M_INVERT(0,0,0,1));
|
||||
assert (M_RET_ARG1 M_INVERT(0,0,0,0,1));
|
||||
}
|
||||
|
||||
static void test_min(void)
|
||||
{
|
||||
assert (M_MIN(1,2) == 1);
|
||||
assert (M_MIN(1,-2) == -2);
|
||||
assert (M_MAX(1,2) == 2);
|
||||
assert (M_MAX(1,-2) == 1);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_cat();
|
||||
test_power2();
|
||||
test_incdec();
|
||||
test_return();
|
||||
test_invert();
|
||||
test_min();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <limits.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
DICT_DEF2(str, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
|
||||
ARRAY_DEF(string, string_t, STRING_OPLIST)
|
||||
|
||||
array_string_t v;
|
||||
|
||||
static void init_data(int data_size)
|
||||
{
|
||||
uint32_t x = 11;
|
||||
string_t s;
|
||||
string_init (s);
|
||||
printf("--- generating data\n");
|
||||
for (int i = 0; i < data_size; ++i) {
|
||||
int j = (unsigned)(data_size * ((double)x / UINT_MAX) / 4) * 271828183u;
|
||||
string_printf(s, "%x", j);
|
||||
array_string_push_back (v, s);
|
||||
x = 1664525L * x + 1013904223L;
|
||||
}
|
||||
string_clear(s);
|
||||
printf("--- done!\n");
|
||||
}
|
||||
|
||||
static void clear_data(void)
|
||||
{
|
||||
array_string_clear(v);
|
||||
}
|
||||
|
||||
static void test_data(void)
|
||||
{
|
||||
dict_str_t dict;
|
||||
int data_size = (int) array_string_size(v);
|
||||
|
||||
dict_str_init (dict);
|
||||
for (int i = 0; i < data_size; ++i) {
|
||||
dict_str_set_at(dict, *array_string_cget(v, i), *array_string_cget(v, (i+1) % data_size));
|
||||
}
|
||||
assert(dict_str_size(dict) == 1227176);
|
||||
dict_str_clear (dict);
|
||||
}
|
||||
|
||||
static void timing(void (*f)(void))
|
||||
{
|
||||
clock_t t = clock();
|
||||
(*f)();
|
||||
printf("timing %.3lf sec\n", (double)(clock() - t) / CLOCKS_PER_SEC);
|
||||
}
|
||||
|
||||
static void check_io(void)
|
||||
{
|
||||
M_LET(str, STRING_OPLIST)
|
||||
M_LET(dict, DICT_OPLIST(str)) {
|
||||
dict_str_get_str(str, dict, false);
|
||||
assert (string_cmp_str (str, "{}") == 0);
|
||||
dict_str_set_at (dict, STRING_CTE("LICENCE"), STRING_CTE("BSD3"));
|
||||
dict_str_get_str(str, dict, false);
|
||||
assert (string_cmp_str (str, "{\"LICENCE\":\"BSD3\"}") == 0);
|
||||
dict_str_set_at (dict, STRING_CTE("AUTHOR"), STRING_CTE("PP"));
|
||||
dict_str_get_str(str, dict, false);
|
||||
assert (string_cmp_str (str, "{\"AUTHOR\":\"PP\",\"LICENCE\":\"BSD3\"}") == 0);
|
||||
FILE *f = fopen ("a.dat", "wt");
|
||||
if (!f) abort();
|
||||
dict_str_out_str(f, dict);
|
||||
fclose (f);
|
||||
f = fopen ("a.dat", "rt");
|
||||
if (!f) abort();
|
||||
M_LET(dict2, DICT_OPLIST(str)) {
|
||||
bool b = dict_str_in_str(dict2, f);
|
||||
assert (b == true);
|
||||
/* assert (dict_str_equal_p (dict, dict2)); */
|
||||
}
|
||||
fclose (f);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
dict_str_t dict;
|
||||
string_t key, ref;
|
||||
|
||||
dict_str_init(dict);
|
||||
string_init(key);
|
||||
string_init(ref);
|
||||
|
||||
FILE *f = fopen("dict.txt", "rt");
|
||||
if (!f) abort();
|
||||
dict_str_set_at(dict, STRING_CTE("LICENCE"), STRING_CTE("BSD3"));
|
||||
while (!feof(f) && !ferror(f)) {
|
||||
string_fgets(key, f, STRING_READ_PURE_LINE);
|
||||
size_t idx = string_search_char(key, ':');
|
||||
string_set(ref, key);
|
||||
string_right(ref, idx+1);
|
||||
string_left(key, idx);
|
||||
dict_str_set_at (dict, key, ref);
|
||||
}
|
||||
fclose(f);
|
||||
assert(dict_str_size(dict) == 19);
|
||||
|
||||
f = fopen("dict.txt", "rt");
|
||||
if (!f) abort();
|
||||
while (!feof(f) && !ferror(f)) {
|
||||
string_fgets(key, f, STRING_READ_PURE_LINE);
|
||||
size_t idx = string_search_char(key, ':');
|
||||
string_set(ref, key);
|
||||
string_right(ref, idx+1);
|
||||
string_left(key, idx);
|
||||
string_t *ptr = dict_str_get (dict, key);
|
||||
assert(ptr != NULL);
|
||||
assert(string_equal_p (*ptr, ref) || string_cmp_str(ref, "lisez-moi") == 0);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
dict_str_set_at(dict, STRING_CTE("LICENCE"), STRING_CTE("BSD3"));
|
||||
assert(dict_str_size(dict) == 19);
|
||||
dict_str_set_at(dict, STRING_CTE("LICENCE"), STRING_CTE("BSD3"));
|
||||
assert(dict_str_size(dict) == 19);
|
||||
|
||||
size_t s = 0;
|
||||
bool check1 = false, check2= false;
|
||||
for M_EACH(r, dict, DICT_OPLIST(str)) {
|
||||
if (string_cmp_str((*r)->key, "README") == 0)
|
||||
check1 = true;
|
||||
if (string_cmp_str((*r)->value, "BSD3") == 0)
|
||||
check2 = true;
|
||||
//printf ("key=%s value=%s\n", string_get_cstr((*r)->key), string_get_cstr((*r)->value));
|
||||
s++;
|
||||
}
|
||||
assert(s == 19);
|
||||
assert(check1);
|
||||
assert(check2);
|
||||
string_clear(key);
|
||||
string_clear(ref);
|
||||
dict_str_clear(dict);
|
||||
|
||||
check_io();
|
||||
|
||||
init_data(5000000);
|
||||
timing(test_data);
|
||||
clear_data();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
[ key1: value1,
|
||||
key2: value2,
|
||||
key3: value3]
|
||||
|
||||
a;b;"c;e";d;e;f
|
||||
|
||||
TOKEN:
|
||||
* separator ; : , AND .
|
||||
* ignore ' ' '\n'
|
||||
* remove blanck
|
||||
* handle " or ' or ( ) or [ ]
|
||||
* recursive
|
||||
*/
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* MLIB - TEST module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m-i-list.h"
|
||||
|
||||
typedef struct test_s {
|
||||
int n;
|
||||
ILIST_INTERFACE (tname, struct test_s);
|
||||
} test_t;
|
||||
|
||||
ILIST_DEF(tname, test_t)
|
||||
|
||||
static void test(void)
|
||||
{
|
||||
test_t x1, x2, x3;
|
||||
ilist_tname_t list;
|
||||
|
||||
x1.n = 1;
|
||||
x2.n = 2;
|
||||
x3.n = 3;
|
||||
|
||||
ilist_tname_init(list);
|
||||
|
||||
assert (ilist_tname_size (list) == 0);
|
||||
ilist_tname_push_back (list, &x3);
|
||||
assert (ilist_tname_size (list) == 1);
|
||||
ilist_tname_push_front (list, &x1);
|
||||
assert (ilist_tname_size (list) == 2);
|
||||
ilist_tname_push_after (&x1, &x2);
|
||||
assert (ilist_tname_size (list) == 3);
|
||||
assert (ilist_tname_front (list)->n == 1);
|
||||
assert (ilist_tname_back (list)->n == 3);
|
||||
|
||||
int n = 1;
|
||||
for M_EACH(item, list, ILIST_OPLIST(tname)) {
|
||||
assert (n == item->n);
|
||||
n++;
|
||||
}
|
||||
for M_EACH(item, list, ILIST_OPLIST(tname)) {
|
||||
if (item->n == 2)
|
||||
ilist_tname_unlink(item);
|
||||
}
|
||||
assert (ilist_tname_size(list) == 2);
|
||||
assert (&x1 == ilist_tname_pop_front(list));
|
||||
assert (ilist_tname_size(list) == 1);
|
||||
assert (&x3 == ilist_tname_pop_back(list));
|
||||
assert (ilist_tname_size(list) == 0);
|
||||
assert (ilist_tname_empty_p(list));
|
||||
|
||||
for M_EACH(item, list, ILIST_OPLIST(tname)) {
|
||||
(void)item;
|
||||
assert(false);
|
||||
}
|
||||
|
||||
ilist_tname_clear(list);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test();
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <gmp.h> // For testing purpose only.
|
||||
#include "m-list.h"
|
||||
|
||||
LIST_DEF(uint, unsigned int)
|
||||
#define LIST_UINT_OPLIST LIST_OPLIST(uint)
|
||||
|
||||
static void my_mpz_out_str(FILE *f, const mpz_t z)
|
||||
{
|
||||
mpz_out_str (f, 10, z);
|
||||
}
|
||||
|
||||
static bool my_mpz_in_str(mpz_t z, FILE *f)
|
||||
{
|
||||
return mpz_inp_str (z, f, 10) > 0;
|
||||
}
|
||||
|
||||
static bool my_mpz_equal_p(const mpz_t z1, const mpz_t z2)
|
||||
{
|
||||
return mpz_cmp (z1, z2) == 0;
|
||||
}
|
||||
|
||||
#include "m-string.h"
|
||||
static void my_mpz_str(string_t str, const mpz_t z, bool append)
|
||||
{
|
||||
char *s = mpz_get_str(NULL, 10, z);
|
||||
if (append) string_cat_str (str, s);
|
||||
else string_set_str (str, s);
|
||||
free(s);
|
||||
}
|
||||
|
||||
LIST_DEF(mpz, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), \
|
||||
OUT_STR(my_mpz_out_str), IN_STR(my_mpz_in_str), EQUAL(my_mpz_equal_p), \
|
||||
GET_STR(my_mpz_str)))
|
||||
|
||||
static void test_uint(void)
|
||||
{
|
||||
list_uint_t v;
|
||||
list_uint_init(v);
|
||||
|
||||
assert (list_uint_empty_p(v) == true);
|
||||
|
||||
list_uint_push_back(v, 2);
|
||||
assert (list_uint_empty_p(v) == false);
|
||||
unsigned int x ;
|
||||
list_uint_pop_back(&x, v);
|
||||
assert( x == 2);
|
||||
assert (list_uint_empty_p(v) == true);
|
||||
assert (list_uint_size(v) == 0);
|
||||
|
||||
for(unsigned int i = 0; i < 1000; i ++) {
|
||||
list_uint_push_back(v, i);
|
||||
}
|
||||
assert (list_uint_size(v) == 1000);
|
||||
assert (*list_uint_cget(v, 500) == 500);
|
||||
assert (*list_uint_cget(v, 999) == 999);
|
||||
|
||||
list_it_uint_t u;
|
||||
unsigned int s = 0;
|
||||
for(list_uint_it(u, v); !list_uint_end_p(u); list_uint_next(u)) {
|
||||
s += *list_uint_cref(u);
|
||||
}
|
||||
assert (s == 1000*999/2);
|
||||
s = 0;
|
||||
for M_EACH(item, v, LIST_UINT_OPLIST) {
|
||||
s += *item;
|
||||
}
|
||||
assert (s == 1000*999/2);
|
||||
|
||||
list_uint_insert(v, u, 1996); // Insert in back since u is empty
|
||||
assert (list_uint_size(v) == 1001);
|
||||
list_uint_it(u, v);
|
||||
list_uint_insert(v, u, 1997); // Insert in second place
|
||||
assert (list_uint_size(v) == 1002);
|
||||
list_uint_pop_back(&x, v);
|
||||
assert (x == 1996);
|
||||
list_uint_pop_back(&x, v);
|
||||
assert (x == 1997);
|
||||
assert (list_uint_size(v) == 1000);
|
||||
|
||||
list_uint_push_back (v, x);
|
||||
list_uint_pop_back (NULL, v);
|
||||
|
||||
list_uint_t v2;
|
||||
list_it_uint_t u2;
|
||||
list_uint_init(v2);
|
||||
list_uint_set(v2,v);
|
||||
for(list_uint_it(u, v), list_uint_it(u2, v2); !list_uint_end_p(u); list_uint_next(u), list_uint_next(u2)) {
|
||||
assert(list_uint_end_p(u2) == false);
|
||||
assert(*list_uint_cref(u) == *list_uint_cref(u2));
|
||||
}
|
||||
|
||||
list_uint_it(u2, v2); //v2 is the first el
|
||||
assert (*list_uint_cref(u2) == 999);
|
||||
list_uint_next(u2); //v2 is the second el
|
||||
assert (*list_uint_cref(u2) == 998);
|
||||
list_uint_remove(v2, u2);// the second el is deleted
|
||||
list_uint_it(u2, v2); //v2 is the first el
|
||||
assert (*list_uint_cref(u2) == 999);
|
||||
list_uint_next(u2); //v2 is the second el
|
||||
assert (*list_uint_cref(u2) == 997);
|
||||
|
||||
list_uint_it(u2, v2); //v2 is the first el
|
||||
list_uint_remove(v2, u2);// the second el is deleted
|
||||
list_uint_it(u2, v2); //v2 is the first el
|
||||
assert (*list_uint_cref(u2) == 997);
|
||||
|
||||
list_uint_clean(v);
|
||||
assert (list_uint_empty_p(v) == true);
|
||||
assert (list_uint_empty_p(v2) == false);
|
||||
assert (list_uint_size(v2) == 998);
|
||||
|
||||
list_uint_set (v, v2);
|
||||
list_uint_slice (v, v2);
|
||||
assert (list_uint_empty_p(v) == false);
|
||||
assert (list_uint_empty_p(v2) == true);
|
||||
assert (list_uint_size(v) == 998*2);
|
||||
|
||||
list_uint_reverse(v2);
|
||||
assert (list_uint_empty_p(v2) == true);
|
||||
list_uint_push_back(v2, 12);
|
||||
list_uint_push_back(v2, 17);
|
||||
list_uint_reverse(v2);
|
||||
list_uint_pop_back(&x, v2);
|
||||
assert (x == 12);
|
||||
list_uint_pop_back(&x, v2);
|
||||
assert (x == 17);
|
||||
assert (list_uint_empty_p(v2) == true);
|
||||
|
||||
list_uint_clear(v);
|
||||
list_uint_clear(v2);
|
||||
}
|
||||
|
||||
static void test_mpz(void)
|
||||
{
|
||||
list_mpz_t v;
|
||||
mpz_t z, x, s;
|
||||
|
||||
mpz_init (z);
|
||||
mpz_init (x);
|
||||
mpz_init (s);
|
||||
|
||||
list_mpz_init(v);
|
||||
assert (list_mpz_empty_p(v) == true);
|
||||
|
||||
mpz_set_ui (z, 2);
|
||||
list_mpz_push_back(v, z);
|
||||
assert (list_mpz_empty_p(v) == false);
|
||||
|
||||
list_mpz_pop_back(&x, v);
|
||||
assert( mpz_cmp (x, z) == 0);
|
||||
assert (list_mpz_empty_p(v) == true);
|
||||
assert (list_mpz_size(v) == 0);
|
||||
|
||||
for(unsigned int i = 0; i < 1000; i ++) {
|
||||
mpz_set_ui (z, i);
|
||||
list_mpz_push_back(v, z);
|
||||
}
|
||||
assert (list_mpz_size(v) == 1000);
|
||||
|
||||
list_it_mpz_t u;
|
||||
mpz_set_ui (s, 0);
|
||||
for(list_mpz_it(u, v); !list_mpz_end_p(u); list_mpz_next(u)) {
|
||||
mpz_add (s, s, *list_mpz_cref(u));
|
||||
}
|
||||
assert (mpz_get_ui(s) == 1000*999/2);
|
||||
|
||||
FILE *f = fopen ("a.dat", "wt");
|
||||
if (!f) abort();
|
||||
list_mpz_out_str(f, v);
|
||||
fclose (f);
|
||||
|
||||
list_mpz_t list2;
|
||||
list_mpz_init(list2);
|
||||
f = fopen ("a.dat", "rt");
|
||||
bool b = list_mpz_in_str (list2, f);
|
||||
assert (b == true);
|
||||
fclose(f);
|
||||
assert (list_mpz_equal_p (v, list2));
|
||||
list_mpz_clear(list2);
|
||||
|
||||
list_mpz_clean(v);
|
||||
M_LET(str, STRING_OPLIST) {
|
||||
list_mpz_get_str(str, v, false);
|
||||
assert (string_cmp_str (str, "[]") == 0);
|
||||
mpz_set_ui (z, 17);
|
||||
list_mpz_push_back (v, z);
|
||||
list_mpz_get_str(str, v, false);
|
||||
assert (string_cmp_str (str, "[17]") == 0);
|
||||
mpz_set_ui (z, 42);
|
||||
list_mpz_push_back (v, z);
|
||||
list_mpz_get_str(str, v, true);
|
||||
assert (string_cmp_str (str, "[17][42,17]") == 0);
|
||||
}
|
||||
|
||||
list_mpz_clear(v);
|
||||
|
||||
mpz_clear (z);
|
||||
mpz_clear (x);
|
||||
mpz_clear (s);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_uint();
|
||||
test_mpz();
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <gmp.h> // For testing purpose only.
|
||||
#include "m-rbtree.h"
|
||||
|
||||
RBTREE_DEF(uint, unsigned int)
|
||||
#define UINT_OPLIST RBTREE_OPLIST(uint)
|
||||
|
||||
RBTREE_DEF(float, float)
|
||||
#define FLOAT_OP RBTREE_OPLIST(float)
|
||||
|
||||
static void test_uint(void)
|
||||
{
|
||||
rbtree_uint_t tree, tree2;
|
||||
rbtree_uint_init(tree);
|
||||
assert (rbtree_uint_empty_p(tree));
|
||||
rbtree_uint_init_set(tree2, tree);
|
||||
assert (rbtree_uint_empty_p(tree2));
|
||||
rbtree_uint_clear(tree);
|
||||
|
||||
const unsigned int max = 1001;
|
||||
for(unsigned int num = 1; num < max; num++) {
|
||||
rbtree_uint_init(tree);
|
||||
for(unsigned int i = 0; i < num; i++)
|
||||
rbtree_uint_push(tree, i);
|
||||
assert(rbtree_uint_size(tree) == num);
|
||||
assert(rbtree_uint_empty_p(tree) == false);
|
||||
unsigned int count = 0;
|
||||
for M_EACH(item, tree, UINT_OPLIST) {
|
||||
assert (count == *item);
|
||||
count ++;
|
||||
}
|
||||
assert (*rbtree_uint_min(tree) == 0);
|
||||
assert (*rbtree_uint_max(tree) == num-1);
|
||||
assert (count == num);
|
||||
rbtree_uint_set(tree2, tree);
|
||||
unsigned int *ptr = rbtree_uint_get(tree2, num/2);
|
||||
assert (ptr != NULL);
|
||||
assert (*ptr == num/2);
|
||||
rbtree_uint_clear(tree);
|
||||
|
||||
bool b = rbtree_uint_pop(NULL, tree2, num+1);
|
||||
assert (b == false);
|
||||
for(unsigned int i = 0; i < num; i+=3) {
|
||||
b = rbtree_uint_pop(NULL, tree2, i);
|
||||
assert(b);
|
||||
ptr = rbtree_uint_get(tree2, i);
|
||||
assert (ptr == NULL);
|
||||
}
|
||||
for(unsigned int i = 1; i < num; i+=3) {
|
||||
b = rbtree_uint_pop(NULL, tree2, i);
|
||||
assert(b);
|
||||
ptr = rbtree_uint_get(tree2, i);
|
||||
assert (ptr == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
rbtree_uint_clear(tree2);
|
||||
}
|
||||
|
||||
static void test_float(void)
|
||||
{
|
||||
M_LET(tree, FLOAT_OP) {
|
||||
for(float f = -17.42; f < 17.42; f+=0.01)
|
||||
rbtree_float_push (tree, f);
|
||||
bool p = false;
|
||||
float g;
|
||||
for M_EACH(item, tree, FLOAT_OP) {
|
||||
if (p) {
|
||||
assert (g < *item);
|
||||
}
|
||||
g = *item;
|
||||
p = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_uint();
|
||||
test_float();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#include "gmp.h"
|
||||
#include "m-array.h"
|
||||
#include "m-list.h"
|
||||
#include "m-register.h"
|
||||
|
||||
ARRAY_DEF (mpz, mpz_t, (INIT(mpz_init), CLEAR(mpz_clear), SET(mpz_set), INIT_SET(mpz_init_set)))
|
||||
LIST_DEF (uint, unsigned int, M_DEFAULT_OPLIST)
|
||||
|
||||
// Register new class: mpz_t
|
||||
#define TYPE mpz_t
|
||||
#define OPLIST (INIT(mpz_init), CLEAR(mpz_clear), SET(mpz_set), INIT_SET(mpz_init_set))
|
||||
#include M_REGISTER_TYPE
|
||||
|
||||
void mpq_init_set(mpq_t q, const mpq_t p)
|
||||
{
|
||||
mpq_init(q);
|
||||
mpq_set(q, p);
|
||||
}
|
||||
|
||||
// Register new class: mpq_t
|
||||
#define TYPE mpq_t
|
||||
#define OPLIST (INIT(mpq_init), CLEAR(mpq_clear), SET(mpq_set), INIT_SET(mpq_init_set))
|
||||
#include M_REGISTER_TYPE
|
||||
|
||||
#define TYPE array_mpz_t
|
||||
#define OPLIST ARRAY_OPLIST(mpz)
|
||||
//#include M_REGISTER_TYPE
|
||||
|
||||
//#define TYPE list_uint_t
|
||||
//#define OPLIST LIST_OPLIST(unsigned int)
|
||||
//#include M_REGISTER_TYPE
|
||||
|
||||
bool is42(array_mpz_t array)
|
||||
{
|
||||
bool retval = false;
|
||||
mpz_t *z = new(mpz_t);
|
||||
mpz_set_ui (*z, 42);
|
||||
for_each (item, array) {
|
||||
if (equal(*item, *z)) {
|
||||
retval = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete(z);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void example(void)
|
||||
{
|
||||
list_uint_t list;
|
||||
init(list);
|
||||
push(list, 42);
|
||||
push(list, 17);
|
||||
for_each (item, list) {
|
||||
print(*item, "\n");
|
||||
}
|
||||
clear(list);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include "m-shared.h"
|
||||
|
||||
SHARED_PTR_DEF(int, int)
|
||||
|
||||
#include <gmp.h>
|
||||
|
||||
SHARED_PTR_DEF(mpz, mpz_t, (CLEAR(mpz_clear)))
|
||||
|
||||
static int f(const shared_int_t p)
|
||||
{
|
||||
return *shared_int_cref(p);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
shared_int_t p1, p2;
|
||||
|
||||
shared_int_init2(p1, malloc(sizeof(int)));
|
||||
assert(shared_int_ref(p1) != NULL);
|
||||
|
||||
*shared_int_ref(p1) = 12;
|
||||
|
||||
shared_int_init_set(p2, p1);
|
||||
assert(f(p2) == 12);
|
||||
|
||||
shared_int_release(p1);
|
||||
assert(shared_int_NULL_p(p1));
|
||||
assert(f(p2) == 12);
|
||||
|
||||
shared_int_set(p1, p2);
|
||||
|
||||
shared_int_release(p2);
|
||||
assert(shared_int_NULL_p(p2));
|
||||
|
||||
assert(f(p1) == 12);
|
||||
shared_int_set(p2, p1);
|
||||
assert(f(p2) == 12);
|
||||
|
||||
shared_int_release(p2);
|
||||
shared_int_release(p1);
|
||||
|
||||
assert(shared_int_NULL_p(p1));
|
||||
assert(shared_int_NULL_p(p2));
|
||||
|
||||
shared_int_clear(p2);
|
||||
shared_int_clear(p1);
|
||||
|
||||
shared_int_init2(p1, NULL);
|
||||
assert(shared_int_NULL_p(p1));
|
||||
shared_int_clear(p1);
|
||||
|
||||
shared_int_init(p1);
|
||||
assert(shared_int_NULL_p(p1));
|
||||
shared_int_clear(p1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <gmp.h> // For testing purpose only.
|
||||
#include "m-snapshot.h"
|
||||
|
||||
SNAPSHOT_DEF(uint, unsigned int)
|
||||
SNAPSHOT_DEF(mpz, mpz_t,
|
||||
(INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear)))
|
||||
|
||||
static void test_uint(void)
|
||||
{
|
||||
unsigned int *p_w;
|
||||
const unsigned int *p_r;
|
||||
snapshot_uint_t t;
|
||||
snapshot_uint_init(t);
|
||||
|
||||
p_r = snapshot_uint_look(t);
|
||||
assert (p_r == snapshot_uint_get_consummed(t));
|
||||
assert(*p_r == 0);
|
||||
assert(snapshot_uint_look(t) == p_r);
|
||||
|
||||
p_w = snapshot_uint_take(t);
|
||||
assert (p_w != p_r);
|
||||
*p_w = 1;
|
||||
assert (*p_r == 0);
|
||||
assert (snapshot_uint_look(t) != p_r);
|
||||
assert (*snapshot_uint_look(t) == 0);
|
||||
p_r = snapshot_uint_look(t);
|
||||
|
||||
p_w = snapshot_uint_take(t);
|
||||
*p_w = 2;
|
||||
assert (*snapshot_uint_look(t) == 1);
|
||||
|
||||
p_w = snapshot_uint_take(t);
|
||||
assert (p_w == snapshot_uint_get_produced(t));
|
||||
*p_w = 3;
|
||||
p_w = snapshot_uint_take(t);
|
||||
*p_w = 4;
|
||||
assert (*snapshot_uint_look(t) == 3);
|
||||
|
||||
snapshot_uint_t t2;
|
||||
snapshot_uint_init_set (t2, t);
|
||||
snapshot_uint_clear(t);
|
||||
assert (*snapshot_uint_look(t) == 3);
|
||||
snapshot_uint_init(t);
|
||||
snapshot_uint_set (t, t2);
|
||||
assert (*snapshot_uint_look(t) == 3);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_uint();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "m-string.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
string_t s1;
|
||||
STRING_DECL_INIT (s2);
|
||||
size_t i, j;
|
||||
bool b;
|
||||
|
||||
string_init (s1);
|
||||
|
||||
string_set_str (s1, "Hello, world!");
|
||||
assert (string_get_length(s1) == 13);
|
||||
assert (string_get_char(s1, 1) == 'e');
|
||||
|
||||
string_clean(s1);
|
||||
assert (string_get_length(s1) == 0);
|
||||
assert (string_empty_p(s1) == true);
|
||||
assert (strcmp(string_get_cstr(s1), "") == 0);
|
||||
|
||||
string_set_strn(s1, "Hello, world!", 14);
|
||||
assert (strcmp(string_get_cstr(s1), "Hello, world!") == 0);
|
||||
string_clean(s1);
|
||||
string_set_strn(s1, "Hello, world!", 5);
|
||||
assert (strcmp(string_get_cstr(s1), "Hello") == 0);
|
||||
string_clean(s1);
|
||||
|
||||
string_set_str (s1, "Hello beautiful world!");
|
||||
assert (string_get_length(s1) == 22);
|
||||
assert (strcmp(string_get_cstr(s1), "Hello beautiful world!") == 0);
|
||||
|
||||
string_clean(s1);
|
||||
string_set_str(s1, "Hello");
|
||||
string_cat_str(s1, ", world!");
|
||||
assert (string_get_length(s1) == 13);
|
||||
assert (string_cmp_str(s1, "Hello, world!") == 0);
|
||||
string_set_str(s2, "Hello, world!");
|
||||
assert (string_cmp(s1, s2) == 0);
|
||||
|
||||
string_set_str(s2, "hELLO, world!");
|
||||
assert (string_cmpi(s1, s2) == 0);
|
||||
|
||||
i = string_search_char (s1, ',');
|
||||
assert (i == 5);
|
||||
i = string_search_char (s1, 'Z');
|
||||
assert (i == STRING_FAILURE);
|
||||
|
||||
i = string_search_rchar (s1, 'o');
|
||||
assert (i == 8);
|
||||
i = string_search_rchar (s1, 'Z');
|
||||
assert (i == STRING_FAILURE);
|
||||
|
||||
i = string_search_str (s1, "world");
|
||||
assert (i == 7);
|
||||
i = string_search_str (s1, "World");
|
||||
assert (i == STRING_FAILURE);
|
||||
|
||||
string_set (s2, s1);
|
||||
|
||||
j = string_search_char (s1, ',');
|
||||
string_left (s1, j);
|
||||
assert (string_cmp_str (s1, "Hello") == 0);
|
||||
|
||||
string_set (s1, s2);
|
||||
j = string_search_char (s1, ',');
|
||||
string_right (s1, j);
|
||||
assert (string_cmp_str (s1, ", world!") == 0);
|
||||
|
||||
string_set (s1, s2);
|
||||
j = string_search_char (s1, ',');
|
||||
string_mid (s1, j, 2);
|
||||
assert (string_cmp_str (s1, ", ") == 0);
|
||||
|
||||
string_set (s1, s2);
|
||||
b = string_replace_str (s1, "world", "Paul");
|
||||
assert (b == true);
|
||||
assert (string_cmp_str (s1, "Hello, Paul!") == 0);
|
||||
|
||||
b = string_replace_str (s1, "world", "Paul");
|
||||
assert (b == false);
|
||||
assert (string_cmp_str (s1, "Hello, Paul!") == 0);
|
||||
|
||||
b = string_replace_str (s1, "Paul", "Juliette");
|
||||
assert (b == true);
|
||||
assert (string_cmp_str (s1, "Hello, Juliette!") == 0);
|
||||
|
||||
string_printf (s1, "There is %d Paul!", 2);
|
||||
assert (string_cmp_str (s1, "There is 2 Paul!") == 0);
|
||||
assert (string_get_length (s1) == 16);
|
||||
|
||||
string_set_str(s1, "Hello, world()\n");
|
||||
i = string_cspn(s1, ",()");
|
||||
assert (i == 5);
|
||||
string_set_str(s1, "Hello (world)\n");
|
||||
i = string_cspn(s1, ",()");
|
||||
assert (i == 6);
|
||||
string_set_str(s1, "Hello (world)\n");
|
||||
i = string_spn(s1, "Hel");
|
||||
assert (i == 4);
|
||||
|
||||
string_clear (s1);
|
||||
string_init (s1);
|
||||
|
||||
assert (string_cmp_str (s1, "") == 0);
|
||||
assert (string_cmpi (s1, s1) == 0);
|
||||
|
||||
string_set_str(s2, "Hello");
|
||||
string_cat (s2, s1);
|
||||
assert (string_cmp_str (s2, "Hello") == 0);
|
||||
|
||||
string_set_str(s2, "Hello");
|
||||
string_cat (s1, s2);
|
||||
assert (string_cmp_str (s1, "Hello") == 0);
|
||||
|
||||
string_clear (s1);
|
||||
string_init (s1);
|
||||
|
||||
string_left(s1, 100);
|
||||
assert (string_empty_p (s1));
|
||||
assert (string_get_length (s1) == 0);
|
||||
assert (string_cmp_str (s1, "") == 0);
|
||||
|
||||
string_right(s1, 100);
|
||||
assert (string_empty_p (s1));
|
||||
assert (string_get_length (s1) == 0);
|
||||
assert (string_cmp_str (s1, "") == 0);
|
||||
|
||||
string_set_str(s2, "Hello");
|
||||
string_set (s2, s1);
|
||||
assert (string_empty_p (s2));
|
||||
assert (string_get_length (s2) == 0);
|
||||
assert (string_cmp_str (s2, "") == 0);
|
||||
|
||||
string_set_str(s1, "Hello, world!");
|
||||
assert(string_start_with_str_p(s1, "Hello") == true);
|
||||
assert(string_start_with_str_p(s1, "Help") == false);
|
||||
string_set_str(s2, "H");
|
||||
assert(string_start_with_string_p(s1, s2) == true);
|
||||
|
||||
string_cat_printf(s1, " %d little %s.", 10, "suns");
|
||||
string_set_str(s2, "Hello, world! 10 little suns.");
|
||||
assert(string_equal_p(s1, s2) == true);
|
||||
|
||||
string_set_str(s1, " \r\n\t HELLO \n\r\t");
|
||||
string_strim(s1);
|
||||
assert (string_cmp_str (s1, "HELLO") == 0);
|
||||
|
||||
string_set_str(s1, " \r\n\t \n\r\t");
|
||||
string_strim(s1);
|
||||
assert (string_cmp_str (s1, "") == 0);
|
||||
|
||||
string_set_str(s1, "Hello world");
|
||||
string_get_str(s2, s1, false);
|
||||
assert (string_cmp_str (s2, "\"Hello world\"") == 0);
|
||||
string_set_str(s1, "Hello \"world\"");
|
||||
string_get_str(s2, s1, true);
|
||||
assert (string_cmp_str (s2, "\"Hello world\"\"Hello \\\"world\\\"\"") == 0);
|
||||
|
||||
string_set_str(s1, "Hello \"world\"");
|
||||
FILE *f = fopen ("a.dat", "wt");
|
||||
assert (f != NULL);
|
||||
string_out_str (f, s1);
|
||||
fclose (f);
|
||||
f = fopen("a.dat", "rt");
|
||||
assert (f != NULL);
|
||||
b = string_in_str(s2, f);
|
||||
assert(b);
|
||||
fclose(f);
|
||||
assert (string_equal_p(s1, s2));
|
||||
|
||||
string_clear (s1);
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <gmp.h>
|
||||
|
||||
#include "m-string.h"
|
||||
#include "m-tuple.h"
|
||||
|
||||
TUPLE_DEF2(pair,
|
||||
(key, string_t, (INIT(string_init), INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear))),
|
||||
(value, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear) )))
|
||||
|
||||
// No cmp defined
|
||||
TUPLE_DEF2(triple,
|
||||
(key, string_t, (INIT(string_init), INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear), CMP(string_cmp))),
|
||||
(value, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear) )),
|
||||
(data, const char *, ()))
|
||||
|
||||
// cmp shall be defined
|
||||
TUPLE_DEF2(pair3,
|
||||
(key, string_t, (INIT(string_init), INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear), CMP(string_cmp), HASH(string_hash), EQUAL(string_equal_p))),
|
||||
(value, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), CMP(mpz_cmp) )))
|
||||
|
||||
TUPLE_DEF2(pair_str,
|
||||
(vala, string_t, STRING_OPLIST),
|
||||
(valb, string_t, STRING_OPLIST))
|
||||
|
||||
static void check_io(void)
|
||||
{
|
||||
M_LET(s, STRING_OPLIST)
|
||||
M_LET(pair, TUPLE_OPLIST(pair_str, STRING_OPLIST, STRING_OPLIST))
|
||||
M_LET(pair2, TUPLE_OPLIST(pair_str, STRING_OPLIST, STRING_OPLIST)) {
|
||||
string_set_str(pair->vala, "Hello");
|
||||
string_set_str(pair->valb, "World");
|
||||
pair_str_get_str(s, pair, false);
|
||||
assert(string_cmp_str(s, "(\"Hello\",\"World\")") == 0);
|
||||
|
||||
FILE *f = fopen("a.dat", "wt");
|
||||
if (!f) abort();
|
||||
pair_str_out_str(f, pair);
|
||||
fclose(f);
|
||||
|
||||
f = fopen("a.dat", "rt");
|
||||
if (!f) abort();
|
||||
bool b = pair_str_in_str(pair2, f);
|
||||
assert (b);
|
||||
fclose(f);
|
||||
assert (pair_str_equal_p(pair, pair2) == true);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
pair_t p1, p2;
|
||||
|
||||
pair_init (p1);
|
||||
string_set_str(p1->key, "HELLO");
|
||||
mpz_set_str(p1->value, "1742", 10);
|
||||
pair_init_set (p2, p1);
|
||||
assert(mpz_cmp_ui(p2->value, 1742) == 0);
|
||||
assert(string_equal_str_p(p2->key, "HELLO"));
|
||||
string_set_str(p2->key, "HELLO WORLD");
|
||||
mpz_set_str(p2->value, "174217", 10);
|
||||
pair_set(p1, p2);
|
||||
assert(mpz_cmp_ui(p1->value, 174217) == 0);
|
||||
assert(string_equal_str_p(p1->key, "HELLO WORLD"));
|
||||
pair_clear(p1);
|
||||
pair_clear(p2);
|
||||
|
||||
string_t s;
|
||||
mpz_t z;
|
||||
pair3_t p3, p4;
|
||||
string_init_set_str(s, "HELLO");
|
||||
mpz_init_set_ui (z, 1442);
|
||||
pair3_init_set2(p3, s, z);
|
||||
pair3_init_set2(p4, s, z);
|
||||
int i = pair3_cmp (p3, p4);
|
||||
assert (i == 0);
|
||||
mpz_set_ui (z, 1443);
|
||||
pair3_set_value(p4, z);
|
||||
i = pair3_cmp (p3, p4);
|
||||
assert (i < 0);
|
||||
mpz_set_ui (z, 1442);
|
||||
string_set_str(s, "HELLN");
|
||||
pair3_set_key(p4, s);
|
||||
i = pair3_cmp (p3, p4);
|
||||
assert (i > 0);
|
||||
pair3_clear(p3);
|
||||
pair3_clear(p4);
|
||||
string_clear(s);
|
||||
mpz_clear(z);
|
||||
|
||||
check_io();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "m-list.h"
|
||||
|
||||
LIST_DEF(dbl, double)
|
||||
|
||||
void f_push_back(list_dbl_t list)
|
||||
{
|
||||
list_dbl_push_back(list, 2.0);
|
||||
}
|
||||
|
||||
double f_iterator(list_dbl_t list)
|
||||
{
|
||||
list_it_dbl_t it;
|
||||
double s = 0.0;
|
||||
for(list_dbl_it(it, list); !list_dbl_end_p(it); list_dbl_next(it))
|
||||
s += *list_dbl_cref(it);
|
||||
return s;
|
||||
}
|
||||
|
||||
struct tata {
|
||||
int x;
|
||||
};
|
||||
struct tutu {
|
||||
void (* const init) (void);
|
||||
void (* const add) (int *t);
|
||||
struct tata *data;
|
||||
};
|
||||
|
||||
int f(int p)
|
||||
{
|
||||
struct tata el_data;
|
||||
inline void __attribute__((always_inline)) el_init (void) { el_data.x = 0; };
|
||||
inline void __attribute__((always_inline)) el_add (int *t) { el_data.x += *t; };
|
||||
const struct tutu el = { .init = el_init, .add = el_add, .data = &el_data };
|
||||
|
||||
el.init();
|
||||
el.add (&p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF(unsigned int, uint)
|
||||
|
||||
unsigned int add_two(const array_uint_t tab, size_t i, size_t j)
|
||||
{
|
||||
return *array_uint_cref(tab, i) + *array_uint_cref(tab, j);
|
||||
}
|
||||
|
||||
void size_to_exactly(array_uint_t tab, size_t n)
|
||||
{
|
||||
array_uint_resize(tab, 0);
|
||||
array_uint_resize(tab, n);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "m-array.h"
|
||||
ARRAY_DEF(double, double)
|
||||
|
||||
int main(void) {
|
||||
const int n = 250000000;
|
||||
const double x = 0.001;
|
||||
M_LET(v, ARRAY_OPLIST(double)) {
|
||||
array_double_resize(v, n);
|
||||
#pragma omp parallel for
|
||||
for (int i = 0; i < array_double_size(v); ++i) {
|
||||
array_double_set_at(v, i, cos(i * x));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user