├── doc ├── depend.png ├── oplist.odp ├── oplist.png ├── Container.ods ├── bench-array.png ├── bench-list.png ├── bench-oset.png ├── bench-umap.png ├── bench-list-log.png ├── bench-oset-log.png ├── bench-umap-log.png ├── bench-array-log.png ├── cc.sh └── DEV.md ├── example ├── exn-lib.c ├── ex11-json01.json ├── exm-lib.c ├── exm-header.h ├── exm-main.c ├── ex-no-stdio.c ├── exn-header.h ├── ex11-algo02.json ├── exn-main.c ├── ex-array03.c ├── ex11-generic01.c ├── ex-dict04.c ├── ex11-algo01.c ├── ex-tree.c ├── ex-array04.c ├── ex-i-list.c ├── ex-dict05.c ├── ex11-section.c ├── ex-string01.c ├── ex-bptree02.c ├── ex-multi05.c ├── ex-dict01.c ├── ex-algo04.c ├── ex-dict06.c ├── ex-algo03.c ├── ex-string03.c ├── ex-dict02.c ├── ex11-json01.c ├── ex-grep01.c ├── ex-defer01.c ├── ex11-algo05-transform.c ├── ex11-small-name.c ├── ex-array02.c ├── ex11-json-net.c ├── ex-algo02.c ├── ex-try01.c ├── ex-alloc1.c ├── ex-dict03.c ├── ex-bptree01.c ├── ex-alloc2.c ├── ex11-tstc.c ├── ex-multi04.c ├── ex11-algo02.c ├── ex-array01.c ├── ex-multi01.c ├── Makefile ├── ex11-variant01.c ├── ex-string02.c ├── ex-array05.c ├── ex-rbtree01.c ├── ex-list01.c ├── ex11-generic02.c ├── ex-curl.c └── ex11-rbtree02.c ├── tests ├── dict.txt ├── tgen-mserial.c ├── tgen-openmp.c ├── test-mshared-ptr.h ├── synthesis.ref ├── tgen-tuple.c ├── tgen-bitset.c ├── tgen-queue.c ├── tgen-try.c ├── tgen-mstring.c ├── test-mmutex.c ├── check-array.cpp ├── check-rbtree.cpp ├── check-bptree-set.cpp ├── check-dplist.cpp ├── check-uset.cpp ├── check-deque.cpp ├── tgen-mmap.c ├── check-list.cpp ├── tgen-mlist.c ├── tgen-marray.c ├── check-umap.cpp ├── check-bptree-map.cpp ├── except-bitset.c ├── tgen-mdict.c ├── check-prioqueue.cpp ├── except-array.c ├── except-deque.c ├── Make-check-cl.bat ├── test-mgenint.c ├── test-mgeneric.c ├── test-mworker.c └── test-mfuncobj.c ├── .gitignore ├── LICENSE └── .github └── workflows └── codeql-analysis.yml /doc/depend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P-p-H-d/mlib/HEAD/doc/depend.png -------------------------------------------------------------------------------- /doc/oplist.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P-p-H-d/mlib/HEAD/doc/oplist.odp -------------------------------------------------------------------------------- /doc/oplist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P-p-H-d/mlib/HEAD/doc/oplist.png -------------------------------------------------------------------------------- /doc/Container.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P-p-H-d/mlib/HEAD/doc/Container.ods -------------------------------------------------------------------------------- /doc/bench-array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P-p-H-d/mlib/HEAD/doc/bench-array.png -------------------------------------------------------------------------------- /doc/bench-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P-p-H-d/mlib/HEAD/doc/bench-list.png -------------------------------------------------------------------------------- /doc/bench-oset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P-p-H-d/mlib/HEAD/doc/bench-oset.png -------------------------------------------------------------------------------- /doc/bench-umap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P-p-H-d/mlib/HEAD/doc/bench-umap.png -------------------------------------------------------------------------------- /doc/bench-list-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P-p-H-d/mlib/HEAD/doc/bench-list-log.png -------------------------------------------------------------------------------- /doc/bench-oset-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P-p-H-d/mlib/HEAD/doc/bench-oset-log.png -------------------------------------------------------------------------------- /doc/bench-umap-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P-p-H-d/mlib/HEAD/doc/bench-umap-log.png -------------------------------------------------------------------------------- /doc/bench-array-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P-p-H-d/mlib/HEAD/doc/bench-array-log.png -------------------------------------------------------------------------------- /example/exn-lib.c: -------------------------------------------------------------------------------- 1 | // Request M*LIB to define functions for functions defined within M_USE_DECL. 2 | #define M_USE_DEF 3 | #include "exn-header.h" 4 | 5 | -------------------------------------------------------------------------------- /example/ex11-json01.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "surname": "Angel", "age": 1, "present": false}, 3 | { "surname": "Snake", "age": 2, "present": true}, 4 | { "surname": "BallOfBase", "age": 5, "present": true} 5 | ] 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/exm-lib.c: -------------------------------------------------------------------------------- 1 | // Request M*LIB to define functions 2 | // This include both m-string functions and array_str templated functions 3 | // Defining M_USE_EXTERN_DEF override M_USE_EXTERN_DECL definition 4 | #define M_USE_DEF 5 | #include "exm-header.h" 6 | -------------------------------------------------------------------------------- /example/exm-header.h: -------------------------------------------------------------------------------- 1 | #ifndef MY_HEADER 2 | #define MY_HEADER 3 | 4 | // Request M*LIB to not inline functions if not the library source 5 | #define M_USE_DECL 6 | #include "m-string.h" 7 | #include "m-array.h" 8 | 9 | ARRAY_DEF(array_str, string_t) 10 | 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /example/exm-main.c: -------------------------------------------------------------------------------- 1 | #include "exm-header.h" 2 | 3 | int main(void) 4 | { 5 | array_str_t a; 6 | array_str_init(a); 7 | array_str_emplace_back(a, "Hello"); 8 | array_str_emplace_back(a, "World"); 9 | printf("a="); 10 | array_str_out_str(stdout, a); 11 | printf("\n"); 12 | array_str_clear(a); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /example/ex-no-stdio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Micro example to test if M*LIB supports not using stdio.h 3 | */ 4 | #define M_USE_STDIO 0 5 | #define M_RAISE_FATAL(...) abort() 6 | #include "m-array.h" 7 | 8 | ARRAY_DEF(arr, int) 9 | 10 | int main(void) { 11 | arr_t a; 12 | arr_init(a); 13 | arr_push_back(a, 4); 14 | arr_clear(a); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /example/exn-header.h: -------------------------------------------------------------------------------- 1 | #ifndef MY_HEADER 2 | #define MY_HEADER 3 | 4 | // Request M*LIB to not always inline functions 5 | #define M_USE_FINE_GRAINED_LINKAGE 6 | #include "m-string.h" 7 | #include "m-array.h" 8 | 9 | // The following functions will not be inlined: 10 | #define M_USE_DECL 11 | ARRAY_DEF(array_str, string_t) 12 | #undef M_USE_DECL 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /tests/dict.txt: -------------------------------------------------------------------------------- 1 | hello:salut 2 | README:lisez-moi 3 | dictionary:dictionnaire 4 | vector:vecteur 5 | list:liste 6 | buffer:tableau 7 | circular:circulaire 8 | gnu:gnu is not unix 9 | README:LISEZ-MOI 10 | file:fichier 11 | string:chaine de caractere 12 | reference:reference 13 | const:constante 14 | error:erreur 15 | char:caractere 16 | key:cle 17 | value:valeur 18 | print:afficher 19 | -------------------------------------------------------------------------------- /example/ex11-algo02.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "name": "John Doe", "age": 32, "idnum": 14528}, 3 | { "name": "Clint Smith", "age": 31, "idnum": 14529}, 4 | { "name": "Linda Cameron", "age": 20, "idnum": 14527}, 5 | { "name": "Cameron Carrey", "age": 25, "idnum": 14526}, 6 | { "name": "Marty Brown", "age": 26, "idnum": 14525}, 7 | { "name": "Donald Cow", "age": 45, "idnum": 14520} 8 | ] 9 | 10 | -------------------------------------------------------------------------------- /tests/tgen-mserial.c: -------------------------------------------------------------------------------- 1 | #include "m-serial-json.h" 2 | #include "m-tuple.h" 3 | #include "m-string.h" 4 | 5 | TUPLE_DEF2(entry, 6 | (x, float), 7 | (y, float), 8 | (name, string_t) ) 9 | 10 | void save(FILE *f, const entry_t ent) 11 | { 12 | m_serial_write_t serial; 13 | m_serial_json_write_init(serial, f); 14 | entry_out_serial(serial, ent); 15 | m_serial_json_write_clear(serial); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /tests/tgen-openmp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "m-array.h" 4 | ARRAY_DEF(double, double) 5 | 6 | int main(void) { 7 | const int n = 250000000; 8 | const double x = 0.001; 9 | M_LET(v, ARRAY_OPLIST(double)) { 10 | array_double_resize(v, n); 11 | #pragma omp parallel for 12 | for (int i = 0; i < array_double_size(v); ++i) { 13 | array_double_set_at(v, i, cos(i * x)); 14 | } 15 | } 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /example/exn-main.c: -------------------------------------------------------------------------------- 1 | #include "exn-header.h" 2 | 3 | int main(void) 4 | { 5 | string_t s; 6 | string_init_set_str(s, "a="); 7 | string_fputs(stdout, s); 8 | string_clear(s); 9 | array_str_t a; 10 | array_str_init(a); 11 | array_str_emplace_back(a, "Hello"); 12 | array_str_emplace_back(a, "World"); 13 | //printf("a="); 14 | array_str_out_str(stdout, a); 15 | printf("\n"); 16 | array_str_clear(a); 17 | //main2(); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /doc/cc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mkdir -p /tmp/prepro-$USER 3 | name=/tmp/prepro-$USER/$$.c 4 | param1="" 5 | param2="" 6 | while test $# -gt 0 ; do 7 | case $1 in 8 | -c) param2="$param2 -c" ;; 9 | -o) param2="$param2 -o $2" ; shift ;; 10 | *\.c) param1="$param1 $1" ;; 11 | *) param1="$param1 $1" ; param2="$param2 $1" ;; 12 | esac 13 | shift 14 | done 15 | cc $param1 -E |grep -v '^#' > ${name} \ 16 | && perl -pi -e 's/\;/\;\n/g' ${name} \ 17 | && cc $param2 ${name} 18 | -------------------------------------------------------------------------------- /tests/test-mshared-ptr.h: -------------------------------------------------------------------------------- 1 | // Header for coverage purpose 2 | // Expand here all code that shall not be measured in coverage. 3 | // Since the functions are not declared as static inline, their coverage is measured 4 | SHARED_PTR_DEF_EXTERN_AS(shared_int, SharedInt, int, M_BASIC_OPLIST) 5 | SHARED_PTR_DEF_EXTERN_AS(shared_double, SharedDouble, double, M_OPEXTEND(M_BASIC_OPLIST, TYPE(double))) 6 | SHARED_PTR_DEF_EXTERN(shared_array, array_t) 7 | SHARED_PTR_DEF_EXTERN(shared_array_str, array_str_t, ARRAY_OPLIST(array_str, M_STRING_OPLIST)) 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | depend 11 | *.depend 12 | 13 | # Libraries 14 | *.lib 15 | *.a 16 | *.la 17 | *.lo 18 | 19 | # Shared objects (inc. Windows DLLs) 20 | *.dll 21 | *.so 22 | *.so.* 23 | *.dylib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | *.i*86 30 | *.x86_64 31 | *.hex 32 | 33 | # Debug files 34 | *.dSYM/ 35 | *.su 36 | 37 | # Others 38 | other/ 39 | a*.dat 40 | config 41 | config.* 42 | *.log 43 | .vscode 44 | .vs 45 | tmp-serial.* 46 | *~ 47 | *.gcda 48 | *.gcno 49 | *.gcov 50 | *.synt 51 | -------------------------------------------------------------------------------- /example/ex-array03.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "m-array.h" 3 | 4 | // Let's define an array of 'int' named 'array_int' 5 | ARRAY_DEF(array_int, int) 6 | 7 | const int n = 100000; 8 | 9 | int main(void) 10 | { 11 | // Declare and initialize the array 12 | array_int_t x; 13 | array_int_init(x); 14 | 15 | // Push some integers in the array 16 | for (int i = 0; i < n; i++) { 17 | array_int_push_back(x, rand()); 18 | } 19 | 20 | // Insert some integers in the array. 21 | for (int i = 0; i < n; i++) { 22 | array_int_push_at (x, rand() % n, rand()); 23 | } 24 | 25 | // Pop some integers from integer into NULL, 26 | // i.e. erase them. 27 | for (int i = 0; i < n; i++) { 28 | array_int_pop_at (NULL, x, rand() % n); 29 | } 30 | 31 | // Clear the array 32 | array_int_clear(x); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /example/ex11-generic01.c: -------------------------------------------------------------------------------- 1 | #include "m-list.h" 2 | #include "m-generic.h" 3 | 4 | LIST_DEF(list_uint, unsigned int) 5 | // Register for M_LET & M_EACH 6 | #define M_OPL_list_uint_t() LIST_OPLIST(list_uint, M_BASIC_OPLIST) 7 | // Register for Generic: 8 | #define M_GENERIC_ORG_1() (USER) 9 | #define M_GENERIC_ORG_USER_COMP_1() (CORE) 10 | #define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_1() M_OPL_list_uint_t() 11 | 12 | int main(void) 13 | { 14 | M_LET(list, list_uint_t) { 15 | // We can push in the list. It will call the registered method. 16 | push(list, 42); 17 | push(list, 17); 18 | // We can iterate over the list 19 | for each(item, list) { 20 | M_PRINT("ITEM=", *item, "\n"); 21 | } 22 | // We can print directly the list. It will use the registered method 23 | M_PRINT("List = ", list, "\n"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /example/ex-dict04.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "m-string.h" 3 | #include "m-dict.h" 4 | 5 | /* program that reads text from standard-input, 6 | and prints the total number of distinct words found in the text. 7 | */ 8 | 9 | /* Definition of a set (hashset) of unique string_t */ 10 | DICT_SET_DEF(dict_str, string_t, STRING_OPLIST) 11 | 12 | int main(void) 13 | { 14 | // Define word as a string_t 15 | M_LET(word, STRING_OPLIST) 16 | // Define wordcount as a set of string_t 17 | M_LET(wordcount, DICT_SET_OPLIST(dict_str, STRING_OPLIST)) { 18 | // Read a word from the standard input 19 | while (string_fget_word(word, " \t\n,.!;:?", stdin)) { 20 | // Push this word in the set. 21 | // Do nothing if it already exists. 22 | dict_str_push(wordcount, word); 23 | } 24 | // Print the number of words of the standard input. 25 | printf ("Words: %zu\n", dict_str_size(wordcount)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /example/ex11-algo01.c: -------------------------------------------------------------------------------- 1 | /* Based on https://en.cppreference.com/w/cpp/algorithm/for_each 2 | Need to be built in C11 mode */ 3 | 4 | #include 5 | #include "m-array.h" 6 | #include "m-algo.h" 7 | 8 | /* Define a dynamic array of int */ 9 | ARRAY_DEF(vector_int, int) 10 | #define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int) 11 | 12 | /* Define operator increment on int */ 13 | #define INC(n) (n)++ 14 | 15 | int main(void) 16 | { 17 | M_LET( (nums, 3, 4, 2, 8, 15, 267), vector_int_t) { 18 | // Print the array before 19 | printf ("before:"); 20 | ALGO_FOR_EACH(nums, vector_int_t, M_PRINT, " "); 21 | printf ("\n"); 22 | 23 | // Increment each element of the array 24 | ALGO_FOR_EACH(nums, vector_int_t, INC); 25 | 26 | // Print the array after 27 | printf ("after: "); 28 | ALGO_FOR_EACH(nums, vector_int_t, M_PRINT, " "); 29 | printf ("\n"); 30 | 31 | // Sum the elements of the array 32 | int sum = 0; 33 | ALGO_REDUCE(sum, nums, vector_int_t, add); 34 | M_PRINT("sum = ", sum, "\n"); 35 | } 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /example/ex-tree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "m-tree.h" 3 | 4 | TREE_DEF(tree, int) 5 | 6 | // Compute sum of the tree using iterator and a pre-order walk 7 | static int tree_sum_iter(tree_t t) 8 | { 9 | int s = 0; 10 | for(tree_it_t it = tree_it(t); !tree_end_p(it); tree_next(&it)) { 11 | s += *tree_cref(it); 12 | } 13 | return s; 14 | } 15 | 16 | // Compute sum of the tree using recursive call 17 | static int tree_sum_recur(tree_it_t it) 18 | { 19 | if (tree_end_p(it)) 20 | return 0; 21 | if (tree_leaf_p(it)) 22 | return *tree_cref(it); 23 | assert( tree_degree(it) == 2); 24 | return *tree_cref(it) + tree_sum_recur(tree_down(it)) + tree_sum_recur(tree_right(tree_down(it))); 25 | } 26 | 27 | int main(void) 28 | { 29 | tree_t t; 30 | tree_init(t); 31 | tree_it_t r = tree_set_root(t, 1); 32 | tree_it_t l = tree_insert_child(r, 2); 33 | tree_insert_child(r, 5); 34 | tree_insert_child(l, 3); 35 | tree_insert_child(l, 4); 36 | printf("sum = %d vs %d\n", tree_sum_iter(t), tree_sum_recur(tree_it(t))); 37 | tree_clear(t); 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /example/ex-array04.c: -------------------------------------------------------------------------------- 1 | #if HAVE_GMP 2 | 3 | #include 4 | 5 | #include "m-array.h" 6 | #include "m-algo.h" 7 | 8 | /* Define an array of mpz_t */ 9 | ARRAY_DEF(array_mpz, mpz_t, M_CLASSIC_OPLIST(mpz)) 10 | /* Define some algorithm functions on array_mpz_t */ 11 | ALGO_DEF(array_mpz, ARRAY_OPLIST(array_mpz, M_CLASSIC_OPLIST(mpz))) 12 | 13 | static inline void my_mpz_inc(mpz_t *d, const mpz_t a){ 14 | mpz_add(*d, *d, a); 15 | } 16 | static inline bool my_mpz_sqr(mpz_t *d, const mpz_t a, void *data){ 17 | (void) data; 18 | mpz_mul(*d, a, a); 19 | return true; 20 | } 21 | 22 | int main(void) 23 | { 24 | mpz_t z; 25 | mpz_init_set_ui(z, 1); 26 | array_mpz_t a; 27 | array_mpz_init(a); 28 | 29 | array_mpz_push_back(a, z); 30 | for(size_t i = 2 ; i < 1000; i++) { 31 | mpz_mul_ui(z, z, i); 32 | array_mpz_push_back(a, z); 33 | } 34 | 35 | /* Compute z = sum (a[i]^2) */ 36 | array_mpz_transform_reduce (&z, a, my_mpz_inc, my_mpz_sqr, NULL); 37 | gmp_printf ("Z=%Zd\n", z); 38 | 39 | array_mpz_clear(a); 40 | mpz_clear(z); 41 | } 42 | 43 | #else 44 | // Nothing to do 45 | int main(void) { return 0; } 46 | #endif 47 | -------------------------------------------------------------------------------- /example/ex-i-list.c: -------------------------------------------------------------------------------- 1 | #include "m-i-list.h" 2 | 3 | typedef struct data_s { 4 | M_ILIST_INTERFACE(list1, struct data_s); 5 | char *ptr; 6 | int n; 7 | } data_t; 8 | 9 | static void 10 | data_init(data_t *p) 11 | { 12 | M_ILIST_INIT_FIELD(list1, *p); 13 | p->ptr = malloc(100); 14 | p->n = 100; 15 | } 16 | 17 | static void 18 | data_clear(data_t *p) 19 | { 20 | free(p->ptr); 21 | p->n = 0; 22 | } 23 | 24 | static void 25 | data_init_set(data_t *p, data_t s) 26 | { 27 | p->ptr = malloc(s.n); 28 | p->n = s.n; 29 | memcpy(p->ptr, s.ptr, s.n); 30 | } 31 | 32 | #define DATA_OP (INIT(API_2(data_init)), INIT_SET(API_2(data_init_set)), CLEAR(API_2(data_clear)) ) 33 | 34 | M_ILIST_DEF(list1, data_t, DATA_OP) 35 | 36 | data_t pool[100]; 37 | 38 | int main(void) 39 | { 40 | list1_t l; 41 | 42 | list1_init(l); 43 | data_init(&pool[0]); 44 | list1_push_back(l, &pool[0]); 45 | data_init(&pool[1]); 46 | list1_push_back(l, &pool[1]); 47 | 48 | list1_it_t it; 49 | list1_it(it, l); 50 | data_init(&pool[2]); 51 | list1_insert(l, it, &pool[2]); 52 | 53 | list1_clear(l); 54 | 55 | exit(0); 56 | } 57 | -------------------------------------------------------------------------------- /tests/synthesis.ref: -------------------------------------------------------------------------------- 1 | | M-ALGO | 100.00% of 1160 | 2 | | M-ARRAY | 98.24% of 908 | 3 | | M-BITSET | 98.31% of 413 | 4 | | M-BBPTREE | 99.60% of 998 | 5 | | M-BUFFER | 98.86% of 877 | 6 | | M-CONCURRENT | 100.00% of 102 | 7 | | M-CORE | 100.00% of 268 | 8 | | M-DEQUE | 99.47% of 943 | 9 | | M-DICT | 93.00% of 1528 | 10 | | M-FUNCOBJ | 100.00% of 108 | 11 | | M-GENINT | 97.40% of 77 | 12 | | M-I-LIST | 98.10% of 474 | 13 | | M-I-SHARED | 100.00% of 112 | 14 | | M-LIST | 99.12% of 1368 | 15 | | M-MEMPOOL | 97.98% of 99 | 16 | | M-MUTEX | 100.00% of 19 | 17 | | M-PRIOQUEUE | 99.17% of 600 | 18 | | M-RBTREE | 99.04% of 937 | 19 | | M-SERIAL-BIN | 70.87% of 254 | 20 | | M-SERIAL-JSON | 100.00% of 494 | 21 | | M-SHARED | 99.07% of 324 | 22 | | M-SNAPSHOT | 99.54% of 439 | 23 | | M-STRING | 99.40% of 831 | 24 | | M-TREE | 98.46% of 1232 | 25 | | M-TUPLE | 100.00% of 186 | 26 | | M-VARIANT | 99.25% of 266 | 27 | | M-WORKER | 98.73% of 79 | 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2017-2025, Patrick Pelissier 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /example/ex-dict05.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "m-dict.h" 3 | 4 | /* 5 | * Provide OOR methods for OA Hashmap. 6 | * See documentation for definition of OOR 7 | * OOR values are represented as: 8 | * empty (0) is INT_MIN 9 | * deleted (1) is INT_MIN + 1 10 | * So valid range for integers are [INT_MIN+2, INT_MAX] 11 | */ 12 | static inline bool oor_equal_p(int k, char n) 13 | { 14 | return k == INT_MIN + n; 15 | } 16 | 17 | static inline int oor_set(char n) 18 | { 19 | return INT_MIN + n; 20 | } 21 | 22 | /* 23 | * Provide a custom hash function (optional for OA) 24 | */ 25 | static inline size_t hash(int n) 26 | { 27 | return (size_t) n; // Identity hash! 28 | } 29 | 30 | /* Define an OA dictionnay which performs a hashmap between an int to an int */ 31 | DICT_OA_DEF2(dict_oa, 32 | int, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set)), HASH(hash)), 33 | int, M_BASIC_OPLIST) 34 | 35 | int main(void) 36 | { 37 | dict_oa_t d; 38 | dict_oa_init(d); 39 | 40 | for(int i = 0; i < 10; i++) { 41 | dict_oa_set_at(d, i*i, 4*i); 42 | } 43 | dict_oa_set_at(d, 3, -17); 44 | 45 | printf("DICT[3] = %d\n", *dict_oa_get(d, 3)); 46 | 47 | dict_oa_it_t it; 48 | printf("DICT="); 49 | for(dict_oa_it(it, d); !dict_oa_end_p(it); dict_oa_next(it)) { 50 | printf("%d:%d, ", dict_oa_cref(it)->key, dict_oa_cref(it)->value); 51 | } 52 | printf("\n"); 53 | 54 | dict_oa_clear(d); 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /example/ex11-section.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "m-array.h" 4 | #include "m-tuple.h" 5 | #include "m-dict.h" 6 | #include "m-string.h" 7 | 8 | // Let's define a tuple composed of (offset, value) and register it 9 | TUPLE_DEF2(symbol, (offset, long), (value, long)) 10 | #define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_BASIC_OPLIST, M_BASIC_OPLIST) 11 | 12 | // Let's define an array of such tuple and register it 13 | ARRAY_DEF(array_symbol, symbol_t) 14 | #define M_OPL_array_symbol_t() ARRAY_OPLIST(array_symbol, M_OPL_symbol_t()) 15 | 16 | // Let's define a dictionnary associating a string_t to such an array and register it 17 | DICT_DEF2(sections, string_t, array_symbol_t) 18 | #define M_OPL_sections_t() DICT_OPLIST(sections, STRING_OPLIST, M_OPL_array_symbol_t()) 19 | 20 | int main(int argc, const char *argv[]) 21 | { 22 | if (argc < 2) abort(); 23 | FILE *f = fopen(argv[1], "rt"); 24 | if (!f) { 25 | fprintf(stderr, "ERROR: Cannot open %s\n", argv[1]); 26 | return 2; 27 | } 28 | 29 | // Create & initialize sc as sections_t 30 | M_LET(sc, sections_t) { 31 | // Read the section from the FILE 32 | sections_in_str(sc, f); 33 | // Get the section named .text 34 | array_symbol_t *a = sections_get(sc, STRING_CTE(".text")); 35 | if (a == NULL) { 36 | printf("There is no .text section."); 37 | } else { 38 | // Print its content 39 | printf("Section .text is :"); 40 | array_symbol_out_str(stdout, *a); 41 | printf("\n"); 42 | } 43 | } 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /example/ex-string01.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "m-string.h" 5 | 6 | #define MAX_COLUMN 80 7 | 8 | static void format(FILE *f) 9 | { 10 | string_t s; 11 | string_init(s); 12 | while (string_fgets(s, f, STRING_READ_PURE_LINE) == true) 13 | { 14 | size_t n = string_size(s); 15 | if (n > 0 && string_get_char(s, n-1) == '\\' && n < MAX_COLUMN) { 16 | string_left(s, n-1); 17 | while (n < MAX_COLUMN-1) { 18 | string_push_back(s, ' '); 19 | n++; 20 | } 21 | string_push_back(s, '\\'); 22 | } 23 | if (n >= MAX_COLUMN && string_get_char(s, n-1) == '\\') { 24 | n--; 25 | string_left(s, n); 26 | while (n >= MAX_COLUMN-2 && string_get_char(s, n-1) == ' ') { 27 | n--; 28 | string_left(s, n); 29 | } 30 | string_push_back(s, ' '); 31 | string_push_back(s, '\\'); 32 | } 33 | printf("%s\n", string_get_cstr(s)); 34 | } 35 | string_clear(s); 36 | } 37 | 38 | int main(int argc, const char *argv[]) 39 | { 40 | if (argc < 2) 41 | { 42 | fprintf(stderr, "ERROR: Missing argument filename.\nUSAGE: %s filename.h\n", argv[0]); 43 | exit(1); 44 | } 45 | FILE *f = fopen(argv[1], "rt"); 46 | if (!f) { 47 | fprintf(stderr, "ERROR: Cannot open filename '%s' .h\n", argv[1]); 48 | exit(2); 49 | } 50 | format(f); 51 | fclose(f); 52 | exit(0); 53 | } 54 | -------------------------------------------------------------------------------- /example/ex-bptree02.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "m-bptree.h" 4 | 5 | BPTREE_MULTI_DEF2(multimap, 5, int, M_BASIC_OPLIST, int, M_BASIC_OPLIST) 6 | #define M_OPL_map_multimap_t() BPTREE_OPLIST2(multimap, M_BASIC_OPLIST, M_BASIC_OPLIST) 7 | 8 | // Fill in with multiple value 9 | static void 10 | fill_in(multimap_t map) 11 | { 12 | for(int i = 1 ; i < 100; i++) 13 | multimap_set_at(map, i, i); 14 | for(int i = 1 ; i < 100; i+=2) 15 | multimap_set_at(map, i, i*i); 16 | for(int i = 1 ; i < 100; i+=3) 17 | multimap_set_at(map, i, i*i*i); 18 | } 19 | 20 | // Count the number of occurence of a key 21 | static int 22 | count(multimap_t map, int key) 23 | { 24 | int n = 0; 25 | multimap_it_t it; 26 | // it_from is O(n*ln n) complexity 27 | // it_while_p and next are O(1) complexity 28 | for(multimap_it_from(it, map, key); multimap_it_while_p(it, key); multimap_next(it)) 29 | n++; 30 | return n; 31 | } 32 | 33 | // Print the map in details 34 | static void 35 | print(multimap_t map) 36 | { 37 | for(int i = 0; i < 101;i++) { 38 | printf("Key=%d Count=%d ", i, count(map, i)); 39 | multimap_it_t it; 40 | for(multimap_it_from(it, map, i); multimap_it_while_p(it, i); multimap_next(it)) { 41 | printf("Value=%d ", *multimap_ref(it)->value_ptr ); 42 | } 43 | printf("\n"); 44 | } 45 | } 46 | 47 | int main(void) 48 | { 49 | multimap_t map; 50 | multimap_init(map); 51 | fill_in(map); 52 | print(map); 53 | multimap_clear(map); 54 | exit(0); 55 | } 56 | -------------------------------------------------------------------------------- /example/ex-multi05.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "m-array.h" 4 | #include "m-string.h" 5 | 6 | /* This example show ARRAY_DEF usage with string, 7 | M_LET macro usage with complex initialization condition: 8 | how to initialize a dynamic array and initialize it with the given arguments. 9 | It show also the M_EACH keywork 10 | */ 11 | 12 | // Let's create a dynamic array of string_t and register it globaly 13 | // a so called std::vector in C++ 14 | ARRAY_DEF(vector_string, string_t) 15 | #define M_OPL_vector_string_t() ARRAY_OPLIST(vector_string, STRING_OPLIST) 16 | 17 | int main(void) 18 | { 19 | // Let's define a new string named str 20 | M_LET(str, string_t) 21 | // Let's define msg as a vector_array_t 22 | M_LET( (msg, STRING_CTE("Hello"), STRING_CTE("C"), STRING_CTE("World!"), STRING_CTE("Let's"), STRING_CTE("discover"), STRING_CTE("M*LIB!")), vector_string_t) { 23 | // Iterate over all words of the array msg 24 | for M_EACH(word, msg, vector_string_t) { 25 | // Cat the current word into the target string 26 | string_cat(str, *word); 27 | // Also add a space character 28 | string_push_back(str, ' '); 29 | } 30 | // Let's define another string and set it to a formatted value. 31 | M_LET( (count, "\nTo display this it uses \"vector\" of %zu strings!", vector_string_size(msg)), string_t) { 32 | string_cat(str, count); 33 | } 34 | // Print the result 35 | printf("%s\n", string_get_cstr(str) ); 36 | } 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /example/ex-dict01.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "m-dict.h" 5 | #include "m-string.h" 6 | 7 | // Define a dictionary of string --> int 8 | // named 'dict_str' 9 | DICT_DEF2(dict_str, string_t, STRING_OPLIST, int, M_BASIC_OPLIST) 10 | 11 | int main(void) 12 | { 13 | // Declare the dictionary 'h' 14 | dict_str_t h; 15 | int max = 1; 16 | // Declare the string 'key' 17 | string_t key; 18 | 19 | // Initialize the dictionary & the string 20 | dict_str_init(h); 21 | string_init (key); 22 | 23 | // While there is some data in the stream 24 | while (true) 25 | { 26 | // Read a complete line from the stream and fill in the string 'key' 27 | string_fgets (key, stdin, STRING_READ_PURE_LINE); 28 | if (feof(stdin)) break; 29 | // If the 'key' exists in the dictionary 30 | int *v = dict_str_get (h, key); 31 | if (v != NULL) { 32 | // Increment the counter in the dictionary 33 | (*v)++; 34 | max = M_MAX(*v, max); 35 | } else { 36 | // Update the dictionary with h[key] = 1 37 | dict_str_set_at(h, key, 1); 38 | } 39 | } 40 | printf ("Max occurrence = %d\n", max); 41 | 42 | // Iterate on the dictionary 43 | dict_str_it_t it; 44 | for(dict_str_it(it, h); !dict_str_end_p(it); dict_str_next(it)) { 45 | // Get a constant reference on the pair stored in the dictionary 46 | const struct dict_str_pair_s *pair = dict_str_cref(it); 47 | printf ("Key=%s Value=%d\n", 48 | string_get_cstr(pair->key), pair->value); 49 | } 50 | 51 | // Clear variables 52 | string_clear(key); 53 | dict_str_clear(h); 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /example/ex-algo04.c: -------------------------------------------------------------------------------- 1 | #include "m-algo.h" 2 | #include "m-array.h" 3 | #include "m-string.h" 4 | 5 | /* Define an array of int */ 6 | ARRAY_DEF(vector_int, int) 7 | /* Register the oplist of this array of int globally */ 8 | #define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int) 9 | 10 | /* Concat two strings by insertion a '-' within them */ 11 | #define str_cat(s1, s2) (string_cat_str(s1, "-"), string_cat(s1, s2)) 12 | 13 | int main(void) 14 | { 15 | // Let 's' be a string_t and initialize it. 16 | M_LET(s, string_t) 17 | // Let 'v' be a vector of integer and initialize it. 18 | M_LET( (v, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), vector_int_t) { 19 | int sum = 0, product = 0; 20 | 21 | // Compute the sum of theses integers. 22 | // 'add' is a registered keyword, recognized by M*LIB to perform a sum. 23 | ALGO_REDUCE(sum, v, vector_int_t, add); 24 | 25 | // Compute the product of theses integers. 26 | // 'mul' is a registered keyword, recognized by M*LIB to perform a product. 27 | ALGO_REDUCE(product, v, vector_int_t, mul); 28 | 29 | /* Example of reduction with a transformation of the type from int to string_t 30 | By default, the result ("s") should be of the same type as the base type 31 | of the container. This is not the case here, we want to transform the 32 | type. As such, we add the precision of the type 'string_t' to 's'. 33 | The transformation from string to integer is done by string_set_si */ 34 | ALGO_REDUCE( (s, string_t), v, vector_int_t, str_cat, string_set_si); 35 | 36 | printf ("sum: %d\n" 37 | "product: %d\n" 38 | "dash str: %s\n", sum, product, string_get_cstr(s)); 39 | } 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /example/ex-dict06.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "m-dict.h" 3 | 4 | /* 5 | * Provide OOR methods for OA Hashmap. 6 | * See documentation for definition of OOR 7 | * OOR values are represented as: 8 | * empty (0) is "EMPTY" 9 | * deleted (1) is "DELETED" 10 | */ 11 | static const char empty_str[] = "EMPTY"; 12 | static const char deleted_str[] = "DELETED"; 13 | static const char *const oor_table[] = { empty_str, deleted_str }; 14 | 15 | static inline bool oor_equal_p(const char *k, int n) 16 | { 17 | return k == oor_table[n]; 18 | } 19 | 20 | static inline const char *oor_set(int n) 21 | { 22 | return oor_table[n]; 23 | } 24 | 25 | /* 26 | * Provide a custom hash function (optional for OA) 27 | */ 28 | static inline size_t hash(const char *k) 29 | { 30 | size_t r = 17; 31 | while (*k) { 32 | r = *k * 33 + r; 33 | k++; 34 | } 35 | return r; 36 | } 37 | 38 | /* Define an OA dictionnay which performs a hashmap between a CSTR to an int */ 39 | DICT_OA_DEF2(dict_oa, 40 | const char *, M_OPEXTEND(M_CSTR_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set)), HASH(hash)), 41 | int, M_BASIC_OPLIST) 42 | 43 | int main(void) 44 | { 45 | dict_oa_t d; 46 | dict_oa_init(d); 47 | 48 | dict_oa_set_at(d, "THIS", -17); 49 | dict_oa_set_at(d, "IS", -170); 50 | dict_oa_set_at(d, "AN", 7); 51 | dict_oa_set_at(d, "EXAMPLE", 77); 52 | 53 | printf("DICT[\"AN\"] = %d\n", *dict_oa_get(d, "AN")); 54 | 55 | dict_oa_it_t it; 56 | printf("DICT="); 57 | for(dict_oa_it(it, d); !dict_oa_end_p(it); dict_oa_next(it)) { 58 | printf("%s:%d, ", dict_oa_cref(it)->key, dict_oa_cref(it)->value); 59 | } 60 | printf("\n"); 61 | 62 | dict_oa_clear(d); 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /tests/tgen-tuple.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include 24 | #include "m-try.h" 25 | #include "m-tuple.h" 26 | #include "m-string.h" 27 | 28 | TUPLE_DEF2( tuple, (name, string_t), (surname, string_t), (value, int)) 29 | 30 | void duplicate(tuple_t dst, const tuple_t src) 31 | { 32 | tuple_init_set(dst, src); 33 | } 34 | 35 | -------------------------------------------------------------------------------- /tests/tgen-bitset.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #include "m-bitset.h" 25 | 26 | void f_b(bitset_t s, size_t i, bool b) 27 | { 28 | bitset_set_at(s, i, b); 29 | } 30 | 31 | void f_0(bitset_t s, size_t i) 32 | { 33 | bitset_set_at(s, i, false); 34 | } 35 | 36 | void f_1(bitset_t s, size_t i) 37 | { 38 | bitset_set_at(s, i, true); 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /example/ex-algo03.c: -------------------------------------------------------------------------------- 1 | #include "m-dict.h" 2 | #include "m-array.h" 3 | #include "m-algo.h" 4 | #include "m-string.h" 5 | 6 | /* Define a dictionnary (or hash_map or unordered_map) 7 | * from a string_t to int */ 8 | DICT_DEF2(dict, string_t, int) 9 | /* Register the oplist of this dictionnary globally */ 10 | #define M_OPL_dict_t() DICT_OPLIST(dict, STRING_OPLIST, M_BASIC_OPLIST) 11 | 12 | /* Define an array of integer */ 13 | ARRAY_DEF(vector_int, int) 14 | /* Register the oplist of this array of integer globally */ 15 | #define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int) 16 | 17 | /* Micro macro to detect if the key string starts with the given pattern */ 18 | #define start_with(pattern, item) \ 19 | string_start_with_str_p((item).key, (pattern)) 20 | 21 | /* Micro macro to get the value of a pair of (key, value) */ 22 | #define get_value(out, item) ((out) = (item).value) 23 | 24 | int main(void) 25 | { 26 | int s = 0; 27 | // Init keys as a vector_int_t, initialize it (and prepare its destruction) 28 | M_LET(keys, vector_int_t) 29 | // Initialize m as a dictionnary and initialize it with the given database 30 | // Initialize tmp as a dictionnary 31 | M_LET( (m, (STRING_CTE("foo"), 1), (STRING_CTE("bar"), 42), (STRING_CTE("bluez"), 7), (STRING_CTE("stop"), 789) ), tmp, dict_t) { 32 | /* Extract all elements of 'm' that starts with 'b' and fills tmp with it */ 33 | ALGO_EXTRACT(tmp, dict_t, m, dict_t, start_with, "b"); 34 | /* Extract the values of theses elements */ 35 | ALGO_TRANSFORM(keys, vector_int_t, tmp, dict_t, get_value); 36 | /* Sum theses values */ 37 | ALGO_REDUCE(s, keys, vector_int_t, sum); 38 | printf("Sum of elements starting with 'b' is: %d\n", s); 39 | } 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /example/ex-string03.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "m-string.h" 3 | #include "m-dict.h" 4 | #include "m-array.h" 5 | 6 | /* Definition of an associative map string_t --> size_t */ 7 | DICT_DEF2(dict_str, string_t, size_t) 8 | #define M_OPL_dict_str_t() DICT_OPLIST(dict_str, STRING_OPLIST, M_BASIC_OPLIST) 9 | 10 | /* Definition of an array of string_t */ 11 | ARRAY_DEF(vector_str, string_t) 12 | #define M_OPL_vector_str_t() ARRAY_OPLIST(vector_str, STRING_OPLIST) 13 | 14 | int main(void) 15 | { 16 | // Construct an array of string, performing a convertion of the C const char * 17 | // into a proper string_t at real time and push then into a dynamic array 18 | // that is declared, initialized and cleared. 19 | M_LET( (words, ("This"), ("is"), ("a"), ("useless"), ("sentence"), ("."), 20 | ("It"), ("is"), ("used"), ("a"), ("bit"), ("to"), ("count"), ("words"), (".") ), 21 | vector_str_t) { 22 | // Print the arrays. 23 | printf("The words are: "); 24 | vector_str_out_str(stdout, words); 25 | printf("\n"); 26 | 27 | // Count the words. 28 | M_LET(map, dict_str_t) { 29 | // Count the words into the dictionnary 'map' 30 | for M_EACH(w, words, vector_str_t) { 31 | (*dict_str_safe_get(map, *w)) ++; 32 | } 33 | 34 | // Print the count: 35 | for M_EACH(p, map, dict_str_t) { 36 | // In C11 version we can use the M_PRINT macro that simplifies formatting. 37 | #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) 38 | M_PRINT(p->value, " occurences of ", p->key, "\n"); 39 | #else 40 | printf ("%zu occurences of %s\n", p->value, string_get_cstr(p->key)); 41 | #endif 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/tgen-queue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #include "m-buffer.h" 25 | 26 | QUEUE_MPMC_DEF(queue_uint, unsigned int, BUFFER_QUEUE) 27 | queue_uint_t g_buff2; 28 | 29 | extern void push(unsigned int r); 30 | void push(unsigned int r) 31 | { 32 | queue_uint_push(g_buff2, r ); 33 | } 34 | 35 | extern unsigned int pop(void); 36 | unsigned int pop(void) 37 | { 38 | unsigned int r = -1; 39 | queue_uint_pop(&r, g_buff2 ); 40 | return r; 41 | } 42 | -------------------------------------------------------------------------------- /example/ex-dict02.c: -------------------------------------------------------------------------------- 1 | #include "m-dict.h" 2 | 3 | // Let's define a dictionary of 'unsigned int' --> 'char 4 | DICT_DEF2(dict_m32, unsigned int, M_BASIC_OPLIST, char, M_BASIC_OPLIST) 5 | 6 | // Let's create a synonym for its oplist. 7 | #define M32_OPLIST DICT_OPLIST(dict_m32, M_BASIC_OPLIST, M_BASIC_OPLIST) 8 | 9 | #if 1 // Non macro version. 10 | 11 | int main(void) { 12 | dict_m32_t h; // Declare h as a dictionary 13 | dict_m32_init(h); // h is initialized. 14 | dict_m32_set_at (h, 5, 10); // h[5] = 10 15 | char *k = dict_m32_get(h, 10); // No 10 in h, so k == NULL 16 | int is_missing = (k != NULL); // true 17 | assert (is_missing); (void) is_missing; 18 | dict_m32_erase(h, 5); // h is now empty 19 | dict_m32_it_t it; // iterate over all dictionnary 20 | for (dict_m32_it (it, h) ; !dict_m32_end_p (it); dict_m32_next(it)) { 21 | struct dict_m32_pair_s *item = dict_m32_ref(it); 22 | item->value = 1; // Set its value to 1 23 | } 24 | dict_m32_clear(h); // h is cleared 25 | return 0; 26 | } 27 | 28 | #else // Use of M_LET & M_FOR macros (otherwise equivalent) 29 | 30 | int main(void) { 31 | M_LET(h, M32_OPLIST) { // h is init 32 | dict_m32_set_at (h, 5, 10); // h[5] = 10 33 | char *k = dict_m32_get(h, 10); // k == NULL 34 | int is_missing = (k != NULL); // true 35 | assert (is_missing); 36 | dict_m32_erase(h, 5); // h is now empty 37 | for M_EACH(item, h, M32_OPLIST) { // traverse each item 38 | item->value = 1; // Set its value to 1 39 | } 40 | } // h is cleared 41 | return 0; 42 | } 43 | 44 | #endif 45 | 46 | 47 | -------------------------------------------------------------------------------- /example/ex11-json01.c: -------------------------------------------------------------------------------- 1 | #include "m-serial-json.h" 2 | #include "m-tuple.h" 3 | #include "m-array.h" 4 | 5 | /* Basic example to show JSON serialization */ 6 | 7 | // Let's define a 'person' composed of several fields. 8 | TUPLE_DEF2(person, 9 | (surname, string_t), 10 | (age, int), 11 | (present, bool) 12 | ) 13 | // Register the oplist of this tuple globaly 14 | #define M_OPL_person_t() TUPLE_OPLIST(person, STRING_OPLIST, M_BASIC_OPLIST, M_BOOL_OPLIST ) 15 | 16 | // Let's define an array of person 17 | ARRAY_DEF(base, person_t) 18 | // Register the oplist of this array globaly 19 | #define M_OPL_base_t() ARRAY_OPLIST(base, M_OPL_person_t()) 20 | 21 | // Let's read an array of person from the given JSON file 22 | static void read(base_t base, const char filename[]) 23 | { 24 | m_serial_read_t in; 25 | m_serial_return_code_t ret; 26 | 27 | // Open the file 28 | FILE *f = fopen(filename, "rt"); 29 | if (!f) { 30 | fprintf(stderr, "ERROR: Cannot open file '%s'.\n", filename); 31 | exit(2); 32 | } 33 | 34 | // Initialize the serializer with the file 35 | m_serial_json_read_init(in, f); 36 | // Read the array 37 | ret = base_in_serial(base, in); 38 | if (ret != M_SERIAL_OK_DONE) { 39 | fprintf(stderr, "ERROR: Cannot read JSON data from file '%s'.\n", filename); 40 | exit(2); 41 | } 42 | // Let's close & clear all 43 | m_serial_json_read_clear(in); 44 | fclose(f); 45 | } 46 | 47 | int main(void) 48 | { 49 | // Let's have base as a base_t 50 | M_LET(base, base_t) { 51 | // Read the JSON file and fill-in base 52 | read(base, "ex11-json01.json"); 53 | base_emplace_back(base, STRING_CTE("John"), 40, false); 54 | // Print the contents of base: 55 | printf ("List of presents:\n"); 56 | for M_EACH(el, base, base_t) { 57 | if ((*el)->present) { 58 | printf("%s\n", string_get_cstr((*el)->surname)); 59 | } 60 | } 61 | } 62 | exit(0); 63 | } 64 | -------------------------------------------------------------------------------- /tests/tgen-try.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #include "m-try.h" 25 | 26 | typedef struct testobj_s { 27 | unsigned int n; 28 | unsigned int a; 29 | bool allocated; 30 | unsigned int *ptr; 31 | } testobj_t[1]; 32 | 33 | extern void testobj_init(testobj_t z); 34 | extern void testobj_clear(testobj_t z); 35 | #define M_OPL_testobj_t() (INIT(testobj_init), CLEAR(testobj_clear), TYPE(testobj_t)) 36 | 37 | void test2(void) 38 | { 39 | M_TRY(test1) { 40 | M_LET(obj, testobj_t) { 41 | f(obj); 42 | } 43 | } M_CATCH(test1, 0) { 44 | assert(0); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /example/ex-grep01.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "m-string.h" 3 | #include "m-array.h" 4 | #include "m-dict.h" 5 | 6 | // Define an array of size_t 7 | ARRAY_DEF(array_size, size_t) 8 | // Register the oplist of this array globaly 9 | #define M_OPL_array_size_t() ARRAY_OPLIST(array_size) 10 | 11 | // Define a dictionary (hashmap) of string_t to array of size_t 12 | DICT_DEF2(map_pos, string_t, array_size_t) 13 | // Register the oplist of this dictionary (hashmap) 14 | #define M_OPL_map_pos_t() DICT_OPLIST(map_pos, STRING_OPLIST, ARRAY_OPLIST(array_size)) 15 | 16 | int main(int argc, const char *argv[]) 17 | { 18 | if (argc != 2) { 19 | printf("USAGE: %s filename\n", argv[0]); 20 | exit(0); 21 | } 22 | 23 | // Define word as a string_t 24 | M_LET(word, string_t) 25 | // Define positions as a map of string_t-->array of size_t 26 | M_LET(positions, map_pos_t) { 27 | // Open the file 28 | FILE *f = fopen(argv[1], "rt"); 29 | if (!f) { 30 | fprintf(stderr, "ERROR: Cannot open %s.\n", argv[1]); 31 | return 1; 32 | } 33 | 34 | // While it reads some word from the file 35 | while (string_fget_word(word, " \t\n\r\"(),=", f)) { 36 | // Get the reference to the array of this word in the dictionnary (or create it if needed) 37 | array_size_t *array = map_pos_safe_get(positions, word); 38 | // Push the new offset to this word in the associated array 39 | array_size_push_back(*array, (size_t)ftell(f) - string_size(word)); 40 | } 41 | 42 | // Close the file 43 | fclose(f); 44 | 45 | // Print the words and where they are: 46 | for M_EACH(pair, positions, map_pos_t) { 47 | string_fputs(stdout, pair->key); 48 | for M_EACH(pos, pair->value, array_size_t) { 49 | printf(" %zu", *pos); 50 | } 51 | printf("\n"); 52 | } 53 | } // All created objects are destroyed beyond this point 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /tests/tgen-mstring.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #include "m-string.h" 25 | 26 | size_t fsize(const char str[]) 27 | { 28 | return m_str1ng_utf8_length(str); 29 | } 30 | 31 | void convert(string_t s, unsigned n) 32 | { 33 | m_string_set_ui(s, n); 34 | } 35 | 36 | void construct(char s[], unsigned n) 37 | { 38 | strcpy(s, M_CSTR("Hello %u worlds", n)); 39 | } 40 | 41 | void iterate(string_t s) 42 | { 43 | string_it_t it; 44 | for(string_it(it, s); !string_end_p(it); string_next(it)) { 45 | printf("%u\n", string_get_cref(it)); 46 | } 47 | } 48 | 49 | bool start_p(char *p) 50 | { 51 | return m_str1ng_utf8_start_p((unsigned char) *p); 52 | } 53 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | name: "CodeQL" 7 | 8 | on: 9 | push: 10 | branches: [master] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [master] 14 | 15 | jobs: 16 | analyze: 17 | name: Analyze 18 | runs-on: ubuntu-latest 19 | 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | # Override automatic language detection by changing the below list 24 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 25 | language: ['cpp'] 26 | # Learn more... 27 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 28 | 29 | steps: 30 | - name: Checkout repository 31 | uses: actions/checkout@v3 32 | with: 33 | # We must fetch at least the immediate parents so that if this is 34 | # a pull request then we can checkout the head. 35 | fetch-depth: 2 36 | 37 | # Initializes the CodeQL tools for scanning. 38 | - name: Initialize CodeQL 39 | uses: github/codeql-action/init@v2 40 | with: 41 | languages: ${{ matrix.language }} 42 | # If you wish to specify custom queries, you can do so here or in a config file. 43 | # By default, queries listed here will override any specified in a config file. 44 | # Prefix the list here with "+" to use these queries and those in the config file. 45 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 46 | 47 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 48 | - name: Autobuild 49 | working-directory: ./tests 50 | run: make exe 51 | 52 | - name: Perform CodeQL Analysis 53 | uses: github/codeql-action/analyze@v2 54 | -------------------------------------------------------------------------------- /tests/test-mmutex.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include 24 | #include "coverage.h" 25 | 26 | #include "m-thread.h" 27 | 28 | M_LOCK_DECL(global_lock); 29 | unsigned long long n = 0; 30 | 31 | static void f(void *arg) 32 | { 33 | (void)arg; // Unused 34 | // Global lock to perform atomic addition. 35 | M_LOCK(global_lock) { 36 | n += 1; 37 | } 38 | } 39 | 40 | static void test_global(void) 41 | { 42 | m_thread_t idx_p[100]; 43 | 44 | n = 0; 45 | for(int i = 0; i < 100; i++) { 46 | m_thread_create (idx_p[i], f, NULL); 47 | } 48 | for(int i = 0; i < 100;i++) { 49 | m_thread_join(idx_p[i]); 50 | } 51 | assert (n == 100); 52 | } 53 | 54 | int main(void) 55 | { 56 | test_global(); 57 | exit(0); 58 | } 59 | -------------------------------------------------------------------------------- /example/ex-defer01.c: -------------------------------------------------------------------------------- 1 | #include "m-core.h" 2 | 3 | /* This example show how to use the M_LET_IF macro 4 | that enables to construct an object and continue 5 | if the construction succeeds. 6 | */ 7 | 8 | // Stubs defined for the example. Real code will use soundio library. 9 | struct SoundIo { int x; }; 10 | struct SoundIoDevice { int x; }; 11 | struct SoundIoOutStream { int x; }; 12 | 13 | static struct SoundIo *soundio_create(void) { return (struct SoundIo *) malloc(sizeof(struct SoundIo)); } 14 | static void soundio_destroy(struct SoundIo *s) { free(s); } 15 | 16 | static struct SoundIoDevice *soundio_get_device(struct SoundIo *io, int def) { (void) io; (void) def; return (struct SoundIoDevice *) malloc(sizeof(struct SoundIoDevice)); } 17 | static void soundio_device_unref(struct SoundIoDevice *s) { free(s); } 18 | 19 | static struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device) { (void) device ; return (struct SoundIoOutStream *) malloc(sizeof(struct SoundIoOutStream)); } 20 | static void soundio_outstream_destroy(struct SoundIoOutStream *s) { free(s); } 21 | 22 | static bool soundio_wait_events(struct SoundIo *s) { (void) s; return false; } 23 | // End of stubs 24 | 25 | int main(void) 26 | { 27 | int err = 1; 28 | 29 | /* Example of using M_LET_IF macro to simplify writing error handling code. 30 | The following code creates some object, test if the object creation succeeds, register the destructor, and print an error if something went wrong 31 | */ 32 | M_LET_IF( struct SoundIo *soundio = soundio_create(), soundio != 0 , soundio_destroy(soundio) , fprintf(stderr, "out of memory for soundio\n") ) 33 | M_LET_IF(struct SoundIoDevice *device = soundio_get_device(soundio, -1), device != 0, soundio_device_unref(device), fprintf(stderr, "out of memory for device\n")) 34 | M_LET_IF(struct SoundIoOutStream *outstream = soundio_outstream_create(device), outstream != 0, soundio_outstream_destroy(outstream), fprintf(stderr, "out of memory for stream\n")) { 35 | err = 0; 36 | bool cont = true; 37 | while (cont) 38 | cont = soundio_wait_events(soundio); 39 | } 40 | return err; 41 | } 42 | -------------------------------------------------------------------------------- /example/ex11-algo05-transform.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "m-array.h" 3 | #include "m-algo.h" 4 | #include "m-string.h" 5 | 6 | ARRAY_DEF(array_int, int) 7 | #define M_OPL_array_int_t() ARRAY_OPLIST(array_int, M_BASIC_OPLIST) 8 | ALGO_DEF(array_int, array_int_t) 9 | 10 | static bool callback1(int *out, int in, void *data) 11 | { 12 | int *cpt = data; 13 | bool ret = true; 14 | if (*cpt == -1 && in == 11) 15 | *cpt = 0; // Start when first reach 11 16 | ret &= (*cpt >= 0); // Skip initial numbers unequal 11 17 | ret &= (in % 2 != 0); // Collect odd numbers 18 | (*cpt) += ret; 19 | ret &= (*cpt <= 5); // Only take five numbers 20 | *out = in * in; // Square each number 21 | return ret; 22 | } 23 | 24 | static void callback_add_int(int *out, int in) 25 | { 26 | *out += in; 27 | } 28 | 29 | static void demo(void) 30 | { 31 | M_LET( (t, M_SEQ(0, 30)), vector, array_int_t) { 32 | printf("t="); array_int_out_str(stdout, t); 33 | int b = -1; 34 | array_int_transform(vector, t, callback1, &b); 35 | printf("\nvector="); array_int_out_str(stdout, vector); printf("\n"); 36 | array_int_reduce(&b, vector, callback_add_int); 37 | printf("Sum=%d\n", b); 38 | } 39 | } 40 | 41 | ARRAY_DEF(array_str, string_t) 42 | #define M_OPL_array_str_t() ARRAY_OPLIST(array_str, M_STRING_OPLIST) 43 | ALGO_DEF(array_str, array_str_t) 44 | 45 | static bool callback2(string_t *out, const string_t in, void *data) 46 | { 47 | char *cp = data, c = *cp; 48 | if (string_search_char(in, c) == M_STRING_FAILURE) 49 | return false; 50 | string_set(*out, in); 51 | return true; 52 | } 53 | 54 | static void demo_split(void) 55 | { 56 | M_LET( (s, ("This is a sentence in C11.")), string_t) 57 | M_LET(words, f_words, array_str_t) { 58 | array_str_split(words, s, ' '); 59 | array_str_transform(f_words, words, callback2, &(char){'i'}); 60 | printf("f_words="); array_str_out_str(stdout, f_words); printf("\n"); 61 | } 62 | } 63 | 64 | int main(void) 65 | { 66 | demo(); 67 | demo_split(); 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /tests/check-array.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include 24 | #include "m-array.h" 25 | 26 | ARRAY_DEF(array_int, int) 27 | 28 | // Container OPLIST 29 | #define CONT_OPL ARRAY_OPLIST(array_int, M_OPL_int()) 30 | 31 | // C++ Base class of the item in the container 32 | #define BASE_CLASS int 33 | 34 | // C++ Container class 35 | #define CONT_CLASS std::vector 36 | 37 | // Compare the M*LIB container a to the C++ container b 38 | #define CMP_CONT(a, b) cmp_cont(a, b) 39 | 40 | void cmp_cont(array_int_t a, std::vector b) 41 | { 42 | size_t s = array_int_size(a); 43 | assert (s == b.size()); 44 | for(size_t i = 0; i < s; i++) { 45 | int *b0 = array_int_get(a, i); 46 | int &b1 = b.at(i); 47 | assert(*b0 == b1); 48 | } 49 | } 50 | 51 | #define DEFAULT_NUMBER 1000000 52 | #define HAVE_RESERVE 53 | #define HAVE_RESIZE 54 | #include "check-generic.hpp" 55 | -------------------------------------------------------------------------------- /example/ex11-small-name.c: -------------------------------------------------------------------------------- 1 | // Disable small name usage 2 | #define M_USE_SMALL_NAME 0 3 | 4 | #include "m-algo.h" 5 | #include "m-array.h" 6 | #include "m-atomic.h" 7 | #include "m-bitset.h" 8 | #include "m-bptree.h" 9 | #include "m-bstring.h" 10 | #include "m-buffer.h" 11 | #include "m-deque.h" 12 | #include "m-dict.h" 13 | #include "m-funcobj.h" 14 | #include "m-generic.h" 15 | #include "m-genint.h" 16 | #include "m-i-list.h" 17 | #include "m-list.h" 18 | #include "m-prioqueue.h" 19 | #include "m-rbtree.h" 20 | #include "m-serial-bin.h" 21 | #include "m-serial-json.h" 22 | #include "m-shared-ptr.h" 23 | #include "m-snapshot.h" 24 | #include "m-string.h" 25 | #include "m-thread.h" 26 | #include "m-tree.h" 27 | #include "m-try.h" 28 | #include "m-tuple.h" 29 | #include "m-variant.h" 30 | #include "m-worker.h" 31 | 32 | M_ARRAY_DEF(array, m_string_t) 33 | M_ALGO_DEF(array, M_ARRAY_OPLIST(array, M_STRING_OPLIST)) 34 | M_BPTREE_DEF2(bptree, 11, m_string_t, m_string_t) 35 | M_BUFFER_DEF(queue, m_string_t, 10, M_BUFFER_QUEUE) 36 | M_LIST_DEF(list, m_string_t) 37 | M_LIST_DUAL_PUSH_DEF(list2, m_string_t) 38 | M_DEQUE_DEF(deque, m_string_t) 39 | M_DICT_DEF2(dict, m_string_t, m_string_t) 40 | M_DICT_OA_DEF2(dict_oa, m_string_t, m_string_t) 41 | M_DICT_SET_DEF(dict_set, m_string_t) 42 | M_DICT_OASET_DEF(dict_oa_set, m_string_t) 43 | M_RBTREE_DEF(rbtree, m_string_t) 44 | M_FUNC_OBJ_INS_DEF(compare_by /* name of the instance */, 45 | array_cmp_obj /* name of the interface */, 46 | (a, b) /* name of the input parameters of the function like object. The type are inherited from the interface. */, { 47 | /* code of the function object */ 48 | if (m_string_equal_cstr_p(self->sort_field, "normal")) 49 | return m_string_cmp(a, b); 50 | else 51 | return -m_string_cmp(a, b); 52 | }, 53 | /* Additional fields stored in the function object */ 54 | (sort_field, m_string_t) ) 55 | M_PRIOQUEUE_DEF(prio_queue, m_string_t) 56 | M_SHARED_PTR_DEF(shared_string, m_string_t) 57 | M_SNAPSHOT_SPSC_DEF(snap1, m_string_t) 58 | M_SNAPSHOT_SPMC_DEF(snap2, m_string_t) 59 | M_SNAPSHOT_MPMC_DEF(snap3, m_string_t) 60 | M_TREE_DEF(tree, m_string_t) 61 | M_TUPLE_DEF2(tuple, (a, m_string_t)) 62 | M_VARIANT_DEF2(variant, (a, m_string_t)) 63 | M_WORKER_SPAWN_DEF2(worker, (filename, m_string_t) ) 64 | 65 | int main(void) 66 | { 67 | exit(0); 68 | } 69 | -------------------------------------------------------------------------------- /tests/check-rbtree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include 24 | #include "m-rbtree.h" 25 | 26 | RBTREE_DEF(tree_int, int) 27 | 28 | // Container OPLIST 29 | #define CONT_OPL RBTREE_OPLIST(tree_int, M_OPL_int()) 30 | 31 | // C++ Base class of the item in the container 32 | #define BASE_CLASS int 33 | 34 | // C++ Container class 35 | #define CONT_CLASS std::set 36 | 37 | // Compare the M*LIB container a to the C++ container b 38 | #define CMP_CONT(a, b) cmp_cont(a, b) 39 | 40 | void cmp_cont(const tree_int_t a, const std::set &b) 41 | { 42 | tree_int_it_t ita; 43 | tree_int_it(ita, a); 44 | auto itb = b.begin(); 45 | while (itb != b.end()) { 46 | assert(!tree_int_end_p(ita)); 47 | const int *b0 = tree_int_cref(ita); 48 | const int &b1 = *itb; 49 | assert(*b0 == b1); 50 | itb++; 51 | tree_int_next(ita); 52 | } 53 | assert(tree_int_end_p(ita)); 54 | } 55 | 56 | #define DEFAULT_NUMBER 1000000 57 | 58 | #define push_back insert 59 | #include "check-generic.hpp" 60 | -------------------------------------------------------------------------------- /tests/check-bptree-set.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2025-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include 24 | #include "m-bptree.h" 25 | 26 | BPTREE_DEF(tree_int, 5, int) 27 | 28 | // Container OPLIST 29 | #define CONT_OPL BPTREE_OPLIST(tree_int, M_OPL_int()) 30 | 31 | // C++ Base class of the item in the container 32 | #define BASE_CLASS int 33 | 34 | // C++ Container class 35 | #define CONT_CLASS std::set 36 | 37 | // Compare the M*LIB container a to the C++ container b 38 | #define CMP_CONT(a, b) cmp_cont(a, b) 39 | 40 | void cmp_cont(const tree_int_t a, const std::set &b) 41 | { 42 | tree_int_it_t ita; 43 | tree_int_it(ita, a); 44 | auto itb = b.begin(); 45 | while (itb != b.end()) { 46 | assert(!tree_int_end_p(ita)); 47 | const int *b0 = tree_int_cref(ita); 48 | const int &b1 = *itb; 49 | assert(*b0 == b1); 50 | itb++; 51 | tree_int_next(ita); 52 | } 53 | assert(tree_int_end_p(ita)); 54 | } 55 | 56 | #define DEFAULT_NUMBER 1000000 57 | 58 | #define push_back insert 59 | #include "check-generic.hpp" 60 | -------------------------------------------------------------------------------- /tests/check-dplist.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include 24 | #include "m-list.h" 25 | 26 | LIST_DUAL_PUSH_DEF(list_int, int) 27 | 28 | // Container OPLIST 29 | #define CONT_OPL LIST_OPLIST(list_int, M_OPL_int()) 30 | 31 | // C++ Base class of the item in the container 32 | #define BASE_CLASS int 33 | 34 | // C++ Container class 35 | #define CONT_CLASS std::list 36 | 37 | // Compare the M*LIB container a to the C++ container b 38 | #define CMP_CONT(a, b) cmp_cont(a, b) 39 | 40 | void cmp_cont(const list_int_t a, const std::list &b) 41 | { 42 | list_int_it_t ita; 43 | list_int_it(ita, a); 44 | auto itb = b.rbegin(); 45 | while (itb != b.rend()) { 46 | assert(!list_int_end_p(ita)); 47 | const int *b0 = list_int_cref(ita); 48 | const int &b1 = *itb; 49 | assert(*b0 == b1); 50 | itb++; 51 | list_int_next(ita); 52 | } 53 | assert(list_int_end_p(ita)); 54 | } 55 | 56 | #define DEFAULT_NUMBER 100000 57 | 58 | #define HAVE_PUSH_FRONT 59 | #define HAVE_REVERSE_IT 60 | 61 | #include "check-generic.hpp" 62 | -------------------------------------------------------------------------------- /tests/check-uset.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include 24 | #include "m-dict.h" 25 | 26 | DICT_SET_DEF(dict_int, int) 27 | 28 | // Container OPLIST 29 | #define CONT_OPL DICT_SET_OPLIST(dict_int, M_OPL_int()) 30 | 31 | // C++ Base class of the item in the container 32 | #define BASE_CLASS int 33 | 34 | // C++ Container class 35 | #define CONT_CLASS std::unordered_set 36 | 37 | // Compare the M*LIB container a to the C++ container b 38 | #define CMP_CONT(a, b) cmp_cont(a, b) 39 | 40 | void cmp_cont(const dict_int_t a, const std::unordered_set &b) 41 | { 42 | size_t n = 0; 43 | auto itb = b.begin(); 44 | while (itb != b.end()) { 45 | const int &b1 = *itb; 46 | const int *b0 = dict_int_get(a, b1); 47 | assert(b0 != nullptr); 48 | assert(*b0 == b1); 49 | itb++; 50 | n++; 51 | } 52 | assert(dict_int_size(a) == n); 53 | } 54 | 55 | #define DEFAULT_NUMBER 1000000 56 | 57 | #define HAVE_GET_KEY_THROUGH_FIND 58 | #define DONT_HAVE_SEQUENCE_IT 59 | 60 | #define push_back insert 61 | #include "check-generic.hpp" 62 | -------------------------------------------------------------------------------- /tests/check-deque.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include 24 | #include "m-deque.h" 25 | 26 | DEQUE_DEF(deque_float, float) 27 | 28 | // Container OPLIST 29 | #define CONT_OPL DEQUE_OPLIST(deque_float, M_OPL_float()) 30 | 31 | // C++ Base class of the item in the container 32 | #define BASE_CLASS float 33 | 34 | // C++ Container class 35 | #define CONT_CLASS std::deque 36 | 37 | // Compare the M*LIB container a to the C++ container b 38 | #define CMP_CONT(a, b) cmp_cont(a, b) 39 | 40 | void cmp_cont(deque_float_t a, std::deque b) 41 | { 42 | deque_float_it_t ita; 43 | deque_float_it(ita, a); 44 | auto itb = b.begin(); 45 | while (itb != b.end()) { 46 | assert(!deque_float_end_p(ita)); 47 | const float *b0 = deque_float_cref(ita); 48 | float &b1 = *itb; 49 | assert(*b0 == b1); 50 | itb++; 51 | deque_float_next(ita); 52 | } 53 | assert(deque_float_end_p(ita)); 54 | } 55 | 56 | #define DEFAULT_NUMBER 1000000 57 | #define HAVE_PUSH_FRONT 58 | #define HAVE_POP_FRONT 59 | #define HAVE_POP_BACK 60 | #include "check-generic.hpp" 61 | -------------------------------------------------------------------------------- /example/ex-array02.c: -------------------------------------------------------------------------------- 1 | // This is the same example as ex-array01.c 2 | // It uses some macros to simplify the writing of the code. 3 | // So it is a shorter version of the first example. 4 | #include "m-array.h" 5 | 6 | // Let's define an array of 'char *' named 'array_charp' 7 | ARRAY_DEF (array_charp, char *) 8 | 9 | // Let's register globaly the oplist of array_charp 10 | // This is done by defining a macro named M_OPL_ and the type 11 | // of the containern, like this: 12 | #define M_OPL_array_charp_t() ARRAY_OPLIST(array_charp) 13 | // An oplist is the interface published by the type. 14 | // It contains all exported methods of the type 15 | // (and which functions shall be called to handle them). 16 | // It is both an input of the ARRAY_DEF macro (the last argument) 17 | // if the type used to create the container has non-standard 18 | // requirements (like pretty much any C structure) and an output 19 | // (using ARRAY_OPLIST) which provides the updated oplist 20 | // which will handle the container itself. 21 | 22 | int main(void) 23 | { 24 | // Create an array list 'al' of type 'array_charp_t' 25 | // M_LET will check if a global oplist has been registered 26 | // with the name array_charp_t, and if it finds it, will 27 | // define the type, initializes it and clears it after 28 | // it disappears from the bracket: 29 | M_LET (al, array_charp_t) { 30 | // add elements to the array list 31 | array_charp_push_back (al,"C"); 32 | array_charp_push_back (al,"A"); 33 | array_charp_push_back (al,"E"); 34 | array_charp_push_back (al,"B"); 35 | array_charp_push_back (al,"D"); 36 | array_charp_push_back (al,"F"); 37 | 38 | // Display contents of al 39 | printf("Original contents of al: "); 40 | // M_EACH is a macro which iterates over a container. 41 | // It first argument is the name of the created variable 42 | // which will be a pointer to one element of the container, 43 | // al is the container to iterate, 44 | // the last argument is either the type of the container 45 | // (if a global oplist has been registered) or is the oplist 46 | // of the container (if none). 47 | // Indeed the macro needs to access the methods of the container 48 | // to iterate over the container. 49 | // So for each element of the array al 50 | for M_EACH(element, al, array_charp_t) { 51 | printf ("%s ", *element); 52 | } 53 | printf("\n"); 54 | } // After this point al is automatically cleared 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /example/ex11-json-net.c: -------------------------------------------------------------------------------- 1 | // Based on https://github.com/nanopb/nanopb/blob/master/examples/simple/simple.c 2 | #include 3 | 4 | #include "m-serial-json.h" 5 | #include "m-tuple.h" 6 | #include "m-string.h" 7 | 8 | // Define a structure with one field 9 | TUPLE_DEF2(SimpleMessage, 10 | (lucky_number, int)) 11 | 12 | int main(void) 13 | { 14 | string_t buffer; 15 | m_serial_return_code_t status; 16 | 17 | /* Let's define a string 'buffer' that will receive the JSON representation of our message*/ 18 | string_init(buffer); 19 | 20 | /* Encode our message */ 21 | { 22 | SimpleMessage_t message; 23 | SimpleMessage_init(message); 24 | 25 | /* Create a stream that will write to our string buffer. */ 26 | m_serial_str_json_write_t stream; 27 | m_serial_str_json_write_init(stream, buffer); 28 | 29 | /* Fill in the lucky number */ 30 | message->lucky_number = 13; 31 | 32 | /* Now we are ready to encode the message! */ 33 | status = SimpleMessage_out_serial(stream, message); 34 | 35 | /* Then just check for any errors.. */ 36 | if (status != M_SERIAL_OK_DONE) 37 | { 38 | printf("Encoding failed: %d\n", status); 39 | return 1; 40 | } 41 | 42 | /* Clear the objets */ 43 | m_serial_str_json_write_clear(stream); 44 | SimpleMessage_clear(message); 45 | } 46 | 47 | /* Now we could transmit the message over network, store it in a file 48 | * It is represented in a string 'buffer' 49 | * but we are doing it right now. 50 | */ 51 | 52 | { 53 | /* Allocate another space for the decoded message. */ 54 | SimpleMessage_t message; 55 | SimpleMessage_init(message); 56 | 57 | /* Create a stream that reads from the buffer. */ 58 | m_serial_str_json_read_t stream; 59 | m_serial_str_json_read_init(stream, string_get_cstr(buffer)); 60 | 61 | /* Now we are ready to decode the message. */ 62 | status = SimpleMessage_in_serial(message, stream); 63 | 64 | /* Check for errors... */ 65 | if (status != M_SERIAL_OK_DONE) 66 | { 67 | printf("Decoding failed: %d\n", status); 68 | return 1; 69 | } 70 | 71 | /* Print the data contained in the message. */ 72 | printf("Your lucky number was %d!\n", message->lucky_number); 73 | 74 | /* Clear the objets */ 75 | m_serial_str_json_read_clear(stream); 76 | SimpleMessage_clear(message); 77 | } 78 | 79 | string_clear(buffer); 80 | 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /tests/tgen-mmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include 24 | #include "m-dict.h" 25 | 26 | DICT_DEF2(map_foo, int, float) 27 | DICT_DEF2(map_bar, long, float) 28 | DICT_DEF2(map_buz, char, float) 29 | 30 | extern void foo(map_foo_t our_map ); 31 | void foo(map_foo_t our_map ) 32 | { 33 | for (int i = 0; i < 10; ++i) 34 | map_foo_set_at(our_map, i, 0.5f * (float) i ); 35 | map_foo_set_at( our_map, 32, 0.34f ); 36 | map_foo_set_at( our_map, 233, 0.324f ); 37 | printf( "%f\n", *map_foo_get( our_map, 5 ) ); 38 | } 39 | 40 | extern void bar(map_bar_t our_map); 41 | void bar(map_bar_t our_map) 42 | { 43 | for (long i = 0; i < 10; ++i) 44 | map_bar_set_at( our_map, i, 0.5f * (float) i ); 45 | map_bar_set_at( our_map, 32, 0.34f ); 46 | map_bar_set_at( our_map, 233, 0.324f ); 47 | printf( "%f\n", *map_bar_get( our_map, 5 ) ); 48 | } 49 | 50 | extern void buz( map_buz_t our_map); 51 | void buz( map_buz_t our_map) 52 | { 53 | for (char i = 0; i < 10; ++i) 54 | map_buz_set_at( our_map, i, 0.5f * (float) i ); 55 | map_buz_set_at( our_map, 32, 0.34f ); 56 | map_buz_set_at( our_map, (char) 233, 0.324f ); 57 | } 58 | -------------------------------------------------------------------------------- /tests/check-list.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include 24 | #include "m-list.h" 25 | 26 | LIST_DEF(list_int, int) 27 | 28 | // Container OPLIST 29 | #define CONT_OPL LIST_OPLIST(list_int, M_OPL_int()) 30 | 31 | // C++ Base class of the item in the container 32 | #define BASE_CLASS int 33 | 34 | // C++ Container class 35 | #define CONT_CLASS std::forward_list 36 | 37 | // Compare the M*LIB container a to the C++ container b 38 | #define CMP_CONT(a, b) cmp_cont(a, b) 39 | 40 | void cmp_cont(list_int_t a, std::forward_list b) 41 | { 42 | list_int_it_t ita; 43 | list_int_it(ita, a); 44 | auto itb = b.begin(); 45 | while (itb != b.end()) { 46 | assert(!list_int_end_p(ita)); 47 | const int *b0 = list_int_cref(ita); 48 | int &b1 = *itb; 49 | assert(*b0 == b1); 50 | itb++; 51 | list_int_next(ita); 52 | } 53 | assert(list_int_end_p(ita)); 54 | } 55 | 56 | #define HAVE_INSERT_AFTER 57 | #define HAVE_ERASE_AFTER 58 | #define DEFAULT_NUMBER 100000 59 | 60 | // C++ forward_list pushs in front instead of in back 61 | #define push_back push_front 62 | #define pop_back pop_front 63 | #define back front 64 | #include "check-generic.hpp" 65 | -------------------------------------------------------------------------------- /tests/tgen-mlist.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #include "m-list.h" 25 | #include "m-i-list.h" 26 | 27 | LIST_DEF(list_dbl, double) 28 | LIST_DUAL_PUSH_DEF(list_dbl2, double) 29 | 30 | void f_push_back(list_dbl_t list); 31 | double f_iterator(list_dbl_t list); 32 | 33 | void f_push_back(list_dbl_t list) 34 | { 35 | list_dbl_push_back(list, 2.0); 36 | } 37 | 38 | double f_iterator(list_dbl_t list) 39 | { 40 | list_dbl_it_t it; 41 | double s = 0.0; 42 | for(list_dbl_it(it, list); !list_dbl_end_p(it); list_dbl_next(it)) 43 | s += *list_dbl_cref(it); 44 | return s; 45 | } 46 | 47 | void f2_push_back(list_dbl2_t list); 48 | double f2_iterator(list_dbl2_t list); 49 | 50 | void f2_push_back(list_dbl2_t list) 51 | { 52 | list_dbl2_push_back(list, 2.0); 53 | } 54 | 55 | double f2_iterator(list_dbl2_t list) 56 | { 57 | list_dbl2_it_t it; 58 | double s = 0.0; 59 | for(list_dbl2_it(it, list); !list_dbl2_end_p(it); list_dbl2_next(it)) 60 | s += *list_dbl2_cref(it); 61 | return s; 62 | } 63 | 64 | 65 | struct itest { 66 | int n; 67 | ILIST_INTERFACE (ilist_list, struct itest); 68 | }; 69 | 70 | ILIST_DEF(ilist_list, struct itest) 71 | 72 | extern void f_init(ilist_list_t l); 73 | void f_init(ilist_list_t l) 74 | { 75 | ilist_list_init(l); 76 | } 77 | 78 | -------------------------------------------------------------------------------- /example/ex-algo02.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "m-array.h" 3 | #include "m-algo.h" 4 | 5 | /* Define a dynamic array of int */ 6 | ARRAY_DEF(vector_int, int) 7 | /* Register the oplist of this dynamic array globally (using implicitely M_BASIC_OPLIST) */ 8 | #define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int) 9 | /* Define some standards algorithms on this dynamic array. We can reuse the prefix of the dynamic array */ 10 | ALGO_DEF(vector_int, vector_int_t) 11 | 12 | /* Define a dynamic array of bool */ 13 | ARRAY_DEF(vector_bool, bool) 14 | /* Register the oplist of this dynamic array globally */ 15 | #define M_OPL_vector_bool_t() ARRAY_OPLIST(vector_bool, M_BOOL_OPLIST) 16 | /* Define some standards algorithms on this dynamic array. We can reuse the prefix of the dynamic array */ 17 | ALGO_DEF(vector_bool, vector_bool_t) 18 | 19 | /* ID function */ 20 | static bool id(bool x) { return x ; } 21 | 22 | int main(void) 23 | { 24 | // Define, init (& later clear) myvector & tmp as vector_int_t 25 | M_LET(myvector, tmp, vector_int_t) { 26 | // Fill myvector with 3 int equal to 20 27 | vector_int_fill_n(myvector, 3, 20); 28 | // Fill tmp with 3 int equal to 33 29 | vector_int_fill_n(tmp, 3, 33); 30 | // Append all tmp in myvector 31 | vector_int_splice(myvector, tmp); 32 | // Fill tmp with 2 int equal to 10 33 | vector_int_fill_n(tmp, 2, 10); 34 | // Append all tmp in myvector 35 | vector_int_splice(myvector, tmp); 36 | // Display the result 37 | printf("myvector contains:"); 38 | // In C11, the for loop can be simplified as : 39 | #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) 40 | ALGO_FOR_EACH(myvector, vector_int_t, M_PRINT, " "); 41 | #else 42 | for M_EACH(it, myvector, vector_int_t) { 43 | printf(" %d", *it); 44 | } 45 | #endif 46 | printf("\n"); 47 | } /* End of M_LET: myvector & tmp are automaticly cleared */ 48 | 49 | // Same thing but with booleans 50 | M_LET(myvector, tmp, vector_bool_t) { 51 | vector_bool_fill_n(myvector, 3, false); 52 | vector_bool_fill_n(tmp, 3, true); 53 | vector_bool_splice(myvector, tmp); 54 | vector_bool_fill_n(tmp, 2, false); 55 | vector_bool_splice(myvector, tmp); 56 | printf("myvector contains:"); 57 | for M_EACH(it, myvector, vector_bool_t) { 58 | printf(" %d", (int)*it); 59 | } 60 | printf("\n"); 61 | printf ("ALL: %d ANY: %d NONE: %d\n", 62 | vector_bool_all_of_p(myvector, id), 63 | vector_bool_any_of_p(myvector, id), 64 | vector_bool_none_of_p(myvector, id) ); 65 | } /* End of M_LET: myvector & tmp are automaticly cleared */ 66 | 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /tests/tgen-marray.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #include "m-array.h" 25 | 26 | ARRAY_DEF(array_uint, unsigned int) 27 | 28 | unsigned int add_two(const array_uint_t tab, size_t i, size_t j); 29 | void size_to_exactly(array_uint_t tab, size_t n); 30 | void push_back (array_uint_t tab, unsigned int n); 31 | void unpop(array_uint_t tab); 32 | void unpop_if(array_uint_t tab, unsigned int x); 33 | void construct(void *p); 34 | 35 | unsigned int add_two(const array_uint_t tab, size_t i, size_t j) 36 | { 37 | return *array_uint_cget(tab, i) + *array_uint_cget(tab, j); 38 | } 39 | 40 | void size_to_exactly(array_uint_t tab, size_t n) 41 | { 42 | array_uint_resize(tab, 0); 43 | array_uint_resize(tab, n); 44 | } 45 | 46 | void push_back (array_uint_t tab, unsigned int n) 47 | { 48 | array_uint_push_back(tab, n); 49 | } 50 | 51 | void unpop(array_uint_t tab) 52 | { 53 | array_uint_pop_back(NULL, tab); 54 | } 55 | 56 | void unpop_if(array_uint_t tab, unsigned int x) 57 | { 58 | if (x == *array_uint_back(tab)) 59 | array_uint_pop_back(NULL, tab); 60 | } 61 | 62 | array_uint_t global; 63 | extern void f(void *p); 64 | void construct(void *p) 65 | { 66 | array_uint_it_t mark; 67 | array_uint_it_end(mark, global); 68 | f(p); 69 | array_uint_pop_until(global, mark); 70 | } 71 | -------------------------------------------------------------------------------- /tests/check-umap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include 24 | #include "m-dict.h" 25 | 26 | DICT_DEF2(dict_int, int, int) 27 | 28 | // Container OPLIST 29 | #define CONT_OPL DICT_OPLIST(dict_int, M_OPL_int(), M_OPL_int() ) 30 | 31 | // C++ Base class of the item in the container 32 | #define BASE_CLASS int 33 | 34 | // C++ Container class 35 | #define CONT_CLASS std::unordered_map 36 | 37 | // Compare the M*LIB container a to the C++ container b 38 | #define CMP_CONT(a, b) cmp_cont(a, b) 39 | 40 | // Get the value from the iterator 41 | #define CLASS_IT_TO_INT(it) (it)->second 42 | #define TYPE_IT_TO_INT(it) (it)->value 43 | 44 | void cmp_cont(const dict_int_t a, const std::unordered_map &b) 45 | { 46 | size_t n = 0; 47 | auto itb = b.begin(); 48 | while (itb != b.end()) { 49 | const int *b0 = dict_int_get(a, itb->first); 50 | assert(b0 != nullptr); 51 | assert(*b0 == itb->second); 52 | itb++; 53 | n++; 54 | } 55 | assert(dict_int_size(a) == n); 56 | } 57 | 58 | #define DEFAULT_NUMBER 1000000 59 | 60 | // Use find to perform GET_KEY for C++ 61 | #define HAVE_GET_KEY_THROUGH_FIND 62 | // Container are nor ordered 63 | #define DONT_HAVE_SEQUENCE_IT 64 | // associative array container 65 | #define HAVE_SET_KEY 66 | 67 | #define push_back insert 68 | #include "check-generic.hpp" 69 | -------------------------------------------------------------------------------- /tests/check-bptree-map.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include 24 | #include "m-bptree.h" 25 | 26 | BPTREE_DEF2(tree_int, 5, int, int) 27 | 28 | // Container OPLIST 29 | #define CONT_OPL BPTREE_OPLIST2(tree_int, M_OPL_int(), M_OPL_int() ) 30 | 31 | // C++ Base class of the item in the container 32 | #define BASE_CLASS int 33 | 34 | // C++ Container class 35 | #define CONT_CLASS std::map 36 | 37 | // Compare the M*LIB container a to the C++ container b 38 | #define CMP_CONT(a, b) cmp_cont(a, b) 39 | 40 | #define CLASS_IT_TO_INT(it) (it)->second 41 | #define TYPE_IT_TO_INT(it) (it)->value 42 | 43 | void cmp_cont(const tree_int_t a, const std::map &b) 44 | { 45 | tree_int_it_t ita; 46 | tree_int_it(ita, a); 47 | auto itb = b.begin(); 48 | while (itb != b.end()) { 49 | assert(!tree_int_end_p(ita)); 50 | const int *k0 = tree_int_cref(ita)->key_ptr; 51 | const int &k1 = itb->first; 52 | assert(*k0 == k1); 53 | const int *v0 = tree_int_cref(ita)->value_ptr; 54 | const int &v1 = itb->second; 55 | assert(*v0 == v1); 56 | itb++; 57 | tree_int_next(ita); 58 | } 59 | assert(tree_int_end_p(ita)); 60 | } 61 | 62 | #define DEFAULT_NUMBER 1000000 63 | 64 | #define HAVE_GET_KEY_THROUGH_FIND 65 | #define HAVE_SET_KEY 66 | #define HAVE_KEY_PTR 67 | 68 | #define push_back insert 69 | #include "check-generic.hpp" 70 | -------------------------------------------------------------------------------- /example/ex-try01.c: -------------------------------------------------------------------------------- 1 | #include "m-try.h" 2 | #include "m-array.h" 3 | 4 | // Define & register an array of int 5 | ARRAY_DEF(array, int) 6 | #define M_OPL_array_t() ARRAY_OPLIST(array, M_BASIC_OPLIST) 7 | 8 | // This shall be defined once per program to define the global variables needed 9 | // to handle the exceptions. 10 | M_TRY_DEF_ONCE() 11 | 12 | static void f(void) 13 | { 14 | M_TRY(f_exception) { 15 | // Let's define a variable and do stuff: 16 | // Using M_LET allows the register of destructors for the exception handler. 17 | M_LET(a, array_t) { 18 | array_push_back(a, 5); 19 | array_push_back(a, 4); 20 | array_push_back(a, 3); 21 | array_push_back(a, 2); 22 | array_push_back(a, 1); 23 | // Throw a M_ERROR_MEMORY exception 24 | M_THROW(M_ERROR_MEMORY); 25 | printf("This should never be printed!\n"); 26 | } 27 | } M_CATCH(f_exception, M_ERROR_MEMORY) { 28 | // Exception handler than catches the M_ERROR_MEMORY errors. 29 | // Here the destructor of variable a has been called to free memory 30 | printf("Memory exception %d received in f function, thrown by %s:%d\n", 31 | f_exception->error_code, f_exception->filename, f_exception->line); 32 | } 33 | } 34 | 35 | static void g(void) 36 | { 37 | M_TRY(f_exception) { 38 | // Let's define a variable and do stuff: 39 | // Using M_LET allows the register of destructors for the exception handler. 40 | M_LET(a, array_t) { 41 | array_push_back(a, 5); 42 | array_push_back(a, 4); 43 | array_push_back(a, 3); 44 | array_push_back(a, 2); 45 | array_push_back(a, 1); 46 | // Throw an unkown exception 47 | M_THROW(42); 48 | printf("This should never be printed!\n"); 49 | } 50 | } M_CATCH(f_exception, M_ERROR_MEMORY) { 51 | printf("Memory exception %d received in f function, thrown by %s:%d\n", 52 | f_exception->error_code, f_exception->filename, f_exception->line); 53 | printf("This should never be printed!\n"); 54 | } 55 | } 56 | 57 | int main(void) 58 | { 59 | // Let's do a global exception handler 60 | M_TRY(main_exception) { 61 | f(); 62 | g(); 63 | } M_CATCH(main_exception, 0) { 64 | // Exception handler than catches all errors. 65 | // Here the destructor of variable a has been called to free memory 66 | printf("Exception %d received in main function, thrown by %s:%d\n", 67 | main_exception->error_code, main_exception->filename, main_exception->line); 68 | } 69 | printf("You should run it under valgrind to check that all memory allocations are freed.\n"); 70 | exit(0); 71 | } 72 | -------------------------------------------------------------------------------- /tests/except-bitset.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Test that the bitset module properly support exceptions 3 | * 4 | * Copyright (c) 2017-2025, Patrick Pelissier 5 | * All rights reserved. 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * + Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * + Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 15 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | #include "test-obj-except.h" 26 | #include "m-string.h" 27 | #include "m-bitset.h" 28 | 29 | M_TRY_DEF_ONCE() 30 | 31 | static void test1(unsigned n) 32 | { 33 | FILE *f = m_core_fopen ("a-ebitset.dat", "wt"); 34 | assert(f != NULL); 35 | M_TRY(test1) { 36 | M_LET(data, tmp, bitset_t) { 37 | for(unsigned i = 0; i < 100*n; i++) { 38 | bitset_push_back(data, (bool) (i % 2)); 39 | } 40 | bitset_set(tmp, data); 41 | bitset_resize(tmp, 10000); 42 | bitset_reserve(tmp, 20000); 43 | bitset_push_at(tmp, 23, true); 44 | M_LET( (tmp2, tmp), bitset_t) { 45 | bitset_out_str(f, tmp2); 46 | } 47 | M_LET(str, string_t) { 48 | bitset_get_str(str, tmp, false); 49 | bool b = bitset_parse_str(tmp, string_get_cstr(str), NULL); 50 | assert(b); 51 | } 52 | } 53 | } M_CATCH(test1, 0) { 54 | // Nothing to do 55 | } 56 | fclose(f); 57 | 58 | f = m_core_fopen ("a-ebitset.dat", "rt"); 59 | assert(f != NULL); 60 | M_TRY(test1) { 61 | M_LET(data, bitset_t) { 62 | bool b = bitset_in_str(data, f); 63 | (void)b; 64 | } 65 | } M_CATCH(test1, 0) { 66 | // Nothing to do 67 | } 68 | fclose(f); 69 | } 70 | 71 | int main(void) 72 | { 73 | do_test1(test1); 74 | exit(0); 75 | } 76 | -------------------------------------------------------------------------------- /tests/tgen-mdict.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include 24 | #include "m-dict.h" 25 | #include "m-string.h" 26 | 27 | static inline bool my_oor_equal_p(uint64_t k, unsigned char n) 28 | { 29 | return k == ~(uint64_t) n; 30 | } 31 | static inline void my_oor_set(uint64_t *k, unsigned char n) 32 | { 33 | *k = ~(uint64_t)n; 34 | } 35 | DICT_OA_DEF2(dict, 36 | uint64_t, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(my_oor_equal_p), OOR_SET(my_oor_set M_IPTR)), 37 | uint32_t, M_BASIC_OPLIST) 38 | 39 | extern void set_at(dict_t d, uint64_t key, uint32_t value); 40 | void set_at(dict_t d, uint64_t key, uint32_t value) 41 | { 42 | dict_set_at(d, key, value); 43 | } 44 | 45 | extern uint32_t get(dict_t d, uint64_t key); 46 | uint32_t get(dict_t d, uint64_t key) 47 | { 48 | uint32_t *p = dict_get(d, key); 49 | return p == NULL ? 0: *p; 50 | } 51 | 52 | extern void increment(dict_t d, uint64_t key); 53 | void increment(dict_t d, uint64_t key) 54 | { 55 | uint32_t *p = dict_get(d, key); 56 | if (p != NULL) { 57 | (*p) ++; 58 | } else { 59 | dict_set_at(d, key, 1); 60 | } 61 | } 62 | 63 | extern void clean(dict_t d); 64 | void clean(dict_t d) 65 | { 66 | dict_reset(d); 67 | } 68 | 69 | extern bool testempty(uint64_t d); 70 | bool testempty(uint64_t d) 71 | { 72 | if (my_oor_equal_p(d, 0) || my_oor_equal_p(d, 1)) 73 | return true; 74 | else 75 | return false; 76 | } 77 | 78 | extern bool testempty2(string_t d); 79 | bool testempty2(string_t d) 80 | { 81 | if (string_oor_equal_p(d, 0) || string_oor_equal_p(d, 1)) 82 | return true; 83 | else 84 | return false; 85 | } 86 | -------------------------------------------------------------------------------- /example/ex-alloc1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //////////////////////////////////////////////////////////// 5 | 6 | static size_t allocated_size = 0; 7 | 8 | static void* my_alloc(size_t s) 9 | { 10 | printf("Alloc called s=%lu!\n", s); 11 | allocated_size += s; 12 | return malloc(s); 13 | } 14 | 15 | static void my_free(void *ptr, size_t s) 16 | { 17 | printf("Free called s=%lu!\n", s); 18 | allocated_size -= s; 19 | free(ptr); 20 | } 21 | 22 | //////////////////////////////////////////////////////////// 23 | 24 | static void *last_alloc; 25 | 26 | static void* my_array_alloc(size_t s, void *org, size_t n) 27 | { 28 | printf("Array Alloc called org=%p of n=%zu elements of size s=%lu!\n", org, n, s); 29 | last_alloc = realloc(org, s*n); 30 | return last_alloc; 31 | } 32 | 33 | static void my_array_free(void *ptr) 34 | { 35 | printf("Array Free called ptr=%p last_alloc=%p!\n", ptr, last_alloc); 36 | if (ptr != last_alloc) { 37 | printf("Somthing went wrong.\n"); 38 | exit(4); 39 | } 40 | free(ptr); 41 | } 42 | 43 | //////////////////////////////////////////////////////////// 44 | 45 | // Allocate for single object 46 | # define M_MEMORY_ALLOC(ctx, type) my_alloc (sizeof (type)) 47 | # define M_MEMORY_DEL(ctx, ptr) my_free(ptr, sizeof *ptr) 48 | 49 | // Allocate for array of objects 50 | # define M_MEMORY_REALLOC(ctx, type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n) 51 | # define M_MEMORY_FREE(ctx, type, ptr, n) my_array_free(ptr) 52 | 53 | #include "m-list.h" 54 | #include "m-array.h" 55 | 56 | //////////////////////////////////////////////////////////// 57 | 58 | LIST_DEF(list_int, int) 59 | 60 | static void test_list(void) 61 | { 62 | printf("List demo\n"); 63 | 64 | list_int_t list; 65 | list_int_init(list); 66 | 67 | list_int_push_back(list, 34); 68 | list_int_push_back(list, 34); 69 | 70 | if (allocated_size == 0) { 71 | printf("Nothing was allocated... Very strange...\n"); 72 | exit(1); 73 | } 74 | list_int_clear(list); 75 | 76 | if (allocated_size != 0) { 77 | printf("Nothing was freed (%lu)... Very strange...\n", allocated_size); 78 | exit(2); 79 | } 80 | printf("Global custom allocator for list works!\n"); 81 | } 82 | 83 | //////////////////////////////////////////////////////////// 84 | 85 | ARRAY_DEF(array_int, int) 86 | 87 | static void test_array(void) 88 | { 89 | printf("Array demo\n"); 90 | 91 | array_int_t array; 92 | array_int_init(array); 93 | 94 | array_int_push_back(array, 34); 95 | array_int_push_back(array, 34); 96 | 97 | array_int_clear(array); 98 | 99 | printf("Global custom allocator for array works!\n"); 100 | } 101 | 102 | //////////////////////////////////////////////////////////// 103 | 104 | int main(void) 105 | { 106 | test_list(); 107 | test_array(); 108 | exit(0); 109 | } 110 | -------------------------------------------------------------------------------- /example/ex-dict03.c: -------------------------------------------------------------------------------- 1 | // Based upon http://www.sanfoundry.com/cpp-program-implement-map-stl/ 2 | #include 3 | #include 4 | 5 | #include "m-dict.h" 6 | #include "m-string.h" 7 | 8 | // Define a dictionary (hashmap) from 'char' to 'int' 9 | DICT_DEF2(dict_map, char, int) 10 | 11 | int main(void) 12 | { 13 | dict_map_t mp; 14 | dict_map_it_t it; 15 | int choice, item; 16 | string_t str; 17 | char s; 18 | 19 | dict_map_init(mp); 20 | string_init (str); 21 | 22 | while (true) 23 | { 24 | printf ("\n---------------------\n"); 25 | printf ("Map Implementation in M*LIB\n"); 26 | printf ("\n---------------------\n"); 27 | printf("1.Insert Element into the Map\n"); 28 | printf("2.Delete Element of the Map\n"); 29 | printf("3.Size of the Map\n"); 30 | printf("4.Find Element at a key in Map\n"); 31 | printf("5.Display by Iterator\n"); 32 | printf("6.Exit\n"); 33 | printf("Enter your Choice: "); 34 | 35 | string_fgets (str, stdin, STRING_READ_PURE_LINE); 36 | choice = atoi(string_get_cstr(str)); 37 | 38 | switch(choice) 39 | { 40 | case 1: 41 | printf("Enter value to be inserted: "); 42 | string_fgets (str, stdin, STRING_READ_PURE_LINE); 43 | item = atoi(string_get_cstr(str)); 44 | printf("Enter the key: "); 45 | string_fgets (str, stdin, STRING_READ_PURE_LINE); 46 | s = atoi(string_get_cstr(str)); 47 | dict_map_set_at(mp, s, item); 48 | break; 49 | 50 | case 2: 51 | printf("Enter the mapped string to be deleted: "); 52 | string_fgets (str, stdin, STRING_READ_PURE_LINE); 53 | s = atoi(string_get_cstr(str)); 54 | dict_map_erase(mp, s); 55 | break; 56 | 57 | case 3: 58 | printf("Size of Map: %zu\n", dict_map_size(mp) ); 59 | break; 60 | 61 | case 4: 62 | printf("Enter the key at which value to be found: "); 63 | string_fgets (str, stdin, STRING_READ_PURE_LINE); 64 | s = atoi(string_get_cstr(str)); 65 | int *ref = dict_map_get(mp, s); 66 | if (ref != NULL) 67 | { 68 | printf("Found %d\n", *ref); 69 | } 70 | else 71 | { 72 | printf("No Element Found\n"); 73 | } 74 | break; 75 | 76 | case 5: 77 | printf("Displaying Map by Iterator:\n"); 78 | for (dict_map_it(it, mp); !dict_map_end_p(it); dict_map_next(it)) 79 | { 80 | const struct dict_map_pair_s *cref = dict_map_cref(it); 81 | printf ("%d : %d\n", cref->key, cref->value); 82 | } 83 | break; 84 | 85 | case 6: 86 | dict_map_clear(mp); 87 | string_clear (str); 88 | exit(0); 89 | break; 90 | 91 | default: 92 | printf("Wrong Choice\n"); 93 | break; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /example/ex-bptree01.c: -------------------------------------------------------------------------------- 1 | #include "m-bptree.h" 2 | #include "m-string.h" 3 | 4 | // Define a map int -> string named map_employee_id 5 | // The number 5 is the number of elements in a node of the B+TREE 6 | BPTREE_DEF2(map_employee_id, 5, int, string_t) 7 | // Register the oplist of this map globally. 8 | #define M_OPL_map_employee_id_t() BPTREE_OPLIST2(map_employee_id, M_BASIC_OPLIST, STRING_OPLIST) 9 | 10 | // Define a map string -> int named map_employee_name 11 | // The number 5 is the number of elements in a node of the B+TREE 12 | BPTREE_DEF2(map_employee_name, 5, string_t, int) 13 | // Register the oplist of this map globally. 14 | #define M_OPL_map_employee_name_t() BPTREE_OPLIST2(map_employee_name, STRING_OPLIST, M_BASIC_OPLIST) 15 | 16 | int main(void) 17 | { 18 | map_employee_id_t Employees; 19 | map_employee_id_init(Employees); 20 | 21 | // Assign the map with some data 22 | map_employee_id_set_at(Employees, 17425, STRING_CTE("Mike")); 23 | map_employee_id_set_at(Employees, 7147, STRING_CTE("Tango")); 24 | map_employee_id_set_at(Employees, 841, STRING_CTE("Charlie")); 25 | map_employee_id_set_at(Employees, 11632, STRING_CTE("John Do")); 26 | map_employee_id_set_at(Employees, 852, STRING_CTE("Peter")); 27 | map_employee_id_set_at(Employees, 530, STRING_CTE("Amanda")); 28 | 29 | // You can also emplace the structure 30 | map_employee_id_emplace_val(Employees, 4258, "Elisabeth"); 31 | 32 | printf("Number of employees: %zu\n", map_employee_id_size(Employees)); 33 | 34 | // Iterate over the employee list 35 | printf("\nList of employees (sorted by id):\n"); 36 | map_employee_id_it_t it; 37 | for(map_employee_id_it(it, Employees); !map_employee_id_end_p(it); map_employee_id_next(it)) { 38 | // Get a pointer to this employee from the iterator 39 | const map_employee_id_itref_t *e = map_employee_id_cref(it); 40 | // Print it 41 | printf ("%d: %s\n", *(e->key_ptr), string_get_cstr(*(e->value_ptr))); 42 | } 43 | 44 | // Now, let's go using some macros! 45 | 46 | // Let's create a reverse map 47 | M_LET(Employees_r, map_employee_name_t) { 48 | 49 | // Let's fill in the reverse map with each employee 50 | // (using macro M_EACH) 51 | for M_EACH(e, Employees, map_employee_id_t) { 52 | map_employee_name_set_at(Employees_r, *(e->value_ptr), *(e->key_ptr)); 53 | } 54 | 55 | // Iterate over the employee list 56 | printf("\nList of employees (sorted by name):\n"); 57 | for M_EACH(e, Employees_r, map_employee_name_t) { 58 | printf ("%d: %s\n", *(e->value_ptr), string_get_cstr(*(e->key_ptr))); 59 | } 60 | 61 | // Print 62 | printf("\nElisabeth has id = %d\n", *map_employee_name_get(Employees_r, STRING_CTE("Elisabeth"))); 63 | // Print using emplace (we give a const char [] isntead of a const string_t, avoiding macro STRING_CTE) 64 | printf("\nElisabeth has id = %d\n", *map_employee_name_get_emplace(Employees_r, "Elisabeth")); 65 | } /* Employees_r is cleared beyond this point */ 66 | 67 | // But employee is not since we don't use M_LET 68 | map_employee_id_clear(Employees); 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /example/ex-alloc2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "m-list.h" 5 | #include "m-array.h" 6 | 7 | //////////////////////////////////////////////////////////// 8 | 9 | static size_t allocated_size = 0; 10 | 11 | static void* my_alloc(size_t s) 12 | { 13 | printf("Alloc called s=%lu!\n", s); 14 | allocated_size += s; 15 | return malloc(s); 16 | } 17 | 18 | static void my_free(void *ptr, size_t s) 19 | { 20 | printf("Free called s=%lu!\n", s); 21 | allocated_size -= s; 22 | free(ptr); 23 | } 24 | 25 | // Allocate for single object 26 | # define MY_MEMORY_ALLOC(ctx, type) my_alloc (sizeof (type)) 27 | # define MY_MEMORY_DEL(ctx, ptr) my_free(ptr, sizeof *ptr) 28 | 29 | //////////////////////////////////////////////////////////// 30 | 31 | // Override only for this container the memory allocation function 32 | LIST_DEF(list_int, int, M_OPEXTEND(M_BASIC_OPLIST, NEW(MY_MEMORY_ALLOC), DEL(MY_MEMORY_DEL))) 33 | 34 | static void test_list(void) 35 | { 36 | printf("List demo\n"); 37 | 38 | list_int_t list; 39 | list_int_init(list); 40 | 41 | list_int_push_back(list, 34); 42 | list_int_push_back(list, 34); 43 | 44 | if (allocated_size == 0) { 45 | printf("Nothing was allocated... Very strange...\n"); 46 | exit(1); 47 | } 48 | list_int_clear(list); 49 | 50 | if (allocated_size != 0) { 51 | printf("Nothing was freed (%lu)... Very strange...\n", allocated_size); 52 | exit(2); 53 | } 54 | printf("Global custom allocator for list works!\n"); 55 | } 56 | 57 | //////////////////////////////////////////////////////////// 58 | 59 | static void *last_alloc; 60 | 61 | static void* my_array_alloc(size_t s, void *org, size_t n) 62 | { 63 | printf("Array Alloc called org=%p of n=%zu elements of size s=%lu!\n", org, n, s); 64 | last_alloc = realloc(org, s*n); 65 | return last_alloc; 66 | } 67 | 68 | static void my_array_free(void *ptr) 69 | { 70 | printf("Array Free called ptr=%p last_alloc=%p!\n", ptr, last_alloc); 71 | if (ptr != last_alloc) { 72 | printf("Somthing went wrong.\n"); 73 | exit(4); 74 | } 75 | free(ptr); 76 | } 77 | 78 | // Allocate for array of objects 79 | # define MY_MEMORY_REALLOC(ctx, type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n) 80 | # define MY_MEMORY_FREE(ctx, type, ptr, n) my_array_free(ptr) 81 | 82 | //////////////////////////////////////////////////////////// 83 | 84 | // Override only for this container the memory allocation function 85 | ARRAY_DEF(array_int, int, M_OPEXTEND(M_BASIC_OPLIST, REALLOC(MY_MEMORY_REALLOC), FREE(MY_MEMORY_FREE))) 86 | 87 | static void test_array(void) 88 | { 89 | printf("Array demo\n"); 90 | 91 | array_int_t array; 92 | array_int_init(array); 93 | 94 | array_int_push_back(array, 34); 95 | array_int_push_back(array, 34); 96 | 97 | array_int_clear(array); 98 | 99 | printf("Global custom allocator for array works!\n"); 100 | } 101 | 102 | //////////////////////////////////////////////////////////// 103 | 104 | int main(void) 105 | { 106 | test_list(); 107 | test_array(); 108 | exit(0); 109 | } 110 | -------------------------------------------------------------------------------- /example/ex11-tstc.c: -------------------------------------------------------------------------------- 1 | /* Based on the example of STC https://github.com/tylov/STC */ 2 | #include "m-dict.h" 3 | #include "m-array.h" 4 | #include "m-deque.h" 5 | #include "m-list.h" 6 | #include "m-rbtree.h" 7 | #include "m-algo.h" 8 | #include "m-tuple.h" 9 | 10 | // NOTE: After each definition of a container, we register its oplist 11 | // It is not mandatory, but it makes the code easier to write and read. 12 | 13 | // Define a basic structure (POD structure) using a tuple to get the default functions 14 | TUPLE_DEF2(Point, (x, float), (y, float)) 15 | #define M_OPL_Point_t() TUPLE_OPLIST(Point, M_BASIC_OPLIST, M_BASIC_OPLIST) 16 | 17 | // NOTE: array, list, deque don't have a native find function. 18 | // We'll use the algorithm header to create a find function for such containers. 19 | 20 | // Define a set of int & register its oplist 21 | DICT_SET_DEF(cset_i, int) 22 | #define M_OPL_cset_i_t() DICT_SET_OPLIST(cset_i, M_BASIC_OPLIST) 23 | 24 | // Define an array of Point, register its oplist & include some basic algorithms 25 | ARRAY_DEF(cvec_p, Point_t) 26 | #define M_OPL_cvec_p_t() ARRAY_OPLIST(cvec_p, M_OPL_Point_t()) 27 | ALGO_DEF(cvec_p, cvec_p_t) 28 | 29 | // Define a deque of int, including some basic algorithms 30 | DEQUE_DEF(cdeq_i, int) 31 | #define M_OPL_cdeq_i_t() DEQUE_OPLIST(cdeq_i, M_BASIC_OPLIST) 32 | ALGO_DEF(cdeq_i, cdeq_i_t) 33 | 34 | // Define a backward list, including some basic algorithms 35 | LIST_DEF(clist_i, int) 36 | #define M_OPL_clist_i_t() LIST_OPLIST(clist_i, M_BASIC_OPLIST) 37 | ALGO_DEF(clist_i, clist_i_t) 38 | 39 | // Define an unordered map of int to int 40 | DICT_DEF2(csmap_i, int, int) 41 | #define M_OPL_csmap_i_t() DICT_OPLIST(csmap_i, M_BASIC_OPLIST, M_BASIC_OPLIST) 42 | 43 | int main(void) 44 | { 45 | // Define, init & set the different containers. 46 | M_LET( (set, 10, 20, 30), cset_i_t) 47 | M_LET( (vec, (10, 1), (20, 2), (30, 3) ), cvec_p_t) 48 | M_LET( (deq, 10, 20, 30), cdeq_i_t) 49 | M_LET( (lst, 10, 20, 30), clist_i_t) 50 | M_LET( (map, (20, 2), (10, 1), (30,3) ), csmap_i_t) { 51 | 52 | // add one more element to each container 53 | cset_i_push(set, 40); 54 | cvec_p_push_back(vec, (Point_t) {{40, 4}} ); 55 | cdeq_i_push_front(deq, 5); 56 | clist_i_push_back(lst, 5); 57 | csmap_i_set_at(map, 40, 4); 58 | 59 | M_PRINT("vec= ", (vec, cvec_p_t)); 60 | 61 | // Find an element (either native or through the algo header) 62 | int *i1 = cset_i_get(set, 20); 63 | cvec_p_it_t i2; cvec_p_find(i2, vec, (Point_t) {{20, 2}}); 64 | cdeq_i_it_t i3; cdeq_i_find(i3, deq, 20); 65 | clist_i_it_t i4; clist_i_find(i4, lst, 20); 66 | int *i5 = csmap_i_get(map, 20); 67 | printf("\nFound: %d, (%g, %g), %d, %d, [%d: %d]\n", 68 | *i1, 69 | (*cvec_p_ref(i2))->x, (*cvec_p_ref(i2))->y, 70 | *cdeq_i_ref(i3), 71 | *clist_i_ref(i4), 72 | 20, *i5); 73 | 74 | // Erase the elements found (through key or through iterators) 75 | cset_i_erase(set, *i1); 76 | cvec_p_remove(vec, i2); 77 | cdeq_i_remove(deq, i3); 78 | clist_i_remove(lst, i4); 79 | csmap_i_erase(map, *i5); 80 | 81 | // Display everything in one call by using the registered print functions of the different types. 82 | M_PRINT("After erasing elements found:\n", 83 | "set: ", (set, cset_i_t), "\n", 84 | "vec: ", (vec, cvec_p_t), "\n", 85 | "deq: ", (deq, cdeq_i_t), "\n", 86 | "map: ", (map, csmap_i_t), "\n"); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /example/ex-multi04.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "m-tuple.h" 4 | #include "m-array.h" 5 | #include "m-string.h" 6 | #include "m-list.h" 7 | #include "m-buffer.h" 8 | 9 | /* This example chains the structure in different ways in 10 | order to show/test the good chaining of the structures */ 11 | 12 | TUPLE_DEF2(symbol, (type, int), (name, string_t)) 13 | #define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_BASIC_OPLIST, STRING_OPLIST) 14 | 15 | ARRAY_DEF(symbol_list, symbol_t) 16 | #define M_OPL_symbol_list_t() ARRAY_OPLIST(symbol_list, M_OPL_symbol_t()) 17 | 18 | TUPLE_DEF2(record, (fields, symbol_list_t)) 19 | #define M_OPL_record_t() TUPLE_OPLIST(record, M_OPL_symbol_list_t()) 20 | 21 | TUPLE_DEF2(my_tuple, (name, string_t), (value, int)) 22 | #define M_OPL_my_tuple_t() TUPLE_OPLIST(my_tuple, STRING_OPLIST, M_BASIC_OPLIST) 23 | 24 | ARRAY_DEF(my_list_of_tuple, my_tuple_t) 25 | #define M_OPL_my_list_of_tuple_t() ARRAY_OPLIST(my_list_of_tuple) 26 | 27 | TUPLE_DEF2(my_tuple_of_tuple, (name, string_t), (inner_tuple, my_tuple_t)) 28 | #define M_OPL_my_tuple_of_tuple_t() TUPLE_OPLIST(my_tuple_of_tuple, STRING_OPLIST, M_OPL_my_tuple_t() ) 29 | 30 | LIST_DEF(list_of_tuple_of_tuple, my_tuple_of_tuple_t) 31 | #define M_OPL_list_of_tuple_of_tuple_t() LIST_OPLIST(list_of_tuple_of_tuple, M_OPL_my_tuple_of_tuple_t() ) 32 | 33 | TUPLE_DEF2(my_triple_tuple, (name, string_t), (inner_tuple, my_tuple_t), (list, list_of_tuple_of_tuple_t) ) 34 | #define M_OPL_my_triple_tuple_t() TUPLE_OPLIST(my_triple_tuple, STRING_OPLIST, M_OPL_my_tuple_t(), M_OPL_list_of_tuple_of_tuple_t()) 35 | 36 | BUFFER_DEF(trbuff, my_triple_tuple_t, 100, BUFFER_QUEUE) 37 | #define M_OPL_trbuff_t() BUFFER_OPLIST(trbuff, M_OPL_my_triple_tuple_t()) 38 | 39 | TUPLE_DEF2(my_junction, (active, bool), (buffer, trbuff_t)) 40 | #define M_OPL_my_junction_t() TUPLE_OPLIST(my_junction, M_BASIC_OPLIST, M_OPL_trbuff_t()) 41 | 42 | TUPLE_DEF2(mlib_point, (x, int), (y, int)) 43 | #define M_OPL_mlib_point_t() \ 44 | TUPLE_OPLIST(mlib_point, M_BASIC_OPLIST, M_BASIC_OPLIST) 45 | 46 | TUPLE_DEF2(mlib_points, (first_ref, mlib_point_ptr, M_PTR_OPLIST), 47 | (second_ref, mlib_point_ptr, M_PTR_OPLIST), 48 | (third, mlib_point_t)) 49 | #define M_OPL_mlib_points_t() \ 50 | TUPLE_OPLIST(mlib_points, M_PTR_OPLIST, M_PTR_OPLIST, M_OPL_mlib_point_t()) 51 | 52 | static void let2(void) 53 | { 54 | // Initialize p1 as mlib_point_t with (4,4) 55 | // and p2 as mlib_point_t with (5,5) 56 | // and pair as mlib_point_t with default value 57 | M_LET((p1, 4, 4), (p2, 5, 5), mlib_point_t) { 58 | M_LET(pair, mlib_points_t) { 59 | pair->first_ref = p1; 60 | pair->second_ref = p2; 61 | pair->third->x = pair->third->y = 6; 62 | 63 | assert(pair->first_ref->x == 4); 64 | p1->x = 10; 65 | assert(pair->first_ref->x == 10); 66 | 67 | assert(pair->third->x == 6); 68 | } 69 | } 70 | } 71 | 72 | static void let(void) 73 | { 74 | // Let's initialize all the declared types 75 | M_LET(s, symbol_t) 76 | M_LET(l, symbol_list_t) 77 | M_LET(r,record_t) 78 | M_LET(tup, my_tuple_t) 79 | M_LET(l2, my_list_of_tuple_t) 80 | M_LET(tuptup, my_tuple_of_tuple_t) 81 | M_LET(ltuptup, list_of_tuple_of_tuple_t) 82 | M_LET(tuptuptup, my_triple_tuple_t) 83 | M_LET(junc, my_junction_t) 84 | { 85 | printf("Init ok\n"); 86 | } 87 | } 88 | 89 | int main(void) 90 | { 91 | let(); 92 | let2(); 93 | } 94 | 95 | -------------------------------------------------------------------------------- /tests/check-prioqueue.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2025-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include 24 | #include "m-prioqueue.h" 25 | 26 | // Invert the order of priority for the integers to match the C++ one 27 | #define CMP_REVERT(a,b) ((a) > (b) ? -1 : (a) < (b)) 28 | PRIOQUEUE_DEF(prio_int, int, M_OPEXTEND(M_BASIC_OPLIST, CMP(CMP_REVERT) )) 29 | 30 | // Container OPLIST (disable iterators & reset) 31 | #define CONT_OPL \ 32 | M_OPEXTEND( PRIOQUEUE_OPLIST(prio_int, M_OPL_int()), \ 33 | RESET(0), \ 34 | IT_TYPE(0), \ 35 | IT_FIRST(0), \ 36 | IT_END(0), \ 37 | IT_SET(0), \ 38 | IT_END_P(0), \ 39 | IT_EQUAL_P(0), \ 40 | IT_LAST_P(0), \ 41 | IT_NEXT(0), \ 42 | IT_CREF(0) ) 43 | 44 | // C++ Base class of the item in the container 45 | #define BASE_CLASS int 46 | 47 | // C++ Container class 48 | #define CONT_CLASS std::priority_queue 49 | 50 | // Compare the M*LIB container a to the C++ container b 51 | #define CMP_CONT(a, b) cmp_cont(a, b) 52 | 53 | void cmp_cont(const prio_int_t a, const std::priority_queue &b) 54 | { 55 | std::priority_queue cb = b; 56 | prio_int_t ca; 57 | prio_int_init_set(ca, a); 58 | while (!cb.empty()) { 59 | int n; 60 | prio_int_pop(&n, ca); 61 | assert(n == cb.top()); 62 | cb.pop(); 63 | } 64 | assert(prio_int_empty_p(ca)); 65 | prio_int_clear(ca); 66 | } 67 | 68 | // There is no reset, so the prioqueue keeps increasing ==> Limit the number of operation. 69 | #define DEFAULT_NUMBER 1500 70 | 71 | #define push_back push 72 | #define pop_back pop 73 | #define back top 74 | #include "check-generic.hpp" 75 | -------------------------------------------------------------------------------- /example/ex11-algo02.c: -------------------------------------------------------------------------------- 1 | #include "m-tuple.h" 2 | #include "m-array.h" 3 | #include "m-algo.h" 4 | #include "m-funcobj.h" 5 | #include "m-serial-json.h" 6 | #include "m-string.h" 7 | 8 | /* Define the employee class */ 9 | TUPLE_DEF2(employee, 10 | (name, string_t), 11 | (age, int), 12 | (idnum, int)) 13 | /* Register globaly the employee_t oplist */ 14 | #define M_OPL_employee_t() TUPLE_OPLIST(employee, STRING_OPLIST, M_BASIC_OPLIST, M_BASIC_OPLIST) 15 | 16 | /* Define an array of employee, register the oplist and define further algorithms on it */ 17 | ARRAY_DEF(vector_employee, employee_t) 18 | #define M_OPL_vector_employee_t() ARRAY_OPLIST(vector_employee, M_OPL_employee_t()) 19 | ALGO_DEF(vector_employee, vector_employee_t) 20 | 21 | /* Define the function object to select the sort order. 22 | * It is named 'compare_by' and is an instance of the interface 23 | * 'vector_employee_cmp_obj' created by ALGO_DEF. 24 | */ 25 | FUNC_OBJ_INS_DEF(compare_by /* name of the instance */, 26 | vector_employee_cmp_obj /* name of the interface */, 27 | (a, b) /* name of the input parameters of the function like object. The type are inherited from the interface. */, { 28 | /* code of the function object */ 29 | if (string_equal_str_p(self->sort_field, "name")) 30 | return string_cmp(a->name, b->name); 31 | else if (string_equal_str_p(self->sort_field, "age")) 32 | return a->age < b->age ? -1 : a->age > b->age; 33 | else 34 | return a->idnum < b->idnum ? -1 : a->idnum > b->idnum; 35 | }, 36 | /* Additional fields stored in the function object */ 37 | (sort_field, string_t) ) 38 | #define M_OPL_compare_by_t() FUNC_OBJ_INS_OPLIST(compare_by, STRING_OPLIST) 39 | 40 | // Let's read an array of person from the given JSON file 41 | static void read(vector_employee_t base, const char filename[]) 42 | { 43 | m_serial_return_code_t ret; 44 | 45 | // Open the file 46 | FILE *f = fopen(filename, "rt"); 47 | if (!f) { 48 | // Handle errors 49 | fprintf(stderr, "ERROR: Cannot open file '%s'.\n", filename); 50 | exit(2); 51 | } 52 | 53 | // Initialize the JSON serializer with this file 54 | M_LET( (in,f), m_serial_json_read_t) 55 | // Read the JSON file and fill in 'base' with it. 56 | ret = vector_employee_in_serial(base, in); 57 | 58 | // Let's handle serialization error 59 | if (ret != M_SERIAL_OK_DONE) { 60 | fprintf(stderr, "ERROR: Cannot read JSON data from file '%s'.\nParsing stops at:\n", filename); 61 | while (!feof(f)) { fputc(fgetc(f), stdout); } 62 | fclose(f); 63 | exit(2); 64 | } 65 | 66 | // Close the FILE 67 | fclose(f); 68 | } 69 | 70 | int main(void) 71 | { 72 | M_LET(emps, vector_employee_t) { 73 | /* Code to populate database from JSON */ 74 | read(emps, "ex11-algo02.json"); 75 | 76 | // Sort the database by employee ID number 77 | M_LET( (cmp, STRING_CTE("idnum")), compare_by_t ) 78 | vector_employee_sort_fo(emps, compare_by_as_interface(cmp)); 79 | M_PRINT("Employees sorted by idnum are: ", (emps, vector_employee_t), "\n" ); 80 | 81 | // Sort the database by employee name 82 | M_LET( (cmp, STRING_CTE("name")), compare_by_t ) 83 | vector_employee_sort_fo(emps, compare_by_as_interface(cmp)); 84 | M_PRINT("Employees sorted by name are: ", (emps, vector_employee_t), "\n" ); 85 | 86 | // End 87 | } 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /example/ex-array01.c: -------------------------------------------------------------------------------- 1 | /* 2 | * All the definition are included in the file m-array.h 3 | * You don't need to link with any library. 4 | */ 5 | #include "m-array.h" 6 | 7 | // First you need to instanciate your code for the type you want. 8 | // This is done by calling the ARRAY_DEF macro with the name 9 | // of the instance (here array_charp) and the type of the instance 10 | // (here a pointer to char). 11 | // This will create all types and functions to handle an 12 | // array of char pointers. 13 | // So let's define an array of 'char *' named 'array_charp' 14 | ARRAY_DEF (array_charp, char *) 15 | // Ok everything has been defined. We can use everything like 16 | // standard C function. 17 | 18 | int main(void) 19 | { 20 | // Declare an array of 'char *'. 21 | // The used name for the container is the name concatened with '_t'. 22 | array_charp_t al; 23 | 24 | // Like a good POD it needs to be explicitly initialized. 25 | // Notice that we don't to pass the address of the variable as input 26 | // to the function, but the variable. 27 | // In fact, the array is automatically passed by reference to any 28 | // function. 29 | array_charp_init(al); 30 | 31 | // Let's do some basic stuff: 32 | // add some elements to the array list 33 | array_charp_push_back (al,"C"); 34 | array_charp_push_back (al,"A"); 35 | array_charp_push_back (al,"E"); 36 | array_charp_push_back (al,"B"); 37 | array_charp_push_back (al,"D"); 38 | array_charp_push_back (al,"F"); 39 | 40 | // Use iterator to display contents of al 41 | printf("Original contents of al: "); 42 | // The iterator has also been defined with the ARRAY_DEF macro. 43 | // All iterators of all containers follow the same logic, 44 | // so that you can change the type of the container without 45 | // changing your code. 46 | array_charp_it_t itr; 47 | // You initialized the iterator to the first element of the container, 48 | // iterate until not the end of the container is reached, 49 | // while moving the iterator to the next element of the array. 50 | // This is pretty overkill for an array, but this works for any container. 51 | for (array_charp_it(itr, al) ; !array_charp_end_p (itr); array_charp_next(itr)) { 52 | // Let's get a reference to the data pointed by the iterator. 53 | // You'll always get a pointer to this data, not the data itself. 54 | // So you need an extra '*' to read the data. 55 | char *element = *array_charp_ref(itr); 56 | printf ("%s ", element); 57 | } 58 | printf("\n"); 59 | 60 | // Now, display the list backwards 61 | // As the iterator as reached the end of the array, 62 | // let's go back by one element, 63 | // iterate until not the end of the container is reached, 64 | // while moving the iterator to the previous element of the array. 65 | printf("Array backwards: "); 66 | for (array_charp_previous (itr) ; !array_charp_end_p (itr); array_charp_previous(itr)) { 67 | char *element = *array_charp_ref(itr); 68 | printf ("%s ", element); 69 | } 70 | printf("\n"); 71 | 72 | // As it is an array, we can also iterate using a standard integer: 73 | printf("Array Direct: "); 74 | for(size_t i = 0 ; i < array_charp_size(al); ++i) { 75 | // Like for getting a reference of an iterator 76 | // the get operator returns a pointer to the data. 77 | // This allows handling non-copying type within the container 78 | // (like array). 79 | char *element = *array_charp_get(al, i); 80 | printf ("%s ", element); 81 | } 82 | printf("\n"); 83 | 84 | // Like POD, we need to clear the array explicitly 85 | array_charp_clear(al); 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /tests/except-array.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Test that the array module properly support exceptions 3 | * 4 | * Copyright (c) 2017-2025, Patrick Pelissier 5 | * All rights reserved. 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * + Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * + Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 15 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | #include "test-obj-except.h" 26 | #include "m-array.h" 27 | #include "m-string.h" 28 | 29 | M_TRY_DEF_ONCE() 30 | 31 | ARRAY_DEF(array_obj, test_obj_except__t, TEST_OBJ_EXCEPT_OPLIST) 32 | #define M_OPL_array_obj_t() ARRAY_OPLIST(array_obj, TEST_OBJ_EXCEPT_OPLIST) 33 | 34 | static void test1(unsigned n) 35 | { 36 | FILE *f = m_core_fopen ("a-earray.dat", "wt"); 37 | assert(f != NULL); 38 | M_TRY(test1) { 39 | M_LET(obj, test_obj_except__t) 40 | M_LET(array, tmp, array_obj_t) { 41 | for(unsigned i = 0; i < n; i++) { 42 | test_obj_except__set_ui(obj, i); 43 | array_obj_push_back(array, obj); 44 | } 45 | array_obj_set(tmp, array); 46 | M_LET( (tmp2, tmp), array_obj_t) { 47 | array_obj_out_str(f, tmp2); 48 | } 49 | array_obj_push_back(tmp, obj); 50 | array_obj_resize(tmp, 4); 51 | array_obj_push_new(tmp); 52 | array_obj_resize(tmp, 20); 53 | array_obj_set_at(tmp, 10, obj); 54 | array_obj_push_at(tmp, 10, obj); 55 | test_obj_except__t *ref = array_obj_safe_get(tmp, 30); 56 | assert(ref != NULL); 57 | array_obj_splice(tmp, array); 58 | M_LET(str, string_t) { 59 | array_obj_get_str(str, tmp, false); 60 | bool b = array_obj_parse_str(array, string_get_cstr(str), NULL); 61 | assert(b); 62 | } 63 | array_obj_insert_v(tmp, 12, 3); 64 | array_obj_emplace_back_ui(tmp, 345); 65 | array_obj_emplace_back_str(tmp, "345"); 66 | } 67 | } M_CATCH(test1, 0) { 68 | // Nothing to do 69 | } 70 | fclose(f); 71 | 72 | f = m_core_fopen ("a-earray.dat", "rt"); 73 | assert(f != NULL); 74 | M_TRY(test1) { 75 | M_LET(obj, test_obj_except__t) 76 | M_LET(array, tmp, array_obj_t) { 77 | bool b = array_obj_in_str(array, f); 78 | (void)b; 79 | } 80 | } M_CATCH(test1, 0) { 81 | // Nothing to do 82 | } 83 | fclose(f); 84 | } 85 | 86 | int main(void) 87 | { 88 | do_test1(test1); 89 | exit(0); 90 | } 91 | -------------------------------------------------------------------------------- /tests/except-deque.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Test that the deque module properly support exceptions 3 | * 4 | * Copyright (c) 2017-2025, Patrick Pelissier 5 | * All rights reserved. 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * + Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * + Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 15 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | #include "test-obj-except.h" 26 | #include "m-deque.h" 27 | #include "m-string.h" 28 | 29 | M_TRY_DEF_ONCE() 30 | 31 | DEQUE_DEF(list_obj, test_obj_except__t, TEST_OBJ_EXCEPT_OPLIST) 32 | #define M_OPL_list_obj_t() LIST_OPLIST(list_obj, TEST_OBJ_EXCEPT_OPLIST) 33 | 34 | static void test1(unsigned n) 35 | { 36 | FILE *f = m_core_fopen ("a-edeque.dat", "wt"); 37 | assert(f != NULL); 38 | M_TRY(test1) { 39 | M_LET(obj, test_obj_except__t) 40 | M_LET(list, tmp, list_obj_t) { 41 | for(unsigned i = 0; i < n; i++) { 42 | test_obj_except__set_ui(obj, i); 43 | list_obj_push_back(list, obj); 44 | } 45 | list_obj_set(tmp, list); 46 | M_LET( (tmp2, tmp), list_obj_t) { 47 | list_obj_out_str(f, tmp2); 48 | } 49 | list_obj_push_back_new(tmp); 50 | M_LET(str, string_t) { 51 | list_obj_get_str(str, tmp, false); 52 | bool b = list_obj_parse_str(list, string_get_cstr(str), NULL); 53 | assert(b); 54 | } 55 | list_obj_emplace_back_ui(list, 345); 56 | list_obj_emplace_back_str(list, "345"); 57 | } 58 | } M_CATCH(test1, 0) { 59 | // Nothing to do 60 | } 61 | fclose(f); 62 | 63 | f = m_core_fopen ("a-edeque.dat", "rt"); 64 | assert(f != NULL); 65 | M_TRY(test1) { 66 | M_LET(obj, test_obj_except__t) 67 | M_LET(list, tmp, list_obj_t) { 68 | bool b = list_obj_in_str(list, f); 69 | (void)b; 70 | } 71 | } M_CATCH(test1, 0) { 72 | // Nothing to do 73 | } 74 | fclose(f); 75 | } 76 | 77 | static void test3(unsigned n) 78 | { 79 | M_TRY(test1) { 80 | M_LET(obj, test_obj_except__t) 81 | M_LET(list, tmp, list_obj_t) { 82 | for(unsigned i = 0; i < n; i++) { 83 | test_obj_except__set_ui(obj, i); 84 | list_obj_push_front(list, obj); 85 | } 86 | list_obj_push_front_new(list); 87 | list_obj_emplace_front_ui(list, 345); 88 | list_obj_emplace_front_str(list, "345"); 89 | } 90 | } M_CATCH(test1, 0) { 91 | // Nothing to do 92 | } 93 | } 94 | 95 | int main(void) 96 | { 97 | do_test1(test1); 98 | do_test1(test3); 99 | exit(0); 100 | } 101 | -------------------------------------------------------------------------------- /example/ex-multi01.c: -------------------------------------------------------------------------------- 1 | /* Based on: 2 | https://github.com/kostya/benchmarks/blob/master/brainfuck/brainfuck.cpp */ 3 | #include 4 | #include "m-array.h" 5 | #include "m-string.h" 6 | 7 | // Define an array of integer 8 | ARRAY_DEF(array_int, int) 9 | 10 | typedef struct { 11 | int pos; 12 | array_int_t tape; 13 | } tape_t[1]; 14 | 15 | static void tape_init(tape_t tape) { 16 | tape->pos =0; 17 | array_int_init(tape->tape); 18 | array_int_push_back(tape->tape, 0); 19 | } 20 | static void tape_clear(tape_t tape) { array_int_clear(tape->tape); } 21 | static int tape_get(tape_t tape) { return *array_int_cget(tape->tape, tape->pos); } 22 | static void tape_inc(tape_t tape) { (*array_int_get(tape->tape, tape->pos)) ++; } 23 | static void tape_dec(tape_t tape) { (*array_int_get(tape->tape, tape->pos)) --; } 24 | 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); } 25 | static void tape_devance(tape_t tape) { if (tape->pos > 0) tape->pos--; } 26 | 27 | typedef struct { 28 | string_t code; 29 | array_int_t bracket_map; 30 | } program_t[1]; 31 | 32 | static void program_init(program_t p, string_t text) { 33 | string_init (p->code); 34 | array_int_init (p->bracket_map); 35 | array_int_t leftstack; 36 | string_t symbols; 37 | array_int_init(leftstack); 38 | string_init_set_str(symbols, "[]<>+-,."); 39 | int pc = 0; 40 | for (size_t i = 0; i < string_size(text); i++) { 41 | char c = string_get_char(text, i); 42 | 43 | if (string_search_char(symbols, c) == STRING_FAILURE) continue; 44 | 45 | if (c == '[') array_int_push_back (leftstack, pc); 46 | else 47 | if (c == ']' && array_int_size (leftstack) != 0) { 48 | int left; 49 | array_int_pop_back(&left, leftstack); 50 | int right = pc; 51 | *array_int_safe_get (p->bracket_map, left) = right; 52 | *array_int_safe_get (p->bracket_map, right) = left; 53 | } 54 | 55 | pc++; 56 | string_push_back(p->code, c); 57 | } 58 | array_int_clear(leftstack); 59 | string_clear(symbols); 60 | } 61 | static void program_clear(program_t p) { 62 | string_clear(p->code); 63 | array_int_clear(p->bracket_map); 64 | } 65 | static void program_run(program_t p){ 66 | tape_t tape; 67 | tape_init(tape); 68 | for(size_t pc = 0; pc < string_size(p->code); pc++) { 69 | switch (string_get_char(p->code, pc)) { 70 | case '+': 71 | tape_inc(tape); 72 | break; 73 | case '-': 74 | tape_dec(tape); 75 | break; 76 | case '>': 77 | tape_advance(tape); 78 | break; 79 | case '<': 80 | tape_devance(tape); 81 | break; 82 | case '[': 83 | if (tape_get(tape) == 0) pc = *array_int_cget(p->bracket_map, pc); 84 | break; 85 | case ']': 86 | if (tape_get(tape) != 0) pc = *array_int_cget(p->bracket_map, pc); 87 | break; 88 | case '.': 89 | printf("%c", tape_get(tape)); 90 | fflush(stdout); 91 | break; 92 | default: 93 | abort(); 94 | break; 95 | } 96 | } 97 | tape_clear(tape); 98 | } 99 | 100 | static void read_file(string_t str, const string_t filename) { 101 | FILE *f = fopen(string_get_cstr(filename), "rt"); 102 | if (!f) { 103 | fprintf(stderr, "ERROR: Cannot open %s\n", string_get_cstr(filename)); 104 | exit(2); 105 | } 106 | // Read the full FILE in the string 107 | string_fgets (str, f, STRING_READ_FILE); 108 | fclose(f); 109 | } 110 | 111 | int main(int argc, const char*argv[]) 112 | { 113 | string_t filename, text; 114 | assert (argc >= 2); 115 | string_init_set_str(filename, argv[1]); 116 | string_init(text); 117 | read_file(text, filename); 118 | program_t p; 119 | program_init(p, text); 120 | program_run(p); 121 | program_clear(p); 122 | string_clear(text); 123 | string_clear(filename); 124 | return 0; 125 | } 126 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017-2023, Patrick Pelissier 2 | # All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | # + Redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer. 8 | # + Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # 12 | # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | # DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | 23 | CC=cc -std=c99 24 | 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 -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -g 25 | GMP_DIR= 26 | MPFR_DIR=$(GMP_DIR) 27 | CPPFLAGS=-I.. 28 | LDFLAGS=-pthread 29 | RM=rm -f 30 | 31 | .SUFFIXES: .c .exe 32 | 33 | .c.exe: 34 | $(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ `cat config` `cat config.curl` $(LDFLAGS) 35 | 36 | .c.o: 37 | @$(MAKE) config 38 | $(CC) $(CFLAGS) $(CPPFLAGS) -O2 `cat config.link` -DNDEBUG -g $< -c -o $@ 39 | 40 | all: config 41 | $(MAKE) `ls ex-*.c|sed -e 's/\.c/\.exe/g'` 42 | if test "$(CC)" = "cc -std=c99" ; then $(MAKE) `ls ex11-*.c|sed -e 's/\.c/\.exe/g'` CC="cc -std=c11" ; fi 43 | $(MAKE) exm.exe exn.exe 44 | 45 | exm.exe: exm-lib.o exm-main.o 46 | $(CC) `cat config.link` -g $^ -o $@ 47 | 48 | exn.exe: exn-lib.o exn-main.o 49 | $(CC) `cat config.link` -g $^ -o $@ 50 | 51 | config: 52 | printf "#include \nint main(void){mpz_t z; mpz_init(z); return 0;}\n" > config-test.c 53 | $(CC) $(CFLAGS) $(CPPFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib config-test.c -lgmp -o config-test.exe $(LDFLAGS) 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=0 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0 -DHAVE_MPFR=0 " > config 54 | printf "#include \nint main(void){mpfr_t z; mpfr_init(z); return 0;}\n" > config-test.c 55 | $(CC) $(CFLAGS) $(CPPFLAGS) -I$(GMP_DIR)/include -I$(MPFR_DIR)/include -L$(GMP_DIR)/lib -L$(MPFR_DIR)/lib config-test.c -lmpfr -lgmp -o config-test.exe $(LDFLAGS) 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -I$(MPFR_DIR)/include -L$(MPFR_DIR)/lib -lmpfr -lgmp" > config || echo "MPFR not available" 56 | printf "#include \nint main(void){curl_global_init(CURL_GLOBAL_DEFAULT);}" > config-test.c 57 | $(CC) $(CFLAGS) $(CPPFLAGS) config-test.c `curl-config --cflags --libs` -o config-test.exe 2> /dev/null && echo "-DHAVE_CURL=1 `curl-config --cflags --libs`" > config.curl || echo "-DHAVE_CURL=0 " > config.curl 58 | printf "#include \nint main(void){printf(\"Ok\"); return 0;}\n" > config-test.c 59 | $(CC) $(CFLAGS) $(CPPFLAGS) config-test.c -ffunction-sections -fdata-sections -Wl,--gc-sections 2> /dev/null && echo "-ffunction-sections -fdata-sections -Wl,--gc-sections" > config.link || echo "" > config.link 60 | $(RM) config-test.c config-test.exe 61 | 62 | clean: 63 | $(RM) *.exe *.s *~ *.o ./a.dat config config.link config.curl 64 | -------------------------------------------------------------------------------- /example/ex11-variant01.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "m-variant.h" 3 | #include "m-list.h" 4 | 5 | // Define the variant with the given basic types 6 | // A variant is an union of all its type, with the information needed to identify which type it holds 7 | VARIANT_DEF2(obj, 8 | (boolean, bool, M_BOOL_OPLIST), 9 | (integer, int, M_BASIC_OPLIST), 10 | (real, double, M_BASIC_OPLIST), 11 | (cstr, const char*, M_CSTR_OPLIST)) 12 | // Associate obj_t to its oplist, so that we can only use 'obj_t' 13 | // and M*LIB knows how to handle this type properly 14 | // We need to extend the oplist with FIELD so that M*LIB is able to generate 'emplace' functions 15 | #define M_OPL_obj_t() \ 16 | VARIANT_OPLIST(obj, M_OPEXTEND(M_BOOL_OPLIST, FIELD(boolean)), \ 17 | M_OPEXTEND(M_BASIC_OPLIST, FIELD(integer)), \ 18 | M_OPEXTEND(M_BASIC_OPLIST, FIELD(real)), \ 19 | M_OPEXTEND(M_CSTR_OPLIST, FIELD(cstr))) 20 | 21 | // Define a list over the variant 22 | LIST_DEF(list, obj_t) 23 | // Associate list_t to its oplist, so that we can only use 'list_t' 24 | #define M_OPL_list_t() LIST_OPLIST(list, M_OPL_obj_t()) 25 | 26 | /* Print the type of the object */ 27 | static void print_obj(obj_t o, const char name[]) 28 | { 29 | if (obj_empty_p(o)) { 30 | printf("Object %s is empty\n", name); 31 | } 32 | if (obj_boolean_p(o)) { 33 | printf("Object %s is a boolean (%d)\n", name, *obj_get_boolean(o)); 34 | } 35 | if (obj_integer_p(o)) { 36 | printf("Object %s is an integer (%d)\n", name, *obj_get_integer(o)); 37 | } 38 | if (obj_real_p(o)) { 39 | printf("Object %s is a float (%f)\n", name, *obj_get_real(o)); 40 | } 41 | if (obj_cstr_p(o)) { 42 | printf("Object %s is C string (%s)\n", name, *obj_get_cstr(o)); 43 | } 44 | } 45 | 46 | 47 | static void f(void) 48 | { 49 | // Initialize & afterward clear the object 50 | M_LET(o, obj_t) { 51 | print_obj(o, "1st init"); 52 | obj_set_real(o, 23.4); 53 | print_obj(o, "1st+set"); 54 | } // Now the object is out of scope and is cleared. 55 | 56 | // Initialize, set as an integer of value '12' & afterward clear the object 57 | // () around 12 means that we want to 'emplace' object using the input '12' to construct the object in-place, 58 | // rather than setting it from an already existing 'obj_t'. 59 | // It checks for the type of 12, find it is an integer, and initialize o with this value 60 | // It won't work if there is multiple compatible type in the variant 61 | M_LET( (o, (12)), obj_t) { 62 | print_obj(o, "2nd init"); 63 | obj_set_cstr(o, "Hello"); 64 | print_obj(o, "2nd+set"); 65 | } 66 | 67 | M_LET( (o, (true)), obj_t) { 68 | // In C11, a 'true' value is an 'int' type, not a bool! 69 | print_obj(o, "3rd init"); 70 | obj_set_boolean(o, true); 71 | print_obj(o, "3rd+set"); 72 | // Without "()" around the source, it will set the value using the object builtin copy. 73 | M_LET( (p, o), obj_t) { 74 | print_obj(o, "3rd+rec"); 75 | // We can also print the object directly: 76 | printf("OBJ="); 77 | obj_out_str(stdout, o); 78 | printf("\n"); 79 | } 80 | } 81 | } 82 | 83 | static void g(void) 84 | { 85 | // Initialize a list of obj_t and clear it afterwards 86 | M_LET(l, list_t){ 87 | // Let's emplace some type in the list 88 | list_emplace_back_boolean(l, true); 89 | list_emplace_back_integer(l, 12); 90 | list_emplace_back_cstr(l, "World"); 91 | list_emplace_back_real(l, 17.42); 92 | // We can iterate on the list 93 | for M_EACH(item, l, list_t) { 94 | print_obj(*item, "loop"); 95 | } 96 | // We can also print the object directly: 97 | printf("LIST="); 98 | list_out_str(stdout, l); 99 | printf("\n"); 100 | } // Clear & free the list 101 | } 102 | 103 | int main(void) 104 | { 105 | f(); 106 | g(); 107 | exit(0); 108 | } 109 | -------------------------------------------------------------------------------- /example/ex-string02.c: -------------------------------------------------------------------------------- 1 | #include "m-array.h" 2 | #include "m-string.h" 3 | 4 | // Define an array of string_t. Since the oplist of string_t is registered globaly 5 | // there is no need to give it to this definition. 6 | ARRAY_DEF(str_array, string_t) 7 | 8 | // First the verbose way and (nearly) macro free: 9 | static void main_macrofree(void) 10 | { 11 | str_array_t tab_name; 12 | str_array_init(tab_name); 13 | 14 | // Push some elements in the array (long way) 15 | str_array_push_back(tab_name, STRING_CTE("My")); 16 | str_array_push_back(tab_name, STRING_CTE("CD")); 17 | str_array_push_back(tab_name, STRING_CTE("IS")); 18 | str_array_push_back(tab_name, STRING_CTE("OUT")); 19 | 20 | // Overwrite element 1 of the array. 21 | str_array_set_at(tab_name, 1, STRING_CTE("DVD")); 22 | 23 | // Finaly rewrite 1 element of the array 24 | string_set_str(*str_array_get(tab_name, 1), "BLU-RAY"); 25 | 26 | // Format some strings and push them back in the array 27 | string_t format; 28 | string_init_printf(format, "There are %d elements", str_array_size(tab_name)); 29 | str_array_push_back(tab_name, format); 30 | string_printf(format, "There is a capacty of %d", str_array_capacity(tab_name)); 31 | string_replace_all_str(format, "capacty", "capacity"); 32 | str_array_push_back(tab_name, format); 33 | string_printf(format, "The third element is '%s'", string_get_cstr(*str_array_get(tab_name, 2))); 34 | str_array_push_back(tab_name, format); 35 | string_clear(format); 36 | 37 | // Display the content of the array. 38 | str_array_it_t it; 39 | int i = 0; 40 | for (str_array_it(it, tab_name) ; !str_array_end_p(it); str_array_next(it)) { 41 | printf("item[%d] = '%s'\n", i, string_get_cstr(*str_array_cref(it)) ); 42 | i++; 43 | } 44 | 45 | // Clear the array 46 | str_array_clear(tab_name); 47 | } 48 | 49 | // Then the short version with macros. 50 | // For this we need to register the oplist of the array of string globally. 51 | #define M_OPL_str_array_t() ARRAY_OPLIST(str_array, STRING_OPLIST) 52 | 53 | static void main_macro(void) 54 | { 55 | // Define and fill an array of string with some elements in it: 56 | M_LET( (tab_name, STRING_CTE("My"), STRING_CTE("CD"), STRING_CTE("IS"), STRING_CTE("OUT")), str_array_t) { 57 | // Overwrite element 1 of the array. 58 | str_array_set_at(tab_name, 1, STRING_CTE("DVD")); 59 | 60 | // Finaly rewrite 1 element of the array 61 | string_set_str(*str_array_get(tab_name, 1), "BLU-RAY"); 62 | 63 | // Format some strings and push them back in the array 64 | M_LET(format, string_t) { 65 | string_printf(format, "There are %d elements", str_array_size(tab_name)); 66 | str_array_push_back(tab_name, format); 67 | string_printf(format, "There is a capacty of %d", str_array_capacity(tab_name)); 68 | string_replace_all_str(format, "capacty", "capacity"); 69 | str_array_push_back(tab_name, format); 70 | string_printf(format, "The third element is '%s'", string_get_cstr(*str_array_get(tab_name, 2))); 71 | str_array_push_back(tab_name, format); 72 | #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L 73 | // Set format to a formated string 74 | // In C11, we can mix string_t and char *. 75 | // We can also use M_CSTR to create a printf formated string. 76 | string_sets(format, "FILE=", getenv("PWD"), "/", *str_array_get(tab_name, 2), M_CSTR("-%zu.txt", str_array_size(tab_name) )); 77 | str_array_push_back(tab_name, format); 78 | #endif 79 | } // beyond this point format is cleared 80 | 81 | // Display the content of the array. 82 | int i = 0; 83 | for M_EACH(item, tab_name, str_array_t) { 84 | printf("item[%d] = '%s'\n", i, string_get_cstr(*item) ); 85 | i++; 86 | } 87 | } // beyond this point tab_name is cleared 88 | } 89 | 90 | int main(void) 91 | { 92 | printf("Version macrofree:\n"); 93 | main_macrofree(); 94 | printf("Version macro:\n"); 95 | main_macro(); 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /example/ex-array05.c: -------------------------------------------------------------------------------- 1 | #include "m-array.h" 2 | #include "m-string.h" 3 | 4 | /* This example show how to use complex structure with array 5 | embedding another library */ 6 | 7 | /* This is a typical trivial library with its interface */ 8 | typedef struct lib_ext_struct { 9 | int id; 10 | // Other data may be added 11 | } lib_ext_struct; 12 | 13 | /* Method to create a duplicate of the object. 14 | The new object is heap allocated */ 15 | static lib_ext_struct *lib_ext_struct_Duplicate(const lib_ext_struct *obj) 16 | { 17 | lib_ext_struct *p = malloc(sizeof(lib_ext_struct)); 18 | if (!p) abort(); 19 | p->id = obj->id; 20 | return p; 21 | } 22 | 23 | /* Method to delete any object */ 24 | static void lib_ext_struct_Delete(lib_ext_struct *obj) 25 | { 26 | free(obj); 27 | } 28 | 29 | /* This is the complex structure */ 30 | typedef struct { 31 | uint32_t id; 32 | string_t type; 33 | lib_ext_struct* properties; 34 | } data_node; 35 | 36 | /* This method shall initialize the object data_node to 37 | the init state. 38 | It takes as first argument the object to initialize, 39 | and since it takes by reference through a pointer, 40 | it is compatible with 'API_2' convention for oplist */ 41 | static void data_node_init(data_node *obj) 42 | { 43 | obj->id = 0; 44 | string_init(obj->type); 45 | obj->properties = NULL; 46 | } 47 | 48 | /* This method shall initialize the object data_node to 49 | the same state as the 'src' object (creating a copy, a duplicate) . 50 | It takes as first argument the object to initialize, 51 | and as second argument the source object. 52 | It takes both object by reference through pointers, 53 | as such it is compatible with 'API_6' convention for oplist */ 54 | static void data_node_init_set(data_node *obj, const data_node *src) 55 | { 56 | obj->id = src->id; 57 | string_init_set(obj->type, src->type); 58 | if (src->properties) 59 | obj->properties = lib_ext_struct_Duplicate(src->properties); 60 | else 61 | obj->properties = NULL; 62 | } 63 | 64 | /* This method shall set the object data_node to 65 | the same state as the 'src' object (creating a copy, a duplicate) . 66 | THe object was already initialized. 67 | It takes as first argument the object to initialize, 68 | and as second argument the source object. 69 | It takes both object by reference through pointers, 70 | as such it is compatible with 'API_6' convention for oplist */ 71 | static void data_node_set(data_node *obj, const data_node *src) 72 | { 73 | obj->id = src->id; 74 | string_set(obj->type, src->type); 75 | if (obj->properties) 76 | lib_ext_struct_Delete(obj->properties); 77 | if (src->properties) 78 | obj->properties = lib_ext_struct_Duplicate(src->properties); 79 | else 80 | obj->properties = NULL; 81 | } 82 | 83 | /* This method shall clear the object data_node to 84 | the cleared state (aka it shall free any resource). 85 | It takes as first argument the object to initialize, 86 | and since it takes by reference through a pointer, 87 | it is compatible with 'API_2' convention for oplist */ 88 | static void data_node_clear(data_node *obj) 89 | { 90 | string_clear(obj->type); 91 | if (obj->properties) 92 | lib_ext_struct_Delete(obj->properties); 93 | } 94 | 95 | /* Create a dynamic array of 'data_node' named array_data_node_t 96 | and gives the minimum oplist allowing M*LIB to handle 97 | properly the object 'data_node' with the API convention 98 | to respect for calling the methods. 99 | The Manual defines the different supported API. 100 | */ 101 | ARRAY_DEF(/* the array prefix */ array_data_node, 102 | /* the object type */ data_node, 103 | /* the object oplist */ (INIT(API_2(data_node_init)), 104 | SET(API_6(data_node_set)), 105 | INIT_SET(API_6(data_node_init_set)), 106 | CLEAR(API_2(data_node_clear)))) 107 | 108 | /* Define a global array with the created type */ 109 | array_data_node_t global_array; 110 | 111 | int main(void) 112 | { 113 | /* Call the created method */ 114 | array_data_node_init(global_array); 115 | /* Do stuff... */ 116 | array_data_node_clear(global_array); 117 | } 118 | -------------------------------------------------------------------------------- /example/ex-rbtree01.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "m-rbtree.h" 6 | 7 | // Let's define one utility function. 8 | static void *xmalloc(size_t n) 9 | { 10 | void *p = malloc (n); 11 | if (!p) abort(); 12 | return p; 13 | } 14 | 15 | // Let's define a new type. 16 | typedef struct { 17 | int key; 18 | char *data; 19 | } my_type_t[1]; 20 | 21 | #define SIZE 256 22 | 23 | // Let's define the prototypes of the methods of this new type. 24 | void my_type_init(my_type_t x); 25 | void my_type_clear(my_type_t x); 26 | void my_type_init_set(my_type_t x, const my_type_t y); 27 | void my_type_set(my_type_t x, const my_type_t y); 28 | void my_type_init_move(my_type_t x, my_type_t y); 29 | int my_type_cmp(const my_type_t x, const my_type_t y); 30 | size_t my_type_hash(const my_type_t x); 31 | void my_type_out_str(FILE *f, const my_type_t x); 32 | bool my_type_in_str(my_type_t x, FILE *f); 33 | void my_type_rand(my_type_t x); 34 | 35 | // Let's define its constructor 36 | void my_type_init(my_type_t x) 37 | { 38 | x->key = 0; 39 | x->data = xmalloc (SIZE); 40 | } 41 | 42 | // Let's define its destructor 43 | void my_type_clear(my_type_t x) 44 | { 45 | free (x->data); 46 | } 47 | 48 | // Let's define its copy constructor 49 | void my_type_init_set(my_type_t x, const my_type_t y) 50 | { 51 | x->key = y->key; 52 | x->data = xmalloc (SIZE); 53 | memcpy(x->data, y->data, SIZE); 54 | } 55 | 56 | // Let's define its copy method 57 | void my_type_set(my_type_t x, const my_type_t y) 58 | { 59 | x->key = y->key; 60 | memcpy(x->data, y->data, SIZE); 61 | } 62 | 63 | // Let's define its move constructor 64 | void my_type_init_move(my_type_t x, my_type_t y) 65 | { 66 | x->key = y->key; 67 | x->data = y->data; 68 | } 69 | 70 | // Let's define its comparison method 71 | int my_type_cmp(const my_type_t x, const my_type_t y) 72 | { 73 | return (x->key < y->key) ? -1 : (x->key > y->key); 74 | } 75 | 76 | // Let's define its hash method 77 | // (Not needed for tree) 78 | size_t my_type_hash(const my_type_t x) 79 | { 80 | return m_core_hash(&x->key, sizeof(x->key)); 81 | } 82 | 83 | // Let's define its output method 84 | void my_type_out_str(FILE *f, const my_type_t x) 85 | { 86 | fprintf (f, "{ key: %d, data: ", x->key); 87 | for(int i = 0; i < SIZE; i++) { 88 | fprintf (f, "%02x", x->data[i]); 89 | } 90 | fprintf(f, "}"); 91 | } 92 | 93 | // Let's define its input method 94 | bool my_type_in_str(my_type_t x, FILE *f) 95 | { 96 | char buffer[256]; 97 | buffer[0] = 0; 98 | fgets (buffer, 8, f); 99 | if (strcmp (buffer, "{ key: ") != 0) 100 | return false; 101 | if (fscanf (f, "%d", &x->key) != 1) 102 | return false; 103 | fgets (buffer, 9, f); 104 | if (strcmp (buffer, ", data: ") != 0) 105 | return false; 106 | for(int i = 0; i < SIZE; i++) { 107 | fgets (buffer, 3, f); 108 | unsigned int n; 109 | if (fscanf (f, "%02x", &n) != 1) 110 | return false; 111 | x->data[i] = n; 112 | } 113 | fgets (buffer, 2, f); 114 | if (strcmp (buffer, "}") != 0) 115 | return false; 116 | return true; 117 | } 118 | 119 | void my_type_rand(my_type_t x) 120 | { 121 | x->key = rand(); 122 | for(int i = 0 ; i < SIZE; i ++) { 123 | x->data[i] = rand(); 124 | } 125 | } 126 | 127 | // Let's define its oplist 128 | #define MY_TYPE_OPLIST (TYPE(my_type_t), INIT(my_type_init), CLEAR(my_type_clear), INIT_SET(my_type_init_set), SET(my_type_set), INIT_MOVE(my_type_init_move), CMP(my_type_cmp), HASH(my_type_hash), OUT_STR(my_type_out_str), IN_STR(my_type_in_str)) 129 | 130 | // Let's define a Red Black Tree over this structure 131 | RBTREE_DEF(rbtree_my_type, my_type_t, MY_TYPE_OPLIST) 132 | 133 | int main(int argc, const char *argv[]) 134 | { 135 | rbtree_my_type_t tree; 136 | my_type_t x; 137 | int n = (argc >= 2) ? atoi(argv[1]) : 10; 138 | 139 | rbtree_my_type_init(tree); 140 | 141 | // Init the tree with random values 142 | my_type_init(x); 143 | for(int i = 0 ; i < n; i++) { 144 | my_type_rand(x); 145 | rbtree_my_type_push (tree, x); 146 | } 147 | my_type_clear(x); 148 | 149 | // Printf the trees 150 | rbtree_my_type_out_str (stdout, tree); 151 | printf ("\n"); 152 | 153 | // Quit 154 | rbtree_my_type_clear(tree); 155 | } 156 | -------------------------------------------------------------------------------- /tests/Make-check-cl.bat: -------------------------------------------------------------------------------- 1 | REM Copyright (c) 2017-2025, Patrick Pelissier 2 | REM All rights reserved. 3 | REM 4 | REM Redistribution and use in source and binary forms, with or without 5 | REM modification, are permitted provided that the following conditions are met: 6 | REM + Redistributions of source code must retain the above copyright 7 | REM notice, this list of conditions and the following disclaimer. 8 | REM + Redistributions in binary form must reproduce the above copyright 9 | REM notice, this list of conditions and the following disclaimer in the 10 | REM documentation and/or other materials provided with the distribution. 11 | REM 12 | REM THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | REM EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | REM WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | REM DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | REM DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | REM (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | REM LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | REM ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | REM (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | REM SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | 23 | REM Execute the test suite for Microsoft Visual Studio 24 | REM 25 | REM Load Micosoft Visual Studio environement file (2019 or 2022) 26 | IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" ( 27 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 28 | ) 29 | IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ( 30 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 31 | ) 32 | 33 | IF EXIST "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" ( 34 | call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 35 | ) 36 | IF EXIST "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ( 37 | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 38 | ) 39 | 40 | REM Add clang-cl in the PATH. It is the default install of clang for MSVC: 41 | REM %VCINSTALLDIR%\Tools\Llvm\bin;%VCINSTALLDIR%\Tools\Llvm\x64\bin 42 | REM Adding x64 version 43 | REM See https://docs.microsoft.com/de-de/cpp/build/clang-support-msbuild?view=vs-2019 44 | SET PATH=%PATH%;%VCINSTALLDIR%\Tools\Llvm\x64\bin 45 | 46 | REM Remove previous results 47 | DEL *.log *.dat 48 | 49 | REM Select compiler to use (either cl or clang-cl) 50 | set "compiler=%1" 51 | 52 | echo "Compiler full version (%compiler%):" 53 | %compiler% /Bv 54 | %compiler% -v 55 | 56 | REM Perform for each test 57 | for %%f in (test-*.c) do ( 58 | echo ================================================= 59 | echo Testing %%f 60 | REM Copy the test file as a C++ file as CL.EXE only support C++ file 61 | del test.exe 62 | copy %%f test.cpp || EXIT /B 1 63 | REM Compile the test suite 64 | REM /Zc:preprocessor is mandatory to have a compliant preprocessor 65 | REM /Zc:__cplusplus is needed to report the real value of __cplusplus, so that M*LIB uses the C++ atomic, and not its emulation. 66 | REM Enable warnings and basic optimization 67 | REM Inform M*LIB to use Annex K by defining __STDC_WANT_LIB_EXT1__ 68 | echo Compiling %%f with %compiler% 69 | %compiler% /I.. /O2 /W3 /std:c++14 /Zc:__cplusplus /Zc:preprocessor /D__STDC_WANT_LIB_EXT1__ /EHsc test.cpp > %%f.log 2>&1 || ( 70 | echo *** BUILD ERROR for %%f *** >> %%f.log 71 | type %%f.log 72 | EXIT /B 1 73 | ) 74 | REM Execute it 75 | echo Running %%f 76 | test.exe >> %%f.log 2>&1 && echo Test OK for %%f >> %%f.log || ( 77 | echo *** RUNTIME ERROR for %%f *** >> %%f.log 78 | type %%f.log 79 | EXIT /B 1 80 | ) 81 | type %%f.log 82 | ) 83 | echo "All tests passed" 84 | exit /B 0 85 | -------------------------------------------------------------------------------- /tests/test-mgenint.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include "test-obj.h" 24 | #include "m-thread.h" 25 | #include "m-atomic.h" 26 | #include "m-core.h" 27 | #include "coverage.h" 28 | #include "m-genint.h" 29 | 30 | #define MAX_N 256 31 | 32 | static void test(size_t n) 33 | { 34 | m_genint_t s; 35 | size_t i; 36 | 37 | m_genint_init(s, (unsigned int) n); 38 | for(int k = 0; k < 3; k++) { 39 | for(size_t j = 0; j< n ; j++) { 40 | i = m_genint_pop(s); 41 | assert (i == j); 42 | } 43 | i = m_genint_pop(s); 44 | assert (i == M_GENINT_ERROR); 45 | assert (m_genint_pop(s) == M_GENINT_ERROR); 46 | 47 | for(size_t j = 0; j< n ; j++) { 48 | m_genint_push(s, (unsigned int) ((j + (size_t) k) % n )); 49 | } 50 | } 51 | 52 | m_genint_clear(s); 53 | } 54 | 55 | /*******************************************************/ 56 | 57 | m_genint_t global; 58 | atomic_bool tab_g[MAX_N]; 59 | 60 | static void conso(void *p) 61 | { 62 | size_t n = *(size_t*)p; 63 | for(int i = 0; i < 100000; i++) { 64 | unsigned int tab[4]; 65 | for(int j= 0; j < 4; j++) { 66 | tab[j] = m_genint_pop(global); 67 | if (tab[j] != M_GENINT_ERROR) { 68 | assert (tab[j] < n); 69 | assert (atomic_load(&tab_g[tab[j]]) == false); 70 | atomic_store(&tab_g[tab[j]], true); 71 | } 72 | } 73 | for(int j = 0; j < 4; j++) { 74 | if (tab[j] != M_GENINT_ERROR) { 75 | assert (tab[j] < n); 76 | assert (atomic_load(&tab_g[tab[j]]) == true); 77 | atomic_store(&tab_g[tab[j]], false); 78 | m_genint_push(global, tab[j]); 79 | } 80 | } 81 | } 82 | } 83 | 84 | static void test2(size_t n) 85 | { 86 | m_thread_t idx[4]; 87 | 88 | m_genint_init(global, (unsigned int) n); 89 | for(int i = 0; i < MAX_N; i++) 90 | atomic_init(&tab_g[i], false); 91 | 92 | for(int i = 0; i < 4; i++) { 93 | m_thread_create (idx[i], conso, (void*)&n); 94 | } 95 | for(int i = 0; i < 4;i++) { 96 | m_thread_join(idx[i]); 97 | } 98 | 99 | m_genint_clear(global); 100 | } 101 | 102 | // In this test, the dimension of the global and the number of threads 103 | // match: we cannot have a failure. 104 | static void conso2(void *p) 105 | { 106 | size_t n = *(size_t*)p; 107 | for(int i = 0; i < 1000000; i++) { 108 | unsigned int j = m_genint_pop(global); 109 | assert (j != M_GENINT_ERROR); 110 | assert (j < n); 111 | m_genint_push(global, j); 112 | } 113 | } 114 | 115 | static void test3(size_t n) 116 | { 117 | m_thread_t idx[MAX_N]; 118 | assert (n <= MAX_N); 119 | 120 | m_genint_init(global, (unsigned int) n); 121 | for(size_t i = 0; i < n; i++) { 122 | m_thread_create (idx[i], conso2, (void*)&n); 123 | } 124 | for(size_t i = 0; i < n;i++) { 125 | m_thread_join(idx[i]); 126 | } 127 | m_genint_clear(global); 128 | } 129 | 130 | int main(void) 131 | { 132 | for(size_t n = 1; n < MAX_N; n++) { 133 | test(n); 134 | } 135 | for(size_t n = 1; n < MAX_N; n+=17) { 136 | test2(n); 137 | } 138 | for(size_t n = 2; n < 6; n++) { 139 | test3(n); 140 | } 141 | exit(0); 142 | } 143 | -------------------------------------------------------------------------------- /tests/test-mgeneric.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #include "test-obj.h" 25 | #include "m-string.h" 26 | #include "m-array.h" 27 | #include "m-list.h" 28 | #include "m-generic.h" 29 | #include "coverage.h" 30 | 31 | // Generic is not supported if not C11 32 | #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L 33 | 34 | ARRAY_DEF(array_int, int) 35 | #define M_OPL_array_int_t() ARRAY_OPLIST(array_int, M_BASIC_OPLIST) 36 | 37 | LIST_DEF(list_int, int) 38 | #define M_OPL_list_int_t() LIST_OPLIST(list_int, M_BASIC_OPLIST) 39 | 40 | static void h(string_t x) 41 | { 42 | string_set_str(x, "TEST STRING"); 43 | } 44 | 45 | // Global variable to test genericity on a global variable 46 | const string_t gx; 47 | 48 | #define FLT1 (GENTYPE(float), TYPE(float), INIT(M_INIT_BASIC), INIT_SET(M_SET_BASIC), SET(M_SET_BASIC), \ 49 | CLEAR(M_NOTHING_DEFAULT) ) 50 | #define INT1 (GENTYPE(int), TYPE(int), INIT(M_INIT_BASIC), INIT_SET(M_SET_BASIC), SET(M_SET_BASIC), \ 51 | CLEAR(M_NOTHING_DEFAULT) ) 52 | 53 | //NOTE: string_t is registered by the CORE component of the MLIB organization 54 | 55 | #define M_GENERIC_ORG_2() (USER) 56 | #define M_GENERIC_ORG_USER_COMP_1() (CORE) 57 | #define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_6() FLT1 58 | #define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_1() INT1 59 | 60 | #define M_GENERIC_ORG_3() (ARRAY) 61 | #define M_GENERIC_ORG_ARRAY_COMP_5() (AINT) 62 | #define M_GENERIC_ORG_ARRAY_COMP_AINT_OPLIST_6() M_OPL_array_int_t() 63 | #define M_GENERIC_ORG_ARRAY_COMP_10() (LINT) 64 | #define M_GENERIC_ORG_ARRAY_COMP_LINT_OPLIST_30() M_OPL_list_int_t() 65 | 66 | static bool test_empty(const string_t p) 67 | { 68 | return empty_p(p); 69 | } 70 | 71 | static void test_string(string_t p) 72 | { 73 | string_t s , d; 74 | 75 | init(s); 76 | h(s); 77 | init_set(d, s); 78 | h(d); 79 | init_set(p, s); 80 | bool b = test_empty(p); 81 | assert(!b); 82 | push(p, 'c'); 83 | out_str(stdout, p); 84 | clear(s); 85 | clear(d); 86 | 87 | float f; 88 | init(f); 89 | clear(f); 90 | 91 | clear(p); 92 | } 93 | 94 | static void test_array(void) 95 | { 96 | M_LET(a, array_int_t) { 97 | bool b = empty_p(a); 98 | assert(b); 99 | push(a, 14); 100 | b = empty_p(a); 101 | assert(!b); 102 | push(a, 15); 103 | out_str(stdout, a); 104 | for each(it, a) { 105 | printf("=%d, ", *it); 106 | } 107 | int z; 108 | pop(&z, a); 109 | assert(z == 15); 110 | } 111 | // Just change the type, same code! 112 | M_LET(a, list_int_t) { 113 | push(a, 14); 114 | push(a, 15); 115 | out_str(stdout, a); 116 | for each(it, a) { 117 | printf("=%d, ", *it); 118 | } 119 | } 120 | } 121 | 122 | static void test_print(void) 123 | { 124 | int x = 0; 125 | M_PRINT("X= ", x, "\n"); 126 | M_LET( (s, "Hello"), string_t) { 127 | M_PRINT("s=", s, "\n"); 128 | } 129 | M_LET( (a, 3,4,5), array_int_t) { 130 | M_PRINT("a=", a, "\n"); 131 | } 132 | } 133 | 134 | int main(void) 135 | { 136 | FILE *f = freopen("atmp-generic.dat", "w", stdout); 137 | if (!f) abort(); 138 | string_t p; 139 | test_string(p); 140 | test_array(); 141 | test_print(); 142 | exit(0); 143 | } 144 | 145 | #else 146 | int main(void) 147 | { 148 | exit(0); 149 | } 150 | #endif 151 | -------------------------------------------------------------------------------- /tests/test-mworker.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include "test-obj.h" 24 | #include "coverage.h" 25 | #include "m-worker.h" 26 | 27 | /* Compute Fibonacci number using thread systems. */ 28 | static worker_t w_g; 29 | static int fib(int n); 30 | struct fib2_s { 31 | int x, n; 32 | }; 33 | atomic_bool resetFunc_called = M_ATOMIC_VAR_INIT(false); 34 | static void resetFunc(void) 35 | { 36 | atomic_store(&resetFunc_called, true); 37 | } 38 | 39 | static void subfunc_1 (void *data) { 40 | struct fib2_s *f = M_ASSIGN_CAST (struct fib2_s *, data); 41 | f->x = fib (f->n ); 42 | } 43 | static int fib(int n) 44 | { 45 | if (n < 2) 46 | return n; 47 | 48 | struct fib2_s f; 49 | worker_sync_t b; 50 | 51 | worker_start(b, w_g); 52 | f.n = n - 2; 53 | worker_spawn (b, subfunc_1, &f); 54 | int y = fib (n-1); 55 | worker_sync(b); 56 | return f.x + y; 57 | } 58 | 59 | static void test1(void) 60 | { 61 | atomic_store(&resetFunc_called, false); 62 | worker_init(w_g, 0, 0, resetFunc); 63 | int result = fib(39); 64 | assert (result == 63245986); 65 | worker_clear(w_g); 66 | assert (atomic_load(&resetFunc_called) == true || m_work3r_get_cpu_count() == 1); 67 | } 68 | 69 | static void test1bis(void) 70 | { 71 | atomic_store(&resetFunc_called, false); 72 | worker_init(w_g, 0, 0, NULL, resetFunc); 73 | int result = fib(4); 74 | assert (result == 3); 75 | worker_clear(w_g); 76 | assert (atomic_load(&resetFunc_called) == true || m_work3r_get_cpu_count() == 1); 77 | } 78 | 79 | 80 | #if defined(__GNUC__) && (!defined(__clang__) || (defined(WORKER_USE_CLANG_BLOCK) && WORKER_USE_CLANG_BLOCK) || (defined(WORKER_USE_CPP_FUNCTION) && WORKER_USE_CPP_FUNCTION)) 81 | 82 | /* The macro version will generate warnings about shadow variables. 83 | There is no way to avoid this. */ 84 | #pragma GCC diagnostic push 85 | #pragma GCC diagnostic ignored "-Wshadow" 86 | 87 | static int fib2(int n) 88 | { 89 | if (n < 2) 90 | return n; 91 | 92 | worker_sync_t b; 93 | int y1, y2; 94 | worker_start(b, w_g); 95 | WORKER_SPAWN(b, (n), { y2 = fib2(n-2); }, (y2)); 96 | y1 = fib (n-1); 97 | worker_sync(b); 98 | return y1 + y2; 99 | } 100 | 101 | #pragma GCC diagnostic pop 102 | 103 | static void test2(void) 104 | { 105 | worker_init(w_g, 0, 0, NULL); 106 | int result = fib2(39); 107 | assert (result == 63245986); 108 | worker_clear(w_g); 109 | } 110 | #else 111 | static void test2(void) {} 112 | #endif 113 | 114 | 115 | // Test using specialization of worker_spawn 116 | M_WORKER_SPAWN_DEF2(fib, (out, int *, M_PTR_OPLIST), (in, int) ) 117 | 118 | static int fib3(int); 119 | static void subfib3 (int *dst, int n) { 120 | *dst = fib3 (n); 121 | } 122 | static int fib3(int n) 123 | { 124 | if (n < 2) 125 | return n; 126 | 127 | worker_sync_t b; 128 | 129 | worker_start(b, w_g); 130 | int x; 131 | m_worker_spawn_fib (b, subfib3, &x, n-2); 132 | int y = fib (n-1); 133 | worker_sync(b); 134 | return x + y; 135 | } 136 | 137 | static void test3(void) 138 | { 139 | worker_init(w_g, 0); 140 | int result = fib3(39); 141 | assert (result == 63245986); 142 | worker_clear(w_g); 143 | } 144 | 145 | 146 | int main(void) 147 | { 148 | test1(); 149 | test1bis(); 150 | test2(); 151 | test3(); 152 | exit(0); 153 | } 154 | -------------------------------------------------------------------------------- /example/ex-list01.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "m-list.h" 8 | #include "m-string.h" 9 | #include "m-algo.h" 10 | 11 | // Let's create a list of string by using the M*LIB dynamic string 'string_t' 12 | // The prefix used for generating functions will be 'list_string' 13 | LIST_DEF(list_string, string_t) 14 | 15 | // Let's register the oplist globally so that other M*LIB macros 16 | // can get the oplist without us giving it explictly to them. 17 | // An oplist is the association of operators to the provided methods 18 | // so that generic code can use correctly an object of such type. 19 | // LIST_OPLIST is a macro used to generate the oplist associated to the 20 | // list itself. It needs the prefix used for generating the list (aka list_string here) 21 | // and the oplist of the item in the list (aka the string oplist) 22 | #define M_OPL_list_string_t() LIST_OPLIST(list_string, STRING_OPLIST) 23 | 24 | // Let's define some basic algorithms over this list of string. 25 | // We reuse the prefix of the list to simplify usage, but algorithms can use separate namespace. 26 | ALGO_DEF(list_string, M_OPL_list_string_t()) 27 | 28 | int main(void) 29 | { 30 | // Let's create a variable named 'list' which is a list of string_t 31 | // This variable is only defined within the associated '{' '}' block. 32 | // The constructor/destructor of the variable will be called within this block 33 | // You can also define the variable (list_string_t) and use explicitly 34 | // its constructor (list_string_init) / destructor (list_string_clear). 35 | M_LET (list, list_string_t) 36 | M_LET (tmpstr, string_t) { // And let's create also a string_t 37 | 38 | // add string elements to the list in different ways 39 | // First is pushing a const string. 40 | // The macro STRING_CTE creates a const string_t based on the given const char * string. 41 | list_string_push_back (list, STRING_CTE("AB")); 42 | // Second is creating a separate string_t and then pushing it in the list 43 | string_printf(tmpstr, "%d", 12); 44 | list_string_push_back (list, tmpstr); 45 | // Third is to emplace directly in the list by constructing a new string_t based on the given const char * 46 | list_string_emplace_back (list, "CD"); 47 | 48 | // Serialize the list of string into a big string. 49 | list_string_get_str (tmpstr, list, false); 50 | 51 | // print it 52 | printf("Number of elements = %zu\n", list_string_size(list)); 53 | printf("Final string = %s\n", string_get_cstr(tmpstr)); 54 | 55 | // Let's iterate over each element of the list 56 | // using the macro for iteration over a container. 57 | printf ("Using macro EACH:\n"); 58 | for M_EACH (item, list, list_string_t) { 59 | printf ("Item = "); 60 | string_fputs (stdout, *item); 61 | printf ("\n"); 62 | } 63 | 64 | // You can also use classic iterator: 65 | list_string_it_t it; 66 | printf ("Using iterators:\n"); 67 | for(list_string_it(it, list) ; !list_string_end_p(it) ; list_string_next(it)) { 68 | const string_t *item = list_string_cref (it); 69 | printf ("Item = "); 70 | string_fputs (stdout, *item); 71 | printf ("\n"); 72 | } 73 | 74 | #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) 75 | // Another way: we map each element to the M_PRINT function. 76 | printf ("Using macro ALGO_FOR_EACH:"); 77 | ALGO_FOR_EACH(list, list_string_t, M_PRINT, "\nItem = "); 78 | printf ("\n"); 79 | #endif 80 | 81 | // Get the min and the max of the list 82 | string_t *p = list_string_min(list); 83 | printf ("Min string is %s\n", string_get_cstr(*p)); 84 | p = list_string_max(list); 85 | printf ("Max string is %s\n", string_get_cstr(*p)); 86 | 87 | // We can even sort the list. 88 | list_string_sort(list); 89 | for M_EACH (item, list, list_string_t) { 90 | printf ("Sort Item = %s\n", string_get_cstr(*item) ); 91 | } 92 | 93 | // Split a string into a list. 94 | string_set_str(tmpstr, "HELLO;JOHN;HOW;ARE;YOU"); 95 | list_string_split(list, tmpstr, ';'); 96 | // Iterate over the splitted list 97 | for M_EACH (item, list, list_string_t) { 98 | printf ("Split Item = %s\n", string_get_cstr(*item) ); 99 | } 100 | 101 | } // Everything is cleared after this point. 102 | 103 | // Let's create another list of string and init it. 104 | list_string_t list; 105 | list_string_init(list); 106 | // Let's put some elements in it: 107 | list_string_emplace_back (list, "A"); 108 | list_string_emplace_back (list, "B"); 109 | list_string_emplace_back (list, "C"); 110 | list_string_emplace_back (list, "D"); 111 | // Reverse it 112 | list_string_reverse(list); 113 | // Let's display the string by serializing the elements of the list: 114 | printf ("List of string = "); 115 | list_string_out_str(stdout, list); 116 | printf ("\n"); 117 | // Don't forget to clear the list before leaving 118 | list_string_clear(list); 119 | 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /example/ex11-generic02.c: -------------------------------------------------------------------------------- 1 | #if HAVE_GMP 2 | 3 | #include 4 | #include 5 | 6 | #include "m-array.h" 7 | #include "m-list.h" 8 | #include "m-generic.h" 9 | 10 | // Register an organization for generic: USER 11 | // Each index (here '1') shall be unique for the whole program 12 | #define M_GENERIC_ORG_1() (USER) 13 | // Register a component for the organization USER: CORE 14 | // Each index (here '1') shall be unique for the whole organization 15 | #define M_GENERIC_ORG_USER_COMP_1() (CORE) 16 | 17 | // Register the oplist of a mpz_t. It is a classic oplist. 18 | // Adding support for emplace and initialization 19 | // Adding the ability to output its value for serialization/printing 20 | // Adding type information for handling correctly the generic association 21 | #define M_OPL_mpz_t() M_OPEXTEND(M_CLASSIC_OPLIST(mpz), \ 22 | INIT_WITH(mpz_init_set_ui), EMPLACE_TYPE(unsigned int), \ 23 | OUT_STR( API( mpz_out_str, VOID, ARG1, 10, ARG2)), \ 24 | GENTYPE(__mpz_struct *), TYPE(mpz_t) ) 25 | // Register the oplist as a generic type of the component CORE of the organization USER 26 | // Each index (here '1') shall be unique for the whole component 27 | #define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_1() M_OPL_mpz_t() 28 | 29 | // Define an instance of an array of mpz_t (both type and function) 30 | ARRAY_DEF(array_mpz, mpz_t) 31 | // Register the oplist of the created instance of array of mpz_t 32 | #define M_OPL_array_mpz_t() ARRAY_OPLIST(array_mpz, M_OPL_mpz_t()) 33 | // Register the oplist as a generic type of the component CORE of the organization USER 34 | // Each index (here '10') shall be unique for the whole component 35 | #define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_10() M_OPL_array_mpz_t() 36 | 37 | // Define an instance of a list of mpz_t (both type and function) 38 | LIST_DEF(list_mpz, mpz_t) 39 | // Register the oplist of the created instance of array of mpz_t 40 | #define M_OPL_list_mpz_t() LIST_OPLIST(list_mpz, M_OPL_mpz_t()) 41 | // Register the oplist as a generic type of the component CORE of the organization USER 42 | #define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_11() M_OPL_list_mpz_t() 43 | 44 | // Define an instance of a list of unsigned int (both type and function) 45 | LIST_DEF(list_uint, unsigned) 46 | // Register the oplist of the created instance of list of unsigned 47 | #define M_OPL_list_uint_t() LIST_OPLIST(list_uint, M_BASIC_OPLIST) 48 | // Register the oplist as a generic type of the component CORE of the organization USER 49 | #define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_12() M_OPL_list_uint_t() 50 | 51 | // Define an instance of a array of unsigned int (both type and function) 52 | ARRAY_DEF(array_uint, unsigned) 53 | // Register the oplist of the created instance of list of unsigned 54 | #define M_OPL_array_uint_t() ARRAY_OPLIST(array_uint, M_BASIC_OPLIST) 55 | // Register the oplist as a generic type of the component CORE of the organization USER 56 | #define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_13() M_OPL_array_uint_t() 57 | 58 | int main(void) { 59 | 60 | print("LIST UINT = "); 61 | // Initialize list as list_uint_t and push 17 & 42 in it. 62 | let( (list, 17, 42), list_uint_t) { 63 | push(list, 1742); 64 | // Iterate over all elements of the list of unsigned int 65 | for each (item, list) { 66 | // Print the element 67 | print(*item, " "); 68 | } 69 | // Print the full list too 70 | print("\n","List=", list, "\n"); 71 | } 72 | // Now list has been cleared. 73 | 74 | print("Array UINT = "); 75 | // Initialize list as array_uint_t and push 17 & 42 in it. 76 | let( (list, 17, 42), array_uint_t) { 77 | push(list, 1742); 78 | // Iterate over all elements of the array of unsigned int 79 | for each (item, list) { 80 | // Print the element 81 | print(*item, " "); 82 | } 83 | // Print the full array too 84 | print("\n","List=", list, "\n"); 85 | } 86 | // Now array has been cleared. 87 | 88 | print("LIST MPZ = "); 89 | // Initialize list as array_mpz_t and push_emplace mpz_t from 17 & 42 in it. 90 | // The parenthesis around 17 in (17) means to emplace 91 | let( (list, (17), (42)), list_mpz_t) { 92 | list_mpz_emplace_back(list, 1742); // Generic emplace is not supported yet 93 | // Iterate over all elements of the array of mpz_t 94 | for each (item, list) { 95 | // Print the element 96 | // Since we registered the out_str of a mpz_t, we can display it directly 97 | print(*item, " "); 98 | } 99 | // Print the full list too 100 | print("\n","List=", list, "\n"); 101 | } 102 | 103 | print("ARRAY MPZ = "); 104 | // Same as before but for array 105 | let( (list, (17), (42)), array_mpz_t) { 106 | array_mpz_emplace_back(list, 1742); 107 | for each (item, list) { 108 | print(*item, " "); 109 | } 110 | print("\n","List=", list, "\n"); 111 | } 112 | exit(0); 113 | } 114 | 115 | #else 116 | int main(void) {} 117 | #endif 118 | -------------------------------------------------------------------------------- /tests/test-mfuncobj.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025, Patrick Pelissier 3 | * All rights reserved. 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * + Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * + Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * 12 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 13 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 16 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | #include "test-obj.h" 24 | #include "m-string.h" 25 | #include "m-funcobj.h" 26 | #include "coverage.h" 27 | 28 | START_COVERAGE 29 | 30 | /* Define one interface with some params 31 | and 2 instances with some data and no data*/ 32 | FUNC_OBJ_ITF_DEF(interface1, int, int, const int *) 33 | 34 | FUNC_OBJ_INS_DEF(instance11, 35 | interface1, 36 | (a, b), { 37 | assert(string_equal_str_p(self->c, "INIT")); 38 | string_set_str(self->c, "CALLED"); 39 | return self->sort_field*(a - *b); 40 | }, 41 | (sort_field, int), 42 | (c, string_t, STRING_OPLIST) ) 43 | 44 | FUNC_OBJ_INS_DEF(instance12, 45 | interface1, 46 | (a, b), { 47 | return a - *b; 48 | }) 49 | 50 | /* Define one interface with no param 51 | and 2 instances with some data and no data*/ 52 | FUNC_OBJ_ITF_DEF(interface2, int) 53 | 54 | FUNC_OBJ_INS_DEF(instance21, 55 | interface2, 56 | (), { 57 | return 1; 58 | }) 59 | 60 | FUNC_OBJ_INS_DEF(instance22, 61 | interface2, 62 | (), { 63 | self->a ++; 64 | return self->a; 65 | }, (a, int) ) 66 | 67 | END_COVERAGE 68 | 69 | #define M_OPL_instance22_t() FUNC_OBJ_INS_OPLIST(instance22, M_BASIC_OPLIST) 70 | 71 | FUNC_OBJ_ITF_DEF_AS(Interface, Interface, double, double) 72 | 73 | FUNC_OBJ_INS_DEF_AS(Instance, Instance, 74 | Interface, 75 | (a), { 76 | return a * self->a + self->b; 77 | }, 78 | (a, double), 79 | (b, double) ) 80 | #define M_OPL_Instance() FUNC_OBJ_INS_OPLIST(Instance, M_BASIC_OPLIST, M_BASIC_OPLIST) 81 | 82 | static void test_instance11(void) 83 | { 84 | instance11_t cmp; 85 | int n = 2; 86 | instance11_init_with(cmp, -1, STRING_CTE("INIT") ); 87 | interface1_t interface = instance11_as_interface(cmp); 88 | int x = interface1_call(interface, 10, &n); 89 | assert(x == -8); 90 | assert(string_equal_str_p(cmp->c, "CALLED")); 91 | instance11_clear(cmp); 92 | 93 | instance11_init_with(cmp, 1, STRING_CTE("INIT") ); 94 | x = interface1_call(instance11_as_interface(cmp), 100, &n); 95 | assert(x == 98); 96 | assert(string_equal_str_p(cmp->c, "CALLED")); 97 | instance11_clear(cmp); 98 | } 99 | 100 | static void test_instance12(void) 101 | { 102 | instance12_t cmp; 103 | int n = 0; 104 | instance12_init(cmp); 105 | int x = interface1_call(instance12_as_interface(cmp), 10, &n); 106 | assert(x == 10); 107 | instance12_clear(cmp); 108 | } 109 | 110 | static void test_instance21(void) 111 | { 112 | instance21_t cmp; 113 | instance21_init(cmp); 114 | interface2_t interface = instance21_as_interface(cmp); 115 | int x = interface2_call(interface); 116 | assert(x == 1); 117 | instance21_clear(cmp); 118 | } 119 | 120 | static void test_instance22(void) 121 | { 122 | M_LET( (cmp, 1), instance22_t) { 123 | int x = interface2_call(instance22_as_interface(cmp)); 124 | assert(x == 2); 125 | x = interface2_call(instance22_as_interface(cmp)); 126 | assert(x == 3); 127 | x = interface2_call(instance22_as_interface(cmp)); 128 | assert(x == 4); 129 | } 130 | } 131 | 132 | static void test_double(void) 133 | { 134 | M_LET( (func, 2.0, 3.0), Instance) { 135 | double d = Interface_call(Instance_as_interface(func), 4.0); 136 | assert (d == 2.0 * 4.0 + 3.0); 137 | } 138 | } 139 | 140 | int main(void) 141 | { 142 | test_instance11(); 143 | test_instance12(); 144 | test_instance21(); 145 | test_instance22(); 146 | test_double(); 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /doc/DEV.md: -------------------------------------------------------------------------------- 1 | How to make a release? 2 | ====================== 3 | 4 | 1) Check that all test pass on all primary systems. 5 | Run 'make check' or 'make checkall' on all primary systems. 6 | No error shall be reported. 7 | 8 | 2) Check that no undefined behavior, nor data race, ... is reported by sanitizer: 9 | Run 'make sanitize' in tests folder on a system. 10 | This needs at least GCC 7 11 | 12 | 3) Check that coverage is reasonable. 13 | Run 'make coverage' and analyze result. 14 | 15 | 4) Publish the release 16 | 17 | In case of problem, open a problem report. 18 | 19 | 20 | List of automatically tested systems 21 | ==================================== 22 | 23 | * gcc on linux/x86-64 (32 bits and 64 bits) 24 | * g++ on linux/x86-64 (32 bits and 64 bits) 25 | * clang on macos/x86-64 26 | * clang++ on macos/x86-64 27 | * tcc on linux/x86-64 28 | * gcc on windows/x86-64 (mingw) 29 | * msvc on windows/x86-64 30 | * clang on windows/x86-64 31 | 32 | List of manually tested systems 33 | =============================== 34 | 35 | * clang on linux/x86-64 36 | * clang on linux/armv7l 37 | * gcc on linux/powerpc 38 | * gcc on linux/armv7l 39 | 40 | Atomic library 41 | ============== 42 | 43 | For the targets armel, m68k, mips, mipsel, powerpc, powerpcspe or sh4, 44 | you may need to run the test suite by adding the atomic library: 45 | 46 | make check LDFLAGS="-pthread -latomic" 47 | 48 | since 'atomic' library is not automatically included for 32 bits systems. 49 | 50 | 51 | Cross compilation 52 | ================= 53 | 54 | There is no need to cross compile the library as it is a header only library. 55 | 56 | However if you want to run the tests with a cross-compiler, do like the following 57 | command. It performs a cross-compilation of the test suite from linux to windows 58 | and run the test suite with wine: 59 | 60 | make CC="i586-mingw32msvc-gcc -std=c99 -DWINVER=0x600 -D_WIN32_WINNT=0x600" LOG_COMPILER=wine check 61 | 62 | 63 | Handling issues 64 | =============== 65 | 66 | Issues are opened in the bug tracker of the project (typically https://github.com/P-p-H-d/mlib/issues ) 67 | 68 | If the issue cannot be taken into account quickly and are long term, 69 | it should be moved into the long term issues included in the repository: 70 | https://github.com/P-p-H-d/mlib/blob/master/doc/ISSUES.org 71 | This is a file in ORG mode: the issues are created with the proper tags. 72 | 73 | The original issue in the tracker can then be closed with the issuer agreement. 74 | 75 | This will have the following gains: 76 | 77 | - no hard dependencies on any bug tracking infrastructure (can be migrated easily). 78 | - a release will automatically contain all its open problem reports. 79 | 80 | Once one issue of ISSUES.org is taken into account, 81 | its state shall be changed to DONE (the issue shall not be removed). 82 | 83 | 84 | Debugging 85 | ========= 86 | 87 | Debugging the library can be quite difficult 88 | as it performs heavy preprocessing expansion 89 | and expands all code in one line. 90 | Different strategy for debugging the library itself are still possible: 91 | 92 | 1) Good old printf. 93 | Add printf of interresting values in the debugged function. 94 | 95 | 96 | 2) Preprocess the library and then compile the preprocessed file like this: 97 | 98 | cc -std=c99 -E test-file.c > test-file.i 99 | perl -pi -e 's/;/;\n/g' test-file.i 100 | cc -std=c99 -c -Wall test-file.i 101 | 102 | The resulting executable can be debugged much more easily. 103 | 104 | 105 | 3) To debug the preprocessing itself, the Boot Wave library can be used 106 | and in particular the [wave driver](https://www.boost.org/doc/libs/1_71_0/libs/wave/doc/wave_driver.html) 107 | 108 | Add in the code the following pragmas around the code to debug: 109 | 110 | #pragma wave trace(enable) 111 | ARRAY_DEF (array_charp, char *) 112 | #pragma wave trace(disable) 113 | 114 | Run the wave driver: 115 | 116 | ./wave ex-array01.c -I .. --c99 -t test.trace 117 | 118 | The different expansion performed by the library are described in test.trace 119 | 120 | Coding rules 121 | ============ 122 | 123 | * Use of non standard C shall be protected under a specific compiler test, 124 | so that the library remains compatible with a strict C99 compiler. 125 | 126 | * C11 features shall be optional. 127 | 128 | * Use 'make format' to format the header files properly. 129 | 130 | * External types shall be suffixed by _t and in lower case 131 | but shall be optional if the user doesn't want then. 132 | 133 | * Internal types shall be suffixed by _ct and in lower case 134 | (as confidential types) 135 | 136 | * External / Internal functions shall be in lower case. 137 | 138 | * External / Internal macros shall be in upper case. 139 | 140 | * Internal macros / functions shall be prefixed by m_ 141 | with container is the name of the container with one letter transformed: 142 | o --> 0 143 | e --> 3 144 | i --> 1 145 | y --> 4 146 | This prevents the automatic completion to work when the user starts writing its function. 147 | 148 | * Test functions shall be predicated and be suffixed by '_p' 149 | 150 | 151 | Misc 152 | ==== 153 | 154 | To put a breakpoint for the thread sanitizer in case of error, in gdb add: 155 | 156 | $ set env TSAN_OPTIONS=halt_on_error=1,abort_on_error=1 157 | -------------------------------------------------------------------------------- /example/ex-curl.c: -------------------------------------------------------------------------------- 1 | #if HAVE_CURL 2 | 3 | #include 4 | #include "m-dict.h" 5 | #include "m-tuple.h" 6 | #include "m-string.h" 7 | #include "m-list.h" 8 | #include "m-serial-json.h" 9 | 10 | ///////////////////////////////////////// 11 | 12 | // Define container types 13 | // First a generic map string to string 14 | DICT_DEF2(map_str, string_t, string_t) 15 | #define M_OPL_map_str_t() DICT_OPLIST(map_str, STRING_OPLIST, STRING_OPLIST) 16 | 17 | // This structure matches the JSON structure returns by the used WEB server 18 | // for the GET command. 19 | // It can be whatever you want provided it matches what is expected by the WEB server 20 | TUPLE_DEF2(web_data, 21 | (args, map_str_t), 22 | (headers, map_str_t), 23 | (origin, string_t), 24 | (url, string_t)) 25 | #define M_OPL_web_data_t() TUPLE_OPLIST(web_data, M_OPL_map_str_t(), M_OPL_map_str_t(), STRING_T, STRING_T) 26 | 27 | ///////////////////////////////////////// 28 | 29 | 30 | static size_t 31 | write_data(void *buffer, size_t size, size_t nmemb, void *userp) 32 | { 33 | (void) size; // Parameter not used 34 | char *src = buffer; 35 | string_ptr str = userp; 36 | for(size_t i = 0; i < nmemb; i++) { 37 | string_push_back(str, src[i]); 38 | } 39 | return nmemb; 40 | } 41 | 42 | static bool get_data(web_data_t data, const char url[]) 43 | { 44 | m_serial_return_code_t r = M_SERIAL_FAIL; 45 | CURLcode res; 46 | string_t str; 47 | CURL *handle = curl_easy_init(); 48 | if (handle) { 49 | string_init(str); 50 | // Perform an http GET request and fill in str with the JSON answer 51 | curl_easy_setopt(handle, CURLOPT_URL, url); 52 | curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data); 53 | curl_easy_setopt(handle, CURLOPT_WRITEDATA, str); 54 | res = curl_easy_perform(handle); 55 | curl_easy_cleanup(handle); 56 | if (res == CURLE_OK) { 57 | // Parse the string and fill in the object 58 | m_serial_str_json_read_t serial; 59 | m_serial_str_json_read_init(serial, string_get_cstr(str)); 60 | r = web_data_in_serial(data, serial); 61 | m_serial_str_json_read_clear(serial); 62 | } 63 | string_clear(str); 64 | } 65 | return r == M_SERIAL_OK_DONE; 66 | } 67 | 68 | ///////////////////////////////////////// 69 | 70 | static size_t 71 | ignore_data(void *buffer, size_t size, size_t nmemb, void *userp) 72 | { 73 | (void) buffer; // Parameter not used 74 | (void) size; // Parameter not used 75 | (void) userp; // Parameter not used 76 | return nmemb; 77 | } 78 | 79 | static bool post_data(web_data_t data, const char url[], bool display_answer) 80 | { 81 | m_serial_return_code_t r = M_SERIAL_FAIL; 82 | CURLcode res = 0; 83 | string_t str; 84 | CURL *handle = curl_easy_init(); 85 | if (handle) { 86 | string_init(str); 87 | // Get a JSON string 88 | m_serial_str_json_write_t serial; 89 | m_serial_str_json_write_init(serial, str); 90 | r = web_data_out_serial(serial, data); 91 | m_serial_str_json_write_clear(serial); 92 | if (r == M_SERIAL_OK_DONE) { 93 | // Post JSON string 94 | struct curl_slist *headers=NULL; 95 | headers = curl_slist_append(headers, "Content-Type: text/json"); 96 | if (headers != NULL) { 97 | curl_easy_setopt(handle, CURLOPT_POSTFIELDS, string_get_cstr(str)); 98 | curl_easy_setopt(handle, CURLOPT_URL, url); 99 | curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); 100 | if (display_answer == false) { 101 | curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ignore_data); 102 | curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL); 103 | } 104 | res = curl_easy_perform(handle); 105 | curl_slist_free_all(headers); 106 | } 107 | } 108 | curl_easy_cleanup(handle); 109 | string_clear(str); 110 | } 111 | return (r == M_SERIAL_OK_DONE) && (res == CURLE_OK); 112 | } 113 | 114 | ///////////////////////////////////////// 115 | 116 | // Remote server URL 117 | #define URL_GET "https://httpbin.org/get" 118 | #define URL_POST "https://httpbin.org/post" 119 | 120 | int main(void) 121 | { 122 | CURLcode ret = curl_global_init(CURL_GLOBAL_DEFAULT); 123 | if (ret != CURLE_OK) abort(); 124 | 125 | web_data_t data; 126 | web_data_init(data); 127 | 128 | // Test http GET 129 | bool b = get_data(data, URL_GET); 130 | if (b) { 131 | // We success receiving the JSON object and fill in the C object web_data with it. 132 | // Let's display the object content: 133 | printf("SUCCESS. Receive data =\n"); 134 | web_data_out_str(stdout, data); 135 | printf("\n"); 136 | } else { 137 | printf("ERROR: Cannot GET data or get data are not in expected format\n"); 138 | } 139 | 140 | // Test http POST 141 | web_data_emplace_origin(data, "This is the origin"); 142 | web_data_emplace_url(data, "This is the URL"); 143 | //web_data_set_origin(data, STRING_CTE("This is the origin")); 144 | //web_data_set_url(data, STRING_CTE("This is the URL")); 145 | b = post_data(data, URL_POST, false); 146 | if (b) { 147 | printf("SUCCESS: Post\n"); 148 | } else { 149 | printf("ERROR post\n"); 150 | } 151 | 152 | web_data_clear(data); 153 | 154 | curl_global_cleanup(); 155 | return 0; 156 | } 157 | 158 | #else 159 | int main(void) { return 0; } 160 | #endif 161 | -------------------------------------------------------------------------------- /example/ex11-rbtree02.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "m-rbtree.h" 6 | #include "m-string.h" 7 | 8 | // Let's define a Red Black Tree over the constant C strings 9 | // Notice that we need to specify the oplist for this case 10 | // so that M*LIB handle the pointers to const char correctly. 11 | RBTREE_DEF(tree_cstr, const char *, M_CSTR_OPLIST) 12 | 13 | // The classic C way 14 | // It is probably the best for beginner in M*LIB to start like this. 15 | static void classic1(void) 16 | { 17 | // Let's declare a tree on the stack. 18 | // Even if the tree itself is allocated on the stack, 19 | // the nodes will be allocated on the heap. 20 | tree_cstr_t tree; 21 | // Initialize the tree using the provided constructor 22 | tree_cstr_init(tree); 23 | 24 | // Let's fill in the tree 25 | // Note that the object of the tree are pointer 26 | // to array of char. Therefore the strings themselves 27 | // are not stored in the tree but only a reference to then 28 | // As such, the pointed objects shall not moved nor being 29 | // destroyed, which is the case for const C string. 30 | tree_cstr_push (tree, "Hello"); 31 | tree_cstr_push (tree, "World"); 32 | tree_cstr_push (tree, "How"); 33 | tree_cstr_push (tree, "Are"); 34 | tree_cstr_push (tree, "You"); 35 | 36 | // Let's print the tree. 37 | // We'll use the OUT_STR method to display the tree 38 | // without iterating ourself in the tree. 39 | printf("\nUsing C string, the generated (sorted) tree is "); 40 | tree_cstr_out_str(stdout, tree); 41 | printf ("\n"); 42 | 43 | // Let's search for the key "How" in the tree. 44 | // If it is not found a NULL pointer is returned. 45 | // Otherwise a pointer to the key within the tree is returned. 46 | // This pointer is valid until a modification operation on the tree is done. 47 | const char *present = tree_cstr_get(tree, "How") == NULL ? "not " : ""; 48 | printf("The word 'How' is %spresent\n", present); 49 | 50 | present = tree_cstr_get(tree, "Not") == NULL ? "not " : ""; 51 | printf("The word 'Not' is %spresent\n", present); 52 | 53 | // Destroy the tree by calling the destructor. 54 | tree_cstr_clear(tree); 55 | } 56 | 57 | 58 | // Let's define another Red Black Tree over the M*LIB strings 59 | // Notice that we don't need to specify the oplist for this case. 60 | // since the oplist of a string_t is registered globally. 61 | RBTREE_DEF(tree_str, string_t) 62 | 63 | // The classic C way 64 | // It is probably the best for beginner in M*LIB to start like this. 65 | static void classic2(void) 66 | { 67 | tree_str_t tree; 68 | 69 | tree_str_init(tree); 70 | 71 | // STRING_CTE enables to construct a temporary const string_t from a const char * 72 | // usable for function call. 73 | // Note that this time the full string is stored within the tree, 74 | // and not only a pointer to it. 75 | tree_str_push (tree, STRING_CTE("Hello")); 76 | tree_str_push (tree, STRING_CTE("World")); 77 | tree_str_push (tree, STRING_CTE("How")); 78 | tree_str_push (tree, STRING_CTE("Are")); 79 | // We may also push a const C string into a string_t by calling the emplace function 80 | tree_str_emplace (tree, "You"); 81 | 82 | // Let's print the tree 83 | printf("\nUsing M*LIB string_t, the generated (sorted) tree is "); 84 | tree_str_out_str(stdout, tree); 85 | printf ("\n"); 86 | 87 | // Let's search for the string "How" 88 | // We convert it to a temporary string_t, and let's test 89 | // if it is found or not by testing if the returned pointer to string_t 90 | // is null or not. 91 | const char *present = tree_str_get(tree, STRING_CTE("How")) == NULL ? "not " : ""; 92 | printf("The word 'How' is %spresent\n", present); 93 | 94 | present = tree_str_get(tree, STRING_CTE("Not")) == NULL ? "not " : ""; 95 | printf("The word 'Not' is %spresent\n", present); 96 | 97 | tree_str_clear(tree); 98 | } 99 | 100 | 101 | // Registering the oplist helps writting the macro 102 | // as we can only refer to the type in the macro. 103 | #define M_OPL_tree_str_t() RBTREE_OPLIST(tree_str, STRING_OPLIST) 104 | 105 | static void macro(void) 106 | { 107 | // Using macro (shorter but may be unfamiliar syntax for novive with M*LIB) 108 | // This will declare the variable 'tree' as a 'tree_str_t' and initialize with 109 | // the given initialization list '("Hello"), ("World"), ("How"), ("Are"), ("You")' 110 | // The strings are given within '()' so that the constructor performs an emplace 111 | // of the value to push in the tree (to initialize a string_t with a const char * type) 112 | // instead of a push (which takes a compliant string_t as argument). 113 | // An alternative is to use STRING_CTE for the arguments. 114 | M_LET( (tree, ("Hello"), ("World"), ("How"), ("Are"), ("You")), tree_str_t) { 115 | // In C11, the M_PRINT macro allows the use of a simplified syntax for printing. 116 | M_PRINT("\nUsing M*LIB string_t + macro, the generated (sorted) tree is ", (tree, tree_str_t), "\n"); 117 | 118 | const char *present = tree_str_get(tree, STRING_CTE("How")) == NULL ? "not " : ""; 119 | printf("The word 'How' is %spresent\n", present); 120 | 121 | present = tree_str_get(tree, STRING_CTE("Not")) == NULL ? "not " : ""; 122 | printf("The word 'Not' is %spresent\n", present); 123 | } 124 | } 125 | 126 | int main(void) 127 | { 128 | classic1(); 129 | classic2(); 130 | macro(); 131 | return 0; 132 | } 133 | --------------------------------------------------------------------------------