Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e694d83cc4 | ||
|
|
19fc150763 | ||
|
|
3784f653d9 | ||
|
|
eb40cff6a1 | ||
|
|
b7f84236d3 | ||
|
|
65e3f1049b | ||
|
|
cc45b9c1fe | ||
|
|
9340c2e55c | ||
|
|
9710e014f2 | ||
|
|
7761fb6bf1 | ||
|
|
2f4df5f67c | ||
|
|
b841f81416 | ||
|
|
72fd53ab44 | ||
|
|
8335bc525b | ||
|
|
9e5d14ce36 | ||
|
|
3bafede8b7 | ||
|
|
3f2904ab0d | ||
|
|
933b495ed1 | ||
|
|
77813adc00 | ||
|
|
ce2adea6c0 | ||
|
|
3ecdfff8f0 | ||
|
|
a103ceb850 | ||
|
|
9f24b89487 | ||
|
|
8be06cadb3 | ||
|
|
c488d979cf | ||
|
|
f4c24f07af | ||
|
|
3d2ce63d63 | ||
|
|
0ac2c62ffe | ||
|
|
6001781e68 | ||
|
|
d90cb7caf3 | ||
|
|
88a4835025 | ||
|
|
75ae7a06e5 | ||
|
|
3885cb29a2 | ||
|
|
bf3ffd1766 | ||
|
|
d884d257bb | ||
|
|
a87cac84dd | ||
|
|
d1ae26f0fd | ||
|
|
9c58e73c37 | ||
|
|
024b62a7a7 | ||
|
|
c59731775e | ||
|
|
4668476c6a | ||
|
|
743959ebde | ||
|
|
dd27fa7e72 | ||
|
|
f2025f83d3 | ||
|
|
8c06b43b2b | ||
|
|
3cde7a1731 | ||
|
|
e9db1d28b8 | ||
|
|
adffaf0e87 | ||
|
|
49a2e600c4 | ||
|
|
0bedcba32b | ||
|
|
c531f805b0 | ||
|
|
da0ab5ea98 | ||
|
|
6774afd751 | ||
|
|
6d489136e7 | ||
|
|
4ea6dbc7fa | ||
|
|
defc58f6a3 | ||
|
|
006d0d16a5 | ||
|
|
b8af8bb344 | ||
|
|
e249be1142 | ||
|
|
05fde6c3cf | ||
|
|
aaa1d7dc4b | ||
|
|
8c479b2e5a | ||
|
|
45d2a529b5 | ||
|
|
7d17223332 | ||
|
|
12bc65b6a8 | ||
|
|
a849d5c031 | ||
|
|
f195b09657 | ||
|
|
439177ec71 | ||
|
|
aadd4f11b1 | ||
|
|
113fdbf388 | ||
|
|
648406a99a | ||
|
|
055e74d350 | ||
|
|
ac3d7568f2 | ||
|
|
6c222b9ad7 | ||
|
|
4426a60904 | ||
|
|
34f70a031f | ||
|
|
79f2f396b9 | ||
|
|
88143f7d52 | ||
|
|
c1261dd0f2 | ||
|
|
8f7a60ea73 | ||
|
|
4758bbd6cc | ||
|
|
3f66325c19 | ||
|
|
6f10d7deb9 | ||
|
|
919900c90a | ||
|
|
e6daaf429c | ||
|
|
1200f30695 | ||
|
|
fca1120990 | ||
|
|
3735704c95 | ||
|
|
8c0c1b3102 | ||
|
|
db192993f1 | ||
|
|
4f44b3f60b | ||
|
|
b196fcc3c0 | ||
|
|
395f1af19e | ||
|
|
d8f761e889 | ||
|
|
563ffb4275 | ||
|
|
9ba2de4b70 | ||
|
|
0ac6a53fe9 | ||
|
|
4431e9f9ae | ||
|
|
48526ff5c7 | ||
|
|
4ee453025c | ||
|
|
1e7b543c0f | ||
|
|
8c2b4f8cf9 | ||
|
|
13cadfa470 | ||
|
|
deb595372b | ||
|
|
01fd5d929e | ||
|
|
2d60bd2c1b | ||
|
|
9655b13203 | ||
|
|
6b97a7436d | ||
|
|
1c792dd0a4 | ||
|
|
dcbd9f496f | ||
|
|
9804120cde | ||
|
|
a9b06718f0 | ||
|
|
963d819e22 | ||
|
|
28847af43f | ||
|
|
130fa36970 | ||
|
|
ab99035291 | ||
|
|
6de43d8a45 | ||
|
|
7b46891622 | ||
|
|
a0a32d8c6c | ||
|
|
1ffd07dc6e | ||
|
|
cb49cd7100 | ||
|
|
923b340a80 | ||
|
|
5b8750ee2a | ||
|
|
d438d089fb | ||
|
|
843ddac3dd | ||
|
|
c5238e0a4c | ||
|
|
f99ee8aa40 | ||
|
|
18c7d0e11a | ||
|
|
4e67823593 | ||
|
|
e7fcefb391 | ||
|
|
be06426783 | ||
|
|
e558e83be3 | ||
|
|
d77a235b2a | ||
|
|
3add6bb5bf | ||
|
|
4367daaa00 | ||
|
|
4d46b3d126 | ||
|
|
548cd84a7f | ||
|
|
d87ffaa572 | ||
|
|
370cdb4e45 | ||
|
|
068d023917 | ||
|
|
86b6ad54d5 | ||
|
|
bdf999a9fc | ||
|
|
39f8b6828b | ||
|
|
11f84ab34b | ||
|
|
c3a5306266 | ||
|
|
1fe9e4c14c | ||
|
|
e69203dc50 | ||
|
|
342954f272 | ||
|
|
741d6b8828 | ||
|
|
f1f41ef320 | ||
|
|
785792d1f4 | ||
|
|
9affe3106c | ||
|
|
eb9fd14e2c | ||
|
|
c281a2c339 | ||
|
|
cb109eb479 | ||
|
|
3c6d194974 | ||
|
|
653a0d9734 | ||
|
|
a5fbd8405c | ||
|
|
70994d4f60 | ||
|
|
f15203afb2 | ||
|
|
0a0d707afd | ||
|
|
e206c3fe48 | ||
|
|
7f5704d321 | ||
|
|
4f7b0b9455 | ||
|
|
f5f16015df | ||
|
|
935325e0cb | ||
|
|
7b9530ac58 | ||
|
|
a9fc259420 | ||
|
|
6f603b52df | ||
|
|
aeb2a47952 | ||
|
|
ca7cea3fe3 | ||
|
|
f14aca8808 | ||
|
|
f1e5e9d9db | ||
|
|
cecba9777a | ||
|
|
4352267034 | ||
|
|
0c3730d9a3 | ||
|
|
5111b0c726 | ||
|
|
8ecd3f1592 | ||
|
|
0a6f8851c9 |
No files matched your search
@@ -26,9 +26,20 @@ jobs:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install MINGW
|
||||
run: choco install mingw --no-progress
|
||||
- name: make
|
||||
shell: bash
|
||||
run: mingw32-make CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1"
|
||||
- name: make check
|
||||
shell: bash
|
||||
run: mingw32-make CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
|
||||
build_windows_visual:
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [windows-latest]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make check
|
||||
shell: cmd
|
||||
working-directory: ./tests
|
||||
run: Make-check-cl.bat
|
||||
|
||||
@@ -38,3 +38,5 @@ depend
|
||||
other/
|
||||
a*.dat
|
||||
config
|
||||
fail*.log
|
||||
.vscode
|
||||
@@ -1,6 +1,6 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2017-2019, Patrick Pelissier
|
||||
Copyright (c) 2017-2020, Patrick Pelissier
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -10,15 +10,15 @@ PREFIX=/usr/local
|
||||
DESTDIR=
|
||||
|
||||
# Package name & version.
|
||||
PACKAGE=m*lib-$(VERSION)
|
||||
VERSION=0.3.0
|
||||
PACKAGE=m_lib-$(VERSION)
|
||||
VERSION=0.4.0
|
||||
|
||||
# Define the contain of the distribution tarball
|
||||
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tuple.h m-variant.h m-worker.h
|
||||
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tuple.h m-variant.h m-worker.h
|
||||
DOC1=LICENSE README.md
|
||||
DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/depend.png doc/DEV.md doc/ISSUES.org doc/oplist.odp doc/oplist.png
|
||||
EXAMPLE=example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-json01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-rbtree01.c example/ex-section.c example/Makefile
|
||||
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.c tests/test-mcmempool.c tests/test-mconcurrent.c tests/test-mcore.c tests/test-mdeque.c tests/test-mdict.c tests/test-mgenint.c tests/test-milist.c tests/test-mlist.c tests/test-mmempool.c tests/test-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.c tests/test-mshared.c tests/test-msnapshot.c tests/test-mstring.c tests/test-mtuple.c tests/test-mvariant.c tests/test-mworker.c tests/tgen-bitset.c tests/tgen-marray.c tests/tgen-mdict.c tests/tgen-mlist.c tests/tgen-mstring.c tests/tgen-openmp.c tests/tgen-queue.c tests/tgen-shared.c tests/wip-mregister.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt
|
||||
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.c tests/test-mcmempool.c tests/test-mconcurrent.c tests/test-mcore.c tests/test-mdeque.c tests/test-mdict.c tests/test-mfuncobj.c tests/test-mgenint.c tests/test-milist.c tests/test-mlist.c tests/test-mmempool.c tests/test-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.c tests/test-mshared.c tests/test-msnapshot.c tests/test-mstring.c tests/test-mtuple.c tests/test-mvariant.c tests/test-mworker.c tests/tgen-bitset.c tests/tgen-marray.c tests/tgen-mdict.c tests/tgen-mlist.c tests/tgen-mstring.c tests/tgen-openmp.c tests/tgen-queue.c tests/tgen-shared.c tests/wip-mregister.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt
|
||||
|
||||
.PHONY: all test check doc clean distclean depend install uninstall dist
|
||||
|
||||
|
||||
+20
-17
@@ -7,7 +7,7 @@ N=4
|
||||
BENCH_DEF=
|
||||
RM=rm -rf
|
||||
|
||||
.PHONY: all pgo container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain
|
||||
.PHONY: all pgo container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain
|
||||
|
||||
all: container queue mempool string plain
|
||||
|
||||
@@ -17,7 +17,7 @@ pgo:
|
||||
|
||||
#########################################################################
|
||||
|
||||
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-hopscotchmap
|
||||
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-densehashmap bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-uthash bench-qlibc bench-libsrt bench-nedtries bench-rigtorp-hashmap
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost
|
||||
@@ -160,12 +160,12 @@ bench-densehashmap0:
|
||||
@./bench-densehashmap.exe 42
|
||||
@./bench-densehashmap.exe 43
|
||||
|
||||
# COLLECTIONC shall point to the directory where the 'src' directory is.
|
||||
# COLLECTIONC shall point to the directory where it is installed
|
||||
bench-collectionc:
|
||||
@if test -n "$${COLLECTIONC}" ; then $(MAKE) bench-collectionc0 ; else echo "Nothing to be done for COLLECTIONC." ; fi
|
||||
|
||||
bench-collectionc0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${COLLECTIONC}/include" -L "$${COLLECTIONC}" -static bench-collectionc.c common.c -lcollectc -o bench-collectionc.exe
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${COLLECTIONC}/include/collectc" bench-collectionc.c common.c "$${COLLECTIONC}/lib/libcollectc.a" -o bench-collectionc.exe
|
||||
@./bench-collectionc.exe 10
|
||||
@./bench-collectionc.exe 20
|
||||
@./bench-collectionc.exe 30
|
||||
@@ -196,6 +196,17 @@ bench-flathashmap0:
|
||||
@./bench-flathashmap.exe 46
|
||||
@./bench-flathashmap.exe 43
|
||||
|
||||
# EMILIB shall point to the directory where the headers are
|
||||
bench-emilib:
|
||||
@if test -n "$${EMILIB}" ; then $(MAKE) bench-emilib0 ; else echo "Nothing to be done for EMILIB." ; fi
|
||||
|
||||
bench-emilib0:
|
||||
$(CXX) -std=c++14 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${EMILIB}" bench-emilib.cpp common.c -o bench-emilib.exe
|
||||
@./bench-emilib.exe 41
|
||||
@./bench-emilib.exe 42
|
||||
@./bench-emilib.exe 46
|
||||
@./bench-emilib.exe 43
|
||||
|
||||
# HOPSCOTCHMAP shall point to the directory where the source are
|
||||
bench-hopscotchmap:
|
||||
@if test -n "$${HOPSCOTCHMAP}" ; then $(MAKE) bench-hopscotchmap0 ; else echo "Nothing to be done for HOPSCOTCHMAP." ; fi
|
||||
@@ -214,9 +225,8 @@ bench-uthash0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${UTHASH}" bench-uthash.c common.c -o bench-uthash.exe
|
||||
@./bench-uthash.exe 10
|
||||
@./bench-uthash.exe 20
|
||||
@./bench-uthash.exe 40
|
||||
@./bench-uthash.exe 41
|
||||
@./bench-uthash.exe 42
|
||||
@./bench-uthash.exe 43
|
||||
@./bench-uthash.exe 50
|
||||
|
||||
# QLIBC shall point to the directory where the library is installed.
|
||||
@@ -228,21 +238,14 @@ bench-qlibc0:
|
||||
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 10
|
||||
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 20
|
||||
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 30
|
||||
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 42
|
||||
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 41
|
||||
|
||||
# LIBSRT shall point to the directory where the source are
|
||||
# The library shall be built.
|
||||
# LIBSRT shall point to the directory where it is installed
|
||||
bench-libsrt:
|
||||
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-libsrt0 ; else echo "Nothing to be done for LIBSRT." ; fi
|
||||
|
||||
bench-libsrt0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/src" bench-libsrt.c common.c -o bench-libsrt.exe $${LIBSRT}/libsrt.a
|
||||
@./bench-libsrt.exe 10
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/include/libsrt" bench-libsrt.c common.c -o bench-libsrt.exe $${LIBSRT}/lib/libsrt.a
|
||||
@./bench-libsrt.exe 20
|
||||
@./bench-libsrt.exe 41
|
||||
@./bench-libsrt.exe 42
|
||||
@./bench-libsrt.exe 43
|
||||
@./bench-libsrt.exe 50
|
||||
|
||||
|
||||
@@ -320,12 +323,12 @@ bench-maxdict:
|
||||
############################################################################
|
||||
|
||||
# BSTRLIB shall point to the BSTRLIB sources
|
||||
# LIBSRT shall point to the LIBSRT sources
|
||||
# LIBSRT shall point to the LIBSRT install directory
|
||||
bench-string:
|
||||
@if test -n "$${BSTRLIB}" ; then $(MAKE) bench-string-step1 BENCH_DEF="-DBENCH_CAN_USE_BSTRLIB -I ${BSTRLIB} $${BSTRLIB}/obj/bstrlib.o $${BSTRLIB}/obj/bstraux.o $${BSTRLIB}/obj/bstrwrap.o" ; else $(MAKE) bench-string-step1 ; fi
|
||||
|
||||
bench-string-step1:
|
||||
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/src $${LIBSRT}/libsrt.a" ; else $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/include/libsrt $${LIBSRT}/lib/libsrt.a" ; else $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
#NOTE: Need to build by hand sds.o since it is not build by default and sds.c is not compatible with C++
|
||||
bench-string-step2:
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "emilib/hash_map.hpp"
|
||||
|
||||
using namespace emilib;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[rand_get()] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict2_linear(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[i] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long>::iterator it = dict.find(i);
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
struct char_array_s {
|
||||
char a[256];
|
||||
char_array_s () { a[0] = 0 ; }
|
||||
char_array_s ( const char_array_s & other) { strcpy(a, other.a); }
|
||||
bool operator==(const char_array_s &other) const { return strcmp(a, other.a) == 0; }
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <> struct hash<char_array_s> {
|
||||
std::size_t operator()(const char_array_s &k) const {
|
||||
size_t hash = 0;
|
||||
const char *s = k.a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
HashMap<char_array_s, char_array_s> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
HashMap<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
HashMap<string, string> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
HashMap<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict", 1000000, 0, test_dict2, 0},
|
||||
{ 43, "DictStr", 1000000, 0, test_dict_str, 0},
|
||||
{ 46, "DictLinear", 1000000, 0, test_dict2_linear, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("EMILIB", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -134,6 +134,6 @@ const config_func_t table[] = {
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("DENSE-HASPMAP", numberof(table), table, argc, argv);
|
||||
test("FLAT-HASPMAP", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -7,6 +7,9 @@
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Needed due to compilation error in pool.h
|
||||
#include <pthread.h>
|
||||
|
||||
#include "dynamic.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
+3
-13
@@ -14,8 +14,8 @@
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
sv_t *a1 = sv_alloc ( sizeof (unsigned int), 16, NULL);
|
||||
sv_t *a2 = sv_alloc ( sizeof (unsigned int), 16, NULL);
|
||||
srt_vector *a1 = sv_alloc ( sizeof (unsigned int), 16, NULL);
|
||||
srt_vector *a2 = sv_alloc ( sizeof (unsigned int), 16, NULL);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int value = rand_get();
|
||||
@@ -48,7 +48,7 @@ static int cmp_float (const void *a, const void *b)
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
sv_t *a1 = sv_alloc(sizeof(float), 16, cmp_float);
|
||||
srt_vector *a1 = sv_alloc(sizeof(float), 16, cmp_float);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int value = rand_get();
|
||||
sv_push(&a1, &value );
|
||||
@@ -72,13 +72,3 @@ int main(int argc, const char *argv[])
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 20)
|
||||
test_function("Array", 100000000, test_array);
|
||||
if (n == 50)
|
||||
test_function("Sort", 10000000, test_sort);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - String Bench
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#define NDEBUG
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -202,9 +203,8 @@ static void test_sort(size_t n)
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0}
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 50, "sort", 10000000, 0, test_sort, 0}
|
||||
};
|
||||
|
||||
|
||||
+123
-15
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -26,6 +26,9 @@
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
|
||||
// Maximum supported value for repeat argument
|
||||
#define MAX_REPEAT 10000
|
||||
|
||||
// The global result
|
||||
unsigned long g_result;
|
||||
|
||||
@@ -46,8 +49,9 @@ void compiler_barrier(void *p)
|
||||
struct parse_opt_s {
|
||||
int test_function;
|
||||
double from, to, step, grow;
|
||||
double within;
|
||||
unsigned repeat;
|
||||
bool graph, best, average, quiet;
|
||||
bool graph, best, best_within, average, quiet;
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -62,9 +66,11 @@ parse_config(struct parse_opt_s *opt, int argc, const char *argv[])
|
||||
opt->grow = 1.1;
|
||||
opt->graph = false;
|
||||
opt->best = false;
|
||||
opt->best_within = false;
|
||||
opt->average = false;
|
||||
opt->quiet = false;
|
||||
opt->repeat = 1;
|
||||
opt->within = .05;
|
||||
|
||||
for(int i = 1; i < argc ; i++)
|
||||
{
|
||||
@@ -88,14 +94,23 @@ parse_config(struct parse_opt_s *opt, int argc, const char *argv[])
|
||||
} else if (strcmp(argv[i], "--repeat") == 0) {
|
||||
i++;
|
||||
opt->repeat = strtol(argv[i], &end, 10);
|
||||
opt->repeat = (opt->repeat > MAX_REPEAT) ? MAX_REPEAT : opt->repeat;
|
||||
} else if (strcmp(argv[i], "--graph") == 0) {
|
||||
opt->graph = true;
|
||||
} else if (strcmp(argv[i], "--best") == 0) {
|
||||
opt->best = true;
|
||||
opt->average = false;
|
||||
opt->best_within = false;
|
||||
} else if (strcmp(argv[i], "--best-within") == 0) {
|
||||
opt->best_within = true;
|
||||
opt->best = false;
|
||||
opt->average = false;
|
||||
i++;
|
||||
opt->within = strtod(argv[i], &end) / 100.0;
|
||||
} else if (strcmp(argv[i], "--average") == 0) {
|
||||
opt->average = true;
|
||||
opt->best = false;
|
||||
opt->best_within = false;
|
||||
} else if (strcmp(argv[i], "--quiet") == 0) {
|
||||
opt->quiet = true;
|
||||
} else {
|
||||
@@ -131,14 +146,78 @@ select_config(int func, size_t n, const config_func_t functions[])
|
||||
for(size_t i = 0; i < n;i++) {
|
||||
fprintf(stderr, " %d: %s\n", functions[i].num, functions[i].funcname);
|
||||
}
|
||||
fprintf(stderr, "USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--best|--average] [--quiet|--graph]\n");
|
||||
fprintf(stderr,
|
||||
"USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--grapĥ]\n"
|
||||
"[--repeat number] [--best|--average|--best-within] [--quiet]\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Utility function for qsort
|
||||
static int cmp_double(const void *pa, const void *pb)
|
||||
{
|
||||
const double *a = (const double *) pa, *b = (const double *)pb;
|
||||
return (*a < *b) ? -1 : *a > *b;
|
||||
}
|
||||
|
||||
/* Get the longest sequence of values within 'f'% */
|
||||
static int
|
||||
get_sequence(int i, int n, double tab[], double f)
|
||||
{
|
||||
int j;
|
||||
for(j = i + 1; j < n; j++) {
|
||||
if (tab[j] > f * tab[i])
|
||||
break;
|
||||
}
|
||||
return j-i;
|
||||
}
|
||||
|
||||
/* Return the minimum of the longest sequence of values with 'f'% */
|
||||
static double
|
||||
get_best_within(int n, double tab[], double f)
|
||||
{
|
||||
qsort(tab, n, sizeof(double), cmp_double);
|
||||
int best_i = 0;
|
||||
int best_seq = get_sequence(0, n, tab, f);
|
||||
for(int i = 1; i < n && (n-i) > best_seq ; i++) {
|
||||
int seq = get_sequence(i, n, tab, f);
|
||||
if (seq > best_seq) {
|
||||
best_i = i;
|
||||
best_seq = seq;
|
||||
}
|
||||
}
|
||||
return tab[best_i];
|
||||
}
|
||||
|
||||
// Integer sqrt function (to avoid depending on libm)
|
||||
static unsigned integer_sqrt(unsigned n)
|
||||
{
|
||||
// Find greatest shift.
|
||||
int shift = 2;
|
||||
unsigned nShifted = n >> shift;
|
||||
// We check for nShifted being n, since some implementations
|
||||
// perform shift operations modulo the word size.
|
||||
while (nShifted != 0 && nShifted != n){
|
||||
shift += 2;
|
||||
nShifted = n >> shift;
|
||||
}
|
||||
shift -= 2;
|
||||
// Find digits of result.
|
||||
unsigned result = 0;
|
||||
while (shift >= 0) {
|
||||
result = result << 1;
|
||||
unsigned candidateResult = result + 1;
|
||||
if (candidateResult*candidateResult <= n >> shift) {
|
||||
result = candidateResult;
|
||||
}
|
||||
shift -= 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
test(const char library[], size_t n, const config_func_t functions[], int argc, const char *argv[])
|
||||
{
|
||||
// options
|
||||
// Init & parse arguments
|
||||
// NUMBER
|
||||
// --from NUMBER --to NUMBER --step NUMBER --grow NUMBER
|
||||
// --graph --best --average --quiet
|
||||
@@ -146,8 +225,10 @@ test(const char library[], size_t n, const config_func_t functions[], int argc,
|
||||
struct parse_opt_s arg;
|
||||
parse_config(&arg, argc, argv);
|
||||
int i = select_config(arg.test_function, n, functions);
|
||||
double from = arg.from == 0 ? functions[i].default_n : arg.from;
|
||||
double to = arg.from == 0 ? functions[i].default_n : arg.to;
|
||||
double from = (arg.from == 0) ? functions[i].default_n : arg.from;
|
||||
double to = (arg.to == 0) ? functions[i].default_n : arg.to;
|
||||
|
||||
// Open plot file if needed
|
||||
FILE *graph_file = NULL;
|
||||
if (arg.graph) {
|
||||
char filename[100];
|
||||
@@ -159,32 +240,59 @@ test(const char library[], size_t n, const config_func_t functions[], int argc,
|
||||
}
|
||||
fprintf(graph_file, "# plotting %s-%d : %s\n# N T", library, arg.test_function, functions[i].funcname);
|
||||
}
|
||||
|
||||
// Do the bench
|
||||
for(double n = from; n <= to ; n = (arg.grow == 0 ? n + arg.step : n * arg.grow))
|
||||
for(double n = from; n <= to ; n = ((arg.grow == 0) ? n + arg.step : n * arg.grow))
|
||||
{
|
||||
double best = (1.0/0.0);
|
||||
double avg = 0.0;
|
||||
double variance = 0.0;
|
||||
static double measure[MAX_REPEAT];
|
||||
double ba = 0.0;
|
||||
|
||||
if (functions[i].init != NULL)
|
||||
functions[i].init(n);
|
||||
|
||||
// Measure the time of the test_function
|
||||
for(unsigned r = 0; r < arg.repeat; r++) {
|
||||
double t0 = test_function(arg.graph|arg.best|arg.average|arg.quiet ? NULL : functions[i].funcname, (size_t) n, functions[i].func);
|
||||
best = t0 < best ? t0 : best;
|
||||
double t0 = test_function( (arg.graph|arg.best|arg.average|arg.quiet) ? NULL : functions[i].funcname, (size_t) n, functions[i].func);
|
||||
best = (t0 < best) ? t0 : best;
|
||||
avg += t0;
|
||||
variance += t0 * t0;
|
||||
measure[r] = t0;
|
||||
}
|
||||
|
||||
// Closure of the tests
|
||||
if (functions[i].clear != NULL)
|
||||
functions[i].clear();
|
||||
avg /= arg.repeat;
|
||||
|
||||
// Finish computing the different times
|
||||
if (arg.repeat > 1) {
|
||||
avg /= arg.repeat;
|
||||
variance = (variance - arg.repeat * avg * avg) / (arg.repeat - 1);
|
||||
ba = get_best_within(arg.repeat, measure, 1. + arg.within);
|
||||
}
|
||||
|
||||
// The average value shall be around best_within (and greater)
|
||||
// otherwise the result doesn't seem reliable.
|
||||
bool reliable = (ba <= avg && ba * (1.0+arg.within/2) + 0.5 > avg);
|
||||
|
||||
// Print the result
|
||||
if (arg.graph) {
|
||||
fprintf(graph_file, "%f %f\n", n, arg.average ? avg : best);
|
||||
fprintf(graph_file, "%f %f\n", n, arg.average ? avg : arg.best ? best : ba);
|
||||
} else if (arg.quiet) {
|
||||
printf("%lu\n", (unsigned long)(arg.average ? avg : best));
|
||||
printf("%ld\n", (long)(arg.average ? avg : arg.best ? best : reliable ? ba : -1));
|
||||
} else if (arg.repeat > 1) {
|
||||
if (arg.average == false)
|
||||
if (arg.average == false && arg.best_within == false)
|
||||
printf ("%20.20s time %lu ms for n = %lu *** BEST ***\n", functions[i].funcname, (unsigned long) best, (unsigned long) n);
|
||||
if (arg.best == false)
|
||||
printf ("%20.20s time %lu ms for n = %lu *** AVERAGE ***\n", functions[i].funcname, (unsigned long) avg, (unsigned long) n);
|
||||
if (arg.best == false && arg.best_within == false)
|
||||
printf ("%20.20s time %lu ms +/- %u ms for n = %lu *** AVERAGE ***\n", functions[i].funcname, (unsigned long) avg, 2*integer_sqrt(variance), (unsigned long) n);
|
||||
if (arg.best == false && arg.average == false)
|
||||
printf ("%20.20s time %lu ms for n = %lu *** BEST within %d%% *** %s\n", functions[i].funcname, (unsigned long) ba, (unsigned long) n, (int)(100*arg.within), reliable ? "" : "(unreliable result)");
|
||||
}
|
||||
}
|
||||
|
||||
// Close the FILE if needed
|
||||
if (arg.graph) {
|
||||
fclose(graph_file);
|
||||
printf("File plot-%s-%d.dat generated.\n"
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MLIB - TEST module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
#ifndef NDEBUG
|
||||
#define NDEBUG
|
||||
#endif
|
||||
#undef NDEBUG
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "benchmark.h"
|
||||
@@ -48,7 +43,7 @@ int test_int(int N, const unsigned *data)
|
||||
if (dict_int_get (h, data[i]) == NULL) {
|
||||
dict_int_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_int_remove(h, data[i]);
|
||||
dict_int_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_int_size(h);
|
||||
@@ -64,7 +59,7 @@ int test_str(int N, char * const *data)
|
||||
if (dict_str_get (h, data[i]) == NULL) {
|
||||
dict_str_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_str_remove(h, data[i]);
|
||||
dict_str_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_str_size(h);
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
#include "m-dict.h"
|
||||
#include "m-mempool.h"
|
||||
|
||||
DICT_DEF2(dict_int,
|
||||
DICT_STOREHASH_DEF2(dict_int,
|
||||
int, M_OPEXTEND(M_DEFAULT_OPLIST, MEMPOOL(mpool_int), MEMPOOL_LINKAGE(static)),
|
||||
int, M_DEFAULT_OPLIST)
|
||||
DICT_DEF2(dict_str,
|
||||
DICT_STOREHASH_DEF2(dict_str,
|
||||
const char *, M_OPEXTEND (M_CSTR_OPLIST, MEMPOOL(mpool_str), MEMPOOL_LINKAGE(static)),
|
||||
int, M_DEFAULT_OPLIST)
|
||||
|
||||
@@ -20,7 +20,7 @@ int test_int(int N, const unsigned *data)
|
||||
if (dict_int_get (h, data[i]) == NULL) {
|
||||
dict_int_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_int_remove(h, data[i]);
|
||||
dict_int_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_int_size(h);
|
||||
@@ -38,7 +38,7 @@ int test_str(int N, char * const *data)
|
||||
if (dict_str_get (h, data[i]) == NULL) {
|
||||
dict_str_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_str_remove(h, data[i]);
|
||||
dict_str_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_str_size(h);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "../common.c"
|
||||
#define DICTI_OA_PROBING(s) 1
|
||||
#include "m-dict.h"
|
||||
|
||||
static inline bool oor_equal_p(unsigned int k, unsigned char n)
|
||||
@@ -11,10 +12,10 @@ static inline void oor_set(unsigned int *k, unsigned char n)
|
||||
}
|
||||
|
||||
DICT_OA_DEF2(dict_oa_uint,
|
||||
unsigned int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
|
||||
unsigned int, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(hash_fn), OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
|
||||
unsigned int, M_DEFAULT_OPLIST)
|
||||
|
||||
void test_int(uint32_t n, uint32_t x0)
|
||||
uint32_t test_int(uint32_t n, uint32_t x0)
|
||||
{
|
||||
uint32_t i, x, z = 0;
|
||||
dict_oa_uint_t h;
|
||||
@@ -22,10 +23,12 @@ void test_int(uint32_t n, uint32_t x0)
|
||||
for (i = 0, x = x0; i < n; ++i) {
|
||||
x = hash32(x);
|
||||
unsigned int key = get_key(n, x);
|
||||
unsigned int *ptr = dict_oa_uint_get(h, key);
|
||||
if (ptr) { (*ptr)++; z+= *ptr; }
|
||||
else { dict_oa_uint_set_at(h, key, 1); z+=1; }
|
||||
unsigned int *ptr = dict_oa_uint_get_at(h, key);
|
||||
(*ptr)++;
|
||||
z += *ptr;
|
||||
}
|
||||
fprintf(stderr, "# unique keys: %d; checksum: %u\n", (int) dict_oa_uint_size(h), z);
|
||||
z = dict_oa_uint_size(h);
|
||||
dict_oa_uint_clear(h);
|
||||
return z;
|
||||
}
|
||||
+7
-1
@@ -38,4 +38,10 @@ V0.2.*: * worker_start takes a 'worker_t' as an additional parameter
|
||||
V0.3.*: * Remove B+TREE _remove method as it has been deprecated (use _erase instead)
|
||||
* Remove DICT _remove method as it has been deprecated (use _erase instead)
|
||||
* Make _it_to_p method of B+TREE / RB-TREE as deprecated (uses _it_until_p instead ).
|
||||
|
||||
* Deprecated buffer options BUFFER_BLOCKING* and BUFFER_UNBLOCKING*
|
||||
as the _push_blocking and _pop_blocking functions can do the same and are more versatil.
|
||||
* Iteration over the items of a dictionnary/tree returns const iterators for access through
|
||||
OPLIST (impact: algorithm & M_EACH) as the IT_REF operator is no longer exported.
|
||||
The _it_ref method is still defined and can be used, so you can still modify the values
|
||||
but it won't be automatically used anymore (as the keys CANNOT be modified).
|
||||
(Previously it generates incorrect algorithm when used with m-dict).
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 103 KiB |
Binary file not shown.
+3
-2
@@ -1,5 +1,5 @@
|
||||
CC=cc -std=c99
|
||||
CFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function
|
||||
CFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -g
|
||||
GMP_DIR=
|
||||
CPPFLAGS=-I..
|
||||
LDFLAGS=-pthread
|
||||
@@ -12,11 +12,12 @@ RM=rm -f
|
||||
|
||||
all: config
|
||||
$(MAKE) `ls ex-*.c|sed -e 's/\.c/\.exe/g'`
|
||||
if test "$(CC)" = "cc -std=c99" ; then $(MAKE) `ls ex11-*.c|sed -e 's/\.c/\.exe/g'` CC="cc -std=c11" ; fi
|
||||
|
||||
config:
|
||||
printf "#include <gmp.h>\nint main(void){mpz_t z; mpz_init(z); return 0;}\n" > config-test.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp config-test.c -o config-test.exe 2> /dev/null && echo "-DHAVE_GMP=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0" > config
|
||||
$(RM) config-test.*
|
||||
$(RM) config-test.c config-test.exe
|
||||
|
||||
clean:
|
||||
$(RM) *.exe *.s *~ *.o ./a.dat config
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <stdio.h>
|
||||
#include "m-array.h"
|
||||
#include "m-algo.h"
|
||||
|
||||
/* Define a dynamic array of int */
|
||||
ARRAY_DEF(vector_int, int)
|
||||
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
|
||||
ALGO_DEF(vector_int, vector_int_t)
|
||||
|
||||
/* Define a dynamic array of bool */
|
||||
ARRAY_DEF(vector_bool, bool)
|
||||
#define M_OPL_vector_bool_t() ARRAY_OPLIST(vector_bool)
|
||||
ALGO_DEF(vector_bool, vector_bool_t)
|
||||
|
||||
static bool id(bool x) { return x ; }
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET(myvector, tmp, vector_int_t) {
|
||||
vector_int_fill_n(myvector, 3, 20);
|
||||
vector_int_fill_n(tmp, 3, 33);
|
||||
vector_int_splice(myvector, tmp);
|
||||
vector_int_fill_n(tmp, 2, 10);
|
||||
vector_int_splice(myvector, tmp);
|
||||
printf("myvector contains:");
|
||||
// In C11, the for loop can be simplified as :
|
||||
// ALGO_FOR_EACH(myvector, vector_int_t, M_PRINT, " ");
|
||||
for M_EACH(it, myvector, vector_int_t) {
|
||||
printf(" %d", *it);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
M_LET(myvector, tmp, vector_bool_t) {
|
||||
vector_bool_fill_n(myvector, 3, false);
|
||||
vector_bool_fill_n(tmp, 3, true);
|
||||
vector_bool_splice(myvector, tmp);
|
||||
vector_bool_fill_n(tmp, 2, false);
|
||||
vector_bool_splice(myvector, tmp);
|
||||
printf("myvector contains:");
|
||||
// In C11, the for loop can be simplified as :
|
||||
// ALGO_FOR_EACH(myvector, vector_bool_t, M_PRINT, " ");
|
||||
for M_EACH(it, myvector, vector_bool_t) {
|
||||
printf(" %d", (int)*it);
|
||||
}
|
||||
printf("\n");
|
||||
printf ("ALL: %d ANY: %d NONE: %d\n",
|
||||
vector_bool_all_of_p(myvector, id),
|
||||
vector_bool_any_of_p(myvector, id),
|
||||
vector_bool_none_of_p(myvector, id) );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-string.h"
|
||||
|
||||
DICT_DEF2(dict, string_t, int)
|
||||
#define M_OPL_dict_t() DICT_OPLIST(dict, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
ARRAY_DEF(vector_int, int)
|
||||
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
|
||||
|
||||
#define start_with(pattern, item) \
|
||||
string_start_with_str_p((item).key, (pattern))
|
||||
#define get_value(out, item) ((out) = (item).value)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int s;
|
||||
M_LET(keys, vector_int_t)
|
||||
M_LET( (m, (STRING_CTE("foo"), 1), (STRING_CTE("bar"), 42), (STRING_CTE("bluez"), 7), (STRING_CTE("stop"), 789) ), tmp, dict_t) {
|
||||
|
||||
/* Extract all elements of 'm' that starts with 'b' */
|
||||
ALGO_EXTRACT(tmp, dict_t, m, dict_t, start_with, "b");
|
||||
/* Extract the values of theses elements */
|
||||
ALGO_TRANSFORM(keys, vector_int_t, tmp, dict_t, get_value);
|
||||
/* Sum theses values */
|
||||
ALGO_REDUCE(s, keys, vector_int_t, sum);
|
||||
printf("Sum of elements starting with 'b' is: %d\n", s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "m-algo.h"
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
ARRAY_DEF(vector_int, int)
|
||||
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
|
||||
|
||||
#define str_ui(s, i) string_printf(s, "%d", i)
|
||||
#define str_cat(s1, s2) (string_cat_str(s1, "-"), string_cat(s1, s2))
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET(s, string_t)
|
||||
M_LET( (v, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), vector_int_t) {
|
||||
int sum, product;
|
||||
|
||||
ALGO_REDUCE(sum, v, vector_int_t, add);
|
||||
ALGO_REDUCE(product, v, vector_int_t, mul);
|
||||
/* Example of reduction with a transformation of the type from int to string_t */
|
||||
ALGO_REDUCE( (s, string_t), v, vector_int_t, str_cat, str_ui);
|
||||
|
||||
printf ("sum: %d\n"
|
||||
"product: %d\n"
|
||||
"dash str: %s\n", sum, product, string_get_cstr(s));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+42
-4
@@ -4,12 +4,14 @@
|
||||
/* This example show how to use complex structure with array
|
||||
embedding another library */
|
||||
|
||||
/* This is a trivial library */
|
||||
/* This is a typical trivial library with its interface */
|
||||
typedef struct lib_ext_struct {
|
||||
int id;
|
||||
// Other data
|
||||
// Other data may be added
|
||||
} lib_ext_struct;
|
||||
|
||||
/* Method to create a duplicate of the object.
|
||||
The new object is heap allocated */
|
||||
static lib_ext_struct *lib_ext_struct_Duplicate(const lib_ext_struct *obj)
|
||||
{
|
||||
lib_ext_struct *p = malloc(sizeof(lib_ext_struct));
|
||||
@@ -18,6 +20,7 @@ static lib_ext_struct *lib_ext_struct_Duplicate(const lib_ext_struct *obj)
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Method to delete any object */
|
||||
static void lib_ext_struct_Delete(lib_ext_struct *obj)
|
||||
{
|
||||
free(obj);
|
||||
@@ -30,6 +33,11 @@ typedef struct {
|
||||
lib_ext_struct* properties;
|
||||
} data_node;
|
||||
|
||||
/* This method shall initialize the object data_node to
|
||||
the init state.
|
||||
It takes as first argument the object to initialize,
|
||||
and since it takes by reference through a pointer,
|
||||
it is compatible with 'API_2' convention for oplist */
|
||||
static void data_node_init(data_node *obj)
|
||||
{
|
||||
obj->id = 0;
|
||||
@@ -37,6 +45,12 @@ static void data_node_init(data_node *obj)
|
||||
obj->properties = NULL;
|
||||
}
|
||||
|
||||
/* This method shall initialize the object data_node to
|
||||
the same state as the 'src' object (creating a copy, a duplicate) .
|
||||
It takes as first argument the object to initialize,
|
||||
and as second argument the source object.
|
||||
It takes both object by reference through pointers,
|
||||
as such it is compatible with 'API_6' convention for oplist */
|
||||
static void data_node_init_set(data_node *obj, const data_node *src)
|
||||
{
|
||||
obj->id = src->id;
|
||||
@@ -47,6 +61,13 @@ static void data_node_init_set(data_node *obj, const data_node *src)
|
||||
obj->properties = NULL;
|
||||
}
|
||||
|
||||
/* This method shall set the object data_node to
|
||||
the same state as the 'src' object (creating a copy, a duplicate) .
|
||||
THe object was already initialized.
|
||||
It takes as first argument the object to initialize,
|
||||
and as second argument the source object.
|
||||
It takes both object by reference through pointers,
|
||||
as such it is compatible with 'API_6' convention for oplist */
|
||||
static void data_node_set(data_node *obj, const data_node *src)
|
||||
{
|
||||
obj->id = src->id;
|
||||
@@ -59,6 +80,11 @@ static void data_node_set(data_node *obj, const data_node *src)
|
||||
obj->properties = NULL;
|
||||
}
|
||||
|
||||
/* This method shall clear the object data_node to
|
||||
the cleared state (aka it shall free any resource).
|
||||
It takes as first argument the object to initialize,
|
||||
and since it takes by reference through a pointer,
|
||||
it is compatible with 'API_2' convention for oplist */
|
||||
static void data_node_clear(data_node *obj)
|
||||
{
|
||||
string_clear(obj->type);
|
||||
@@ -66,13 +92,25 @@ static void data_node_clear(data_node *obj)
|
||||
lib_ext_struct_Delete(obj->properties);
|
||||
}
|
||||
|
||||
/* Create a dynamic array of 'data_node' named array_data_node_t
|
||||
and gives the minimum oplist allowing M*LIB to handle
|
||||
properly the object 'data_node' with the API convention
|
||||
to respect for calling the methods.
|
||||
*/
|
||||
ARRAY_DEF(/* the array prefix */ array_data_node,
|
||||
/* the object type */ data_node,
|
||||
/* the object oplist */ (INIT(API_2(data_node_init)),
|
||||
SET(API_6(data_node_set)),
|
||||
INIT_SET(API_6(data_node_init_set)),
|
||||
CLEAR(API_2(data_node_clear))))
|
||||
|
||||
ARRAY_DEF(array_data_node, data_node, (INIT(API_2(data_node_init)),SET(API_6(data_node_set)),INIT_SET(API_6(data_node_init_set)),CLEAR(API_2(data_node_clear))))
|
||||
|
||||
/* Define a global array with the created type */
|
||||
array_data_node_t global_array;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Call the created method */
|
||||
array_data_node_init(global_array);
|
||||
/* Do stuff... */
|
||||
array_data_node_clear(global_array);
|
||||
}
|
||||
@@ -52,11 +52,11 @@ int main(void)
|
||||
// Dictionary iterator are pair (key,value)
|
||||
if (my_integer_n_p(p->value)) {
|
||||
printf ("It is a long long, value = %lld\n",
|
||||
*my_integer_get_n(p->value));
|
||||
*my_integer_cget_n(p->value));
|
||||
}
|
||||
if (my_integer_z_p(p->value)) {
|
||||
printf ("It is a mpz_t, value =");
|
||||
mpz_out_str(stdout, 10, *my_integer_get_z(p->value));
|
||||
mpz_out_str(stdout, 10, *my_integer_cget_z(p->value));
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Let's create an array of string_t and register it globaly
|
||||
ARRAY_DEF(vector_string, string_t)
|
||||
#define M_OPL_vector_string_t() ARRAY_OPLIST(vector_string, STRING_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Let's define a new string named str
|
||||
M_LET(str, string_t)
|
||||
// Let's define msg as a vector_array_t
|
||||
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) {
|
||||
// Iterate over all words of the array msg
|
||||
for M_EACH(word, msg, vector_string_t) {
|
||||
// Cat the current word into the target string
|
||||
string_cat(str, *word);
|
||||
// Also add a space character
|
||||
string_push_back(str, ' ');
|
||||
}
|
||||
// Let's define another string and set it to a formatted value.
|
||||
M_LET( (count, "\nTo display this it uses \"vector\" of %zu strings!", vector_string_size(msg)), string_t) {
|
||||
string_cat(str, count);
|
||||
}
|
||||
// Print the result
|
||||
printf("%s\n", string_get_cstr(str) );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+10
-8
@@ -4,6 +4,15 @@
|
||||
|
||||
#include "m-rbtree.h"
|
||||
|
||||
// Let's define one utility function.
|
||||
void *xmalloc(size_t n);
|
||||
void *xmalloc(size_t n)
|
||||
{
|
||||
void *p = malloc (n);
|
||||
if (!p) abort();
|
||||
return p;
|
||||
}
|
||||
|
||||
// Let's define a new type.
|
||||
typedef struct {
|
||||
int key;
|
||||
@@ -12,7 +21,7 @@ typedef struct {
|
||||
|
||||
#define SIZE 256
|
||||
|
||||
void *xmalloc(size_t n);
|
||||
// Let's define the prototypes of the methods of this new type.
|
||||
void my_type_init(my_type_t x);
|
||||
void my_type_clear(my_type_t x);
|
||||
void my_type_init_set(my_type_t x, const my_type_t y);
|
||||
@@ -24,13 +33,6 @@ void my_type_out_str(FILE *f, const my_type_t x);
|
||||
bool my_type_in_str(my_type_t x, FILE *f);
|
||||
void my_type_rand(my_type_t x);
|
||||
|
||||
void *xmalloc(size_t n)
|
||||
{
|
||||
void *p = malloc (n);
|
||||
if (!p) abort();
|
||||
return p;
|
||||
}
|
||||
|
||||
// Let's define its constructor
|
||||
void my_type_init(my_type_t x)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Based on https://en.cppreference.com/w/cpp/algorithm/for_each
|
||||
Need to be built in C11 mode */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "m-array.h"
|
||||
#include "m-algo.h"
|
||||
|
||||
/* Define a dynamic array of int */
|
||||
ARRAY_DEF(vector_int, int)
|
||||
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
|
||||
|
||||
/* Define operator increment on int */
|
||||
#define INC(n) (n)++
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET( (nums, 3, 4, 2, 8, 15, 267), vector_int_t) {
|
||||
// Print the array before
|
||||
printf ("before:");
|
||||
ALGO_FOR_EACH(nums, vector_int_t, M_PRINT, " ");
|
||||
printf ("\n");
|
||||
|
||||
// Increment each element of the array
|
||||
ALGO_FOR_EACH(nums, vector_int_t, INC);
|
||||
|
||||
// Print the array after
|
||||
printf ("after: ");
|
||||
ALGO_FOR_EACH(nums, vector_int_t, M_PRINT, " ");
|
||||
printf ("\n");
|
||||
|
||||
// Sum the elements of the array
|
||||
int sum = 0;
|
||||
ALGO_REDUCE(sum, nums, vector_int_t, add);
|
||||
M_PRINT("sum = ", sum, "\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#include "m-tuple.h"
|
||||
#include "m-array.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-funcobj.h"
|
||||
#include "m-serial-json.h"
|
||||
#include "m-string.h"
|
||||
|
||||
/* Define the employee */
|
||||
TUPLE_DEF2(employee,
|
||||
(name, string_t),
|
||||
(age, int),
|
||||
(idnum, int))
|
||||
#define M_OPL_employee_t() TUPLE_OPLIST(employee, STRING_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
/* Define an array of employee and some algorithms on it */
|
||||
ARRAY_DEF(vector_employee, employee_t)
|
||||
#define M_OPL_vector_employee_t() ARRAY_OPLIST(vector_employee, M_OPL_employee_t())
|
||||
ALGO_DEF(vector_employee, vector_employee_t)
|
||||
|
||||
/* Define the function object to select the sort order */
|
||||
FUNC_OBJ_INS_DEF(compare_by,
|
||||
vector_employee_cmp_obj,
|
||||
(a, b), {
|
||||
if (string_equal_str_p(self->sort_field, "name"))
|
||||
return string_cmp(a->name, b->name);
|
||||
else if (string_equal_str_p(self->sort_field, "age"))
|
||||
return a->age < b->age ? -1 : a->age > b->age;
|
||||
else
|
||||
return a->idnum < b->idnum ? -1 : a->idnum > b->idnum;
|
||||
},
|
||||
(sort_field, string_t) )
|
||||
#define M_OPL_compare_by_t() FUNC_OBJ_INS_OPLIST(compare_by, STRING_OPLIST)
|
||||
|
||||
// Let's read an array of person from the given JSON file
|
||||
static void read(vector_employee_t base, const char filename[])
|
||||
{
|
||||
m_serial_return_code_t ret;
|
||||
|
||||
// Open the file
|
||||
FILE *f = fopen(filename, "rt");
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot open file '%s'.\n", filename);
|
||||
exit(2);
|
||||
}
|
||||
// Initialize the JSON serializer with this file
|
||||
M_LET( (in,f), m_serial_json_read_t)
|
||||
ret = vector_employee_in_serial(base, in);
|
||||
// Let's handle errors
|
||||
if (ret != M_SERIAL_OK_DONE) {
|
||||
fprintf(stderr, "ERROR: Cannot read JSON data from file '%s'.\nParsing stops at:\n", filename);
|
||||
while (!feof(f)) { fputc(fgetc(f), stdout); }
|
||||
fclose(f);
|
||||
exit(2);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET(emps, vector_employee_t) {
|
||||
/* Code to populate database from JSON */
|
||||
read(emps, "ex11-algo02.json");
|
||||
|
||||
// Sort the database by employee ID number
|
||||
M_LET( (cmp, STRING_CTE("idnum")), compare_by_t )
|
||||
vector_employee_sort_fo(emps, compare_by_as_interface(cmp));
|
||||
printf("Employees sorted by idnum are: ");
|
||||
vector_employee_out_str(stdout, emps);
|
||||
|
||||
M_LET( (cmp, STRING_CTE("name")), compare_by_t )
|
||||
vector_employee_sort_fo(emps, compare_by_as_interface(cmp));
|
||||
printf("\nEmployees sorted by name are: ");
|
||||
vector_employee_out_str(stdout, emps);
|
||||
printf("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
[
|
||||
{ "name": "John Doe", "age": 32, "idnum": 14528},
|
||||
{ "name": "Clint Smith", "age": 31, "idnum": 14529},
|
||||
{ "name": "Linda Cameron", "age": 20, "idnum": 14527},
|
||||
{ "name": "Cameron Carrey", "age": 25, "idnum": 14526},
|
||||
{ "name": "Marty Brown", "age": 26, "idnum": 14525},
|
||||
{ "name": "Donald Cow", "age": 45, "idnum": 14520}
|
||||
]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - dynamic ARRAY module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -34,6 +34,7 @@
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name,_it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t))))
|
||||
|
||||
|
||||
/* Define the oplist of a dynamic array given its name and its oplist.
|
||||
If no oplist is given it is assumed to be M_DEFAULT_OPLIST
|
||||
USAGE: ARRAY_OPLIST(name[, oplist of the type]) */
|
||||
@@ -52,10 +53,18 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define ARRAYI_OPLIST_P1(arg) ARRAYI_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define ARRAYI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(ARRAYI_OPLIST_P3, ARRAYI_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define ARRAYI_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_ARRAY_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
|
||||
/* OPLIST definition of a dynamic array */
|
||||
/* FIXME: Do we want to export some methods as they are slow and
|
||||
are not fit to be used for building other methods (like _it_remove)? */
|
||||
#define ARRAYI_OPLIST_P2(name, oplist) \
|
||||
#define ARRAYI_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
@@ -121,6 +130,14 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define ARRAYI_DEF_P1(arg) ARRAYI_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define ARRAYI_DEF_P2(name, type, oplist, array_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(ARRAYI_DEF_P3, ARRAYI_DEF_FAILURE)(name, type, oplist, array_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define ARRAYI_DEF_FAILURE(name, type, oplist, array_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ARRAY_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Internal definition:
|
||||
- name: prefix to be used
|
||||
- type: type of the elements of the array
|
||||
@@ -128,7 +145,7 @@
|
||||
- array_t: alias for M_C(name, _t) [ type of the array ]
|
||||
- it_t: alias for M_C(name, _it_t) [ iterator of the array ]
|
||||
*/
|
||||
#define ARRAYI_DEF_P2(name, type, oplist, array_t, it_t) \
|
||||
#define ARRAYI_DEF_P3(name, type, oplist, array_t, it_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
size_t size; /* Number of elements in the array */ \
|
||||
@@ -145,6 +162,8 @@
|
||||
const struct M_C(name, _s) *array; /* Reference of the array */ \
|
||||
} it_t[1]; \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(array_t v) \
|
||||
{ \
|
||||
@@ -272,6 +291,7 @@
|
||||
type *ret = &v->ptr[v->size]; \
|
||||
v->size++; \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ASSUME(ret != NULL); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
@@ -279,8 +299,8 @@
|
||||
M_C(name, _push_back)(array_t v, type const x) \
|
||||
{ \
|
||||
type *data = M_C(name, _push_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_CALL_INIT_SET(oplist, *data, x); \
|
||||
} \
|
||||
\
|
||||
@@ -860,7 +880,7 @@
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
assert (str != NULL); \
|
||||
M_C(name,_clean)(array); \
|
||||
M_C(name,_clean)(array); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
@@ -873,12 +893,13 @@
|
||||
do { \
|
||||
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
if (b == false || c == 0) { goto exit; } \
|
||||
M_C(name, _push_back)(array, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
if (b == false || c == 0) { goto exit_clear; } \
|
||||
M_C(name, _push_back)(array, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
success = (c == ']'); \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
exit: \
|
||||
if (endp) *endp = str; \
|
||||
return success; \
|
||||
|
||||
+40
-11
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin stdatomic wrapper for C++ compatibility
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -99,11 +99,17 @@ using std::memory_order_seq_cst;
|
||||
#define _Atomic(T) std::atomic< T >
|
||||
|
||||
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
|
||||
|| ( defined(__GNUC__) && !defined(__clang__) && !defined(__cplusplus) && (__GNUC__*100 + __GNUC_MINOR__) >= 409) \
|
||||
|| (defined(__clang__) && __clang_major__ >= 4)
|
||||
|| ( defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__cplusplus) && (__GNUC__*100 + __GNUC_MINOR__) >= 409) \
|
||||
|| (defined(__clang__) && __clang_major__ >= 4) \
|
||||
|| (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1800)
|
||||
|
||||
/* CLANG 3.5 has issues with GCC's stdatomic.h
|
||||
and doesn't provide its own stdatomic.h */
|
||||
/* C11 has mandatory working stdatomic
|
||||
STDATOMIC doesn't work with C++ except for clang
|
||||
GCC < 4.9 doesn't provide a compliant stdatomic.h
|
||||
CLANG 3.5 has issues with GCC's stdatomic.h
|
||||
and doesn't provide its own stdatomic.h
|
||||
ICC < 18 doesn't provide a compliant stdatomic.h
|
||||
*/
|
||||
#include <stdatomic.h>
|
||||
|
||||
/* MSYS2 has a conflict between cdefs.h which defines a _Atomic macro (if not C11)
|
||||
@@ -129,11 +135,13 @@ using std::memory_order_seq_cst;
|
||||
*/
|
||||
#include "m-mutex.h"
|
||||
|
||||
/* The structure is quite large:
|
||||
/* _Atomic qualifier for a type (emulation).
|
||||
The structure is quite large:
|
||||
_val : value of the atomic type,
|
||||
_zero : zero value of the atomic type (constant),
|
||||
_previous: temporary value used within the mutex lock,
|
||||
_lock : the mutex lock.
|
||||
Support up to sizeof (long long) type.
|
||||
*/
|
||||
#define _Atomic(T) \
|
||||
struct { \
|
||||
@@ -143,7 +151,8 @@ using std::memory_order_seq_cst;
|
||||
m_mutex_t _lock; \
|
||||
}
|
||||
|
||||
/* Even if memory order is defined, only the strongest constraint is used */
|
||||
/* Define the supported memory order.
|
||||
Even if memory order is defined, only the strongest constraint is used */
|
||||
typedef enum {
|
||||
memory_order_relaxed,
|
||||
memory_order_consume,
|
||||
@@ -187,25 +196,26 @@ typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
|
||||
#if (defined (INTMAX_C) && defined (UINTMAX_C) && !defined(__cplusplus)) || \
|
||||
defined (_STDINT_H) || defined (_STDINT_H_) || defined (_STDINT) || \
|
||||
defined (_SYS_STDINT_H_)
|
||||
/* Define additional atomic types */
|
||||
typedef _Atomic(intmax_t) atomic_intmax_t;
|
||||
typedef _Atomic(uintmax_t) atomic_uintmax_t;
|
||||
#endif
|
||||
|
||||
/* Unlock the mutex and return the given value */
|
||||
/* (INTERNAL) Unlock the mutex and return the given value */
|
||||
static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
{
|
||||
m_mutex_unlock (*lock);
|
||||
return val;
|
||||
}
|
||||
|
||||
/* This is the heart of the wrapper:
|
||||
/* (INTERNAL) This is the heart of the wrapper:
|
||||
lock the atomic value, read it and returns the value.
|
||||
In order to avoid any compiler extension, we need to transform the
|
||||
atomic type into 'long long' then convert it back to its value.
|
||||
This is because _previous can't be read after the lock, and we can't
|
||||
generate temporary variable within a macro.
|
||||
The trick is computing _val - _zero within the lock, then
|
||||
returns retvalue + _zero after the lock.
|
||||
returns retvalue + _zero after the release of the lock.
|
||||
*/
|
||||
#define atomic_fetch_op(ptr, val, op) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
@@ -213,33 +223,51 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
(ptr)->_val op (val), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, (ptr)->_previous-(ptr)->_zero)+(ptr)->_zero)
|
||||
|
||||
/* Perform an atomic add (EMULATION) */
|
||||
#define atomic_fetch_add(ptr, val) atomic_fetch_op(ptr, val, +=)
|
||||
/* Perform an atomic sub (EMULATION) */
|
||||
#define atomic_fetch_sub(ptr, val) atomic_fetch_op(ptr, val, -=)
|
||||
/* Perform an atomic or (EMULATION) */
|
||||
#define atomic_fetch_or(ptr, val) atomic_fetch_op(ptr, val, |=)
|
||||
/* Perform an atomic xor (EMULATION) */
|
||||
#define atomic_fetch_xor(ptr, val) atomic_fetch_op(ptr, val, ^=)
|
||||
/* Perform an atomic and (EMULATION) */
|
||||
#define atomic_fetch_and(ptr, val) atomic_fetch_op(ptr, val, &=)
|
||||
/* Perform an atomic exchange (EMULATION) */
|
||||
#define atomic_exchange(ptr, val) atomic_fetch_op(ptr, val, =)
|
||||
|
||||
/* Initialize an atomic GLOBAL variable */
|
||||
#define ATOMIC_VAR_INIT(val) { val, 0, 0, M_MUTEXI_INIT_VALUE }
|
||||
|
||||
/* Initialize an atomic variable */
|
||||
#define atomic_init(ptr, val) \
|
||||
(m_mutex_init((ptr)->_lock), (ptr)->_val = val, (ptr)->_zero = 0)
|
||||
|
||||
/* (INTERNAL) Load an atomic variable within a lock
|
||||
(needed for variable greater than CPU atomic size) */
|
||||
#define atomic_load_lock(ptr) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, (ptr)->_previous-(ptr)->_zero)+(ptr)->_zero)
|
||||
|
||||
/* (INTERNAL) Store an atomic variable within a lock
|
||||
(needed for variable greater than CPU atomic size) */
|
||||
#define atomic_store_lock(ptr, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_val = (val), \
|
||||
m_mutex_unlock((ptr)->_lock))
|
||||
|
||||
/* Atomic load of a variable (EMULATION)
|
||||
If the atomic type size is not greater than the CPU atomic size,
|
||||
we can perform a direct read of the variable (much faster) */
|
||||
#define atomic_load(ptr) \
|
||||
( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE \
|
||||
? (ptr)->_val \
|
||||
: atomic_load_lock(ptr))
|
||||
|
||||
/* Atomic store of a variable (EMULATION)
|
||||
If the atomic type size is not greater than the CPU atomic size,
|
||||
we can perform a direct write of the variable (much faster) */
|
||||
#define atomic_store(ptr, val) do { \
|
||||
if ( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE) { \
|
||||
(ptr)->_val = (val); \
|
||||
@@ -249,6 +277,7 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Perform a CAS (Compare and swap) operation (EMULATION) */
|
||||
#define atomic_compare_exchange_strong(ptr, exp, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, \
|
||||
@@ -273,7 +302,7 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
#define atomic_compare_exchange_weak_explicit(ptr, exp, val, mem1, mem2) atomic_compare_exchange_strong(ptr, exp, val)
|
||||
#define atomic_compare_exchange_weak(ptr, exp, val) atomic_compare_exchange_strong(ptr, exp, val)
|
||||
|
||||
/* TODO: Missing atomic_flag. Problem: it needs to be lock free! */
|
||||
/* TODO: Missing atomic_flag. Problem: it is supposed to be lock free! */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - BITSET module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+243
-164
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - B+TREE module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -78,53 +78,19 @@
|
||||
USAGE: BPTREE_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define BPTREE_OPLIST(...) \
|
||||
BPTREEI_KEY_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLISTR ), \
|
||||
(__VA_ARGS__ )))
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define the oplist of a rbtree of type (from BPTREE_DEF2).
|
||||
USAGE: BPTREE_OPLIST2(name, key_oplist, value_oplist) */
|
||||
#define BPTREE_OPLIST2(name, key_oplist, value_oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
SET(M_C(name, _set)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(name, _swap)), \
|
||||
TYPE(M_C(name,_t)), \
|
||||
SUBTYPE(M_C(name, _type_t)), \
|
||||
TEST_EMPTY(M_C(name,_empty_p)), \
|
||||
IT_TYPE(M_C(name, _it_t)), \
|
||||
IT_FIRST(M_C(name,_it)), \
|
||||
IT_SET(M_C(name,_it_set)), \
|
||||
IT_END(M_C(name,_it_end)), \
|
||||
IT_END_P(M_C(name,_end_p)), \
|
||||
IT_EQUAL_P(M_C(name,_it_equal_p)), \
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_REF(M_C(name,_ref)), \
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
CLEAN(M_C(name,_clean)), \
|
||||
GET_MIN(M_C(name,_min)), \
|
||||
GET_MAX(M_C(name,_max)), \
|
||||
KEY_TYPE(M_C(name, _key_type_t)), \
|
||||
VALUE_TYPE(M_C(name, _value_type_t)), \
|
||||
SET_KEY(M_C(name, _set_at)), \
|
||||
GET_KEY(M_C(name, _get)), \
|
||||
ERASE_KEY(M_C(name, _erase)), \
|
||||
KEY_OPLIST(key_oplist), \
|
||||
VALUE_OPLIST(value_oplist), \
|
||||
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)(GET_STR(M_C(name, _get_str)),), \
|
||||
M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)(PARSE_STR(M_C(name, _parse_str)),), \
|
||||
M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)(OUT_STR(M_C(name, _out_str)),), \
|
||||
M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)(IN_STR(M_C(name, _in_str)),), \
|
||||
M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)(OUT_SERIAL(M_C(name, _out_serial)),), \
|
||||
M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)(IN_SERIAL(M_C(name, _in_serial)),), \
|
||||
M_IF_METHOD_BOTH(EQUAL, key_oplist, value_oplist)(EQUAL(M_C(name, _equal_p)),), \
|
||||
M_IF_METHOD_BOTH(HASH, key_oplist, value_oplist)(HASH(M_C(name, _hash)),) \
|
||||
,M_IF_METHOD(NEW, key_oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, key_oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
,M_IF_METHOD(DEL, key_oplist)(DEL(M_GET_DEL oplist),) \
|
||||
)
|
||||
USAGE: BPTREE_OPLIST2(name[, key_oplist, value_oplist])
|
||||
NOTE: IT_REF is not exported so that the contained appears as not modifiable
|
||||
by algorithm.
|
||||
*/
|
||||
#define BPTREE_OPLIST2(...) \
|
||||
BPTREEI_OPLIST2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
|
||||
@@ -134,8 +100,16 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define BPTREEI_KEY_OPLIST_P1(arg) BPTREEI_KEY_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplists */
|
||||
#define BPTREEI_KEY_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(BPTREEI_KEY_OPLIST_P3, BPTREEI_KEY_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define BPTREEI_KEY_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
|
||||
/* OPLIST definition of a b+tree */
|
||||
#define BPTREEI_KEY_OPLIST_P2(name, oplist) \
|
||||
#define BPTREEI_KEY_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
SET(M_C(name, _set)), \
|
||||
@@ -171,7 +145,64 @@
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
)
|
||||
|
||||
/* Internal contract of a B+TREE node */
|
||||
/* Deferred evaluation */
|
||||
#define BPTREEI_OPLIST2_P1(arg) BPTREEI_OPLIST2_P2 arg
|
||||
|
||||
/* Validation of the given oplists */
|
||||
#define BPTREEI_OPLIST2_P2(name, key_oplist, value_oplist) \
|
||||
M_IF_OPLIST(key_oplist)(BPTREEI_OPLIST2_P3, BPTREEI_OPLIST2_FAILURE)(name, key_oplist, value_oplist)
|
||||
#define BPTREEI_OPLIST2_P3(name, key_oplist, value_oplist) \
|
||||
M_IF_OPLIST(value_oplist)(BPTREEI_OPLIST2_P4, BPTREEI_OPLIST2_FAILURE)(name, key_oplist, value_oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define BPTREEI_OPLIST2_FAILURE(name, key_oplist, value_oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, key_oplist, value_oplist)
|
||||
|
||||
#define BPTREEI_OPLIST2_P4(name, key_oplist, value_oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
SET(M_C(name, _set)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(name, _swap)), \
|
||||
TYPE(M_C(name,_t)), \
|
||||
SUBTYPE(M_C(name, _type_t)), \
|
||||
TEST_EMPTY(M_C(name,_empty_p)), \
|
||||
IT_TYPE(M_C(name, _it_t)), \
|
||||
IT_FIRST(M_C(name,_it)), \
|
||||
IT_SET(M_C(name,_it_set)), \
|
||||
IT_END(M_C(name,_it_end)), \
|
||||
IT_END_P(M_C(name,_end_p)), \
|
||||
IT_EQUAL_P(M_C(name,_it_equal_p)), \
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
CLEAN(M_C(name,_clean)), \
|
||||
GET_MIN(M_C(name,_min)), \
|
||||
GET_MAX(M_C(name,_max)), \
|
||||
KEY_TYPE(M_C(name, _key_type_t)), \
|
||||
VALUE_TYPE(M_C(name, _value_type_t)), \
|
||||
SET_KEY(M_C(name, _set_at)), \
|
||||
GET_KEY(M_C(name, _get)), \
|
||||
ERASE_KEY(M_C(name, _erase)), \
|
||||
KEY_OPLIST(key_oplist), \
|
||||
VALUE_OPLIST(value_oplist), \
|
||||
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)(GET_STR(M_C(name, _get_str)),), \
|
||||
M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)(PARSE_STR(M_C(name, _parse_str)),), \
|
||||
M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)(OUT_STR(M_C(name, _out_str)),), \
|
||||
M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)(IN_STR(M_C(name, _in_str)),), \
|
||||
M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)(OUT_SERIAL(M_C(name, _out_serial)),), \
|
||||
M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)(IN_SERIAL(M_C(name, _in_serial)),), \
|
||||
M_IF_METHOD_BOTH(EQUAL, key_oplist, value_oplist)(EQUAL(M_C(name, _equal_p)),), \
|
||||
M_IF_METHOD_BOTH(HASH, key_oplist, value_oplist)(HASH(M_C(name, _hash)),) \
|
||||
,M_IF_METHOD(NEW, key_oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, key_oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
,M_IF_METHOD(DEL, key_oplist)(DEL(M_GET_DEL oplist),) \
|
||||
)
|
||||
|
||||
|
||||
|
||||
/* Internal contract of a B+TREE node 'node' or root 'root' */
|
||||
#ifdef NDEBUG
|
||||
# define BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, node, root) do { } while (0)
|
||||
#else
|
||||
@@ -213,6 +244,18 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define BPTREEI_DEF_P1(arg) BPTREEI_DEF_P2 arg
|
||||
|
||||
/* Validate the key oplist before going further */
|
||||
#define BPTREEI_DEF_P2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t) \
|
||||
M_IF_OPLIST(key_oplist)(BPTREEI_DEF_P3, BPTREEI_DEF_FAILURE)(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t)
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define BPTREEI_DEF_P3(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t) \
|
||||
M_IF_OPLIST(value_oplist)(BPTREEI_DEF_P4, BPTREEI_DEF_FAILURE)(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define BPTREEI_DEF_FAILURE(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(BPTREE*_DEF): one of the given argument is not a valid oplist: " M_AS_STR(key_oplist) " / " M_AS_STR(value_oplist))
|
||||
|
||||
/* Internal b+tree definition
|
||||
- name: prefix to be used
|
||||
- N: size of the node
|
||||
@@ -227,7 +270,7 @@
|
||||
- node_t: alias for M_C(name, _node_t) [ node ]
|
||||
- pit_t: alias for M_C(name, _pit_t) [parent iterator]
|
||||
*/
|
||||
#define BPTREEI_DEF_P2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t) \
|
||||
#define BPTREEI_DEF_P4(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t) \
|
||||
\
|
||||
M_IF(isMap)( \
|
||||
/* Type returned by the iterator. Due to having key and value \
|
||||
@@ -275,7 +318,11 @@
|
||||
int idx; \
|
||||
} it_t[1]; \
|
||||
\
|
||||
/* TODO: Can be optimized to alloc for leaf or for node */ \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, key_t, key_oplist) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 2, value_t, value_oplist) \
|
||||
\
|
||||
/* Allocate a new node */ \
|
||||
/* TODO: Can be specialized to alloc for leaf or for non leaf */ \
|
||||
static inline node_t M_C(name, _new_node)(void) \
|
||||
{ \
|
||||
node_t n = M_CALL_NEW(key_oplist, struct M_C(name, _node_s)); \
|
||||
@@ -295,13 +342,15 @@
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
static inline bool M_C(name, _is_leaf)(node_t n) \
|
||||
static inline bool M_C(name, _is_leaf)(const node_t n) \
|
||||
{ \
|
||||
/* We consider the empty node as a leaf */ \
|
||||
/* We consider the empty node as a leaf */ \
|
||||
/* Only the root node can be empty */ \
|
||||
return n->num <= 0; \
|
||||
} \
|
||||
\
|
||||
static inline int M_C(name, _get_num)(node_t n) \
|
||||
/* Return the number of keys of the node */ \
|
||||
static inline int M_C(name, _get_num)(const node_t n) \
|
||||
{ \
|
||||
int num = n->num; \
|
||||
num = num < 0 ? -num : num; \
|
||||
@@ -314,8 +363,9 @@
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
node_t next, n = b->root; \
|
||||
pit_t pit; \
|
||||
/* np is the heigh of the tree */ \
|
||||
int np = 0; \
|
||||
/* Scan down the nodes */ \
|
||||
/* Scan down the nodes to the left down node */ \
|
||||
while (!M_C(name, _is_leaf)(n)) { \
|
||||
pit->parent[np++] = n; \
|
||||
assert (np <= BPTREEI_MAX_STACK); \
|
||||
@@ -339,6 +389,7 @@
|
||||
/* Next node of the same height */ \
|
||||
next = n->next; \
|
||||
if (i != 0) { \
|
||||
/* Free the node if non root */ \
|
||||
M_CALL_DEL(key_oplist, n); \
|
||||
} \
|
||||
n = next; \
|
||||
@@ -359,57 +410,71 @@
|
||||
b->root = NULL; \
|
||||
} \
|
||||
\
|
||||
/* Copy recursively the node 'o' of root node 'root' */ \
|
||||
static inline node_t M_C(name, _copy_node)(const node_t o, const node_t root) \
|
||||
{ \
|
||||
node_t n = M_C(name, _new_node)(); \
|
||||
n->num = o->num; \
|
||||
n->next = NULL; \
|
||||
int num = M_C(name, _get_num)(o); \
|
||||
for(int i = 0; i < num; i++) { \
|
||||
{ \
|
||||
node_t n = M_C(name, _new_node)(); \
|
||||
/* Set default number of keys and type to copy */ \
|
||||
n->num = o->num; \
|
||||
/* By default it is not linked to its brother. \
|
||||
Only the parent of this node can do it. It is fixed by it */ \
|
||||
n->next = NULL; \
|
||||
/* Get number of keys in the node and copy them */ \
|
||||
int num = M_C(name, _get_num)(o); \
|
||||
for(int i = 0; i < num; i++) { \
|
||||
M_CALL_INIT_SET(key_oplist, n->key[i], o->key[i]); \
|
||||
} \
|
||||
if (M_C(name, _is_leaf)(o)) { \
|
||||
M_IF(isMap)( \
|
||||
for(int i = 0; i < num; i++) { \
|
||||
M_CALL_INIT_SET(value_oplist, n->kind.value[i], o->kind.value[i]); \
|
||||
} \
|
||||
,) \
|
||||
} else { \
|
||||
for(int i = 0; i <= num; i++) { \
|
||||
} \
|
||||
if (M_C(name, _is_leaf)(o)) { \
|
||||
/* Copy the associated values if it is a leaf and a MAP */ \
|
||||
M_IF(isMap)( \
|
||||
for(int i = 0; i < num; i++) { \
|
||||
M_CALL_INIT_SET(value_oplist, n->kind.value[i], o->kind.value[i]); \
|
||||
} \
|
||||
, /* End of isMap */) \
|
||||
} else { \
|
||||
/* Copy recursively the associated nodes if it is not a leaf */ \
|
||||
for(int i = 0; i <= num; i++) { \
|
||||
assert(o->kind.node[i] != root); \
|
||||
n->kind.node[i] = M_C(name, _copy_node)(o->kind.node[i], root); \
|
||||
} \
|
||||
for(int i = 0; i < num; i++) { \
|
||||
node_t current = n->kind.node[i]; \
|
||||
n->kind.node[i] = M_C(name, _copy_node)(o->kind.node[i], root); \
|
||||
} \
|
||||
/* The copied nodes don't have their next field correct */ \
|
||||
/* Fix the next field for the copied nodes */ \
|
||||
for(int i = 0; i < num; i++) { \
|
||||
node_t current = n->kind.node[i]; \
|
||||
node_t next = n->kind.node[i+1]; \
|
||||
current->next = next; \
|
||||
/* Go down the tree up to the leaf \
|
||||
and fix the final 'next' link with the copied node */ \
|
||||
while (!M_C(name, _is_leaf)(current)) { \
|
||||
assert(!M_C(name, _is_leaf)(next)); \
|
||||
current = current->kind.node[current->num]; \
|
||||
next = next->kind.node[0]; \
|
||||
current->next = next; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, (o==root) ? n : root); \
|
||||
return n; \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _init_set)(tree_t b, const tree_t o) \
|
||||
{ \
|
||||
return n; \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _init_set)(tree_t b, const tree_t o) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, o); \
|
||||
assert (b != NULL); \
|
||||
assert (b != NULL); \
|
||||
/* Just copy recursively the root node */ \
|
||||
b->root = M_C(name, _copy_node)(o->root, o->root); \
|
||||
b->size = o->size; \
|
||||
b->size = o->size; \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _set)(tree_t b, const tree_t o) \
|
||||
{ \
|
||||
M_C(name, _clear)(b); \
|
||||
M_C(name, _init_set)(b, o); \
|
||||
} \
|
||||
\
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _set)(tree_t b, const tree_t o) \
|
||||
{ \
|
||||
/* NOTE: We could reuse the already allocated nodes of 'b'. \
|
||||
Not sure if it worth the effort */ \
|
||||
M_C(name, _clear)(b); \
|
||||
M_C(name, _init_set)(b, o); \
|
||||
} \
|
||||
\
|
||||
static inline bool M_C(name, _empty_p)(const tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
@@ -428,19 +493,22 @@
|
||||
node_t n = b->root; \
|
||||
int np = 0; \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
/* Go down the tree while searching for key */ \
|
||||
while (!M_C(name, _is_leaf)(n)) { \
|
||||
assert (np <= BPTREEI_MAX_STACK); \
|
||||
int i, hi = n->num; \
|
||||
assert (hi > 0); \
|
||||
/* Linear search is usually faster than binary search for \
|
||||
B+TREE (due to cache effect). If a binary tree is faster for \
|
||||
the choosen type and size , it simply means that the \
|
||||
size of B+TREE is too big (TBC) and shall be reduced. */ \
|
||||
the choosen type and size , it probably means that the \
|
||||
size of B+TREE is too big and should be reduced. */ \
|
||||
for(i = 0; i < hi; i++) { \
|
||||
if (M_CALL_CMP(key_oplist, key, n->key[i]) <= 0) \
|
||||
break; \
|
||||
} \
|
||||
/* Update the Parent iterator */ \
|
||||
pit->parent[np++] = n; \
|
||||
/* Select the new node to go down to */ \
|
||||
n = n->kind.node[i]; \
|
||||
assert (n != NULL); \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
@@ -453,20 +521,25 @@
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
pit_t pit; \
|
||||
/* Get the leaf node where the key can be */ \
|
||||
node_t n = M_C(name, _search_for_leaf)(pit, b, key); \
|
||||
int cmp = 0; \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
/* Search in the leaf for key */ \
|
||||
for(int i = 0; cmp >= 0 && i < -n->num; i++) { \
|
||||
cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \
|
||||
if (cmp == 0) \
|
||||
if (cmp == 0) { \
|
||||
/* Return the value if MAP mode or the key if SET mode */ \
|
||||
return M_IF(isMap)(&n->kind.value[i],&n->key[i]); \
|
||||
} \
|
||||
} \
|
||||
/* Key not found */ \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
static inline const value_t *M_C(name, _cget)(const tree_t b, key_t const key) \
|
||||
static inline value_t const *M_C(name, _cget)(const tree_t b, key_t const key) \
|
||||
{ \
|
||||
return M_CONST_CAST(value_t, M_C(name, _get)(b, key)); \
|
||||
return M_CONST_CAST(value_t, M_C(name, _get)(b, key)); \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
@@ -476,6 +549,7 @@
|
||||
assert (M_C(name, _is_leaf)(n)); \
|
||||
int i, num = M_C(name, _get_num)(n); \
|
||||
assert (num <= N); \
|
||||
/* Search for the key in the node n (a leaf) for insertion */ \
|
||||
for(i = 0; i < num; i++) { \
|
||||
int cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \
|
||||
if (cmp <= 0) { \
|
||||
@@ -492,8 +566,10 @@
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
/* Insert key & value if MAP mode */ \
|
||||
M_CALL_INIT_SET(key_oplist, n->key[i], key); \
|
||||
M_IF(isMap)(M_CALL_INIT_SET(value_oplist, n->kind.value[i], value);,) \
|
||||
/* Increase the number of key in the node */ \
|
||||
n->num += -1; /* Increase num as num<0 for leaf */ \
|
||||
return i; \
|
||||
} \
|
||||
@@ -504,6 +580,7 @@
|
||||
assert (!M_C(name, _is_leaf)(n)); \
|
||||
int i, num = M_C(name, _get_num)(n); \
|
||||
assert (num <= N); \
|
||||
/* Search for the key in the node n (not a leaf) for insertion */ \
|
||||
for(i = 0; i < num; i++) { \
|
||||
if (n->kind.node[i] == l) { \
|
||||
/* Move tables to make space for insertion */ \
|
||||
@@ -512,8 +589,10 @@
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
/* Insert key in node */ \
|
||||
/* TBC: DO_INIT_MOVE instead ? If key was in a node !*/ \
|
||||
M_CALL_INIT_SET(key_oplist, n->key[i], key); \
|
||||
/* Increase the number of key in the node */ \
|
||||
n->num += 1; \
|
||||
return i; \
|
||||
} \
|
||||
@@ -715,7 +794,7 @@
|
||||
M_IF(isMap)(memmove(&left->kind.value[num_left], &right->kind.value[0], sizeof(value_t)*num_right);,) \
|
||||
left->num = -num_left - num_right; \
|
||||
} else { \
|
||||
assert (num_left + num_right <= N -1); \
|
||||
assert (num_left + num_right <= N -1); \
|
||||
memmove(&left->key[num_left+1], &right->key[0], sizeof(key_t)*num_right); \
|
||||
memmove(&left->kind.node[num_left+1], &right->kind.node[0], sizeof(node_t)*(num_right+1)); \
|
||||
M_CALL_INIT_SET(key_oplist, left->key[num_left], parent->key[k]); \
|
||||
@@ -742,7 +821,7 @@
|
||||
return i; \
|
||||
} \
|
||||
assert(false); \
|
||||
return -1; /* unreachable */ \
|
||||
return -1; /* unreachable */ \
|
||||
} \
|
||||
\
|
||||
static inline bool M_C(name, _erase)(tree_t b, key_t const key) \
|
||||
@@ -888,31 +967,31 @@
|
||||
); \
|
||||
} \
|
||||
\
|
||||
static inline const M_C(name, _type_t) * \
|
||||
static inline M_C(name, _type_t) const * \
|
||||
M_C(name, _cref)(it_t it) \
|
||||
{ \
|
||||
return M_CONST_CAST(M_C(name, _type_t), M_C(name, _ref)(it)); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_from)(it_t it, const tree_t b, key_t const key) \
|
||||
M_C(name, _it_from)(it_t it, const tree_t b, key_t const key) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
assert (it != NULL); \
|
||||
pit_t pit; \
|
||||
pit_t pit; \
|
||||
node_t n = M_C(name, _search_for_leaf)(pit, b, key); \
|
||||
it->node = n; \
|
||||
int i; \
|
||||
int i; \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
for(i = 0; i < -n->num; i++) { \
|
||||
if (M_CALL_CMP(key_oplist, key, n->key[i]) <= 0) \
|
||||
break; \
|
||||
for(i = 0; i < -n->num; i++) { \
|
||||
if (M_CALL_CMP(key_oplist, key, n->key[i]) <= 0) \
|
||||
break; \
|
||||
} \
|
||||
if (i == -n->num && n->next != NULL) { \
|
||||
it->node = n->next; \
|
||||
i = 0; \
|
||||
} \
|
||||
if (i == -n->num && n->next != NULL) { \
|
||||
it->node = n->next; \
|
||||
i = 0; \
|
||||
} \
|
||||
it->idx = i; \
|
||||
} \
|
||||
\
|
||||
@@ -920,9 +999,9 @@
|
||||
M_C(name, _it_until_p)(it_t it, key_t const key) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
node_t n = it->node; \
|
||||
if (it->idx >= -n->num) return true; \
|
||||
int cmp = M_CALL_CMP(key_oplist, n->key[it->idx], key); \
|
||||
node_t n = it->node; \
|
||||
if (it->idx >= -n->num) return true; \
|
||||
int cmp = M_CALL_CMP(key_oplist, n->key[it->idx], key); \
|
||||
return (cmp >= 0); \
|
||||
} \
|
||||
\
|
||||
@@ -930,88 +1009,88 @@
|
||||
M_C(name, _it_while_p)(it_t it, key_t const key) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
node_t n = it->node; \
|
||||
if (it->idx >= -n->num) return false; \
|
||||
int cmp = M_CALL_CMP(key_oplist, n->key[it->idx], key); \
|
||||
node_t n = it->node; \
|
||||
if (it->idx >= -n->num) return false; \
|
||||
int cmp = M_CALL_CMP(key_oplist, n->key[it->idx], key); \
|
||||
return (cmp <= 0); \
|
||||
} \
|
||||
\
|
||||
static inline bool M_ATTR_DEPRECATED \
|
||||
M_C(name, _it_to_p)(it_t it, key_t const key) \
|
||||
M_C(name, _it_to_p)(it_t it, key_t const key) \
|
||||
{ \
|
||||
return M_C(name, _it_until_p)(it, key); \
|
||||
} \
|
||||
\
|
||||
static inline value_t * \
|
||||
M_C(name, _min)(const tree_t b) \
|
||||
static inline value_t * \
|
||||
M_C(name, _min)(const tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
assert (b->size > 0); \
|
||||
assert (b->size > 0); \
|
||||
node_t n = b->root; \
|
||||
/* Scan down the nodes */ \
|
||||
while (!M_C(name, _is_leaf)(n)) { \
|
||||
n = n->kind.node[0]; \
|
||||
} \
|
||||
return &n->M_IF(isMap)(kind.value, key)[0]; \
|
||||
return &n->M_IF(isMap)(kind.value, key)[0]; \
|
||||
} \
|
||||
\
|
||||
static inline value_t * \
|
||||
M_C(name, _max)(const tree_t b) \
|
||||
\
|
||||
static inline value_t * \
|
||||
M_C(name, _max)(const tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
node_t n = b->root; \
|
||||
/* Scan down the nodes */ \
|
||||
while (!M_C(name, _is_leaf)(n)) { \
|
||||
n = n->kind.node[n->num]; \
|
||||
n = n->kind.node[n->num]; \
|
||||
} \
|
||||
return &n->M_IF(isMap)(kind.value, key)[-n->num-1]; \
|
||||
return &n->M_IF(isMap)(kind.value, key)[-n->num-1]; \
|
||||
} \
|
||||
\
|
||||
static inline const value_t * \
|
||||
M_C(name, _cmin)(const tree_t tree) \
|
||||
\
|
||||
static inline value_t const * \
|
||||
M_C(name, _cmin)(const tree_t tree) \
|
||||
{ \
|
||||
return M_CONST_CAST(value_t, M_C(name, _min)(tree)); \
|
||||
return M_CONST_CAST(value_t, M_C(name, _min)(tree)); \
|
||||
} \
|
||||
\
|
||||
static inline const value_t * \
|
||||
M_C(name, _cmax)(const tree_t tree) \
|
||||
\
|
||||
static inline value_t const * \
|
||||
M_C(name, _cmax)(const tree_t tree) \
|
||||
{ \
|
||||
return M_CONST_CAST(value_t, M_C(name, _max)(tree)); \
|
||||
return M_CONST_CAST(value_t, M_C(name, _max)(tree)); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(tree_t b, tree_t ref) \
|
||||
M_C(name, _init_move)(tree_t b, tree_t ref) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, ref); \
|
||||
assert (b != NULL && b != ref); \
|
||||
b->size = ref->size; \
|
||||
b->root = ref->root; \
|
||||
assert (b != NULL && b != ref); \
|
||||
b->size = ref->size; \
|
||||
b->root = ref->root; \
|
||||
ref->root = NULL; \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(tree_t b, tree_t ref) \
|
||||
M_C(name, _move)(tree_t b, tree_t ref) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, ref); \
|
||||
assert (b != ref); \
|
||||
M_C(name,_clear)(b); \
|
||||
M_C(name,_init_move)(b, ref); \
|
||||
assert (b != ref); \
|
||||
M_C(name,_clear)(b); \
|
||||
M_C(name,_init_move)(b, ref); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(tree_t tree1, tree_t tree2) \
|
||||
M_C(name, _swap)(tree_t tree1, tree_t tree2) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, tree1); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, tree2); \
|
||||
M_SWAP(size_t, tree1->size, tree2->size); \
|
||||
M_SWAP(node_t, tree1->root, tree2->root); \
|
||||
M_SWAP(node_t, tree1->root, tree2->root); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, tree1); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, tree2); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
BPTREEI_FUNC_ADDITIONAL_DEF2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t)
|
||||
|
||||
|
||||
@@ -1139,7 +1218,7 @@
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
assert (str != NULL); \
|
||||
M_C(name,_clean)(t1); \
|
||||
M_C(name,_clean)(t1); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
@@ -1147,28 +1226,28 @@
|
||||
if (M_UNLIKELY (c == ']')) { success = true; goto exit;} \
|
||||
if (M_UNLIKELY (c == 0)) goto exit; \
|
||||
str--; \
|
||||
key_t key; \
|
||||
M_CALL_INIT(key_oplist, key); \
|
||||
M_IF(isMap)(value_t value; \
|
||||
M_CALL_INIT(value_oplist, value); \
|
||||
,) \
|
||||
key_t key; \
|
||||
M_CALL_INIT(key_oplist, key); \
|
||||
M_IF(isMap)(value_t value; \
|
||||
M_CALL_INIT(value_oplist, value); \
|
||||
, /* No isMap */) \
|
||||
do { \
|
||||
bool b = M_CALL_PARSE_STR(key_oplist, key, str, &str); \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
if (b == false) goto exit; \
|
||||
M_IF(isMap)(if (c != ':') goto exit; \
|
||||
if (b == false) goto exit_clear; \
|
||||
M_IF(isMap)(if (c != ':') goto exit_clear; \
|
||||
b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
if (b == false || c == 0) goto exit; \
|
||||
M_C(name, _set_at)(t1, key, value) \
|
||||
, \
|
||||
M_C(name, _push)(t1, key) \
|
||||
); \
|
||||
} while (c == M_GET_SEPARATOR key_oplist); \
|
||||
M_CALL_CLEAR(key_oplist, key); \
|
||||
M_IF(isMap)(M_CALL_CLEAR(value_oplist, value); \
|
||||
,) \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
if (b == false || c == 0) goto exit_clear; \
|
||||
M_C(name, _set_at)(t1, key, value); \
|
||||
, \
|
||||
M_C(name, _push)(t1, key); \
|
||||
) \
|
||||
} while (c == M_GET_SEPARATOR key_oplist); \
|
||||
success = (c == ']'); \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(key_oplist, key); \
|
||||
M_IF(isMap)(M_CALL_CLEAR(value_oplist, value); , /* No isMap */ ) \
|
||||
exit: \
|
||||
if (endp) *endp = str; \
|
||||
return success; \
|
||||
|
||||
+41
-7
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Fixed size (Bounded) QUEUE & STACK interface
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -31,9 +31,9 @@
|
||||
|
||||
/* Define the different kind of policy a lock-based buffer can have:
|
||||
* - the buffer can be either a queue (policy is FIFO) or a stack (policy is FILO),
|
||||
* - if the push method is by default blocking (waiting for the buffer to has some space) or not,
|
||||
* - if the pop method is by default blocking (waiting for the buffer to has some data) or not,
|
||||
* - if both methods are blocking,
|
||||
* - if the push method is by default blocking (waiting for the buffer to has some space) or not, *** deprecated ***
|
||||
* - if the pop method is by default blocking (waiting for the buffer to has some data) or not, *** deprecated ***
|
||||
* - if both methods are blocking, *** deprecated ***
|
||||
* - if it shall be thread safe or not (i.e. remove the mutex lock and atomic costs),
|
||||
* - if the buffer has to be init with empty elements, or if it shall init an element when it is pushed (and moved when popped),
|
||||
* - if the buffer has to overwrite the last element if the buffer is full,
|
||||
@@ -106,7 +106,15 @@ typedef enum {
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define BUFFERI_DEF_P1(arg) BUFFERI_DEF_P2 arg
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define BUFFERI_DEF_P2(name, type, m_size, policy, oplist, buffer_t) \
|
||||
M_IF_OPLIST(oplist)(BUFFERI_DEF_P3, BUFFERI_DEF_FAILURE)(name, type, m_size, policy, oplist, buffer_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define BUFFERI_DEF_FAILURE(name, type, m_size, policy, oplist, buffer_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(BUFFER_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
|
||||
|
||||
#define BUFFERI_DEF_P3(name, type, m_size, policy, oplist, buffer_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
m_mutex_t mutexPush; /* MUTEX used for pushing elements */ \
|
||||
@@ -129,6 +137,8 @@ typedef enum {
|
||||
typedef union { M_C(name, _srcptr) cptr; M_C(name, _ptr) ptr; } M_C(name, _uptr); \
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(buffer_t v, size_t size) \
|
||||
{ \
|
||||
@@ -584,6 +594,14 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define QUEUEI_MPMC_DEF_P1(arg) QUEUEI_MPMC_DEF_P2 arg
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define QUEUEI_MPMC_DEF_P2(name, type, policy, oplist, buffer_t) \
|
||||
M_IF_OPLIST(oplist)(QUEUEI_MPMC_DEF_P3, QUEUEI_MPMC_DEF_FAILURE)(name, type, policy, oplist, buffer_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define QUEUEI_MPMC_DEF_FAILURE(name, type, policy, oplist, buffer_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(QUEUE_MPMC_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define QUEUEI_MPMC_CONTRACT(v) /* nothing */
|
||||
#else
|
||||
@@ -598,7 +616,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define QUEUEI_MPMC_DEF_P2(name, type, policy, oplist, buffer_t) \
|
||||
#define QUEUEI_MPMC_DEF_P3(name, type, policy, oplist, buffer_t) \
|
||||
\
|
||||
/* The sequence number of an element will be equal to either \
|
||||
- 2* the index of the production which creates it, \
|
||||
@@ -784,6 +802,14 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define QUEUEI_SPSC_DEF_P1(arg) QUEUEI_SPSC_DEF_P2 arg
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define QUEUEI_SPSC_DEF_P2(name, type, policy, oplist, buffer_t) \
|
||||
M_IF_OPLIST(oplist)(QUEUEI_SPSC_DEF_P3, QUEUEI_SPSC_DEF_FAILURE)(name, type, policy, oplist, buffer_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define QUEUEI_SPSC_DEF_FAILURE(name, type, policy, oplist, buffer_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(QUEUE_SPSC_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define QUEUEI_SPSC_CONTRACT(table) do { } while (0)
|
||||
#else
|
||||
@@ -798,7 +824,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define QUEUEI_SPSC_DEF_P2(name, type, policy, oplist, buffer_t) \
|
||||
#define QUEUEI_SPSC_DEF_P3(name, type, policy, oplist, buffer_t) \
|
||||
\
|
||||
typedef struct M_C(name, _el_s) { \
|
||||
type x; \
|
||||
@@ -1042,8 +1068,16 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define BUFFERI_OPLIST_P1(arg) BUFFERI_OPLIST_P2 arg
|
||||
|
||||
/* OPLIST defininition of a buffer */
|
||||
/* Validation of the given oplist */
|
||||
#define BUFFERI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(BUFFERI_OPLIST_P3, BUFFERI_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define BUFFERI_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_BUFFER_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
|
||||
/* OPLIST defininition of a buffer */
|
||||
#define BUFFERI_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _int_init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,SET(M_C(name, _set)) \
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Concurrent memory pool allocator
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+30
-4
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Basic Protected Concurrent module over container.
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -62,12 +62,20 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define CONCURRENTI_OPLIST_P1(arg) CONCURRENTI_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define CONCURRENTI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(CONCURRENTI_OPLIST_P3, CONCURRENTI_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define CONCURRENTI_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_CONCURRENT_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
|
||||
/* OPLIST definition
|
||||
GET_KEY is not present as its interface is not compatible with a concurrent
|
||||
container (_get returns a pointer to an internal data, data that may be
|
||||
destroyed by another thread).
|
||||
*/
|
||||
#define CONCURRENTI_OPLIST_P2(name, oplist) \
|
||||
#define CONCURRENTI_OPLIST_P3(name, oplist) \
|
||||
(M_IF_METHOD(INIT, oplist)(INIT(M_C(name, _init)),) \
|
||||
,M_IF_METHOD(INIT_SET, oplist)(INIT_SET(M_C(name, _init_set)),) \
|
||||
,M_IF_METHOD(SET, oplist)(SET(M_C(name, _set)),) \
|
||||
@@ -115,13 +123,21 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define CONCURRENTI_DEF_P1(arg) CONCURRENTI_DEF_P2 arg
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define CONCURRENTI_DEF_P2(name, type, oplist, concurrent_t) \
|
||||
M_IF_OPLIST(oplist)(CONCURRENTI_DEF_P3, CONCURRENTI_DEF_FAILURE)(name, type, oplist, concurrent_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define CONCURRENTI_DEF_FAILURE(name, type, oplist, concurrent_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(CONCURRENT_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
|
||||
|
||||
/* Internal concurrent definition
|
||||
- name: prefix to be used
|
||||
- type: type of the sub container
|
||||
- oplist: oplist of the type of the sub container
|
||||
- concurrent_t: alias for M_C(name, _t) [ type of the container ]
|
||||
*/
|
||||
#define CONCURRENTI_DEF_P2(name, type, oplist, concurrent_t) \
|
||||
#define CONCURRENTI_DEF_P3(name, type, oplist, concurrent_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
struct M_C(name, _s) *self; \
|
||||
@@ -135,6 +151,8 @@
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
/* Define the lock strategy (global & shared lock) */ \
|
||||
static inline void \
|
||||
M_C(name, _internal_init)(concurrent_t out) \
|
||||
@@ -641,13 +659,21 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define CONCURRENTI_RP_DEF_P1(arg) CONCURRENTI_RP_DEF_P2 arg
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define CONCURRENTI_RP_DEF_P2(name, type, oplist, concurrent_t) \
|
||||
M_IF_OPLIST(oplist)(CONCURRENTI_RP_DEF_P3, CONCURRENTI_RP_DEF_FAILURE)(name, type, oplist, concurrent_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define CONCURRENTI_RP_DEF_FAILURE(name, type, oplist, concurrent_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(CONCURRENT_RP_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
|
||||
|
||||
/* Internal RP concurrent definition
|
||||
- name: prefix to be used
|
||||
- type: type of the sub container
|
||||
- oplist: oplist of the type of the sub container
|
||||
- concurrent_t: alias for M_C(name, _t) [ type of the container ]
|
||||
*/
|
||||
#define CONCURRENTI_RP_DEF_P2(name, type, oplist, concurrent_t) \
|
||||
#define CONCURRENTI_RP_DEF_P3(name, type, oplist, concurrent_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
struct M_C(name, _s) *self; \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Extended Pre-processing macros module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -52,7 +52,7 @@
|
||||
/* Define M*LIB version */
|
||||
#define M_CORE_VERSION_MAJOR 0
|
||||
#define M_CORE_VERSION_MINOR 3
|
||||
#define M_CORE_VERSION_PATCHLEVEL 0
|
||||
#define M_CORE_VERSION_PATCHLEVEL 1
|
||||
|
||||
/* M_ASSUME is equivalent to assert, but gives hints to compiler
|
||||
about how to optimize the code if NDEBUG is defined.
|
||||
@@ -103,12 +103,7 @@
|
||||
#define M_ATTR_EXTENSION
|
||||
#endif
|
||||
|
||||
/* Overwrite NO DEFAULT to give a proper error message */
|
||||
#if defined(__GNUC__) \
|
||||
&& (__GNUC__ * 100 + __GNUC_MINOR__) >= 403
|
||||
extern void m_no_default_function(void) __attribute__((error("The requested operator has no method registered in the given OPLIST. ")));
|
||||
#define M_NO_DEFAULT(...) m_no_default_function()
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/***************************************************************/
|
||||
@@ -369,238 +364,238 @@ extern void m_no_default_function(void) __attribute__((error("The requested op
|
||||
|
||||
/* Return the nth argument (either variable or static).
|
||||
Generated by:
|
||||
for i in $(seq 1 53 ) ; do printf "#define M_RETI_ARG%d(" $i; for j in $(seq 1 $i) ; do printf "_%d, " $j ; done ; printf "...) _%d\n#define M_RET_ARG%d(...) M_RETI_ARG%d(__VA_ARGS__)\n\n" $i $i $i ; done
|
||||
for i in $(seq 1 53 ) ; do printf "#define M_RETI_ARG%d(" $i; for j in $(seq 1 $i) ; do printf "_%d, " $j ; done ; printf "...) _%d\n#define M_RET_ARG%d(...) M_RETI_ARG%d(__VA_ARGS__,)\n\n" $i $i $i ; done
|
||||
*/
|
||||
#define M_RETI_ARG(f, ...) f(__VA_ARGS__)
|
||||
#define M_RET_ARG(n, ...) M_RETI_ARG(M_C(M_RET_ARG, n), __VA_ARGS__)
|
||||
|
||||
#define M_RETI_ARG1(_1, ...) _1
|
||||
#define M_RET_ARG1(...) M_RETI_ARG1(__VA_ARGS__)
|
||||
#define M_RET_ARG1(...) M_RETI_ARG1(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG2(_1, _2, ...) _2
|
||||
#define M_RET_ARG2(...) M_RETI_ARG2(__VA_ARGS__)
|
||||
#define M_RET_ARG2(...) M_RETI_ARG2(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG3(_1, _2, _3, ...) _3
|
||||
#define M_RET_ARG3(...) M_RETI_ARG3(__VA_ARGS__)
|
||||
#define M_RET_ARG3(...) M_RETI_ARG3(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG4(_1, _2, _3, _4, ...) _4
|
||||
#define M_RET_ARG4(...) M_RETI_ARG4(__VA_ARGS__)
|
||||
#define M_RET_ARG4(...) M_RETI_ARG4(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG5(_1, _2, _3, _4, _5, ...) _5
|
||||
#define M_RET_ARG5(...) M_RETI_ARG5(__VA_ARGS__)
|
||||
#define M_RET_ARG5(...) M_RETI_ARG5(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG6(_1, _2, _3, _4, _5, _6, ...) _6
|
||||
#define M_RET_ARG6(...) M_RETI_ARG6(__VA_ARGS__)
|
||||
#define M_RET_ARG6(...) M_RETI_ARG6(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG7(_1, _2, _3, _4, _5, _6, _7, ...) _7
|
||||
#define M_RET_ARG7(...) M_RETI_ARG7(__VA_ARGS__)
|
||||
#define M_RET_ARG7(...) M_RETI_ARG7(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG8(_1, _2, _3, _4, _5, _6, _7, _8, ...) _8
|
||||
#define M_RET_ARG8(...) M_RETI_ARG8(__VA_ARGS__)
|
||||
#define M_RET_ARG8(...) M_RETI_ARG8(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG9(_1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9
|
||||
#define M_RET_ARG9(...) M_RETI_ARG9(__VA_ARGS__)
|
||||
#define M_RET_ARG9(...) M_RETI_ARG9(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) _10
|
||||
#define M_RET_ARG10(...) M_RETI_ARG10(__VA_ARGS__)
|
||||
#define M_RET_ARG10(...) M_RETI_ARG10(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) _11
|
||||
#define M_RET_ARG11(...) M_RETI_ARG11(__VA_ARGS__)
|
||||
#define M_RET_ARG11(...) M_RETI_ARG11(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG12(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) _12
|
||||
#define M_RET_ARG12(...) M_RETI_ARG12(__VA_ARGS__)
|
||||
#define M_RET_ARG12(...) M_RETI_ARG12(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG13(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) _13
|
||||
#define M_RET_ARG13(...) M_RETI_ARG13(__VA_ARGS__)
|
||||
#define M_RET_ARG13(...) M_RETI_ARG13(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG14(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) _14
|
||||
#define M_RET_ARG14(...) M_RETI_ARG14(__VA_ARGS__)
|
||||
#define M_RET_ARG14(...) M_RETI_ARG14(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG15(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15
|
||||
#define M_RET_ARG15(...) M_RETI_ARG15(__VA_ARGS__)
|
||||
#define M_RET_ARG15(...) M_RETI_ARG15(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG16(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) _16
|
||||
#define M_RET_ARG16(...) M_RETI_ARG16(__VA_ARGS__)
|
||||
#define M_RET_ARG16(...) M_RETI_ARG16(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG17(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, ...) _17
|
||||
#define M_RET_ARG17(...) M_RETI_ARG17(__VA_ARGS__)
|
||||
#define M_RET_ARG17(...) M_RETI_ARG17(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG18(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, ...) _18
|
||||
#define M_RET_ARG18(...) M_RETI_ARG18(__VA_ARGS__)
|
||||
#define M_RET_ARG18(...) M_RETI_ARG18(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG19(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) _19
|
||||
#define M_RET_ARG19(...) M_RETI_ARG19(__VA_ARGS__)
|
||||
#define M_RET_ARG19(...) M_RETI_ARG19(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG20(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, ...) _20
|
||||
#define M_RET_ARG20(...) M_RETI_ARG20(__VA_ARGS__)
|
||||
#define M_RET_ARG20(...) M_RETI_ARG20(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG21(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, ...) _21
|
||||
#define M_RET_ARG21(...) M_RETI_ARG21(__VA_ARGS__)
|
||||
#define M_RET_ARG21(...) M_RETI_ARG21(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG22(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, ...) _22
|
||||
#define M_RET_ARG22(...) M_RETI_ARG22(__VA_ARGS__)
|
||||
#define M_RET_ARG22(...) M_RETI_ARG22(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG23(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, ...) _23
|
||||
#define M_RET_ARG23(...) M_RETI_ARG23(__VA_ARGS__)
|
||||
#define M_RET_ARG23(...) M_RETI_ARG23(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG24(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, ...) _24
|
||||
#define M_RET_ARG24(...) M_RETI_ARG24(__VA_ARGS__)
|
||||
#define M_RET_ARG24(...) M_RETI_ARG24(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG25(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, ...) _25
|
||||
#define M_RET_ARG25(...) M_RETI_ARG25(__VA_ARGS__)
|
||||
#define M_RET_ARG25(...) M_RETI_ARG25(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG26(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, ...) _26
|
||||
#define M_RET_ARG26(...) M_RETI_ARG26(__VA_ARGS__)
|
||||
#define M_RET_ARG26(...) M_RETI_ARG26(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG27(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, ...) _27
|
||||
#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__)
|
||||
#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG28(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, ...) _28
|
||||
#define M_RET_ARG28(...) M_RETI_ARG28(__VA_ARGS__)
|
||||
#define M_RET_ARG28(...) M_RETI_ARG28(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG29(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, ...) _29
|
||||
#define M_RET_ARG29(...) M_RETI_ARG29(__VA_ARGS__)
|
||||
#define M_RET_ARG29(...) M_RETI_ARG29(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG30(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, ...) _30
|
||||
#define M_RET_ARG30(...) M_RETI_ARG30(__VA_ARGS__)
|
||||
#define M_RET_ARG30(...) M_RETI_ARG30(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG31(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, ...) _31
|
||||
#define M_RET_ARG31(...) M_RETI_ARG31(__VA_ARGS__)
|
||||
#define M_RET_ARG31(...) M_RETI_ARG31(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG32(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, ...) _32
|
||||
#define M_RET_ARG32(...) M_RETI_ARG32(__VA_ARGS__)
|
||||
#define M_RET_ARG32(...) M_RETI_ARG32(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG33(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, ...) _33
|
||||
#define M_RET_ARG33(...) M_RETI_ARG33(__VA_ARGS__)
|
||||
#define M_RET_ARG33(...) M_RETI_ARG33(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG34(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, ...) _34
|
||||
#define M_RET_ARG34(...) M_RETI_ARG34(__VA_ARGS__)
|
||||
#define M_RET_ARG34(...) M_RETI_ARG34(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG35(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, ...) _35
|
||||
#define M_RET_ARG35(...) M_RETI_ARG35(__VA_ARGS__)
|
||||
#define M_RET_ARG35(...) M_RETI_ARG35(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG36(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, ...) _36
|
||||
#define M_RET_ARG36(...) M_RETI_ARG36(__VA_ARGS__)
|
||||
#define M_RET_ARG36(...) M_RETI_ARG36(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG37(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, ...) _37
|
||||
#define M_RET_ARG37(...) M_RETI_ARG37(__VA_ARGS__)
|
||||
#define M_RET_ARG37(...) M_RETI_ARG37(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG38(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, ...) _38
|
||||
#define M_RET_ARG38(...) M_RETI_ARG38(__VA_ARGS__)
|
||||
#define M_RET_ARG38(...) M_RETI_ARG38(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG39(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, ...) _39
|
||||
#define M_RET_ARG39(...) M_RETI_ARG39(__VA_ARGS__)
|
||||
#define M_RET_ARG39(...) M_RETI_ARG39(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG40(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, ...) _40
|
||||
#define M_RET_ARG40(...) M_RETI_ARG40(__VA_ARGS__)
|
||||
#define M_RET_ARG40(...) M_RETI_ARG40(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG41(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, ...) _41
|
||||
#define M_RET_ARG41(...) M_RETI_ARG41(__VA_ARGS__)
|
||||
#define M_RET_ARG41(...) M_RETI_ARG41(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG42(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, ...) _42
|
||||
#define M_RET_ARG42(...) M_RETI_ARG42(__VA_ARGS__)
|
||||
#define M_RET_ARG42(...) M_RETI_ARG42(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG43(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, ...) _43
|
||||
#define M_RET_ARG43(...) M_RETI_ARG43(__VA_ARGS__)
|
||||
#define M_RET_ARG43(...) M_RETI_ARG43(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG44(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, ...) _44
|
||||
#define M_RET_ARG44(...) M_RETI_ARG44(__VA_ARGS__)
|
||||
#define M_RET_ARG44(...) M_RETI_ARG44(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG45(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, ...) _45
|
||||
#define M_RET_ARG45(...) M_RETI_ARG45(__VA_ARGS__)
|
||||
#define M_RET_ARG45(...) M_RETI_ARG45(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG46(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, ...) _46
|
||||
#define M_RET_ARG46(...) M_RETI_ARG46(__VA_ARGS__)
|
||||
#define M_RET_ARG46(...) M_RETI_ARG46(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG47(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, ...) _47
|
||||
#define M_RET_ARG47(...) M_RETI_ARG47(__VA_ARGS__)
|
||||
#define M_RET_ARG47(...) M_RETI_ARG47(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG48(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, ...) _48
|
||||
#define M_RET_ARG48(...) M_RETI_ARG48(__VA_ARGS__)
|
||||
#define M_RET_ARG48(...) M_RETI_ARG48(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG49(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, ...) _49
|
||||
#define M_RET_ARG49(...) M_RETI_ARG49(__VA_ARGS__)
|
||||
#define M_RET_ARG49(...) M_RETI_ARG49(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG50(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, ...) _50
|
||||
#define M_RET_ARG50(...) M_RETI_ARG50(__VA_ARGS__)
|
||||
#define M_RET_ARG50(...) M_RETI_ARG50(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG51(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, ...) _51
|
||||
#define M_RET_ARG51(...) M_RETI_ARG51(__VA_ARGS__)
|
||||
#define M_RET_ARG51(...) M_RETI_ARG51(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG52(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, ...) _52
|
||||
#define M_RET_ARG52(...) M_RETI_ARG52(__VA_ARGS__)
|
||||
#define M_RET_ARG52(...) M_RETI_ARG52(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG53(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, ...) _53
|
||||
#define M_RET_ARG53(...) M_RETI_ARG53(__VA_ARGS__)
|
||||
#define M_RET_ARG53(...) M_RETI_ARG53(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG54(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, ...) _54
|
||||
#define M_RET_ARG54(...) M_RETI_ARG54(__VA_ARGS__)
|
||||
#define M_RET_ARG54(...) M_RETI_ARG54(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG55(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, ...) _55
|
||||
#define M_RET_ARG55(...) M_RETI_ARG55(__VA_ARGS__)
|
||||
#define M_RET_ARG55(...) M_RETI_ARG55(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG56(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, ...) _56
|
||||
#define M_RET_ARG56(...) M_RETI_ARG56(__VA_ARGS__)
|
||||
#define M_RET_ARG56(...) M_RETI_ARG56(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG57(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, ...) _57
|
||||
#define M_RET_ARG57(...) M_RETI_ARG57(__VA_ARGS__)
|
||||
#define M_RET_ARG57(...) M_RETI_ARG57(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG58(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, ...) _58
|
||||
#define M_RET_ARG58(...) M_RETI_ARG58(__VA_ARGS__)
|
||||
#define M_RET_ARG58(...) M_RETI_ARG58(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG59(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, ...) _59
|
||||
#define M_RET_ARG59(...) M_RETI_ARG59(__VA_ARGS__)
|
||||
#define M_RET_ARG59(...) M_RETI_ARG59(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG60(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, ...) _60
|
||||
#define M_RET_ARG60(...) M_RETI_ARG60(__VA_ARGS__)
|
||||
#define M_RET_ARG60(...) M_RETI_ARG60(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG61(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, ...) _61
|
||||
#define M_RET_ARG61(...) M_RETI_ARG61(__VA_ARGS__)
|
||||
#define M_RET_ARG61(...) M_RETI_ARG61(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG62(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, ...) _62
|
||||
#define M_RET_ARG62(...) M_RETI_ARG62(__VA_ARGS__)
|
||||
#define M_RET_ARG62(...) M_RETI_ARG62(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG63(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, ...) _63
|
||||
#define M_RET_ARG63(...) M_RETI_ARG63(__VA_ARGS__)
|
||||
#define M_RET_ARG63(...) M_RETI_ARG63(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG64(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, ...) _64
|
||||
#define M_RET_ARG64(...) M_RETI_ARG64(__VA_ARGS__)
|
||||
#define M_RET_ARG64(...) M_RETI_ARG64(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG65(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, ...) _65
|
||||
#define M_RET_ARG65(...) M_RETI_ARG65(__VA_ARGS__)
|
||||
#define M_RET_ARG65(...) M_RETI_ARG65(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG66(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, ...) _66
|
||||
#define M_RET_ARG66(...) M_RETI_ARG66(__VA_ARGS__)
|
||||
#define M_RET_ARG66(...) M_RETI_ARG66(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG67(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, ...) _67
|
||||
#define M_RET_ARG67(...) M_RETI_ARG67(__VA_ARGS__)
|
||||
#define M_RET_ARG67(...) M_RETI_ARG67(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG68(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, ...) _68
|
||||
#define M_RET_ARG68(...) M_RETI_ARG68(__VA_ARGS__)
|
||||
#define M_RET_ARG68(...) M_RETI_ARG68(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG69(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, ...) _69
|
||||
#define M_RET_ARG69(...) M_RETI_ARG69(__VA_ARGS__)
|
||||
#define M_RET_ARG69(...) M_RETI_ARG69(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG70(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, ...) _70
|
||||
#define M_RET_ARG70(...) M_RETI_ARG70(__VA_ARGS__)
|
||||
#define M_RET_ARG70(...) M_RETI_ARG70(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG71(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, ...) _71
|
||||
#define M_RET_ARG71(...) M_RETI_ARG71(__VA_ARGS__)
|
||||
#define M_RET_ARG71(...) M_RETI_ARG71(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG72(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, ...) _72
|
||||
#define M_RET_ARG72(...) M_RETI_ARG72(__VA_ARGS__)
|
||||
#define M_RET_ARG72(...) M_RETI_ARG72(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG73(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, ...) _73
|
||||
#define M_RET_ARG73(...) M_RETI_ARG73(__VA_ARGS__)
|
||||
#define M_RET_ARG73(...) M_RETI_ARG73(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG74(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, ...) _74
|
||||
#define M_RET_ARG74(...) M_RETI_ARG74(__VA_ARGS__)
|
||||
#define M_RET_ARG74(...) M_RETI_ARG74(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG75(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, ...) _75
|
||||
#define M_RET_ARG75(...) M_RETI_ARG75(__VA_ARGS__)
|
||||
#define M_RET_ARG75(...) M_RETI_ARG75(__VA_ARGS__,)
|
||||
|
||||
#define M_RETI_ARG76(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, ...) _76
|
||||
#define M_RET_ARG76(...) M_RETI_ARG76(__VA_ARGS__)
|
||||
#define M_RET_ARG76(...) M_RETI_ARG76(__VA_ARGS__,)
|
||||
|
||||
/* For a pair of argument (arg0, arg1), return either the first or the second.
|
||||
Needed in case where M_RET_ARGn cannot be used */
|
||||
@@ -798,9 +793,43 @@ extern void m_no_default_function(void) __attribute__((error("The requested op
|
||||
M_IF_EMPTY(arguments)(action if empty, action if not empty) */
|
||||
#define M_IF_EMPTY(...) M_IF(M_EMPTY_P(__VA_ARGS__))
|
||||
|
||||
/* Return 1 if argument is "()" or "(x)" */
|
||||
#define M_PARENTHESISI_DETECT(...) 0, 1,
|
||||
#define M_PARENTHESIS_P(...) M_AND(M_COMMA_P(M_PARENTHESISI_DETECT __VA_ARGS__), M_INV(M_COMMA_P(__VA_ARGS__)))
|
||||
/* Return 1 if argument is "()" or "(x)"
|
||||
* Test if () or (x) can be transformed into a comma,
|
||||
* and that there is no (toplevel) comma
|
||||
* and that there is nothing beyond the parenthesis.
|
||||
*/
|
||||
#define M_PARENTHESISI_DETECT1(...) ,
|
||||
#define M_PARENTHESISI_DETECT2(...)
|
||||
#define M_PARENTHESIS_P(...) \
|
||||
M_AND(M_AND(M_COMMA_P(M_PARENTHESISI_DETECT1 __VA_ARGS__), M_INV(M_COMMA_P(__VA_ARGS__))), \
|
||||
M_EMPTY_P(M_PARENTHESISI_DETECT2 __VA_ARGS__))
|
||||
|
||||
|
||||
/* Return 1 if argument type or variable or function is the keyword.
|
||||
- refFunc is the reference keyword.
|
||||
It shall be either 'and', 'or', 'sum' (equivalent to 'add'), 'bool'
|
||||
- testedFunc is the tested keyword.
|
||||
It cannot start with a special character */
|
||||
#define M_KEYWORD_P(refFunc, testedFunc) \
|
||||
M_COMMA_P(M_C4(M_PATTERN_, refFunc, _, testedFunc))
|
||||
/* The different special recognized patterns: */
|
||||
#define M_PATTERN_and_and ,
|
||||
#define M_PATTERN_or_or ,
|
||||
#define M_PATTERN_sum_sum ,
|
||||
#define M_PATTERN_sum_add ,
|
||||
#define M_PATTERN_add_add ,
|
||||
#define M_PATTERN_add_sum ,
|
||||
#define M_PATTERN_product_product ,
|
||||
#define M_PATTERN_product_mul ,
|
||||
#define M_PATTERN_bool_bool ,
|
||||
#define M_PATTERN_char_char ,
|
||||
#define M_PATTERN_short_short ,
|
||||
#define M_PATTERN_int_int ,
|
||||
#define M_PATTERN_long_long ,
|
||||
#define M_PATTERN_float_float ,
|
||||
#define M_PATTERN_double_double ,
|
||||
#define M_PATTERN_void_void ,
|
||||
|
||||
|
||||
/* Necessary macros to handle recursivity,
|
||||
delaying the evaluation by one (or more) level of macro expansion.
|
||||
@@ -1229,6 +1258,15 @@ extern void m_no_default_function(void) __attribute__((error("The requested op
|
||||
#define M_NDEBUG_TEST 0
|
||||
#define M_IF_DEBUG(a) M_IF(M_TEST_NDEBUG_P())(,a)
|
||||
|
||||
|
||||
/* If the Function Object is included, expands the code,
|
||||
otherwise do nothing.
|
||||
M_FUNCOBJ_IS_NOT_DEFINED is defined to 0.
|
||||
NOTE: M_IF is the variable is not defined assummes yes.
|
||||
*/
|
||||
#define M_IF_FUNCOBJ(a) M_IF(M_FUNCOBJ_IS_NOT_DEFINED)( ,a)
|
||||
|
||||
|
||||
/* Helper macro to redefine a function with a default value :
|
||||
If there is only one variable as the __VA_ARGS__, print
|
||||
__VA_ARGS__ then ', value', instead only __VA_ARGS__.
|
||||
@@ -1597,8 +1635,10 @@ M_PARSE_DEFAULT_TYPE_DEF(m_core_parse_ldouble, long double, strtold, )
|
||||
NOTE: C definition is safer than the C++ one.
|
||||
*/
|
||||
#ifndef __cplusplus
|
||||
/* Cast the object n into type only if it is C assignable */
|
||||
# define M_ASSIGN_CAST(type, n) ((type) { 0 } = (n))
|
||||
#else
|
||||
/* Cast the object n into type using a static_cast */
|
||||
# define M_ASSIGN_CAST(type, n) static_cast<type>(n)
|
||||
#endif
|
||||
|
||||
@@ -1887,6 +1927,7 @@ m_core_hash (const void *str, size_t length)
|
||||
/******************** METHODS handling **********************/
|
||||
/************************************************************/
|
||||
|
||||
|
||||
/* Helper macros to make M_GET_METHOD works.
|
||||
List of supported methods for an oplist */
|
||||
#define M_INIT_INIT(a) ,a,
|
||||
@@ -1908,6 +1949,7 @@ m_core_hash (const void *str, size_t length)
|
||||
#define M_CMP_CMP(a) ,a,
|
||||
#define M_TYPE_TYPE(a) ,a,
|
||||
#define M_SUBTYPE_SUBTYPE(a) ,a,
|
||||
#define M_NAME_NAME(a) ,a,
|
||||
#define M_OPLIST_OPLIST(a) ,a,
|
||||
#define M_SORT_SORT(a) ,a,
|
||||
#define M_UPDATE_UPDATE(a) ,a,
|
||||
@@ -1988,13 +2030,14 @@ m_core_hash (const void *str, size_t length)
|
||||
#define M_GET_CMP(...) M_GET_METHOD(CMP, M_CMP_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_UPDATE(...) M_GET_METHOD(UPDATE, M_SET_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_UPDATE_TYPE(...) M_GET_METHOD(UPDATE_TYPE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_TYPE(...) M_GET_METHOD(TYPE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SUBTYPE(...) M_GET_METHOD(SUBTYPE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_TYPE(...) M_GET_METHOD(TYPE, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_SUBTYPE(...) M_GET_METHOD(SUBTYPE, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_NAME(...) M_GET_METHOD(NAME, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_OPLIST(...) M_GET_METHOD(OPLIST, (), __VA_ARGS__)
|
||||
#define M_GET_SORT(...) M_GET_METHOD(SORT, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SPLICE_BACK(...) M_GET_METHOD(SPLICE_BACK, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SPLICE_AT(...) M_GET_METHOD(SPLICE_AT, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_TYPE(...) M_GET_METHOD(IT_TYPE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_TYPE(...) M_GET_METHOD(IT_TYPE, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_IT_FIRST(...) M_GET_METHOD(IT_FIRST, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_LAST(...) M_GET_METHOD(IT_LAST, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_END(...) M_GET_METHOD(IT_END, M_NO_DEFAULT, __VA_ARGS__)
|
||||
@@ -2014,10 +2057,10 @@ m_core_hash (const void *str, size_t length)
|
||||
#define M_GET_MUL(...) M_GET_METHOD(MUL, M_MUL_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_DIV(...) M_GET_METHOD(DIV, M_DIV_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_CLEAN(...) M_GET_METHOD(CLEAN, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_KEY_TYPE(...) M_GET_METHOD(KEY_TYPE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_VALUE_TYPE(...) M_GET_METHOD(VALUE_TYPE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_KEY_OPLIST(...) M_GET_METHOD(KEY_OPLIST, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_VALUE_OPLIST(...) M_GET_METHOD(VALUE_OPLIST, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_KEY_TYPE(...) M_GET_METHOD(KEY_TYPE, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_VALUE_TYPE(...) M_GET_METHOD(VALUE_TYPE, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_KEY_OPLIST(...) M_GET_METHOD(KEY_OPLIST, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_VALUE_OPLIST(...) M_GET_METHOD(VALUE_OPLIST, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_GET_KEY(...) M_GET_METHOD(GET_KEY, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SET_KEY(...) M_GET_METHOD(SET_KEY, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_GET_SET_KEY(...) M_GET_METHOD(GET_SET_KEY, M_NO_DEFAULT, __VA_ARGS__)
|
||||
@@ -2027,7 +2070,6 @@ m_core_hash (const void *str, size_t length)
|
||||
#define M_GET_POP(...) M_GET_METHOD(POP, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_PUSH_MOVE(...) M_GET_METHOD(PUSH_MOVE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_POP_MOVE(...) M_GET_METHOD(POP_MOVE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
// TODO: PUSH_NEW?
|
||||
#define M_GET_REVERSE(...) M_GET_METHOD(REVERSE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_GET_STR(...) M_GET_METHOD(GET_STR, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_PARSE_STR(...) M_GET_METHOD(PARSE_STR, M_NO_DEFAULT, __VA_ARGS__)
|
||||
@@ -2042,6 +2084,7 @@ m_core_hash (const void *str, size_t length)
|
||||
#define M_GET_OOR_EQUAL(...) M_GET_METHOD(OOR_EQUAL, M_NO_DEFAULT, __VA_ARGS__)
|
||||
|
||||
// Calling method with support of defined transformation API
|
||||
// operators that are not methods are commented
|
||||
#define M_CALL_INIT(oplist, ...) M_APPLY_API(M_GET_INIT oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_INIT_SET(oplist, ...) M_APPLY_API(M_GET_INIT_SET oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_INIT_MOVE(oplist, ...) M_APPLY_API(M_GET_INIT_MOVE oplist, oplist, __VA_ARGS__)
|
||||
@@ -2060,13 +2103,14 @@ m_core_hash (const void *str, size_t length)
|
||||
#define M_CALL_EQUAL(oplist, ...) M_APPLY_API(M_GET_EQUAL oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_CMP(oplist, ...) M_APPLY_API(M_GET_CMP oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_UPDATE(oplist, ...) M_APPLY_API(M_GET_UPDATE oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_TYPE(oplist, ...) M_APPLY_API(M_GET_TYPE oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_SUBTYPE(oplist, ...) M_APPLY_API(M_GET_SUBTYPE oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_OPLIST(oplist, ...) M_APPLY_API(M_GET_OPLIST oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_TYPE(oplist, ...) M_APPLY_API(M_GET_TYPE oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_SUBTYPE(oplist, ...) M_APPLY_API(M_GET_SUBTYPE oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_NAME(oplist, ...) M_APPLY_API(M_GET_NAME oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_OPLIST(oplist, ...) M_APPLY_API(M_GET_OPLIST oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_SORT(oplist, ...) M_APPLY_API(M_GET_SORT oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_SPLICE_BACK(oplist, ...) M_APPLY_API(M_GET_SPLICE_BACK oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_SPLICE_AT(oplist, ...) M_APPLY_API(M_GET_SPLICE_AT oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_IT_TYPE(oplist, ...) M_APPLY_API(M_GET_IT_TYPE oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_IT_TYPE(oplist, ...) M_APPLY_API(M_GET_IT_TYPE oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_IT_FIRST(oplist, ...) M_APPLY_API(M_GET_IT_FIRST oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_IT_LAST(oplist, ...) M_APPLY_API(M_GET_IT_LAST oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_IT_END(oplist, ...) M_APPLY_API(M_GET_IT_END oplist, oplist, __VA_ARGS__)
|
||||
@@ -2102,8 +2146,8 @@ m_core_hash (const void *str, size_t length)
|
||||
#define M_CALL_IN_STR(oplist, ...) M_APPLY_API(M_GET_IN_STR oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_OUT_SERIAL(oplist, ...) M_APPLY_API(M_GET_OUT_SERIAL oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_IN_SERIAL(oplist, ...) M_APPLY_API(M_GET_IN_SERIAL oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_SEPARATOR(oplist, ...) M_APPLY_API(M_GET_SEPARATOR oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_EXT_ALGO(oplist, ...) M_APPLY_API(M_GET_EXT_ALGO oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_SEPARATOR(oplist, ...) M_APPLY_API(M_GET_SEPARATOR oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_EXT_ALGO(oplist, ...) M_APPLY_API(M_GET_EXT_ALGO oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_INC_ALLOC(oplist, ...) M_APPLY_API(M_GET_INC_ALLOC oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_OOR_SET(oplist, ...) M_APPLY_API(M_GET_OOR_SET oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_OOR_EQUAL(oplist, ...) M_APPLY_API(M_GET_OOR_EQUAL oplist, oplist, __VA_ARGS__)
|
||||
@@ -2146,17 +2190,79 @@ m_core_hash (const void *str, size_t length)
|
||||
#define M_OPLAPI_INDIRECT_API_7(...) M_OPLAPI_7
|
||||
#define M_OPLAPI_EXTRACT_API_7(...) __VA_ARGS__
|
||||
|
||||
|
||||
/* Define the no default function that generates a compiler error
|
||||
if the method is expanded. Compiler extensions may have already defined
|
||||
it to provide a better error message
|
||||
if the method is expanded.
|
||||
*/
|
||||
#ifndef M_NO_DEFAULT
|
||||
#define M_NO_DEFAULT(...) m_no_default_function
|
||||
#define M_NO_DEFAULT(...) \
|
||||
M_STATIC_FAILURE(M_LIB_MISSING_METHOD, "The requested operator has no method registered in the given OPLIST. ")
|
||||
|
||||
#define M_NO_DEF_TYPE \
|
||||
M_STATIC_FAILURE(M_LIB_MISSING_METHOD, "The requested operator has no type/subtype/suboplist registered in the given OPLIST. ")
|
||||
|
||||
/* Test if the given variable is a basic C variable:
|
||||
int, float, enum, bool or compatible.
|
||||
NOTE: Not perfect, but catch some errors */
|
||||
#define M_CHECK_DEFAULT_TYPE(a) \
|
||||
M_STATIC_ASSERT(sizeof (a) <= M_MAX(sizeof(long long), \
|
||||
M_MAX(sizeof (long double), \
|
||||
sizeof (uintmax_t))), \
|
||||
M_LIB_NOT_A_DEFAULT_TYPE, \
|
||||
"The given variable is too big to be a default type," \
|
||||
"but the used macro can only be used with such one." \
|
||||
"It is likely the given oplist is not right.")
|
||||
|
||||
/* Check if both variables are of the same type.
|
||||
The test compare their size.
|
||||
NOTE: Not perfect but catch some errors */
|
||||
#define M_CHECK_SAME(a, b) \
|
||||
M_STATIC_ASSERT(sizeof(a) == sizeof(b), \
|
||||
M_LIB_NOT_SAME_TYPE, \
|
||||
"The variable " M_AS_STR(a) " and " M_AS_STR(b) \
|
||||
" are not of same type.")
|
||||
|
||||
/* Check if the oplist is compatible with the type.
|
||||
The oplist should define a TYPE method, in which case it is tested.
|
||||
If it is not exported, do nothing.
|
||||
Compare the type in C11, the size in C99 or C++ */
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
#define M_CHECK_COMPATIBLE_OPLIST(name, inst, type, oplist) \
|
||||
M_IF_METHOD(TYPE, oplist) \
|
||||
( \
|
||||
static inline void M_C3(name, _int_control_type, inst)(void) \
|
||||
{ \
|
||||
type x; \
|
||||
M_STATIC_ASSERT(_Generic(&x, \
|
||||
M_GET_TYPE oplist *: 1 /* Ok, type matches */, \
|
||||
default: 0 /* NOK, type doesn't match */ ), \
|
||||
M_LIB_TYPE_MISTMACH, \
|
||||
"The given type " M_AS_STR(type) \
|
||||
" and the type of the oplist does not match: " \
|
||||
M_AS_STR(oplist) ); \
|
||||
} \
|
||||
, /* End of TYPE */)
|
||||
#else
|
||||
#define M_CHECK_COMPATIBLE_OPLIST(name, inst, type, oplist) \
|
||||
M_IF_METHOD(TYPE, oplist) \
|
||||
( \
|
||||
static inline void M_C3(name, _int_control_type, inst)(void) \
|
||||
{ \
|
||||
M_STATIC_ASSERT(sizeof (type) == sizeof (M_GET_TYPE oplist), \
|
||||
M_LIB_TYPE_MISTMACH, \
|
||||
"The given type " M_AS_STR(type) \
|
||||
" and the type of the oplist does not match: " \
|
||||
M_AS_STR(oplist) ); \
|
||||
} \
|
||||
, /* End of TYPE */)
|
||||
#endif
|
||||
|
||||
/* Define the default method. */
|
||||
|
||||
/* Define the default method.
|
||||
NOTE: M_SET_DEFAULT may be called in conditions where a and b
|
||||
are different but compatible type.
|
||||
*/
|
||||
#define M_INIT_DEFAULT(a) ((a) = 0)
|
||||
#define M_SET_DEFAULT(a,b) ((a) = (b))
|
||||
#define M_SET_DEFAULT(a,b) (M_CHECK_DEFAULT_TYPE(a), (a) = (b))
|
||||
#define M_NOTHING_DEFAULT(...) ((void)(__VA_ARGS__))
|
||||
#define M_EMPTY_DEFAULT(...) ((void)1)
|
||||
#define M_TRUE_DEFAULT(...) true
|
||||
@@ -2176,13 +2282,14 @@ m_core_hash (const void *str, size_t length)
|
||||
/* NOTE: Theses operators are NOT compatible with the '[1]' tricks
|
||||
if the variable is defined as a parameter of a function
|
||||
(sizeof (a) is not portable). */
|
||||
#define M_MOVE_DEFAULT(a,b) (M_STATIC_ASSERT(sizeof(a)==sizeof(b)), M_MEMCPY_DEFAULT(a, b), memset(&(b), 0, sizeof (a)))
|
||||
#define M_MEMCPY_DEFAULT(a,b) (M_STATIC_ASSERT(sizeof(a)==sizeof(b)), memcpy(&(a), &(b), sizeof (a)))
|
||||
#define M_MOVE_DEFAULT(a,b) (M_CHECK_SAME(a, b), M_MEMCPY_DEFAULT(a, b), memset(&(b), 0, sizeof (a)))
|
||||
#define M_MEMCPY_DEFAULT(a,b) (M_CHECK_SAME(a, b), memcpy(&(a), &(b), sizeof (a)))
|
||||
#define M_MEMSET_DEFAULT(a) (memset(&(a), 0, sizeof (a)))
|
||||
#define M_MEMCMP1_DEFAULT(a,b) (M_STATIC_ASSERT(sizeof(a)==sizeof(b)), memcmp(&(a), &(b), sizeof (a)) == 0)
|
||||
#define M_MEMCMP2_DEFAULT(a,b) (M_STATIC_ASSERT(sizeof(a)==sizeof(b)), memcmp(&(a), &(b), sizeof (a)))
|
||||
#define M_MEMCMP1_DEFAULT(a,b) (M_CHECK_SAME(a, b), memcmp(&(a), &(b), sizeof (a)) == 0)
|
||||
#define M_MEMCMP2_DEFAULT(a,b) (M_CHECK_SAME(a, b), memcmp(&(a), &(b), sizeof (a)))
|
||||
#define M_SWAP_DEFAULT(el1, el2) do { \
|
||||
char _tmp[sizeof (el1)]; \
|
||||
M_CHECK_SAME(el1, el2); \
|
||||
memcpy(&_tmp, &(el1), sizeof (el1)); \
|
||||
memcpy(&(el1), &(el2), sizeof (el1)); \
|
||||
memcpy(&(el2), &_tmp, sizeof (el1)); \
|
||||
@@ -2191,11 +2298,11 @@ m_core_hash (const void *str, size_t length)
|
||||
/* NOTE: Theses operators are to be used with the '[1]' tricks
|
||||
if the variable is defined as a parameter of a function
|
||||
(sizeof (a) is not portable). */
|
||||
#define M_MOVE_A1_DEFAULT(a,b) (M_STATIC_ASSERT(sizeof(a[0])==sizeof(b[0])), M_MEMCPY_A1_DEFAULT(a, b), M_MEMSET_A1_DEFAULT(b))
|
||||
#define M_MEMCPY_A1_DEFAULT(a,b) (M_STATIC_ASSERT(sizeof(a[0])==sizeof(b[0])), memcpy(&(a[0]), &(b[0]), sizeof (a[0])))
|
||||
#define M_MOVE_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0], b[0]), M_MEMCPY_A1_DEFAULT(a, b), M_MEMSET_A1_DEFAULT(b))
|
||||
#define M_MEMCPY_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0], b[0]), memcpy(&(a[0]), &(b[0]), sizeof (a[0])))
|
||||
#define M_MEMSET_A1_DEFAULT(a) (memset(&(a[0]), 0, sizeof (a[0])))
|
||||
#define M_MEMCMP1_A1_DEFAULT(a,b) (M_STATIC_ASSERT(sizeof(a[0])==sizeof(b[0])), memcmp(&(a[0]), &(b[0]), sizeof (a[0])) == 0)
|
||||
#define M_MEMCMP2_A1_DEFAULT(a,b) (M_STATIC_ASSERT(sizeof(a[0])==sizeof(b[0])), memcmp(&(a[0]), &(b[0]), sizeof (a[0])))
|
||||
#define M_MEMCMP1_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0],b[0]), memcmp(&(a[0]), &(b[0]), sizeof (a[0])) == 0)
|
||||
#define M_MEMCMP2_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0], b[0]), memcmp(&(a[0]), &(b[0]), sizeof (a[0])))
|
||||
#define M_HASH_A1_DEFAULT(a) (m_core_hash((const void*) &(a[0]), sizeof (a[0])) )
|
||||
|
||||
/* Default oplist for plain structure */
|
||||
@@ -2232,6 +2339,8 @@ m_core_hash (const void *str, size_t length)
|
||||
(INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \
|
||||
CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \
|
||||
INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \
|
||||
ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \
|
||||
MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \
|
||||
HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT) , \
|
||||
IN_STR(M_FSCAN_ARG M_IPTR), OUT_STR(M_FPRINT_ARG), \
|
||||
IN_SERIAL(M_IN_SERIAL_DEFAULT_ARG M_IPTR), OUT_SERIAL(M_OUT_SERIAL_DEFAULT_ARG), \
|
||||
@@ -2242,6 +2351,8 @@ m_core_hash (const void *str, size_t length)
|
||||
(INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \
|
||||
CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \
|
||||
INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \
|
||||
ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \
|
||||
MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \
|
||||
HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT) , \
|
||||
IN_SERIAL(M_IN_SERIAL_DEFAULT_ARG M_IPTR), OUT_SERIAL(M_OUT_SERIAL_DEFAULT_ARG), \
|
||||
PARSE_STR(M_PARSE_DEFAULT_TYPE M_IPTR), M_GET_STR_METHOD_FOR_DEFAULT_TYPE)
|
||||
@@ -2251,6 +2362,8 @@ m_core_hash (const void *str, size_t length)
|
||||
(INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \
|
||||
CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \
|
||||
INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \
|
||||
ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \
|
||||
MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \
|
||||
HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT) )
|
||||
#endif
|
||||
|
||||
@@ -2373,9 +2486,13 @@ m_core_hash (const void *str, size_t length)
|
||||
NOTE: Incomplete test.
|
||||
*/
|
||||
#define M_OPLIST_P(a) \
|
||||
M_AND(M_AND(M_PARENTHESIS_P(a), M_INV(M_PARENTHESIS_P (M_OPFLAT a))), \
|
||||
M_EMPTY_P(M_EAT a))
|
||||
M_AND(M_PARENTHESIS_P(a), M_INV(M_PARENTHESIS_P (M_OPFLAT a)))
|
||||
|
||||
/* Valid if the argument is a valid oplist, or raise a failure otherwise */
|
||||
#define M_VALID_OPLIST(oplist) \
|
||||
M_IF(M_OPLIST_P(oplist))(oplist, M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "The given oplist is invalid: " #oplist))
|
||||
|
||||
#define M_IF_OPLIST(a) M_IF(M_OPLIST_P(a))
|
||||
|
||||
/* If 'a' seems to be an oplist, it returns a,
|
||||
else if a symbol composed of M_OPL_##a() exists and is defined as an oplist, it returns it
|
||||
@@ -2390,6 +2507,9 @@ m_core_hash (const void *str, size_t length)
|
||||
#define M_GLOBALI_OPLIST_ELSE(a) M_GLOBALI_OPLIST_ELSE2(a, M_C(M_OPL_, a)())
|
||||
#define M_GLOBALI_OPLIST_ELSE2(a, op) M_IF( M_OPLIST_P (op))(op, a)
|
||||
|
||||
#define M_GLOBAL_TYPE(a) \
|
||||
M_IF( M_OPLIST_P(a))(M_GLOBALI_TYPE_GET, M_GLOBALI_ID)(a)
|
||||
#define M_GLOBALI_TYPE_GET(a) M_GET_TYPE a
|
||||
|
||||
/* If a symbol composed of M_OPL_##a() exists and is defined as an oplist,
|
||||
it returns it otherwise it returns M_DEFAULT_OPLIST.
|
||||
@@ -2403,15 +2523,38 @@ m_core_hash (const void *str, size_t length)
|
||||
#define M_GLOBALI_OPLIST_OR_DEF_ELSE2(a, op) M_IF( M_OPLIST_P(op))(M_C(M_OPL_, a), M_GLOBALI_OPLIST_DEFAULT2)
|
||||
|
||||
|
||||
/* Register simple classic C types (no qualifier) */
|
||||
#define M_OPL_char() M_DEFAULT_OPLIST
|
||||
#define M_OPL_short() M_DEFAULT_OPLIST
|
||||
#define M_OPL_int() M_DEFAULT_OPLIST
|
||||
#define M_OPL_long() M_DEFAULT_OPLIST
|
||||
#define M_OPL_float() M_DEFAULT_OPLIST
|
||||
#define M_OPL_double() M_DEFAULT_OPLIST
|
||||
|
||||
/* Add as suffix for the given function the number of arguments of the calls.
|
||||
Can be used to call different function in function of the number of arguments. */
|
||||
#define M_SUFFIX_FUNCTION_BY_NARGS(function, ...) M_C3(function, _, M_NARGS(__VA_ARGS__))
|
||||
|
||||
/* Call different INIT_WITH method in function of the number of arguments of the call,
|
||||
* to be used in an OPLIST.
|
||||
* Shall be used with API_1 call (example INIT_WITH(API_1(M_INIT_WITH_NVAR)) )
|
||||
* Shall define a NAME base method
|
||||
* All INIT_WITH methods shall be named as name ## _init_with_ ## NARGS
|
||||
*/
|
||||
#define M_INIT_WITH_NVAR(oplist, ...) \
|
||||
M_SUFFIX_FUNCTION_BY_NARGS(M_C(M_GET_NAME oplist, _init_with), __VA_ARGS__)(__VA_ARGS__)
|
||||
|
||||
|
||||
/************************************************************/
|
||||
/******************** Syntax Enhancing **********************/
|
||||
/************************************************************/
|
||||
|
||||
/* Define M_EACH macro allowing to iterate over a container
|
||||
First argument will be a created pointer to the underlying type.
|
||||
/* M_EACH enables iterating over a container using a for loop.
|
||||
First argument will be a created pointer var to the underlying type.
|
||||
Second argument is the container to iterate.
|
||||
Third argument can be the oplist of the list or the type of the list if a global
|
||||
oplist has been recorded.
|
||||
Example: for M_EACH(item, list, LIST_OPLIST) { action; }
|
||||
USAGE: for M_EACH(item, list, LIST_OPLIST) { M_LETaction; }
|
||||
*/
|
||||
#define M_EACH(item, container, oplist) \
|
||||
M_EACHI_OPLIST(item, container, M_GLOBAL_OPLIST(oplist))
|
||||
@@ -2443,14 +2586,15 @@ m_core_hash (const void *str, size_t length)
|
||||
M_GET_IT_NEXT oplist (iterator))
|
||||
|
||||
|
||||
/* Define M_LET macro allowing to define, auto init & auto clear an object
|
||||
within the next bracket.
|
||||
Example:
|
||||
M_LET(a, STRING_OPLIST) { do something with a } or
|
||||
M_LET(a, b, c, STRING_OPLIST) { do something with a, b & c }
|
||||
M_LET((a, b), c, STRING_OPLIST) { do something with a(init with b) & c }
|
||||
NOTE: The user code can not perform a return or a goto within the {}
|
||||
other wise the clear code of the object won't be called .
|
||||
/* M_LET defines, initializes & clears an object available within the next bracket.
|
||||
USAGE:
|
||||
M_LET(variable_list, variable_oplist|variable_type) { code }
|
||||
* variable_list can be a comma separated list of variable.
|
||||
* A variable alone is initialized to its default value.
|
||||
* A variable with initializer (like '(var, init value...)'
|
||||
is initialized with this init values.
|
||||
NOTE: The code within {} can not perform return or goto command.
|
||||
break is supported and will exit the braket (calling the clear method)
|
||||
Last argument can be the oplist or the type itself if a global
|
||||
oplist has been recorded for this type.
|
||||
*/
|
||||
@@ -2462,25 +2606,31 @@ m_core_hash (const void *str, size_t length)
|
||||
// 1b. Generate a unique name based on the first variable and the line number
|
||||
#define M_LETI_VAR_NAME_A(var) M_C3(_local_cont_, M_RET_ARG1 var, __LINE__)
|
||||
#define M_LETI_VAR_NAME_B(var) M_C3(_local_cont_, var, __LINE__)
|
||||
// 2. Evaluate with or without
|
||||
// 2. Evaluate with or without and inject oplist
|
||||
#define M_LETI1(cont, oplist, ...) \
|
||||
M_LETI2(cont, M_GLOBAL_OPLIST(oplist), __VA_ARGS__)
|
||||
// 3. Map all variables to their own LET
|
||||
// 3. Validate oplist before going any further
|
||||
#define M_LETI2(cont, oplist, ...) \
|
||||
M_IF_OPLIST(oplist)(M_LETI3, M_LETI2_FAILURE)(cont, oplist, __VA_ARGS__)
|
||||
// Stop with a failure (invalid oplist)
|
||||
#define M_LETI2_FAILURE(cont, oplist, ...) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(M_LET): the given argument is not a valid oplist: " M_AS_STR(oplist))
|
||||
// 4. Map all variables to their own LET
|
||||
#define M_LETI3(cont, oplist, ...) \
|
||||
for(bool cont = true; cont ; /* unused */) \
|
||||
M_MAP2(M_LETI_SINGLE, (cont, oplist), __VA_ARGS__)
|
||||
// 4. Dispatch the right LET in function of having or not arguments
|
||||
// 5. Dispatch the right LET in function of having or not arguments
|
||||
#define M_LETI_SINGLE(data, name) \
|
||||
M_IF(M_PARENTHESIS_P(name))( \
|
||||
M_LETI_SINGLE2_SET(M_PAIR_1 data, M_PAIR_2 data, M_RET_ARG1 name, M_SKIPI_1 name), \
|
||||
M_LETI_SINGLE2(M_PAIR_1 data, M_PAIR_2 data, name))
|
||||
// 5a. Define without argument ==> use INIT
|
||||
// 6a. Define without argument ==> use INIT
|
||||
#define M_LETI_SINGLE2(cont, oplist, name) \
|
||||
for(M_GET_TYPE oplist name; \
|
||||
cont && (M_GET_INIT oplist (name), true); \
|
||||
(M_GET_CLEAR oplist (name), cont = false)) \
|
||||
for(;cont;cont = false)
|
||||
// 5b. Define with arguments ==> use INIT_SET (INIT_WITH support pending)
|
||||
// 6b. Define with arguments ==> use INIT_SET (or INIT_WITH support pending)
|
||||
#define M_LETI_SINGLE2_SET(cont, oplist, name, ...) \
|
||||
for(M_GET_TYPE oplist name; \
|
||||
cont && (M_LETI_SINGLE2_INIT(oplist, name, __VA_ARGS__), true); \
|
||||
@@ -2504,6 +2654,14 @@ m_core_hash (const void *str, size_t length)
|
||||
#define M_INIT_VAI_FUNC(d, a) \
|
||||
M_PAIR_2 d (M_PAIR_1 d, a)
|
||||
|
||||
/* Initialize the container 'dest' as per 'oplist'
|
||||
and fill it with the given VA arguments which are pair of (key,value) */
|
||||
#define M_INIT_KEY_VAI(oplist, dest, ...) \
|
||||
(void)(M_GET_INIT oplist (dest) , \
|
||||
M_MAP2_C(M_INIT_KEY_VAI_FUNC, (dest, M_GET_SET_KEY oplist) , __VA_ARGS__))
|
||||
#define M_INIT_KEY_VAI_FUNC(d, a) \
|
||||
M_PAIR_2 d (M_PAIR_1 d, M_PAIR_1 a, M_PAIR_2 a)
|
||||
|
||||
|
||||
/************************************************************/
|
||||
/********************* MEMORY handling **********************/
|
||||
@@ -2555,7 +2713,12 @@ m_core_hash (const void *str, size_t length)
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* Always perform a runtime check of the condition */
|
||||
|
||||
/************************************************************/
|
||||
/********************* ERROR handling **********************/
|
||||
/************************************************************/
|
||||
|
||||
/* Always perform a runtime check of the given condition */
|
||||
#ifndef M_ASSERT_INIT
|
||||
#define M_ASSERT_INIT(expr, object) { \
|
||||
if (!(expr)) { \
|
||||
@@ -2565,12 +2728,41 @@ m_core_hash (const void *str, size_t length)
|
||||
} } while (0)
|
||||
#endif
|
||||
|
||||
/* Force a compilation error if condition is false
|
||||
In this case, it raises "error: negative width in bit-field <anonymous>" */
|
||||
#if defined(__cplusplus)
|
||||
#define M_STATIC_ASSERT(_e) (assert(_e))
|
||||
|
||||
/* Terminate the compilation of the current unit with an error message.
|
||||
The error is classidied as error
|
||||
with an optional message detailling the error.
|
||||
Either use C11 to get a proper message, or at least a good hint in C99
|
||||
error shall be a C name, msg a string.
|
||||
Quite usefull to terminate with a proper error message rather than
|
||||
a garbage of error due to incorrect code generation in the methods
|
||||
expansion.
|
||||
*/
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
# define M_STATIC_FAILURE(error, msg) static_assert(false, #error ": " msg);
|
||||
#else
|
||||
#define M_STATIC_ASSERT(_e) ((void) sizeof(struct { int a:1; int :-!(_e); }))
|
||||
# define M_STATIC_FAILURE(error, msg) struct error { int error : 0;};
|
||||
#endif
|
||||
|
||||
|
||||
/* Test at compile time if the given condition is true.
|
||||
The error is classidied as error
|
||||
with an optional message detailling the error.
|
||||
NOTE: Use bitfield to be compatible with most compilers
|
||||
(so that it properly displays 'error' on the command line
|
||||
NOTE: Cannot use C11 Static Assert as is not usable in expression.
|
||||
NOTE: In C++, use of lambda to encapsulate static_assert in
|
||||
an expression.
|
||||
*/
|
||||
#if defined(__cplusplus)
|
||||
# define M_STATIC_ASSERT(cond, error, msg) \
|
||||
([] { static_assert(cond, #error ": " msg); } ())
|
||||
#elif defined(__GNUC__) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
# define M_STATIC_ASSERT(cond, error, msg) \
|
||||
M_ATTR_EXTENSION ({ static_assert(cond, #error ": " msg); })
|
||||
#else
|
||||
# define M_STATIC_ASSERT(cond, error, msg) \
|
||||
((void) sizeof(struct { int error : !!(cond);}))
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - DEQUE module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -67,15 +67,23 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define DEQUEI_DEF_P1(arg) DEQUEI_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define DEQUEI_DEF_P2(name, type, oplist, deque_t, it_t, node_t) \
|
||||
M_IF_OPLIST(oplist)(DEQUEI_DEF_P3, DEQUEI_DEF_FAILURE)(name, type, oplist, deque_t, it_t, node_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define DEQUEI_DEF_FAILURE(name, type, oplist, deque_t, it_t, node_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DEQUE_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Internal deque definition
|
||||
- name: prefix to be used
|
||||
- type: type of the elements of the array
|
||||
- type: type of the elements of the deque
|
||||
- oplist: oplist of the type of the elements of the container
|
||||
- deque_t: alias for M_C(name, _t) [ type of the container ]
|
||||
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
|
||||
- node_t: alias for M_C(name, _node_t) [ node ]
|
||||
*/
|
||||
#define DEQUEI_DEF_P2(name, type, oplist, deque_t, it_t, node_t) \
|
||||
#define DEQUEI_DEF_P3(name, type, oplist, deque_t, it_t, node_t) \
|
||||
\
|
||||
/* It is a linked list of buckets of the types, \
|
||||
each new created bucket size grows compared to the previous one \
|
||||
@@ -131,6 +139,8 @@
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline M_C(name, _node_t)* \
|
||||
M_C(name, _int_new_node)(deque_t d) \
|
||||
{ \
|
||||
@@ -837,7 +847,7 @@
|
||||
{ \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
assert (str != NULL); \
|
||||
M_C(name,_clean)(deque); \
|
||||
M_C(name,_clean)(deque); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
@@ -850,12 +860,13 @@
|
||||
do { \
|
||||
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
if (b == false || c == 0) { goto exit; } \
|
||||
M_C(name, _push_back)(deque, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
if (b == false || c == 0) { goto exit_clear; } \
|
||||
M_C(name, _push_back)(deque, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
success = (c == ']'); \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
exit: \
|
||||
if (endp) *endp = str; \
|
||||
return success; \
|
||||
@@ -943,8 +954,16 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define DEQUEI_OPLIST_P1(arg) DEQUEI_OPLIST_P2 arg
|
||||
|
||||
/* OPLIST definition of a deque */
|
||||
/* Validation of the given oplist */
|
||||
#define DEQUEI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(DEQUEI_OPLIST_P3, DEQUEI_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define DEQUEI_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_DEQUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
|
||||
/* OPLIST definition of a deque */
|
||||
#define DEQUEI_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - DICTIONARY Module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -121,7 +121,23 @@
|
||||
*/
|
||||
/* Deferred evaluation for arg */
|
||||
#define DICTI_DEF2_P1(arg) DICTI_DEF2_P2 arg
|
||||
|
||||
/* Validate the key oplist before going further */
|
||||
#define DICTI_DEF2_P2(name, key_type, key_oplist, value_type, value_oplist) \
|
||||
M_IF_OPLIST(key_oplist)(DICTI_DEF2_P3, DICTI_DEF2_FAILURE)(name, key_type, key_oplist, value_type, value_oplist)
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define DICTI_DEF2_P3(name, key_type, key_oplist, value_type, value_oplist) \
|
||||
M_IF_OPLIST(value_oplist)(DICTI_DEF2_P4, DICTI_DEF2_FAILURE)(name, key_type, key_oplist, value_type, value_oplist)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define DICTI_DEF2_FAILURE(name, key_type, key_oplist, value_type, value_oplist) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_DEF2): at least one of the given argument is not a valid oplist: " M_AS_STR(key_oplist) " / " M_AS_STR(value_oplist) )
|
||||
|
||||
#define DICTI_DEF2_P4(name, key_type, key_oplist, value_type, value_oplist) \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 2, value_type, value_oplist) \
|
||||
\
|
||||
TUPLE_DEF2(M_C(name, _pair), (key, key_type, key_oplist), (value, value_type, value_oplist)) \
|
||||
\
|
||||
@@ -138,7 +154,7 @@
|
||||
ARRAY_DEF(M_C(name, _array_list_pair), M_C(name, _list_pair_t), \
|
||||
LIST_OPLIST(M_C(name, _list_pair), TUPLE_OPLIST(M_C(name, _pair), key_oplist, value_oplist))) \
|
||||
\
|
||||
DICTI_FUNC_DEF2(name, key_type, key_oplist, value_type, value_oplist, 0, 0, M_C(name, _t), M_C(name, _it_t))
|
||||
DICTI_FUNC_DEF2_P5(name, key_type, key_oplist, value_type, value_oplist, 0, 0, M_C(name, _t), M_C(name, _it_t))
|
||||
|
||||
|
||||
/* Define a dictionary with the key key_type to the value value_type.
|
||||
@@ -148,8 +164,24 @@
|
||||
*/
|
||||
/* Defered evaluation for arg */
|
||||
#define DICTI_SHASH_DEF2_P1(arg) DICTI_SHASH_DEF2_P2 arg
|
||||
|
||||
/* Validate the key oplist before going further */
|
||||
#define DICTI_SHASH_DEF2_P2(name, key_type, key_oplist, value_type, value_oplist) \
|
||||
M_IF_OPLIST(key_oplist)(DICTI_SHASH_DEF2_P3, DICTI_SHASH_DEF2_FAILURE)(name, key_type, key_oplist, value_type, value_oplist)
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define DICTI_SHASH_DEF2_P3(name, key_type, key_oplist, value_type, value_oplist) \
|
||||
M_IF_OPLIST(value_oplist)(DICTI_SHASH_DEF2_P4, DICTI_SHASH_DEF2_FAILURE)(name, key_type, key_oplist, value_type, value_oplist)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define DICTI_SHASH_DEF2_FAILURE(name, key_type, key_oplist, value_type, value_oplist) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_STOREHASH_DEF2): at least one of the given argument is not a valid oplist: " M_AS_STR(key_oplist) " / " M_AS_STR(value_oplist) )
|
||||
|
||||
#define DICTI_SHASH_DEF2_P4(name, key_type, key_oplist, value_type, value_oplist) \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 2, value_type, value_oplist) \
|
||||
\
|
||||
TUPLE_DEF2(M_C(name, _pair), (hash, size_t, M_DEFAULT_OPLIST), (key, key_type, key_oplist), (value, value_type, value_oplist)) \
|
||||
\
|
||||
M_IF_METHOD(MEMPOOL, key_oplist) \
|
||||
@@ -165,7 +197,7 @@
|
||||
ARRAY_DEF(M_C(name, _array_list_pair), M_C(name, _list_pair_t), \
|
||||
LIST_OPLIST(M_C(name, _list_pair), TUPLE_OPLIST(M_C(name, _pair), M_DEFAULT_OPLIST, key_oplist, value_oplist))) \
|
||||
\
|
||||
DICTI_FUNC_DEF2(name, key_type, key_oplist, value_type, value_oplist, 0, 1, M_C(name, _t), M_C(name, _it_t))
|
||||
DICTI_FUNC_DEF2_P5(name, key_type, key_oplist, value_type, value_oplist, 0, 1, M_C(name, _t), M_C(name, _it_t))
|
||||
|
||||
|
||||
/* Define a set with the key key_type
|
||||
@@ -173,8 +205,19 @@
|
||||
representing a bucket).
|
||||
*/
|
||||
#define DICTI_SET_DEF_P1(arg) DICTI_SET_DEF_P2 arg
|
||||
|
||||
/* Validate the key oplist before going further */
|
||||
#define DICTI_SET_DEF_P2(name, key_type, key_oplist) \
|
||||
M_IF_OPLIST(key_oplist)(DICTI_SET_DEF_P4, DICTI_SET_DEF_FAILURE)(name, key_type, key_oplist)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define DICTI_SET_DEF_FAILURE(name, key_type, key_oplist)\
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_SET_DEF): the given argument is not a valid oplist: " M_AS_STR(key_oplist) )
|
||||
|
||||
#define DICTI_SET_DEF_P4(name, key_type, key_oplist) \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \
|
||||
\
|
||||
TUPLE_DEF2(M_C(name, _pair), (key, key_type, key_oplist)) \
|
||||
\
|
||||
M_IF_METHOD(MEMPOOL, key_oplist) \
|
||||
@@ -189,12 +232,12 @@
|
||||
ARRAY_DEF(M_C(name, _array_list_pair), M_C(name, _list_pair_t), \
|
||||
LIST_OPLIST(M_C(name, _list_pair), TUPLE_OPLIST(M_C(name, _pair), key_oplist))) \
|
||||
\
|
||||
DICTI_FUNC_DEF2(name, key_type, key_oplist, key_type, \
|
||||
DICTI_FUNC_DEF2_P5(name, key_type, key_oplist, key_type, \
|
||||
M_EMPTY_OPLIST, 1, 0, M_C(name, _t), M_C(name, _it_t))
|
||||
|
||||
|
||||
/* Define the structure of a chained dictionnary */
|
||||
#define DICTI_FUNC_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, isStoreHash, dict_t, dict_it_t) \
|
||||
#define DICTI_FUNC_DEF2_P5(name, key_type, key_oplist, value_type, value_oplist, isSet, isStoreHash, dict_t, dict_it_t) \
|
||||
\
|
||||
/* NOTE: \
|
||||
if isSet is true, all methods of value_oplist are NOP methods */ \
|
||||
@@ -700,7 +743,7 @@
|
||||
M_C(name, _parse_str)(dict_t dict, const char str[], const char **endp) \
|
||||
{ \
|
||||
assert (str != NULL); \
|
||||
M_C(name, _clean)(dict); \
|
||||
M_C(name, _clean)(dict); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '{')) goto exit; \
|
||||
@@ -716,20 +759,21 @@
|
||||
while (isspace((int) *str)) str++; \
|
||||
bool b = M_CALL_PARSE_STR(key_oplist, key, str, &str); \
|
||||
M_IF(isSet)( \
|
||||
if (b == false) { break; } \
|
||||
if (b == false) { goto exit_clear; } \
|
||||
M_C(name, _push)(dict, key); \
|
||||
, \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
if (b == false || c != ':') { goto exit; } \
|
||||
if (b == false || c != ':') { goto exit_clear; } \
|
||||
b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \
|
||||
if (b == false) { goto exit; } \
|
||||
if (b == false) { goto exit_clear; } \
|
||||
M_C(name, _set_at)(dict, key, value); \
|
||||
) \
|
||||
) \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
} while (c == ','); \
|
||||
} while (c == ','); \
|
||||
success = (c == '}'); \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(key_oplist, key); \
|
||||
M_CALL_CLEAR(value_oplist, value); \
|
||||
success = (c == '}'); \
|
||||
exit: \
|
||||
if (endp) *endp = str; \
|
||||
return success; \
|
||||
@@ -917,10 +961,23 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define DICTI_OPLIST_P1(arg) DICTI_OPLIST_P2 arg
|
||||
|
||||
/* Define the oplist of a dictionnary */
|
||||
#define DICTI_OPLIST_P2(name, key_oplist, value_oplist) \
|
||||
/* Validation of the given oplists */
|
||||
#define DICTI_OPLIST_P2(name, key_oplist, value_oplist) \
|
||||
M_IF_OPLIST(key_oplist)(DICTI_OPLIST_P3, DICTI_OPLIST_FAILURE)(name, key_oplist, value_oplist)
|
||||
#define DICTI_OPLIST_P3(name, key_oplist, value_oplist) \
|
||||
M_IF_OPLIST(value_oplist)(DICTI_OPLIST_P4, DICTI_OPLIST_FAILURE)(name, key_oplist, value_oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define DICTI_OPLIST_FAILURE(name, key_oplist, value_oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_DICT_OPLIST_IS_NOT_AN_OPLIST, name, key_oplist, value_oplist)
|
||||
|
||||
/* Define the oplist of a dictionnary
|
||||
NOTE: IT_REF is not exported so that the contained appears as not modifiable
|
||||
by algorithm.*/
|
||||
#define DICTI_OPLIST_P4(name, key_oplist, value_oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
INIT_WITH(API_1(M_INIT_KEY_VAI)), \
|
||||
SET(M_C(name, _set)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
@@ -937,7 +994,6 @@
|
||||
IT_END_P(M_C(name,_end_p)), \
|
||||
IT_LAST_P(M_C(name,_last_p)), \
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_REF(M_C(name,_ref)), \
|
||||
IT_CREF(M_C(name,_cref)) \
|
||||
,KEY_TYPE(M_C(name, _key_type_t)) \
|
||||
,VALUE_TYPE(M_C(name, _value_type_t)) \
|
||||
@@ -964,8 +1020,16 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define DICTI_SET_OPLIST_P1(arg) DICTI_SET_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define DICTI_SET_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(DICTI_SET_OPLIST_P3, DICTI_SET_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define DICTI_SET_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_DICT_SET_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
|
||||
/* Define the oplist of a set */
|
||||
#define DICTI_SET_OPLIST_P2(name, oplist) \
|
||||
#define DICTI_SET_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
INIT_WITH(API_1(M_INIT_VAI)), \
|
||||
@@ -1066,16 +1130,38 @@ typedef enum {
|
||||
} while (0)
|
||||
|
||||
#define DICTI_OA_DEF_P1(args) DICTI_OA_DEF_P2 args
|
||||
|
||||
/* Validate the key oplist before going further */
|
||||
#define DICTI_OA_DEF_P2(name, key_type, key_oplist, value_type, value_oplist) \
|
||||
DICTI_OA_DEF_P3(name, key_type, key_oplist, value_type, value_oplist, 0, \
|
||||
M_IF_OPLIST(key_oplist)(DICTI_OA_DEF_P3, DICTI_OA_DEF_FAILURE)(name, key_type, key_oplist, value_type, value_oplist)
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define DICTI_OA_DEF_P3(name, key_type, key_oplist, value_type, value_oplist) \
|
||||
M_IF_OPLIST(value_oplist)(DICTI_OA_DEF_P4, DICTI_OA_DEF_FAILURE)(name, key_type, key_oplist, value_type, value_oplist)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define DICTI_OA_DEF_FAILURE(name, key_type, key_oplist, value_type, value_oplist) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_OA_DEF2): at least one of the given argument is not a valid oplist: " M_AS_STR(key_oplist) " / " M_AS_STR(value_oplist) )
|
||||
|
||||
#define DICTI_OA_DEF_P4(name, key_type, key_oplist, value_type, value_oplist) \
|
||||
DICTI_OA_DEF_P5(name, key_type, key_oplist, value_type, value_oplist, 0, \
|
||||
DICTI_OA_LOWER_BOUND, DICTI_OA_UPPER_BOUND, M_C(name,_t), M_C(name, _it_t) )
|
||||
|
||||
#define DICTI_OASET_DEF_P1(args) DICTI_OASET_DEF_P2 args
|
||||
#define DICTI_OASET_DEF_P2(name, key_type, key_oplist) \
|
||||
DICTI_OA_DEF_P3(name, key_type, key_oplist, key_type, M_EMPTY_OPLIST, 1, \
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define DICTI_OASET_DEF_P2(name, key_type, key_oplist) \
|
||||
M_IF_OPLIST(key_oplist)(DICTI_OASET_DEF_P4, DICTI_OASET_DEF_FAILURE)(name, key_type, key_oplist)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define DICTI_OASET_DEF_FAILURE(name, key_type, key_oplist) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_OASET_DEF): the given argument is not a valid oplist: " M_AS_STR(key_oplist) )
|
||||
|
||||
#define DICTI_OASET_DEF_P4(name, key_type, key_oplist) \
|
||||
DICTI_OA_DEF_P5(name, key_type, key_oplist, key_type, M_EMPTY_OPLIST, 1, \
|
||||
DICTI_OA_LOWER_BOUND, DICTI_OA_UPPER_BOUND, M_C(name,_t), M_C(name, _it_t) )
|
||||
|
||||
#define DICTI_OA_DEF_P3(name, key_type, key_oplist, value_type, value_oplist, isSet, coeff_down, coeff_up, dict_t, dict_it_t) \
|
||||
#define DICTI_OA_DEF_P5(name, key_type, key_oplist, value_type, value_oplist, isSet, coeff_down, coeff_up, dict_t, dict_it_t) \
|
||||
\
|
||||
/* NOTE: \
|
||||
if isSet is true, all methods of value_oplist are NOP methods */ \
|
||||
@@ -1092,6 +1178,9 @@ typedef enum {
|
||||
typedef key_type M_C(name, _key_type_t); \
|
||||
typedef value_type M_C(name, _value_type_t); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 2, value_type, value_oplist) \
|
||||
\
|
||||
/* NOTE: We don't want a real oplist for this sub type */ \
|
||||
ARRAY_DEF(M_C(name, _array_pair), M_C(name, _pair_t), \
|
||||
(INIT(M_NOTHING_DEFAULT), SET(M_MEMCPY_DEFAULT), \
|
||||
|
||||
+345
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* M*LIB - Function Object module
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef MSTARLIB_FUNCOBJ_H
|
||||
#define MSTARLIB_FUNCOBJ_H
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define a function object interface of name 'name'
|
||||
* with a function like retcode, type of param1, type of param 2, ...
|
||||
* USAGE:
|
||||
* FUNC_OBJ_ITF_DEF(name, retcode type, type of param1, type of param 2, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_ITF_DEF(name, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_ITF_NO_PARAM_DEF, FUNCOBJI_ITF_PARAM_DEF)(name, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a function object instance of name 'name' based on the interface 'base_name'
|
||||
* The function is defined as per :
|
||||
* - the prototype of the inherited interface
|
||||
* - the parameters of the function are named as per the list param_list
|
||||
* - the core of the function shall be defined in callback_core
|
||||
* - optionals member attributes of the function object can be defined after the core
|
||||
* (just like for tuple & variant: (name, type [, oplist])
|
||||
*
|
||||
* In the core of the function, parameters are accessible just like a normal like
|
||||
* and a special variable 'self' which refers to the function object itself
|
||||
* can be used to access member attributes.
|
||||
*
|
||||
* There shall be **exactly** the same number of parameters in 'param_list' than
|
||||
* the number of parameters of the interface 'base_name'
|
||||
*
|
||||
* USAGE/EXAMPLE:
|
||||
* FUNC_OBJ_INS_DEF(name, base_name, (param1, ...), { return param1 * self->member1 }, (member1, int), ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_DEF(name, base_name, param_list, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_DEF, FUNCOBJI_INS_ATTR_DEF)(name, base_name, param_list, __VA_ARGS__)
|
||||
|
||||
|
||||
/* OPLIST of the instanced function object
|
||||
* USAGE:
|
||||
* FUNC_OBJ_INS_OPLIST(name, oplist of the attr1, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_OPLIST, FUNCOBJI_INS_ATTR_OPLIST_P1)( __VA_ARGS__)
|
||||
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************** INTERNAL ************************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/* To be used by M_IF_FUNCOBJ macro.
|
||||
NOTE: It is reversed (0 instead of 1) so that it can be used in M_IF reliabely.
|
||||
*/
|
||||
#define M_FUNCOBJ_IS_NOT_DEFINED 0
|
||||
|
||||
/* Design Constraints:
|
||||
* callback SHALL be the first member of the structures in all the definitions.
|
||||
*
|
||||
* Structure definitions are specialized in function of the presence or not
|
||||
* of parameters and/or attributes
|
||||
* FIXME: How to factorize reasonnably well between the definitions?
|
||||
*/
|
||||
|
||||
/* Specialization of the OPLIST in function if there is at least one member or not */
|
||||
#define FUNCOBJI_INS_NO_ATTR_OPLIST(name) \
|
||||
(NAME(name), TYPE(M_C(name, _t)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT(M_C(name,_init)) \
|
||||
)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_P1(name, ...) \
|
||||
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(FUNCOBJI_INS_ATTR_OPLIST_P3, FUNCOBJI_INS_ATTR_OPLIST_FAILURE)(name, __VA_ARGS__)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_FAILURE(name, ...) \
|
||||
M_LIB_ERROR(ONE_ARGUMENT_OF_FUNC_OBJ_INS_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)
|
||||
|
||||
/* Define at least the oplist */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_P3(name, ...) \
|
||||
(NAME(name), TYPE(M_C(name, _t)), \
|
||||
INIT_WITH(M_C(name, _init_with)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
|
||||
)
|
||||
|
||||
|
||||
/* Specialization of the definition a function object interface of name 'name'
|
||||
* with a function like retcode () that doesn't have any input parameters.
|
||||
*/
|
||||
#define FUNCOBJI_ITF_NO_PARAM_DEF(name, retcode) \
|
||||
typedef retcode M_C(name, _retcode_t); \
|
||||
\
|
||||
struct M_C(name, _s); \
|
||||
\
|
||||
/* No parameters to the callback */ \
|
||||
typedef retcode(*M_C(name, _callback_t))(struct M_C(name, _s) *); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _callback_t) callback; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
static inline retcode \
|
||||
M_C(name, _call)(M_C(name, _t) funcobj) \
|
||||
{ \
|
||||
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
|
||||
funcobj->callback(funcobj); \
|
||||
}
|
||||
|
||||
|
||||
/* Specialization of the definition a function object interface of name 'name'
|
||||
* with a function like retcode, type of param1, type of param 2, ...
|
||||
* with mandatory input parameters.
|
||||
*/
|
||||
#define FUNCOBJI_ITF_PARAM_DEF(name, retcode, ...) \
|
||||
typedef retcode M_C(name, _retcode_t); \
|
||||
\
|
||||
/* Define types for all paremeters */ \
|
||||
M_MAP3(FUNCOBJI_BASE_TYPE, name, __VA_ARGS__) \
|
||||
\
|
||||
struct M_C(name, _s); \
|
||||
\
|
||||
typedef retcode(*M_C(name, _callback_t))(struct M_C(name, _s) *, __VA_ARGS__); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _callback_t) callback; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
static inline retcode \
|
||||
M_C(name, _call)(M_C(name, _t) funcobj \
|
||||
M_MAP3(FUNCOBJI_BASE_ARGLIST, name, __VA_ARGS__) ) \
|
||||
{ \
|
||||
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
|
||||
funcobj->callback(funcobj M_MAP3(FUNCOBJI_BASE_ARGCALL, name, __VA_ARGS__) ); \
|
||||
}
|
||||
|
||||
|
||||
/* Specialization of the definition a function object instance of name 'name'
|
||||
* with no member attribute.
|
||||
*/
|
||||
#define FUNCOBJI_INS_NO_ATTR_DEF(name, base_name, param_list, callback_core) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(base_name, _callback_t) callback; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
static inline M_C(base_name, _retcode_t) \
|
||||
M_C(name, _callback)(M_C(base_name, _t) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list)\
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
struct M_C(name, _s) *self = (struct M_C(name, _s) *)_self; \
|
||||
(void) self; /* maybe unused */ \
|
||||
callback_core; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_with)(M_C(name, _t) obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(M_C(name, _t) obj) \
|
||||
{ \
|
||||
(void) obj; /* nothing to do */ \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(base_name, _s) * \
|
||||
M_C(name, _as_interface)(M_C(name, _t) obj) \
|
||||
{ \
|
||||
return (struct M_C(base_name, _s) *) obj; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(M_C(name, _t) obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
} \
|
||||
|
||||
|
||||
/* Specialization of the definition a function object instance of name 'name'
|
||||
* with mandatory member attribute.
|
||||
* First inject oplist in member attributes.
|
||||
*/
|
||||
#define FUNCOBJI_INS_ATTR_DEF(name, base_name, param_list, callback_core, ...) \
|
||||
FUNCOBJI_INS_ATTR_DEF_P2(name, base_name, param_list, callback_core, FUNCOBJI_INJECT_GLOBAL(__VA_ARGS__) )
|
||||
|
||||
/* Inject the oplist within the list of arguments */
|
||||
#define FUNCOBJI_INJECT_GLOBAL(...) \
|
||||
M_MAP_C(FUNCOBJI_INJECT_OPLIST_A, __VA_ARGS__)
|
||||
/* Transform (x, type) into (x, type, oplist) if there is global registered oplist
|
||||
or (x, type, M_DEFAULT_OPLIST) if there is no global one,
|
||||
or keep (x, type, oplist) if oplist was already present */
|
||||
#define FUNCOBJI_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
FUNCOBJI_INJECT_OPLIST_B duo_or_trio
|
||||
#define FUNCOBJI_INJECT_OPLIST_B( f, ... ) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
|
||||
|
||||
// Test if all third argument of all arguments is an oplist
|
||||
#define FUNCOBJI_IF_ALL_OPLIST(...) \
|
||||
M_IF(M_REDUCE(FUNCOBJI_IS_OPLIST_P, M_AND, __VA_ARGS__))
|
||||
// Test if the third argument is an oplist
|
||||
#define FUNCOBJI_IS_OPLIST_P(a) \
|
||||
M_OPLIST_P(M_RET_ARG3 a)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define FUNCOBJI_INS_ATTR_DEF_P2(name, base_name, param_list, callback_core, ...) \
|
||||
FUNCOBJI_IF_ALL_OPLIST(__VA_ARGS__)(FUNCOBJI_INS_ATTR_DEF_P3, FUNCOBJI_INS_ATTR_DEF_FAILURE)(name, base_name, param_list, callback_core, __VA_ARGS__)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define FUNCOBJI_INS_ATTR_DEF_FAILURE(name, base_name, param_list, callback_core, ...) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(FUNC_OBJ_INS_DEF): at least one of the given argument is not a valid oplist: " #__VA_ARGS__)
|
||||
|
||||
/* Expand the Function Object with members */
|
||||
#define FUNCOBJI_INS_ATTR_DEF_P3(name, base_name, param_list, callback_core, ...) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
/* Callback is the mandatory first argument */ \
|
||||
M_C(base_name, _callback_t) callback; \
|
||||
/* All the member attribute of the Function Object */ \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_STRUCT, __VA_ARGS__) \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
FUNCOBJI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
\
|
||||
static inline M_C(base_name, _retcode_t) \
|
||||
M_C(name, _callback)(M_C(base_name, _t) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list)\
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
struct M_C(name, _s) *self = (struct M_C(name, _s) *)_self; \
|
||||
(void) self; /* maybe unused */ \
|
||||
callback_core; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_with)(M_C(name, _t) obj M_MAP(FUNCOBJI_INS_ATTR_LIST, __VA_ARGS__)) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_INIT_SET, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(M_C(name, _t) obj) \
|
||||
{ \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_CLEAR, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(base_name, _s) * \
|
||||
M_C(name, _as_interface)(M_C(name, _t) obj) \
|
||||
{ \
|
||||
return (struct M_C(base_name, _s) *) obj; \
|
||||
} \
|
||||
\
|
||||
M_IF(FUNCOBJI_TEST_METHOD_P(INIT, __VA_ARGS)) \
|
||||
( \
|
||||
static inline void \
|
||||
M_C(name, _init)(M_C(name, _t) obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_INIT, __VA_ARGS__); \
|
||||
} \
|
||||
, /* END OF INIT METHOD */ ) \
|
||||
|
||||
|
||||
|
||||
/* Define a numbered type of a parameter of the callback*/
|
||||
#define FUNCOBJI_BASE_TYPE(name, num, type) \
|
||||
typedef type M_C4(name, _param_, num, _t);
|
||||
|
||||
/* Define a list of the type of arguments for a function definition */
|
||||
#define FUNCOBJI_BASE_ARGLIST(name, num, type) \
|
||||
M_DEFERRED_COMMA type M_C(param_, num)
|
||||
|
||||
/* Define a list of arguments for a function call */
|
||||
#define FUNCOBJI_BASE_ARGCALL(name, num, type) \
|
||||
M_DEFERRED_COMMA M_C(param_, num)
|
||||
|
||||
|
||||
/* Helper macros */
|
||||
/* arg = (name, type [, oplist]) */
|
||||
#define FUNCOBJI_INS_ATTR_STRUCT(arg) \
|
||||
M_RET_ARG2 arg M_RET_ARG1 arg;
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_LIST(arg) \
|
||||
M_DEFERRED_COMMA M_RET_ARG2 arg const M_RET_ARG1 arg
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_INIT(arg) \
|
||||
M_CALL_INIT(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg);
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_INIT_SET(arg) \
|
||||
M_CALL_INIT_SET(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg, M_RET_ARG1 arg);
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_CLEAR(arg) \
|
||||
M_CALL_CLEAR(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg);
|
||||
|
||||
/* Define the list of arguments of the instance of the callback */
|
||||
#define FUNCOBJI_INS_ARGLIST(name, num, param) \
|
||||
M_DEFERRED_COMMA M_C4(name, _param_, num, _t) param
|
||||
|
||||
|
||||
/* Macros for testing for a method presence in all the attributes */
|
||||
#define FUNCOBJI_TEST_METHOD2_P(method, op) \
|
||||
M_TEST_METHOD_P(method, op)
|
||||
#define FUNCOBJI_TEST_METHOD1_P(method, arg) \
|
||||
M_APPLY(FUNCOBJI_TEST_METHOD2_P, method, M_RET_ARG3 arg)
|
||||
#define FUNCOBJI_TEST_METHOD_P(method, ...) \
|
||||
M_IF(M_REDUCE2(FUNCOBJI_TEST_METHOD1_P, M_AND, method, __VA_ARGS__))
|
||||
|
||||
/* Macro for checking compatible type and oplist for all the attributes */
|
||||
#define FUNCOBJI_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(FUNCOBJI_CONTROL_OPLIST, name, __VA_ARGS__)
|
||||
#define FUNCOBJI_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, M_RET_ARG1 a, M_RET_ARG2 a, M_RET_ARG3 a)
|
||||
|
||||
|
||||
#endif
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - GENINT module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+21
-5
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Intrusive List module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -70,8 +70,16 @@ typedef struct ilist_head_s {
|
||||
/* Indirection call to allow expanding all arguments */
|
||||
#define ILISTI_OPLIST_P1(arg) ILISTI_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define ILISTI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(ILISTI_OPLIST_P3, ILISTI_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define ILISTI_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_ILIST_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
|
||||
/* Define the oplist of an ilist of type */
|
||||
#define ILISTI_OPLIST_P2(name,oplist) \
|
||||
#define ILISTI_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
@@ -95,8 +103,6 @@ typedef struct ilist_head_s {
|
||||
IT_REMOVE(M_C(name,_remove)), \
|
||||
M_IF_METHOD(NEW, oplist)(IT_INSERT(M_C(name,_insert)),), \
|
||||
OPLIST(oplist), \
|
||||
PUSH(M_C(name,_push_back)), \
|
||||
POP(M_C(name,_pop_back)) \
|
||||
SPLICE_BACK(M_C(name,_splice_back)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
@@ -122,6 +128,14 @@ typedef struct ilist_head_s {
|
||||
/* Indirection call to allow expanding all arguments (TBC) */
|
||||
#define ILISTI_DEF_P1(arg) ILISTI_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define ILISTI_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(ILISTI_DEF_P3, ILISTI_DEF_FAILURE)(name, type, oplist, list_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define ILISTI_DEF_FAILURE(name, type, oplist, list_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ILIST_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Definition of the type and function for an intrusive doubly-linked list.
|
||||
USAGE:
|
||||
name: name of the intrusive list
|
||||
@@ -130,7 +144,7 @@ typedef struct ilist_head_s {
|
||||
list_t: type of the intrusive list (name##_t)
|
||||
it_t: iterator of the intrusive list (name##_it_t)
|
||||
*/
|
||||
#define ILISTI_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
#define ILISTI_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
struct ilist_head_s name; \
|
||||
@@ -147,6 +161,8 @@ typedef struct ilist_head_s {
|
||||
struct ilist_head_s *next; \
|
||||
} it_t[1]; \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void M_C(name, _init)(list_t list) \
|
||||
{ \
|
||||
assert (list != NULL); \
|
||||
|
||||
+25
-4
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - INTRUSIVE SHARED PTR Module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -42,8 +42,9 @@
|
||||
#define ISHARED_PTR_INTERFACE(name, type) \
|
||||
atomic_int M_C(name, _cpt)
|
||||
|
||||
|
||||
/* Define the intrusive shared pointer type and its static inline functions.
|
||||
USAGE: ISHARED_PTR_DEF(name[, oplist]) */
|
||||
USAGE: ISHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define ISHARED_PTR_DEF(name, ...) \
|
||||
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
|
||||
@@ -55,14 +56,22 @@
|
||||
// Deferred evaluation
|
||||
#define ISHAREDI_PTR_OPLIST_P1(arg) ISHAREDI_PTR_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define ISHAREDI_PTR_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(ISHAREDI_PTR_OPLIST_P3, ISHAREDI_PTR_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define ISHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_ISHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
|
||||
// Define the oplist
|
||||
#define ISHAREDI_PTR_OPLIST_P2(name, oplist) ( \
|
||||
#define ISHAREDI_PTR_OPLIST_P3(name, oplist) ( \
|
||||
INIT(M_INIT_DEFAULT), \
|
||||
INIT_SET(M_C(name, _init_set2) M_IPTR), \
|
||||
SET(M_C(name, _set) M_IPTR), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
CLEAN(M_C(name, _clean) M_IPTR), \
|
||||
TYPE(M_C(name, _type_t)), \
|
||||
TYPE(M_C(name, _t)), \
|
||||
OPLIST(oplist), \
|
||||
SUBTYPE(M_C(name, _type_t)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
@@ -73,11 +82,21 @@
|
||||
// Deferred evaluatioin
|
||||
#define ISHAREDI_PTR_DEF_P1(arg) ISHAREDI_PTR_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define ISHAREDI_PTR_DEF_P2(name, type, oplist) \
|
||||
M_IF_OPLIST(oplist)(ISHAREDI_PTR_DEF_P3, ISHAREDI_PTR_DEF_FAILURE)(name, type, oplist)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define ISHAREDI_PTR_DEF_FAILURE(name, type, oplist) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ISHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
#define ISHAREDI_PTR_DEF_P3(name, type, oplist) \
|
||||
\
|
||||
typedef type *M_C(name,_t); \
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline M_C(name,_t) \
|
||||
M_C(name, _init)(type *ptr) \
|
||||
{ \
|
||||
@@ -103,6 +122,7 @@
|
||||
*ptr = M_C(name, _init_set)(shared); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD2(INIT, NEW, oplist)( \
|
||||
static inline M_C(name,_t) \
|
||||
M_C(name, _init_new)(void) \
|
||||
{ \
|
||||
@@ -115,6 +135,7 @@
|
||||
atomic_init (&ptr->M_C(name, _cpt), 1); \
|
||||
return ptr; \
|
||||
} \
|
||||
, /* End of INIT/NEW */) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(M_C(name,_t) shared) \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - LIST module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -34,13 +34,15 @@
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name, _it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name, _it_t) )))
|
||||
|
||||
/* Define a dual-push singly linked list of a given type.
|
||||
USAGE: LIST_DEF(name, type [, oplist_of_the_type]) */
|
||||
|
||||
/* Define a singly linked list of a given type allowing both push.
|
||||
USAGE: LIST_DUAL_PUSH_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define LIST_DUAL_PUSH_DEF(name, ...) \
|
||||
LISTI_DUAL_PUSH_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name, _it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name, _it_t) )))
|
||||
|
||||
|
||||
/* Define the oplist of a list of type.
|
||||
USAGE: LIST_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define LIST_OPLIST(...) \
|
||||
@@ -55,8 +57,16 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define LISTI_OPLIST_P1(arg) LISTI_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define LISTI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(LISTI_OPLIST_P3, LISTI_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define LISTI_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_LIST_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
|
||||
/* OPLIST definition of a list and list_dual_push */
|
||||
#define LISTI_OPLIST_P2(name, oplist) \
|
||||
#define LISTI_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
INIT_WITH(API_1(M_INIT_VAI)), \
|
||||
@@ -106,6 +116,14 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define LISTI_DEF_P1(arg) LISTI_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define LISTI_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(LISTI_DEF_P3, LISTI_DEF_FAILURE)(name, type, oplist, list_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define LISTI_DEF_FAILURE(name, type, oplist, list_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(LIST_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Define allocation functions. If MEMPOOL, we need to define it */
|
||||
#define LISTI_MEMPOOL_DEF(name, type, oplist, list_t, list_it_t) \
|
||||
M_IF_METHOD(MEMPOOL, oplist)( \
|
||||
@@ -132,13 +150,13 @@
|
||||
|
||||
/* Internal list definition
|
||||
- name: prefix to be used
|
||||
- type: type of the elements of the array
|
||||
- type: type of the elements of the list
|
||||
- oplist: oplist of the type of the elements of the container
|
||||
- list_t: alias for M_C(name, _t) [ type of the container ]
|
||||
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
|
||||
- node_t: alias for M_C(name, _node_t) [ node ]
|
||||
*/
|
||||
#define LISTI_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
#define LISTI_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
struct M_C(name, _s) *next; \
|
||||
@@ -154,8 +172,10 @@
|
||||
struct M_C(name, _s) *current; \
|
||||
} it_t[1]; \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
LISTI_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
|
||||
LISTI_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
LISTI_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
LISTI_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
@@ -168,13 +188,13 @@
|
||||
|
||||
/* Internal list function definition
|
||||
- name: prefix to be used
|
||||
- type: type of the elements of the array
|
||||
- type: type of the elements of the list
|
||||
- oplist: oplist of the type of the elements of the container
|
||||
- list_t: alias for M_C(name, _t) [ type of the container ]
|
||||
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
|
||||
- node_t: alias for M_C(name, _node_t) [ node ]
|
||||
*/
|
||||
#define LISTI_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
#define LISTI_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(list_t v) \
|
||||
@@ -612,7 +632,7 @@
|
||||
/* Internal list function definition based on iterator functions
|
||||
(common for all kind of lists)
|
||||
- name: prefix to be used
|
||||
- type: type of the elements of the array
|
||||
- type: type of the elements of the list
|
||||
- oplist: oplist of the type of the elements of the container
|
||||
- list_t: alias for M_C(name, _t) [ type of the container ]
|
||||
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
|
||||
@@ -677,12 +697,13 @@
|
||||
do { \
|
||||
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
if (b == false || c == 0) { goto exit; } \
|
||||
M_C(name, _push_back)(list, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
M_C(name, _reverse)(list); \
|
||||
if (b == false || c == 0) { goto exit_clear; } \
|
||||
M_C(name, _push_back)(list, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_C(name, _reverse)(list); \
|
||||
success = (c == ']'); \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
exit: \
|
||||
if (endp) *endp = str; \
|
||||
return success; \
|
||||
@@ -812,15 +833,22 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define LISTI_DUAL_PUSH_DEF_P1(arg) LISTI_DUAL_PUSH_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define LISTI_DUAL_PUSH_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(LISTI_DUAL_PUSH_DEF_P3, LISTI_DUAL_PUSH_DEF_FAILURE)(name, type, oplist, list_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define LISTI_DUAL_PUSH_DEF_FAILURE(name, type, oplist, list_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(LIST_DUAL_PUSH_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Internal dual-push list definition
|
||||
- name: prefix to be used
|
||||
- type: type of the elements of the array
|
||||
- oplist: oplist of the type of the elements of the container
|
||||
- list_t: alias for M_C(name, _t) [ type of the container ]
|
||||
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
|
||||
- node_t: alias for M_C(name, _node_t) [ node ]
|
||||
*/
|
||||
#define LISTI_DUAL_PUSH_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
#define LISTI_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
struct M_C(name, _s) { \
|
||||
struct M_C(name, _s) *next; \
|
||||
@@ -846,10 +874,13 @@
|
||||
struct M_C(name, _s) *current; \
|
||||
} it_t[1]; \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
LISTI_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
|
||||
LISTI_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
LISTI_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
LISTI_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
/* Define the internal contract of an dual-push list */
|
||||
#define LISTI_DUAL_PUSH_CONTRACT(l) do { \
|
||||
assert (l != NULL); \
|
||||
@@ -865,7 +896,7 @@
|
||||
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
|
||||
- node_t: alias for M_C(name, _node_t) [ node ]
|
||||
*/
|
||||
#define LISTI_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
#define LISTI_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(list_t v) \
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - MEMPOOL module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin Mutex & Thread wrapper
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -35,63 +35,84 @@
|
||||
#include <stdbool.h>
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define a mutex type based on C11 definition */
|
||||
typedef mtx_t m_mutex_t[1];
|
||||
|
||||
/* Define a condition variable type based on C11 definition */
|
||||
typedef cnd_t m_cond_t[1];
|
||||
|
||||
/* Define a thread type based on C11 definition */
|
||||
typedef thrd_t m_thread_t[1];
|
||||
|
||||
/* Initialize the mutex (constructor) */
|
||||
static inline void m_mutex_init(m_mutex_t m)
|
||||
{
|
||||
int rc = mtx_init(m, mtx_plain);
|
||||
// Abort program in case of initialization failure
|
||||
// There is really nothing else to do if a mutex cannot be constructed
|
||||
M_ASSERT_INIT (rc == 0, "mutex");
|
||||
}
|
||||
|
||||
/* Clear the mutex (destructor) */
|
||||
static inline void m_mutex_clear(m_mutex_t m)
|
||||
{
|
||||
mtx_destroy(m);
|
||||
}
|
||||
|
||||
/* Lock the mutex */
|
||||
static inline void m_mutex_lock(m_mutex_t m)
|
||||
{
|
||||
mtx_lock(m);
|
||||
}
|
||||
|
||||
/* Unlock the mutex */
|
||||
static inline void m_mutex_unlock(m_mutex_t m)
|
||||
{
|
||||
mtx_unlock(m);
|
||||
}
|
||||
|
||||
/* Initialize the condition variable (constructor) */
|
||||
static inline void m_cond_init(m_cond_t c)
|
||||
{
|
||||
int rc = cnd_init(c);
|
||||
// Abort program in case of initialization failure
|
||||
// There is really nothing else to do if the object cannot be constructed
|
||||
M_ASSERT_INIT (rc == 0, "conditional variable");
|
||||
}
|
||||
|
||||
/* Clear the condition variable (destructor) */
|
||||
static inline void m_cond_clear(m_cond_t c)
|
||||
{
|
||||
cnd_destroy(c);
|
||||
}
|
||||
|
||||
/* Signal the condition variable to at least one waiting thread */
|
||||
static inline void m_cond_signal(m_cond_t c)
|
||||
{
|
||||
cnd_signal(c);
|
||||
}
|
||||
|
||||
/* Signal the condition variable to all waiting threads */
|
||||
static inline void m_cond_broadcast(m_cond_t c)
|
||||
{
|
||||
cnd_broadcast(c);
|
||||
}
|
||||
|
||||
/* Wait for signaling the condition variable by another thread */
|
||||
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
|
||||
{
|
||||
cnd_wait(c, m);
|
||||
}
|
||||
|
||||
/* Create the thread (constructor) and start it */
|
||||
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void* arg)
|
||||
{
|
||||
int rc = thrd_create(t, (int(*)(void*))(void(*)(void))func, arg);
|
||||
// Abort program in case of initialization failure
|
||||
M_ASSERT_INIT (rc == thrd_success, "thread");
|
||||
}
|
||||
|
||||
/* Wait for the thread to terminate and destroy it (destructor) */
|
||||
static inline void m_thread_join(m_thread_t t)
|
||||
{
|
||||
int rc = thrd_join(*t, NULL);
|
||||
@@ -100,11 +121,15 @@ static inline void m_thread_join(m_thread_t t)
|
||||
(void) rc;
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
Inform the OS to let other threads be scheduled */
|
||||
static inline void m_thread_yield(void)
|
||||
{
|
||||
thrd_yield();
|
||||
}
|
||||
|
||||
/* Sleep the thread for at least usec microseconds.
|
||||
Return true if the sleep was successful */
|
||||
static inline bool m_thread_sleep(unsigned long long usec)
|
||||
{
|
||||
struct timespec tv;
|
||||
@@ -116,12 +141,17 @@ static inline bool m_thread_sleep(unsigned long long usec)
|
||||
|
||||
// Internal type, not exported.
|
||||
typedef once_flag m_oncei_t[1];
|
||||
|
||||
// Initial value for m_oncei_t
|
||||
#define M_ONCEI_INIT_VALUE { ONCE_FLAG_INIT }
|
||||
|
||||
// Call the function exactly once
|
||||
static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
|
||||
{
|
||||
call_once(o,func);
|
||||
}
|
||||
|
||||
// Attribute to use to allocate a global variable to a thread.
|
||||
#define M_THREAD_ATTR _Thread_local
|
||||
|
||||
|
||||
@@ -142,61 +172,77 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
|
||||
#include <stdbool.h>
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define a thread type based on WINDOWS definition */
|
||||
typedef HANDLE m_thread_t[1];
|
||||
|
||||
/* Define a mutex type based on WINDOWS definition */
|
||||
typedef CRITICAL_SECTION m_mutex_t[1];
|
||||
|
||||
/* Define a condition variable type based on WINDOWS definition */
|
||||
typedef CONDITION_VARIABLE m_cond_t[1];
|
||||
|
||||
/* Initialize a mutex (Constructor)*/
|
||||
static inline void m_mutex_init(m_mutex_t m)
|
||||
{
|
||||
InitializeCriticalSection(m);
|
||||
}
|
||||
|
||||
/* Clear a mutex (destructor) */
|
||||
static inline void m_mutex_clear(m_mutex_t m)
|
||||
{
|
||||
DeleteCriticalSection(m);
|
||||
}
|
||||
|
||||
/* Lock a mutex */
|
||||
static inline void m_mutex_lock(m_mutex_t m)
|
||||
{
|
||||
EnterCriticalSection(m);
|
||||
}
|
||||
|
||||
/* Unlock a mutex */
|
||||
static inline void m_mutex_unlock(m_mutex_t m)
|
||||
{
|
||||
LeaveCriticalSection(m);
|
||||
}
|
||||
|
||||
/* Initialize a condition variable (constructor) */
|
||||
static inline void m_cond_init(m_cond_t c)
|
||||
{
|
||||
InitializeConditionVariable(c);
|
||||
}
|
||||
|
||||
/* Clear a condition variable (destructor) */
|
||||
static inline void m_cond_clear(m_cond_t c)
|
||||
{
|
||||
(void) c; // There is no destructor for this object.
|
||||
}
|
||||
|
||||
/* Signal a condition variable to at least one waiting thread */
|
||||
static inline void m_cond_signal(m_cond_t c)
|
||||
{
|
||||
WakeConditionVariable(c);
|
||||
}
|
||||
|
||||
/* Signal a condition variable to all waiting threads */
|
||||
static inline void m_cond_broadcast(m_cond_t c)
|
||||
{
|
||||
WakeAllConditionVariable(c);
|
||||
}
|
||||
|
||||
/* Wait for a condition variable */
|
||||
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
|
||||
{
|
||||
SleepConditionVariableCS(c, m, INFINITE);
|
||||
}
|
||||
|
||||
/* Create a thread (constructor) and start it */
|
||||
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void *arg)
|
||||
{
|
||||
*t = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) (uintptr_t) func, arg, 0, NULL);
|
||||
M_ASSERT_INIT (*t != NULL, "thread");
|
||||
}
|
||||
|
||||
/* Wait for the thread to terminate and destroy it (destructor) */
|
||||
static inline void m_thread_join(m_thread_t t)
|
||||
{
|
||||
DWORD dwWaitResult = WaitForSingleObject(*t, INFINITE);
|
||||
@@ -205,11 +251,15 @@ static inline void m_thread_join(m_thread_t t)
|
||||
CloseHandle(*t);
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
Inform the OS to let other threads be scheduled */
|
||||
static inline void m_thread_yield(void)
|
||||
{
|
||||
Sleep(0);
|
||||
}
|
||||
|
||||
/* Sleep the thread for at least usec microseconds
|
||||
Return true if the sleep was successful */
|
||||
static inline bool m_thread_sleep(unsigned long long usec)
|
||||
{
|
||||
LARGE_INTEGER ft;
|
||||
@@ -241,8 +291,10 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Attribute to use to allocate a global variable to a thread (MSVC def).
|
||||
# define M_THREAD_ATTR __declspec( thread )
|
||||
#else
|
||||
// Attribute to use to allocate a global variable to a thread (GCC def).
|
||||
# define M_THREAD_ATTR __thread
|
||||
#endif
|
||||
|
||||
@@ -261,69 +313,92 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
|
||||
#include <stdbool.h>
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define a mutex type based on PTHREAD definition */
|
||||
typedef pthread_mutex_t m_mutex_t[1];
|
||||
|
||||
/* Define a condition variable type based on PTHREAD definition */
|
||||
typedef pthread_cond_t m_cond_t[1];
|
||||
|
||||
/* Define a thread type based on PTHREAD definition */
|
||||
typedef pthread_t m_thread_t[1];
|
||||
|
||||
/* Initialize the mutex (constructor) */
|
||||
static inline void m_mutex_init(m_mutex_t m)
|
||||
{
|
||||
int _rc = pthread_mutex_init(m, NULL);
|
||||
// Abort program in case of initialization failure
|
||||
// There is really nothing else to do if a mutex cannot be constructed
|
||||
M_ASSERT_INIT (_rc == 0, "mutex");
|
||||
}
|
||||
|
||||
/* Clear the mutex (destructor) */
|
||||
static inline void m_mutex_clear(m_mutex_t m)
|
||||
{
|
||||
pthread_mutex_destroy(m);
|
||||
}
|
||||
|
||||
/* Lock the mutex */
|
||||
static inline void m_mutex_lock(m_mutex_t m)
|
||||
{
|
||||
pthread_mutex_lock(m);
|
||||
}
|
||||
|
||||
/* Unlock the mutex */
|
||||
static inline void m_mutex_unlock(m_mutex_t m)
|
||||
{
|
||||
pthread_mutex_unlock(m);
|
||||
}
|
||||
|
||||
/* Lazy lock initialization */
|
||||
#define M_MUTEXI_INIT_VALUE { PTHREAD_MUTEX_INITIALIZER }
|
||||
|
||||
/* Internal function compatible with lazy lock */
|
||||
static inline void m_mutexi_lazy_lock(m_mutex_t m)
|
||||
{
|
||||
pthread_mutex_lock(m);
|
||||
}
|
||||
|
||||
/* Initialize the condition variable (constructor) */
|
||||
static inline void m_cond_init(m_cond_t c)
|
||||
{
|
||||
int _rc = pthread_cond_init(c, NULL);
|
||||
// Abort program in case of initialization failure
|
||||
// There is really nothing else to do if a mutex cannot be constructed
|
||||
M_ASSERT_INIT (_rc == 0, "conditional variable");
|
||||
}
|
||||
|
||||
/* Clear the condition variable (destructor) */
|
||||
static inline void m_cond_clear(m_cond_t c)
|
||||
{
|
||||
pthread_cond_destroy(c);
|
||||
}
|
||||
|
||||
/* Signal a condition variable to at least a waiting thread */
|
||||
static inline void m_cond_signal(m_cond_t c)
|
||||
{
|
||||
pthread_cond_signal(c);
|
||||
}
|
||||
|
||||
/* Signal a condition variable to all waiting threads */
|
||||
static inline void m_cond_broadcast(m_cond_t c)
|
||||
{
|
||||
pthread_cond_broadcast(c);
|
||||
}
|
||||
|
||||
/* Waiting for a condition variable */
|
||||
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
|
||||
{
|
||||
pthread_cond_wait(c, m);
|
||||
}
|
||||
|
||||
/* Create a thread (constructor) and start it */
|
||||
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void *arg)
|
||||
{
|
||||
int _rc = pthread_create(t, NULL, (void*(*)(void*))(void(*)(void))func, arg);
|
||||
M_ASSERT_INIT (_rc == 0, "thread");
|
||||
}
|
||||
|
||||
/* Wait for the thread to terminate and destroy it (destructor) */
|
||||
static inline void m_thread_join(m_thread_t t)
|
||||
{
|
||||
int _rc = pthread_join(*t, NULL);
|
||||
@@ -331,6 +406,8 @@ static inline void m_thread_join(m_thread_t t)
|
||||
assert (_rc == 0);
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
Inform the OS to let other threads be scheduled */
|
||||
static inline void m_thread_yield(void)
|
||||
{
|
||||
#ifdef _POSIX_PRIORITY_SCHEDULING
|
||||
@@ -338,6 +415,8 @@ static inline void m_thread_yield(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Sleep for at least usec microseconds
|
||||
Return true if the sleep was successful */
|
||||
static inline bool m_thread_sleep(unsigned long long usec)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
+27
-5
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - dynamic priority queue module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -52,10 +52,17 @@
|
||||
/* Deferred evaluation for the definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define PRIOQUEUEI_OPLIST_P1(arg) PRIOQUEUEI_OPLIST_P2 arg
|
||||
#define PRIOQUEUEI_DEF_P1(arg) PRIOQUEUEI_DEF_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define PRIOQUEUEI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(PRIOQUEUEI_OPLIST_P3, PRIOQUEUEI_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define PRIOQUEUEI_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_PRIOQUEUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
|
||||
/* Define oplist of a priority queue */
|
||||
#define PRIOQUEUEI_OPLIST_P2(name, oplist) \
|
||||
#define PRIOQUEUEI_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
@@ -74,6 +81,19 @@
|
||||
,GET_SIZE(M_C(name, _size)) \
|
||||
)
|
||||
|
||||
|
||||
/* Deferred evaluation for the definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define PRIOQUEUEI_DEF_P1(arg) PRIOQUEUEI_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define PRIOQUEUEI_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(PRIOQUEUEI_DEF_P3, PRIOQUEUEI_DEF_FAILURE)(name, type, oplist, prioqueue_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define PRIOQUEUEI_DEF_FAILURE(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(PRIOQUEUE_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Define the priority queue:
|
||||
- name: prefix to use,
|
||||
- type: type of the contained objects,
|
||||
@@ -81,7 +101,7 @@
|
||||
- prioqueue_t: type of the container,
|
||||
- it_t: iterator of the container
|
||||
*/
|
||||
#define PRIOQUEUEI_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
|
||||
#define PRIOQUEUEI_DEF_P3(name, type, oplist, prioqueue_t, it_t) \
|
||||
ARRAY_DEF(M_C(name, _array), type, oplist) \
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
@@ -94,6 +114,8 @@
|
||||
\
|
||||
typedef M_C(name, _array_it_t) it_t; \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(prioqueue_t p) \
|
||||
{ \
|
||||
@@ -354,7 +376,7 @@
|
||||
} \
|
||||
} \
|
||||
\
|
||||
, /* No EQUAL */ \) \
|
||||
, /* No EQUAL */ ) \
|
||||
|
||||
|
||||
// TODO: set all & remove all function
|
||||
|
||||
+230
-171
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - RED BLACK TREE module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -36,6 +36,7 @@
|
||||
(name, __VA_ARGS__ , \
|
||||
M_C(name, _t), M_C(name, _node_t), M_C(name, _it_t))))
|
||||
|
||||
|
||||
/* Define the oplist of a rbtree of type.
|
||||
USAGE: RBTREE_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define RBTREE_OPLIST(...) \
|
||||
@@ -50,8 +51,18 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define RBTREEI_OPLIST_P1(arg) RBTREEI_OPLIST_P2 arg
|
||||
|
||||
/* OPLIST definition of a rbtree */
|
||||
#define RBTREEI_OPLIST_P2(name, oplist) \
|
||||
/* Validation of the given oplist */
|
||||
#define RBTREEI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(RBTREEI_OPLIST_P3, RBTREEI_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define RBTREEI_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_RBTREE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
|
||||
/* OPLIST definition of a rbtree
|
||||
NOTE: IT_REF is not exported so that the contained appears as not modifiable
|
||||
by algorithm.*/
|
||||
#define RBTREEI_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
INIT_WITH(API_1(M_INIT_VAI)), \
|
||||
@@ -73,7 +84,6 @@
|
||||
IT_LAST_P(M_C(name,_last_p)), \
|
||||
IT_EQUAL_P(M_C(name,_it_equal_p)), \
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_REF(M_C(name,_ref)), \
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
CLEAN(M_C(name,_clean)), \
|
||||
PUSH(M_C(name,_push)), \
|
||||
@@ -110,88 +120,114 @@
|
||||
#define RBTREEI_GET_CHILD(x, n) ((x)->child[n])
|
||||
#define RBTREEI_SET_CHILD(x, n, y) ((x)->child[n] = (y))
|
||||
|
||||
// Color of a node of a Red/Black tree
|
||||
typedef enum {
|
||||
RBTREE_BLACK = 0, RBTREE_RED
|
||||
} rbtreei_color_e;
|
||||
|
||||
// General contact of a tree
|
||||
#define RBTREEI_CONTRACT(tree) do { \
|
||||
assert ((tree) != NULL); \
|
||||
assert ((tree)->node == NULL || RBTREEI_IS_BLACK((tree)->node)); \
|
||||
assert ((tree)->size != 0 || (tree)->node == NULL); \
|
||||
// General contact of a Read/Black tree
|
||||
#define RBTREEI_CONTRACT(tree) do { \
|
||||
assert ((tree) != NULL); \
|
||||
assert ((tree)->node == NULL || RBTREEI_IS_BLACK((tree)->node)); \
|
||||
assert ((tree)->size != 0 || (tree)->node == NULL); \
|
||||
} while (0)
|
||||
|
||||
// Contract of a node (doesn't check for equal depth in black)
|
||||
#define RBTREEI_CONTRACT_NODE(node) do { \
|
||||
assert((node) != NULL); \
|
||||
assert(RBTREEI_IS_BLACK(node) || RBTREEI_IS_RED(node)); \
|
||||
assert(RBTREEI_IS_BLACK(node) \
|
||||
|| (((node)->child[0] == NULL || RBTREEI_IS_BLACK(node->child[0])) \
|
||||
#define RBTREEI_CONTRACT_NODE(node) do { \
|
||||
assert((node) != NULL); \
|
||||
assert(RBTREEI_IS_BLACK(node) || RBTREEI_IS_RED(node)); \
|
||||
assert(RBTREEI_IS_BLACK(node) \
|
||||
|| (((node)->child[0] == NULL || RBTREEI_IS_BLACK(node->child[0])) \
|
||||
&& ((node)->child[1] == NULL || RBTREEI_IS_BLACK(node->child[1])))); \
|
||||
} while (0)
|
||||
|
||||
//TODO: UPDATE shall use a separate method than push
|
||||
//TODO: UPDATE method shall be a separate method than push method
|
||||
|
||||
/* Deferred evaluation for the rbtree definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define RBTREEI_DEF_P1(arg) RBTREEI_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define RBTREEI_DEF_P2(name, type, oplist, tree_t, node_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(RBTREEI_DEF_P3, RBTREEI_DEF_FAILURE)(name, type, oplist, tree_t, node_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define RBTREEI_DEF_FAILURE(name, type, oplist, tree_t, note_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(RBTREE_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Internal rbtree definition
|
||||
- name: prefix to be used
|
||||
- type: type of the elements of the array
|
||||
- type: type of the elements of the rbtree
|
||||
- oplist: oplist of the type of the elements of the container
|
||||
- tree_t: alias for M_C(name, _t) [ type of the container ]
|
||||
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
|
||||
- node_t: alias for M_C(name, _node_t) [ node ]
|
||||
*/
|
||||
#define RBTREEI_DEF_P2(name, type, oplist, tree_t, node_t, it_t) \
|
||||
#define RBTREEI_DEF_P3(name, type, oplist, tree_t, node_t, it_t) \
|
||||
\
|
||||
/* Node of Red/Black tree. \
|
||||
Each node has up to two child, a color (Red or black) \
|
||||
and the data stored in it */ \
|
||||
typedef struct M_C(name, _node_s) { \
|
||||
struct M_C(name, _node_s) *child[2]; \
|
||||
type data; \
|
||||
rbtreei_color_e color; \
|
||||
} node_t; \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
size_t size; \
|
||||
node_t *node; \
|
||||
/* Red/Black tree */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
size_t size; /* Number of elements in the tree */ \
|
||||
node_t *node; /* Root node of the tree */ \
|
||||
} tree_t[1]; \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
\
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
\
|
||||
/* Iterator on a tree. The iterator stores the full path to the \
|
||||
current node through all its parents and its depth */ \
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
node_t *stack[RBTREEI_MAX_STACK]; \
|
||||
int8_t which[RBTREEI_MAX_STACK]; \
|
||||
unsigned int cpt; \
|
||||
} it_t[1]; \
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
/* Link with fast memory allocator if requested */ \
|
||||
M_IF_METHOD(MEMPOOL, oplist)( \
|
||||
/* Definition of the memory pool of this kind of node */ \
|
||||
MEMPOOL_DEF(M_C(name, _mempool), node_t) \
|
||||
/* Definition of the global variable used to reference this pool */ \
|
||||
M_GET_MEMPOOL_LINKAGE oplist M_C(name, _mempool_t) M_GET_MEMPOOL oplist; \
|
||||
static inline node_t *M_C(name,_int_new)(void) { \
|
||||
return M_C(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \
|
||||
/* Allocator function */ \
|
||||
static inline node_t *M_C(name,_int_new)(void) { \
|
||||
return M_C(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \
|
||||
} \
|
||||
static inline void M_C(name,_int_del)(node_t *ptr) { \
|
||||
M_C(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \
|
||||
/* Deallocator function */ \
|
||||
static inline void M_C(name,_int_del)(node_t *ptr) { \
|
||||
M_C(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
, /* No mempool allocation */ \
|
||||
\
|
||||
static inline node_t *M_C(name,_int_new)(void) { \
|
||||
/* Callic allocator function (common case) */ \
|
||||
static inline node_t *M_C(name,_int_new)(void) { \
|
||||
return M_CALL_NEW(oplist, node_t); \
|
||||
} \
|
||||
static inline void M_C(name,_int_del)(node_t *ptr) { \
|
||||
/* Callic deallocator function (common case) */ \
|
||||
static inline void M_C(name,_int_del)(node_t *ptr) { \
|
||||
M_CALL_DEL(oplist, ptr); \
|
||||
} ) \
|
||||
\
|
||||
RBTREEI_DEF_P3(name, type, oplist, tree_t, node_t, it_t)
|
||||
\
|
||||
/* Check if the given oplist is compatible with the given type */ \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
/* Generate all functions */ \
|
||||
RBTREEI_DEF_P4(name, type, oplist, tree_t, node_t, it_t)
|
||||
|
||||
#define RBTREEI_DEF_P3(name, type, oplist, tree_t, node_t, it_t) \
|
||||
\
|
||||
|
||||
#define RBTREEI_DEF_P4(name, type, oplist, tree_t, node_t, it_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(tree_t tree) \
|
||||
M_C(name, _init)(tree_t tree) \
|
||||
{ \
|
||||
assert (tree != NULL); \
|
||||
tree->size = 0; \
|
||||
@@ -205,57 +241,70 @@ typedef enum {
|
||||
RBTREEI_CONTRACT(tree); \
|
||||
node_t *stack[RBTREEI_MAX_STACK]; \
|
||||
unsigned int cpt = 0; \
|
||||
/* If nothing (no node) nothing to clean: return */ \
|
||||
if (tree->node == NULL) return; \
|
||||
/* Parse all the tree */ \
|
||||
stack[cpt++] = tree->node; \
|
||||
while (cpt > 0) { \
|
||||
node_t *n = stack[cpt-1]; \
|
||||
/* Go down to the bottom left node that exists */ \
|
||||
while (true) { \
|
||||
RBTREEI_CONTRACT_NODE(n); \
|
||||
/* If there is a left child, get it */ \
|
||||
if (n->child[0] != NULL) { \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
stack[cpt++] = n->child[0]; \
|
||||
n = n->child[0]; \
|
||||
stack[cpt-2]->child[0] = NULL; \
|
||||
/* If there is a right child, get it */ \
|
||||
} else if (n->child[1] != NULL) { \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
stack[cpt++] = n->child[1]; \
|
||||
n = n->child[1]; \
|
||||
stack[cpt-2]->child[1] = NULL; \
|
||||
} else \
|
||||
/* No left nor right child, node can be deleted */ \
|
||||
} else { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
assert (n == stack[cpt - 1]); \
|
||||
/* Clear the bottom left node */ \
|
||||
M_CALL_CLEAR(oplist, n->data); \
|
||||
M_C(name,_int_del) (n); \
|
||||
M_C(name,_int_del) (n); \
|
||||
assert((stack[cpt-1] = NULL) == NULL); \
|
||||
/* Go up to the parent */ \
|
||||
cpt--; \
|
||||
} \
|
||||
/* Mark the root node as empty */ \
|
||||
tree->node = NULL; \
|
||||
tree->size = 0; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(tree_t tree) \
|
||||
M_C(name, _clear)(tree_t tree) \
|
||||
{ \
|
||||
M_C(name, _clean)(tree); \
|
||||
/* Nothing more than clean the tree as everything is cleared */ \
|
||||
M_C(name, _clean)(tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push)(tree_t tree, type const data) \
|
||||
M_C(name, _push)(tree_t tree, type const data) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT(tree); \
|
||||
node_t *tab[RBTREEI_MAX_STACK]; \
|
||||
int8_t which[RBTREEI_MAX_STACK]; \
|
||||
unsigned int cpt = 0; \
|
||||
node_t *n = tree->node; \
|
||||
/* If nothing, create new node */ \
|
||||
/* If there is no root node, create a new node */ \
|
||||
if (n == NULL) { \
|
||||
n = M_C(name,_int_new)(); \
|
||||
n = M_C(name,_int_new)(); \
|
||||
if (M_UNLIKELY (n == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (node_t)); \
|
||||
return; \
|
||||
} \
|
||||
/* Copy the data in the root node */ \
|
||||
M_CALL_INIT_SET(oplist, n->data, data); \
|
||||
/* Mark the root node as black */ \
|
||||
n->child[0] = n->child[1] = NULL; \
|
||||
RBTREEI_SET_BLACK (n); \
|
||||
tree->node = n; \
|
||||
@@ -264,46 +313,50 @@ typedef enum {
|
||||
RBTREEI_CONTRACT(tree); \
|
||||
return; \
|
||||
} \
|
||||
/* Search for insertion point */ \
|
||||
/* Search for insertion point in the tree */ \
|
||||
tab[cpt] = n; \
|
||||
while (n != NULL) { \
|
||||
RBTREEI_CONTRACT_NODE(n); \
|
||||
int cmp = M_CALL_CMP(oplist, n->data, data); \
|
||||
if (cmp == 0) { \
|
||||
/* key found ==> stop analysis */ \
|
||||
break; \
|
||||
} else if (cmp > 0) { \
|
||||
which[cpt++] = 0; \
|
||||
n = n->child[0]; \
|
||||
} else { \
|
||||
which[cpt++] = 1; \
|
||||
n = n->child[1]; \
|
||||
/* go left (if cmp > 0) or right (if cmp < 0) */ \
|
||||
int s = (cmp < 0); \
|
||||
which[cpt++] = s; \
|
||||
n = n->child[s]; \
|
||||
} \
|
||||
/* We cannot overflow the max depth of a tree */ \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
tab[cpt] = n; \
|
||||
} \
|
||||
/* If found, update the data (default is set) */ \
|
||||
if (n != NULL) { \
|
||||
/* FIXME: Use of SET method instead of UPDATE ? */ \
|
||||
M_IF_METHOD (UPDATE, oplist)(M_CALL_UPDATE(oplist, n->data, data) \
|
||||
, M_CALL_SET(oplist, n->data, data)); \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
return; \
|
||||
} \
|
||||
/* Create new */ \
|
||||
n = M_C(name,_int_new)(); \
|
||||
/* Create new node to store the data */ \
|
||||
n = M_C(name,_int_new)(); \
|
||||
if (M_UNLIKELY (n == NULL) ) { \
|
||||
M_MEMORY_FULL (sizeof (node_t)); \
|
||||
return; \
|
||||
} \
|
||||
/* Copy the data and mark the node as red */ \
|
||||
M_CALL_INIT_SET(oplist, n->data, data); \
|
||||
n->child[0] = n->child[1] = NULL; \
|
||||
RBTREEI_SET_RED (n); \
|
||||
/* Add it in the iterator */ \
|
||||
assert (tab[cpt] == NULL); \
|
||||
tab[cpt] = n; \
|
||||
tree->size ++; \
|
||||
/* Add it in the tree */ \
|
||||
tree->size ++; \
|
||||
assert(tab[cpt-1]->child[0+which[cpt-1]] == NULL); \
|
||||
tab[cpt-1]->child[0+which[cpt-1]] = n; \
|
||||
/* Fix the tree */ \
|
||||
/* Fix the tree to still respect the red/back properties */ \
|
||||
while (cpt >= 2 \
|
||||
&& RBTREEI_IS_RED(tab[cpt-1]) \
|
||||
&& tab[cpt-2]->child[1-which[cpt-2]] != NULL \
|
||||
@@ -363,14 +416,15 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const tree_t tree) \
|
||||
M_C(name, _size)(const tree_t tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
return tree->size; \
|
||||
} \
|
||||
\
|
||||
/* Set the iterator to the first (child=0) or last (child=1) element */ \
|
||||
static inline void \
|
||||
M_C(name, _int_it)(it_t it, const tree_t tree, int child) \
|
||||
M_C(name, _int_it)(it_t it, const tree_t tree, int child) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
assert (it != NULL); \
|
||||
@@ -379,6 +433,7 @@ typedef enum {
|
||||
if (tree->node != NULL) { \
|
||||
it->which[cpt] = child; \
|
||||
node_t *n = it->stack[cpt++] = tree->node; \
|
||||
/* Go down the tree and fill in the iterator */ \
|
||||
while (n->child[child] != NULL) { \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
n = n->child[child]; \
|
||||
@@ -391,47 +446,49 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const tree_t tree) \
|
||||
M_C(name, _it)(it_t it, const tree_t tree) \
|
||||
{ \
|
||||
M_C(name, _int_it)(it, tree, 0); \
|
||||
M_C(name, _int_it)(it, tree, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, const tree_t tree) \
|
||||
M_C(name, _it_last)(it_t it, const tree_t tree) \
|
||||
{ \
|
||||
M_C(name,_int_it)(it, tree, 1); \
|
||||
M_C(name,_int_it)(it, tree, 1); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, const tree_t tree) \
|
||||
M_C(name, _it_end)(it_t it, const tree_t tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
assert (it != NULL); \
|
||||
assert (it != NULL); \
|
||||
it->cpt = 0; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(it_t it, const it_t ref) \
|
||||
M_C(name, _it_set)(it_t it, const it_t ref) \
|
||||
{ \
|
||||
assert (it != NULL && ref != NULL); \
|
||||
*it = *ref; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const it_t it) \
|
||||
M_C(name, _end_p)(const it_t it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
return it->cpt == 0; \
|
||||
} \
|
||||
\
|
||||
/* Go to the next (child = 0)or previous element (child = 1) */ \
|
||||
static inline void \
|
||||
M_C(name, _int_next)(it_t it, int child) \
|
||||
M_C(name, _int_next)(it_t it, int child) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
assert (child == 0 || child == 1); \
|
||||
if (it->cpt == 0) return; \
|
||||
unsigned int cpt = it->cpt - 1; \
|
||||
node_t *n = it->stack[cpt]; \
|
||||
/* Get the other child */ \
|
||||
const int right = 1 ^ child; \
|
||||
if (n->child[right] != NULL && it->which[cpt] == child) { \
|
||||
/* Going right */ \
|
||||
@@ -456,19 +513,19 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _next)(it_t it) \
|
||||
M_C(name, _next)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _int_next)(it, 0); \
|
||||
M_C(name, _int_next)(it, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _previous)(it_t it) \
|
||||
M_C(name, _previous)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _int_next)(it, 1); \
|
||||
M_C(name, _int_next)(it, 1); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(const it_t it) \
|
||||
M_C(name, _ref)(const it_t it) \
|
||||
{ \
|
||||
assert(it != NULL && it->cpt > 0); \
|
||||
/* NOTE: partially unsafe if the user modify the order of the el */ \
|
||||
@@ -476,23 +533,22 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const it_t it) \
|
||||
M_C(name, _cref)(const it_t it) \
|
||||
{ \
|
||||
return M_CONST_CAST(type, M_C(name, _ref)(it)); \
|
||||
return M_CONST_CAST(type, M_C(name, _ref)(it)); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_equal_p)(const it_t it1, \
|
||||
const it_t it2) \
|
||||
M_C(name, _it_equal_p)(const it_t it1, const it_t it2) \
|
||||
{ \
|
||||
assert(it1 != NULL && it2 != NULL); \
|
||||
return it1->cpt == it2->cpt \
|
||||
&& it1->stack[it1->cpt-1] == it2->stack[it2->cpt-1]; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_from)(it_t it, \
|
||||
const tree_t tree, type const data) \
|
||||
M_C(name, _it_from)(it_t it, const tree_t tree, type const data) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
assert (it != NULL); \
|
||||
@@ -535,13 +591,13 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline bool M_ATTR_DEPRECATED \
|
||||
M_C(name, _it_to_p)(it_t it, type const data) \
|
||||
M_C(name, _it_to_p)(it_t it, type const data) \
|
||||
{ \
|
||||
return M_C(name, _it_until_p)(it, data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _min)(const tree_t tree) \
|
||||
M_C(name, _min)(const tree_t tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
node_t *n = tree->node; \
|
||||
@@ -552,9 +608,9 @@ typedef enum {
|
||||
} \
|
||||
return &n->data; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _max)(const tree_t tree) \
|
||||
M_C(name, _max)(const tree_t tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
node_t *n = tree->node; \
|
||||
@@ -565,82 +621,84 @@ typedef enum {
|
||||
} \
|
||||
return &n->data; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cmin)(const tree_t tree) \
|
||||
M_C(name, _cmin)(const tree_t tree) \
|
||||
{ \
|
||||
return M_CONST_CAST(type, M_C(name, _min)(tree)); \
|
||||
return M_CONST_CAST(type, M_C(name, _min)(tree)); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cmax)(const tree_t tree) \
|
||||
M_C(name, _cmax)(const tree_t tree) \
|
||||
{ \
|
||||
return M_CONST_CAST(type, M_C(name, _max)(tree)); \
|
||||
return M_CONST_CAST(type, M_C(name, _max)(tree)); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _get)(const tree_t tree, type const data) \
|
||||
M_C(name, _get)(const tree_t tree, type const data) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
node_t *n = tree->node; \
|
||||
/* Go down the tree */ \
|
||||
while (n != NULL) { \
|
||||
RBTREEI_CONTRACT_NODE (n); \
|
||||
int cmp = M_CALL_CMP(oplist, n->data, data); \
|
||||
if (cmp == 0) { \
|
||||
return &n->data; \
|
||||
} else if (cmp > 0) { \
|
||||
n = n->child[0]; \
|
||||
} else { \
|
||||
n = n->child[1]; \
|
||||
/* Go left (if cmp > 0) or right (if cmp < 0) */ \
|
||||
n = n->child[cmp < 0]; \
|
||||
} \
|
||||
} \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cget)(const tree_t tree, type const data) \
|
||||
M_C(name, _cget)(const tree_t tree, type const data) \
|
||||
{ \
|
||||
return M_CONST_CAST(type, M_C(name, _get)(tree, data)); \
|
||||
return M_CONST_CAST(type, M_C(name, _get)(tree, data)); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
/* Create a copy of the given node (recursively) */ \
|
||||
static inline node_t * \
|
||||
M_C(name, _int_copyn)(const node_t *o) \
|
||||
M_C(name, _int_copyn)(const node_t *o) \
|
||||
{ \
|
||||
if (o == NULL) return NULL; \
|
||||
node_t *n = M_C(name,_int_new)(); \
|
||||
node_t *n = M_C(name,_int_new)(); \
|
||||
if (M_UNLIKELY (n == NULL) ) { \
|
||||
M_MEMORY_FULL (sizeof (node_t)); \
|
||||
return NULL; \
|
||||
} \
|
||||
M_CALL_INIT_SET(oplist, n->data, o->data); \
|
||||
n->child[0] = M_C(name, _int_copyn)(o->child[0]); \
|
||||
n->child[1] = M_C(name, _int_copyn)(o->child[1]); \
|
||||
n->child[0] = M_C(name, _int_copyn)(o->child[0]); \
|
||||
n->child[1] = M_C(name, _int_copyn)(o->child[1]); \
|
||||
RBTREEI_COPY_COLOR (n, o); \
|
||||
return n; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(tree_t tree, const tree_t ref) \
|
||||
M_C(name, _init_set)(tree_t tree, const tree_t ref) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (ref); \
|
||||
assert (tree != NULL && tree != ref); \
|
||||
tree->size = ref->size; \
|
||||
tree->node = M_C(name, _int_copyn)(ref->node); \
|
||||
/* Copy the root node recursively */ \
|
||||
tree->node = M_C(name, _int_copyn)(ref->node); \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(tree_t tree, const tree_t ref) \
|
||||
M_C(name, _set)(tree_t tree, const tree_t ref) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
RBTREEI_CONTRACT (ref); \
|
||||
if (tree == ref) return; \
|
||||
M_C(name,_clear)(tree); \
|
||||
M_C(name,_init_set)(tree, ref); \
|
||||
M_C(name,_clear)(tree); \
|
||||
M_C(name,_init_set)(tree, ref); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(tree_t tree, tree_t ref) \
|
||||
M_C(name, _init_move)(tree_t tree, tree_t ref) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (ref); \
|
||||
assert (tree != NULL && tree != ref); \
|
||||
@@ -652,18 +710,18 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(tree_t tree, tree_t ref) \
|
||||
M_C(name, _move)(tree_t tree, tree_t ref) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
RBTREEI_CONTRACT (ref); \
|
||||
assert (tree != ref); \
|
||||
M_C(name,_clear)(tree); \
|
||||
M_C(name,_init_move)(tree, ref); \
|
||||
M_C(name,_clear)(tree); \
|
||||
M_C(name,_init_move)(tree, ref); \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(tree_t tree1, tree_t tree2) \
|
||||
M_C(name, _swap)(tree_t tree1, tree_t tree2) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree1); \
|
||||
RBTREEI_CONTRACT (tree2); \
|
||||
@@ -674,7 +732,7 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const tree_t tree) \
|
||||
M_C(name, _empty_p)(const tree_t tree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT (tree); \
|
||||
return tree->size == 0; \
|
||||
@@ -682,7 +740,7 @@ typedef enum {
|
||||
\
|
||||
/* Take care of the case n == NULL too */ \
|
||||
static inline bool \
|
||||
M_C(name, _int_is_black)(const node_t *n) \
|
||||
M_C(name, _int_is_black)(const node_t *n) \
|
||||
{ \
|
||||
return (n == NULL) ? true : RBTREEI_IS_BLACK(n); \
|
||||
} \
|
||||
@@ -694,7 +752,7 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
static inline node_t * \
|
||||
M_C(name, _int_rotate)(node_t *pp, node_t *ppp, const bool right) \
|
||||
M_C(name, _int_rotate)(node_t *pp, node_t *ppp, const bool right) \
|
||||
{ \
|
||||
assert (pp != NULL && ppp != NULL); \
|
||||
bool left = !right; \
|
||||
@@ -709,12 +767,13 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
M_IF_DEBUG( \
|
||||
/* Compute the depth of a node */ \
|
||||
static size_t \
|
||||
M_C(name, _int_depth)(const node_t *n) \
|
||||
M_C(name, _int_depth)(const node_t *n) \
|
||||
{ \
|
||||
if (n == NULL) return 1; \
|
||||
return RBTREEI_IS_BLACK (n) \
|
||||
+ M_C(name, _int_depth)(n->child[0]); \
|
||||
+ M_C(name, _int_depth)(n->child[0]); \
|
||||
} \
|
||||
) \
|
||||
\
|
||||
@@ -732,8 +791,8 @@ typedef enum {
|
||||
tab[cpt] = n; \
|
||||
while (n != NULL) { \
|
||||
RBTREEI_CONTRACT_NODE (n); \
|
||||
assert(M_C(name, _int_depth)(n->child[0]) \
|
||||
== M_C(name, _int_depth)(n->child[1])); \
|
||||
assert(M_C(name, _int_depth)(n->child[0]) \
|
||||
== M_C(name, _int_depth)(n->child[1])); \
|
||||
int cmp = M_CALL_CMP(oplist, n->data, key); \
|
||||
if (cmp == 0) { \
|
||||
break; \
|
||||
@@ -763,8 +822,8 @@ typedef enum {
|
||||
while (v != NULL) { \
|
||||
/* Always left node */ \
|
||||
RBTREEI_CONTRACT_NODE (v); \
|
||||
assert(M_C(name, _int_depth)(v->child[0]) \
|
||||
== M_C(name, _int_depth)(v->child[1])); \
|
||||
assert(M_C(name, _int_depth)(v->child[0]) \
|
||||
== M_C(name, _int_depth)(v->child[1])); \
|
||||
which[cpt++] = 0; \
|
||||
v = v->child[0]; \
|
||||
assert (cpt < RBTREEI_MAX_STACK); \
|
||||
@@ -842,10 +901,10 @@ typedef enum {
|
||||
rbtreei_color_e p_color = RBTREEI_GET_COLOR (p); \
|
||||
if (childIsRight != nbChild) { \
|
||||
/* left-left or right-right case */ \
|
||||
p = M_C(name, _int_rotate) (p, tab[cpt-1], childIsRight); \
|
||||
p = M_C(name, _int_rotate) (p, tab[cpt-1], childIsRight); \
|
||||
} else { \
|
||||
s = M_C(name, _int_rotate) (s, p, childIsRight); \
|
||||
p = M_C(name, _int_rotate) (p, tab[cpt-1], !nbChild); \
|
||||
s = M_C(name, _int_rotate) (s, p, childIsRight); \
|
||||
p = M_C(name, _int_rotate) (p, tab[cpt-1], !nbChild); \
|
||||
} \
|
||||
RBTREEI_SET_COLOR(p, p_color); \
|
||||
assert(p->child[0] != NULL && p->child[1] != NULL); \
|
||||
@@ -886,22 +945,22 @@ typedef enum {
|
||||
structuraly different but functionnaly equal (you get this by \
|
||||
constructing the tree in a different way). We have to \
|
||||
compare the ordered value within the tree. */ \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
M_C(name, _it)(it2, t2); \
|
||||
while (!M_C(name, _end_p)(it1) \
|
||||
&& !M_C(name, _end_p)(it2)) { \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
type const *ref2 = M_C(name, _cref)(it2); \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
M_C(name, _it)(it2, t2); \
|
||||
while (!M_C(name, _end_p)(it1) \
|
||||
&& !M_C(name, _end_p)(it2)) { \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
type const *ref2 = M_C(name, _cref)(it2); \
|
||||
if (M_CALL_EQUAL(oplist, *ref1, *ref2) == false) \
|
||||
return false; \
|
||||
M_C(name, _next)(it1); \
|
||||
M_C(name, _next)(it2); \
|
||||
M_C(name, _next)(it1); \
|
||||
M_C(name, _next)(it2); \
|
||||
} \
|
||||
return M_C(name, _end_p)(it1) \
|
||||
&& M_C(name, _end_p)(it2); \
|
||||
return M_C(name, _end_p)(it1) \
|
||||
&& M_C(name, _end_p)(it2); \
|
||||
} \
|
||||
, /* NO EQUAL METHOD */ ) \
|
||||
\
|
||||
\
|
||||
M_IF_METHOD(HASH, oplist)( \
|
||||
static inline size_t M_C(name,_hash)(const tree_t t1) { \
|
||||
RBTREEI_CONTRACT(t1); \
|
||||
@@ -909,57 +968,57 @@ typedef enum {
|
||||
/* NOTE: We can't compute the hash directly for the same reason \
|
||||
than for EQUAL operator. */ \
|
||||
it_t it1; \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
while (!M_C(name, _end_p)(it1)) { \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
while (!M_C(name, _end_p)(it1)) { \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
M_HASH_UP(hash, M_CALL_HASH(oplist, *ref1)); \
|
||||
M_C(name, _next)(it1); \
|
||||
M_C(name, _next)(it1); \
|
||||
} \
|
||||
return M_HASH_FINAL (hash); \
|
||||
return M_HASH_FINAL (hash); \
|
||||
} \
|
||||
, /* NO HASH METHOD */ ) \
|
||||
\
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
tree_t const t1, bool append) { \
|
||||
tree_t const t1, bool append) { \
|
||||
RBTREEI_CONTRACT(t1); \
|
||||
assert(str != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
/* NOTE: The print is really naive, and not really efficient */ \
|
||||
bool commaToPrint = false; \
|
||||
it_t it1; \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
while (!M_C(name, _end_p)(it1)) { \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
while (!M_C(name, _end_p)(it1)) { \
|
||||
if (commaToPrint) \
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
commaToPrint = true; \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
M_CALL_GET_STR(oplist, str, *ref1, true); \
|
||||
M_C(name, _next)(it1); \
|
||||
M_C(name, _next)(it1); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
} \
|
||||
, /* NO GET_STR */ ) \
|
||||
\
|
||||
\
|
||||
M_IF_METHOD(OUT_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _out_str)(FILE *file, tree_t const rbtree) \
|
||||
M_C(name, _out_str)(FILE *file, tree_t const rbtree) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT(rbtree); \
|
||||
assert (file != NULL); \
|
||||
fputc ('[', file); \
|
||||
fputc ('[', file); \
|
||||
it_t it; \
|
||||
bool commaToPrint = false; \
|
||||
for (M_C(name, _it)(it, rbtree) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
M_C(name, _next)(it)){ \
|
||||
for (M_C(name, _it)(it, rbtree) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
M_C(name, _next)(it)){ \
|
||||
if (commaToPrint) \
|
||||
fputc (M_GET_SEPARATOR oplist, file); \
|
||||
commaToPrint = true; \
|
||||
type const *item = M_C(name, _cref)(it); \
|
||||
type const *item = M_C(name, _cref)(it); \
|
||||
M_CALL_OUT_STR(oplist, file, *item); \
|
||||
} \
|
||||
fputc (']', file); \
|
||||
fputc (']', file); \
|
||||
} \
|
||||
, /* no out_str */ ) \
|
||||
\
|
||||
@@ -969,7 +1028,7 @@ typedef enum {
|
||||
{ \
|
||||
RBTREEI_CONTRACT(rbtree); \
|
||||
assert (str != NULL); \
|
||||
M_C(name,_clean)(rbtree); \
|
||||
M_C(name,_clean)(rbtree); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
@@ -982,11 +1041,12 @@ typedef enum {
|
||||
do { \
|
||||
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
if (b == false || c == 0) goto exit; \
|
||||
M_C(name, _push)(rbtree, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
if (b == false || c == 0) goto exit_clear; \
|
||||
M_C(name, _push)(rbtree, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
success = (c == ']'); \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
exit: \
|
||||
if (endp) *endp = str; \
|
||||
return success; \
|
||||
@@ -999,8 +1059,8 @@ typedef enum {
|
||||
{ \
|
||||
RBTREEI_CONTRACT(rbtree); \
|
||||
assert (file != NULL); \
|
||||
M_C(name,_clean)(rbtree); \
|
||||
int c = fgetc(file); \
|
||||
M_C(name,_clean)(rbtree); \
|
||||
int c = fgetc(file); \
|
||||
if (M_UNLIKELY (c != '[')) return false; \
|
||||
c = fgetc(file); \
|
||||
if (M_UNLIKELY (c == ']')) return true; \
|
||||
@@ -1011,37 +1071,36 @@ typedef enum {
|
||||
do { \
|
||||
bool b = M_CALL_IN_STR(oplist, item, file); \
|
||||
do { c = fgetc(file); } while (isspace(c)); \
|
||||
if (b == false || c == EOF) break; \
|
||||
M_C(name, _push)(rbtree, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
if (b == false || c == EOF) break; \
|
||||
M_C(name, _push)(rbtree, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
return c == ']'; \
|
||||
} \
|
||||
, /* no in_str */ ) \
|
||||
\
|
||||
\
|
||||
\
|
||||
M_IF_METHOD(OUT_SERIAL, oplist)( \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, tree_t const t1) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT(t1); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
const M_C(name, _type_t) *item; \
|
||||
bool first_done = false; \
|
||||
it_t it; \
|
||||
ret = f->m_interface->write_array_start(local, f, t1->size); \
|
||||
ret = f->m_interface->write_array_start(local, f, t1->size); \
|
||||
for (M_C(name, _it)(it, t1) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
M_C(name, _next)(it)){ \
|
||||
item = M_C(name, _cref)(it); \
|
||||
if (first_done) \
|
||||
ret |= f->m_interface->write_array_next(local, f); \
|
||||
ret |= f->m_interface->write_array_next(local, f); \
|
||||
ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \
|
||||
first_done = true; \
|
||||
} \
|
||||
ret |= f->m_interface->write_array_end(local, f); \
|
||||
ret |= f->m_interface->write_array_end(local, f); \
|
||||
return ret & M_SERIAL_FAIL; \
|
||||
} \
|
||||
, /* no OUT_SERIAL */ ) \
|
||||
@@ -1051,13 +1110,13 @@ typedef enum {
|
||||
M_C(name, _in_serial)(tree_t t1, m_serial_read_t f) \
|
||||
{ \
|
||||
RBTREEI_CONTRACT(t1); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
size_t estimated_size = 0; \
|
||||
type key; \
|
||||
M_C(name,_clean)(t1); \
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
|
||||
type key; \
|
||||
M_C(name,_clean)(t1); \
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
|
||||
M_CALL_INIT(oplist, key); \
|
||||
do { \
|
||||
|
||||
+9
-19
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Serial BIN
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -87,22 +87,17 @@ m_serial_bin_write_float(m_serial_write_t serial, const long double data, const
|
||||
size_t n;
|
||||
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
switch (size_of_type) {
|
||||
case sizeof f1:
|
||||
if (size_of_type == sizeof f1) {
|
||||
f1 = data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &f1), sizeof f1, 1, f);
|
||||
break;
|
||||
case sizeof f2:
|
||||
} else if (size_of_type == sizeof f2) {
|
||||
f2 = data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &f2), sizeof f2, 1, f);
|
||||
break;
|
||||
case sizeof f3:
|
||||
} else if (size_of_type == sizeof f3) {
|
||||
f3 = data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &f3), sizeof f3, 1, f);
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
M_ASSERT_INIT(false, "a float of suitable size");
|
||||
break;
|
||||
}
|
||||
return n == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
}
|
||||
@@ -323,22 +318,17 @@ m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
|
||||
long double f3;
|
||||
size_t n;
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
switch (size_of_type) {
|
||||
case sizeof f1:
|
||||
if (size_of_type == sizeof f1) {
|
||||
n = fread (M_ASSIGN_CAST(void*, &f1), sizeof f1, 1, f);
|
||||
*r = f1;
|
||||
break;
|
||||
case sizeof f2:
|
||||
} else if (size_of_type == sizeof f2) {
|
||||
n = fread (M_ASSIGN_CAST(void*, &f2), sizeof f2, 1, f);
|
||||
*r = f2;
|
||||
break;
|
||||
case sizeof f3:
|
||||
} else if (size_of_type == sizeof f3) {
|
||||
n = fread (M_ASSIGN_CAST(void*, &f3), sizeof f3, 1, f);
|
||||
*r = f3;
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
M_ASSERT_INIT(false, "a float of suitable size");
|
||||
break;
|
||||
}
|
||||
return n == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
}
|
||||
|
||||
+19
-3
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Serial JSON
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -232,7 +232,7 @@ m_serial_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
return n > 0 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
}
|
||||
|
||||
/* The exported interface. */
|
||||
/* The internal exported interface of m_serial_write_json. */
|
||||
static const m_serial_write_interface_t m_serial_write_json_interface = {
|
||||
m_serial_json_write_boolean,
|
||||
m_serial_json_write_integer,
|
||||
@@ -252,19 +252,27 @@ static const m_serial_write_interface_t m_serial_write_json_interface = {
|
||||
m_serial_json_write_variant_end
|
||||
};
|
||||
|
||||
/* Initialize the JSON serial object for writing any object to JSON format in the given FILE */
|
||||
static inline void m_serial_json_write_init(m_serial_write_t serial, FILE *f)
|
||||
{
|
||||
serial->m_interface = &m_serial_write_json_interface;
|
||||
serial->data[0].p = M_ASSIGN_CAST(void*, f);
|
||||
}
|
||||
|
||||
/* CLear the JSON serial object for writing*/
|
||||
static inline void m_serial_json_write_clear(m_serial_write_t serial)
|
||||
{
|
||||
(void) serial; // Nothing to do
|
||||
}
|
||||
|
||||
/* Define a synonym to the JSON serializer with a proper OPLIST */
|
||||
typedef m_serial_write_t m_serial_json_write_t;
|
||||
#define M_OPL_m_serial_json_write_t() \
|
||||
(INIT_WITH(m_serial_json_write_init), CLEAR(m_serial_json_write_clear), TYPE(m_serial_json_write_t) )
|
||||
|
||||
/* Helper function */
|
||||
|
||||
|
||||
/* Helper function to skip a space */
|
||||
static inline int
|
||||
m_serial_json_read_skip (FILE *f)
|
||||
{
|
||||
@@ -528,15 +536,23 @@ static const m_serial_read_interface_t m_serial_json_read_interface = {
|
||||
m_serial_json_read_variant_end
|
||||
};
|
||||
|
||||
/* Initialize the JSON serial object for reading any object from JSON format in the given FILE */
|
||||
static inline void m_serial_json_read_init(m_serial_read_t serial, FILE *f)
|
||||
{
|
||||
serial->m_interface = &m_serial_json_read_interface;
|
||||
serial->data[0].p = M_ASSIGN_CAST(void*, f);
|
||||
}
|
||||
|
||||
/* Clear the JSON serial object for reading from the FILE */
|
||||
static inline void m_serial_json_read_clear(m_serial_read_t serial)
|
||||
{
|
||||
(void) serial; // Nothing to do
|
||||
}
|
||||
|
||||
/* Define a synonym of m_serial_read_t
|
||||
to the JSON serializer with its proper OPLIST */
|
||||
typedef m_serial_read_t m_serial_json_read_t;
|
||||
#define M_OPL_m_serial_json_read_t() \
|
||||
(INIT_WITH(m_serial_json_read_init), CLEAR(m_serial_json_read_clear), TYPE(m_serial_json_read_t) )
|
||||
|
||||
#endif
|
||||
+44
-10
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SHARED Module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -34,7 +34,8 @@
|
||||
#define SHARED_PTR_OPLIST(...) \
|
||||
SHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
_OPLIST(__VA_ARGS__ )))
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define shared pointer and its function.
|
||||
USAGE: SHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
@@ -43,6 +44,7 @@
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_ATOMIC_OPLIST ), \
|
||||
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST)))
|
||||
|
||||
|
||||
/* Define relaxed shared pointer and its function (thread unsafe).
|
||||
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_RELAXED_DEF(name, ...) \
|
||||
@@ -50,6 +52,7 @@
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_INTEGER_OPLIST ), \
|
||||
(name, __VA_ARGS__ , SHAREDI_INTEGER_OPLIST)))
|
||||
|
||||
|
||||
/* Define shared resource and its function.
|
||||
This is a bounded pool of resource shared by multiple owners.
|
||||
USAGE: SHARED_RESOURCE_DEF(name, type, [, oplist]) */
|
||||
@@ -62,10 +65,18 @@
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
// deferred
|
||||
// deferred evaluation
|
||||
#define SHAREDI_PTR_OPLIST_P1(arg) SHAREDI_PTR_OPLIST_P2 arg
|
||||
|
||||
#define SHAREDI_PTR_OPLIST_P2(name, oplist) ( \
|
||||
/* Validation of the given oplist */
|
||||
#define SHAREDI_PTR_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_PTR_OPLIST_P3, SHAREDI_PTR_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define SHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_SHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
|
||||
#define SHAREDI_PTR_OPLIST_P3(name, oplist) ( \
|
||||
INIT(M_C(name, _init)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
@@ -74,14 +85,12 @@
|
||||
CLEAN(M_C(name, _clean)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(name, _swap)) \
|
||||
,TYPE(M_C(name, _t)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
)
|
||||
|
||||
// deferred
|
||||
#define SHAREDI_PTR_DEF_P1(arg) SHAREDI_PTR_DEF_P2 arg
|
||||
|
||||
// OPLIST to handle a counter of atomic type
|
||||
#define SHAREDI_ATOMIC_OPLIST (TYPE(atomic_int), \
|
||||
INIT_SET(atomic_init), \
|
||||
@@ -89,23 +98,38 @@
|
||||
SUB(atomic_fetch_sub), \
|
||||
IT_CREF(atomic_load))
|
||||
|
||||
// OPLIST to handle a counter of non-atomic type with its helper functions.
|
||||
// OPLIST to handle a counter of non-atomic type
|
||||
#define SHAREDI_INTEGER_OPLIST (TYPE(int), \
|
||||
INIT_SET(sharedi_integer_init_set), \
|
||||
ADD(sharedi_integer_add), \
|
||||
SUB(sharedi_integer_sub), \
|
||||
IT_CREF(sharedi_integer_cref))
|
||||
|
||||
/* Atomic like interface for basic integers */
|
||||
static inline void sharedi_integer_init_set(int *p, int val) { *p = val; }
|
||||
static inline int sharedi_integer_add(int *p, int val) { int r = *p; *p += val; return r; }
|
||||
static inline int sharedi_integer_sub(int *p, int val) { int r = *p; *p -= val; return r; }
|
||||
static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
|
||||
/* Contract of a shared pointer */
|
||||
#define SHAREDI_CONTRACT(shared, cpt_oplist) do { \
|
||||
assert(shared != NULL); \
|
||||
assert(*shared == NULL || M_CALL_IT_CREF(cpt_oplist, &(*shared)->cpt) >= 1); \
|
||||
} while (0)
|
||||
|
||||
#define SHAREDI_PTR_DEF_P2(name, type, oplist, cpt_oplist) \
|
||||
// deferred evaluation
|
||||
#define SHAREDI_PTR_DEF_P1(arg) SHAREDI_PTR_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define SHAREDI_PTR_DEF_P2(name, type, oplist, cpt_oplist_t) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_PTR_DEF_P3, SHAREDI_PTR_DEF_FAILURE)(name, type, oplist, cpt_oplist_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SHAREDI_PTR_DEF_FAILURE(name, type, oplist, cpt_oplist) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Code generation */
|
||||
#define SHAREDI_PTR_DEF_P3(name, type, oplist, cpt_oplist) \
|
||||
\
|
||||
typedef struct M_C(name, _s){ \
|
||||
type *data; /* Pointer to the data */ \
|
||||
@@ -120,6 +144,8 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
struct M_C(name, _s) ptr; \
|
||||
} M_C(name, combine_t)[1]; \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(M_C(name, _t) shared) \
|
||||
{ \
|
||||
@@ -299,7 +325,15 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
// deferred
|
||||
#define SHAREDI_RESOURCE_DEF_P1(arg) SHAREDI_RESOURCE_DEF_P2 arg
|
||||
|
||||
#define SHAREDI_RESOURCE_DEF_P2(name, type, oplist) \
|
||||
/* Validate the oplist before going further */
|
||||
#define SHAREDI_RESOURCE_DEF_P2(name, type, oplist) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_RESOURCE_DEF_P3, SHAREDI_RESOURCE_DEF_FAILURE)(name, type, oplist)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SHAREDI_RESOURCE_DEF_FAILURE(name, type, oplist) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_RESOURCE_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
#define SHAREDI_RESOURCE_DEF_P3(name, type, oplist) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _atype_s) { \
|
||||
|
||||
+49
-8
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SNAPSHOT Module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -36,6 +36,7 @@
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
|
||||
(name, __VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define a Single Producer Multiple Consummer snapshot and its functions
|
||||
USAGE: SNAPSHOT_SPMC_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_SPMC_DEF(name, ...) \
|
||||
@@ -43,6 +44,7 @@
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
|
||||
(name, __VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
|
||||
USAGE: SNAPSHOT_MPMC_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_MPMC_DEF(name, ...) \
|
||||
@@ -50,6 +52,7 @@
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
|
||||
(name, __VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define the oplist of a snapshot (SPSC, SPMC or MPMC).
|
||||
USAGE: SNAPSHOT_OPLIST(name[, oplist]) */
|
||||
#define SNAPSHOT_OPLIST(...) \
|
||||
@@ -63,8 +66,16 @@
|
||||
// deferred evaluation of the input
|
||||
#define SNAPSHOTI_OPLIST_P1(arg) SNAPSHOTI_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define SNAPSHOTI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_OPLIST_P3, SNAPSHOTI_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define SNAPSHOTI_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_SNAPSHOT_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
|
||||
/* Define the oplist of a snapshot */
|
||||
#define SNAPSHOTI_OPLIST_P2(name, oplist) \
|
||||
#define SNAPSHOTI_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,SET(M_C(name, _set)) \
|
||||
@@ -109,14 +120,22 @@
|
||||
SNAPSHOTI_SPSC_FLAGS_CONTRACT(f); \
|
||||
} while (0)
|
||||
|
||||
// Defered evaluation of the arguments.
|
||||
#define SNAPSHOTI_SPSC_DEF_P1(arg) SNAPSHOTI_SPSC_DEF_P2 arg
|
||||
|
||||
// A snapshot is basically an atomic triple buffer (Lock Free)
|
||||
// between a single producer thread and a single consummer thread.
|
||||
#define SNAPSHOTI_SPSC_MAX_BUFFER 3
|
||||
|
||||
#define SNAPSHOTI_SPSC_DEF_P2(name, type, oplist) \
|
||||
// Defered evaluation of the arguments.
|
||||
#define SNAPSHOTI_SPSC_DEF_P1(arg) SNAPSHOTI_SPSC_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define SNAPSHOTI_SPSC_DEF_P2(name, type, oplist) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_SPSC_DEF_P3, SNAPSHOTI_SPSC_DEF_FAILURE)(name, type, oplist)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SNAPSHOTI_SPSC_DEF_FAILURE(name, type, oplist) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_SPSC_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
#define SNAPSHOTI_SPSC_DEF_P3(name, type, oplist) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _aligned_type_s) { \
|
||||
@@ -133,6 +152,8 @@
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void M_C(name, _init)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
assert(snap != NULL); \
|
||||
@@ -490,7 +511,15 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in
|
||||
// Defered evaluation
|
||||
#define SNAPSHOTI_SPMC_DEF_P1(arg) SNAPSHOTI_SPMC_DEF_P2 arg
|
||||
|
||||
#define SNAPSHOTI_SPMC_DEF_P2(name, type, oplist) \
|
||||
/* Validate the oplist before going further */
|
||||
#define SNAPSHOTI_SPMC_DEF_P2(name, type, oplist) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_SPMC_DEF_P3, SNAPSHOTI_SPMC_DEF_FAILURE)(name, type, oplist)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SNAPSHOTI_SPMC_DEF_FAILURE(name, type, oplist) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_SPMC_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
#define SNAPSHOTI_SPMC_DEF_P3(name, type, oplist) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _aligned_type_s) { \
|
||||
@@ -505,6 +534,8 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void M_C(name, _init)(M_C(name, _t) snap, size_t nReader) \
|
||||
{ \
|
||||
assert (snap != NULL); \
|
||||
@@ -579,7 +610,15 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in
|
||||
// Defered evaluation
|
||||
#define SNAPSHOTI_MPMC_DEF_P1(arg) SNAPSHOTI_MPMC_DEF_P2 arg
|
||||
|
||||
#define SNAPSHOTI_MPMC_DEF_P2(name, type, oplist) \
|
||||
/* Validate the oplist before going further */
|
||||
#define SNAPSHOTI_MPMC_DEF_P2(name, type, oplist) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_MPMC_DEF_P3, SNAPSHOTI_MPMC_DEF_FAILURE)(name, type, oplist)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SNAPSHOTI_MPMC_DEF_FAILURE(name, type, oplist) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_MPMC_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
#define SNAPSHOTI_MPMC_DEF_P3(name, type, oplist) \
|
||||
\
|
||||
SNAPSHOTI_SPMC_DEF_P1((M_C(name, _mrsw), type, oplist)) \
|
||||
\
|
||||
@@ -589,6 +628,8 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void M_C(name, _init)(M_C(name, _t) snap, size_t nReader, size_t nWriter) \
|
||||
{ \
|
||||
M_C(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \
|
||||
|
||||
+241
-19
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Dynamic Size String Module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -81,21 +81,29 @@ typedef union string_union_u {
|
||||
string_heap_t heap;
|
||||
string_stack_t stack;
|
||||
} string_union_t;
|
||||
// main structure
|
||||
|
||||
// Dynamic string
|
||||
typedef struct string_s {
|
||||
string_union_t u;
|
||||
char *ptr;
|
||||
} string_t[1];
|
||||
|
||||
// Pointer to a Dynamic string
|
||||
typedef struct string_s *string_ptr;
|
||||
|
||||
// Constant pointer to a Dynamic string
|
||||
typedef const struct string_s *string_srcptr;
|
||||
|
||||
/* Input option for the fgets function */
|
||||
/* Input option for string_fgets
|
||||
STRING_READ_LINE (read line),
|
||||
STRING_READ_PURE_LINE (read line and remove CR and LF)
|
||||
STRING_READ_FILE (read all file)
|
||||
*/
|
||||
typedef enum string_fgets_s {
|
||||
STRING_READ_LINE = 0, STRING_READ_PURE_LINE = 1, STRING_READ_FILE = 2
|
||||
} string_fgets_t;
|
||||
|
||||
/* Test if the string is stack based or heap based */
|
||||
/* Internal method to test if the string is stack based or heap based */
|
||||
static inline bool
|
||||
stringi_stack_p(const string_t s)
|
||||
{
|
||||
@@ -115,6 +123,7 @@ stringi_set_size(string_t s, size_t size)
|
||||
s->u.heap.size = size;
|
||||
}
|
||||
|
||||
/* Return the number of characters of the string */
|
||||
static inline size_t
|
||||
string_size(const string_t s)
|
||||
{
|
||||
@@ -125,6 +134,7 @@ string_size(const string_t s)
|
||||
return stringi_stack_p(s) ? s_stack : s_heap;
|
||||
}
|
||||
|
||||
/* Return the capacity of the string */
|
||||
static inline size_t
|
||||
string_capacity(const string_t s)
|
||||
{
|
||||
@@ -145,6 +155,7 @@ stringi_get_str(string_t v)
|
||||
return stringi_stack_p(v) ? ptr_stack : ptr_heap;
|
||||
}
|
||||
|
||||
/* Return the string view a classic C string (const char *) */
|
||||
static inline const char*
|
||||
string_get_cstr(const string_t v)
|
||||
{
|
||||
@@ -155,6 +166,8 @@ string_get_cstr(const string_t v)
|
||||
return stringi_stack_p(v) ? ptr_stack : ptr_heap;
|
||||
}
|
||||
|
||||
/* Initialize the dynamic string (constructor)
|
||||
and make it empty */
|
||||
static inline void
|
||||
string_init(string_t s)
|
||||
{
|
||||
@@ -164,6 +177,7 @@ string_init(string_t s)
|
||||
STRINGI_CONTRACT(s);
|
||||
}
|
||||
|
||||
/* Clear the Dynamic string (destructor) */
|
||||
static inline void
|
||||
string_clear(string_t v)
|
||||
{
|
||||
@@ -180,8 +194,10 @@ string_clear(string_t v)
|
||||
/* NOTE: Internaly used by STRING_DECL_INIT */
|
||||
static inline void stringi_clear2(string_t *v) { string_clear(*v); }
|
||||
|
||||
/* NOTE: The ownership of the data is transfered back to the caller
|
||||
and the returned pointer has to be released by M_MEMORY_FREE. */
|
||||
/* Clear the Dynamic string (destructor)
|
||||
and return a heap pointer to the string.
|
||||
The ownership of the data is transfered back to the caller
|
||||
and the returned pointer has to be released by M_MEMORY_FREE. */
|
||||
static inline char *
|
||||
string_clear_get_str(string_t v)
|
||||
{
|
||||
@@ -206,6 +222,7 @@ string_clear_get_str(string_t v)
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Make the string empty */
|
||||
static inline void
|
||||
string_clean(string_t v)
|
||||
{
|
||||
@@ -215,6 +232,7 @@ string_clean(string_t v)
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Return the selected character of the string */
|
||||
static inline char
|
||||
string_get_char(const string_t v, size_t index)
|
||||
{
|
||||
@@ -223,6 +241,7 @@ string_get_char(const string_t v, size_t index)
|
||||
return string_get_cstr(v)[index];
|
||||
}
|
||||
|
||||
/* Test if the string is empty or not */
|
||||
static inline bool
|
||||
string_empty_p(const string_t v)
|
||||
{
|
||||
@@ -254,7 +273,7 @@ stringi_fit2size (string_t v, size_t size_alloc)
|
||||
char *ptr = M_MEMORY_REALLOC (char, v->ptr, alloc);
|
||||
if (M_UNLIKELY (ptr == NULL)) {
|
||||
M_MEMORY_FULL(sizeof (char) * alloc);
|
||||
// NOTE: Return is broken...
|
||||
// NOTE: Return is currently broken.
|
||||
abort();
|
||||
return NULL;
|
||||
}
|
||||
@@ -270,6 +289,8 @@ stringi_fit2size (string_t v, size_t size_alloc)
|
||||
return stringi_get_str(v);
|
||||
}
|
||||
|
||||
/* Modify the string capacity to be able to handle at least 'alloc'
|
||||
characters (including final nul char) */
|
||||
static inline void
|
||||
string_reserve(string_t v, size_t alloc)
|
||||
{
|
||||
@@ -304,6 +325,7 @@ string_reserve(string_t v, size_t alloc)
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Set the string to the C string str */
|
||||
static inline void
|
||||
string_set_str(string_t v, const char str[])
|
||||
{
|
||||
@@ -316,6 +338,7 @@ string_set_str(string_t v, const char str[])
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Set the string to the n first characters of the C string str */
|
||||
static inline void
|
||||
string_set_strn(string_t v, const char str[], size_t n)
|
||||
{
|
||||
@@ -330,6 +353,7 @@ string_set_strn(string_t v, const char str[], size_t n)
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Set the string to the other one */
|
||||
static inline void
|
||||
string_set (string_t v1, const string_t v2)
|
||||
{
|
||||
@@ -344,6 +368,7 @@ string_set (string_t v1, const string_t v2)
|
||||
STRINGI_CONTRACT (v1);
|
||||
}
|
||||
|
||||
/* Set the string to the n first characters of other one */
|
||||
static inline void
|
||||
string_set_n(string_t v, const string_t ref, size_t offset, size_t length)
|
||||
{
|
||||
@@ -358,6 +383,8 @@ string_set_n(string_t v, const string_t ref, size_t offset, size_t length)
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Initialize the string and set it to the other one
|
||||
(constructor) */
|
||||
static inline void
|
||||
string_init_set(string_t v1, const string_t v2)
|
||||
{
|
||||
@@ -365,6 +392,8 @@ string_init_set(string_t v1, const string_t v2)
|
||||
string_set(v1,v2);
|
||||
}
|
||||
|
||||
/* Initialize the string and set it to the C string
|
||||
(constructor) */
|
||||
static inline void
|
||||
string_init_set_str(string_t v1, const char str[])
|
||||
{
|
||||
@@ -372,6 +401,9 @@ string_init_set_str(string_t v1, const char str[])
|
||||
string_set_str(v1, str);
|
||||
}
|
||||
|
||||
/* Initialize the string, set it to the other one,
|
||||
and destroy the other one.
|
||||
(constructor & destructor) */
|
||||
static inline void
|
||||
string_init_move(string_t v1, string_t v2)
|
||||
{
|
||||
@@ -382,6 +414,7 @@ string_init_move(string_t v1, string_t v2)
|
||||
STRINGI_CONTRACT (v1);
|
||||
}
|
||||
|
||||
/* Swap the string */
|
||||
static inline void
|
||||
string_swap(string_t v1, string_t v2)
|
||||
{
|
||||
@@ -394,6 +427,9 @@ string_swap(string_t v1, string_t v2)
|
||||
STRINGI_CONTRACT (v2);
|
||||
}
|
||||
|
||||
/* Set the string to the other one,
|
||||
and destroy the other one.
|
||||
(destructor) */
|
||||
static inline void
|
||||
string_move(string_t v1, string_t v2)
|
||||
{
|
||||
@@ -401,6 +437,7 @@ string_move(string_t v1, string_t v2)
|
||||
string_init_move(v1,v2);
|
||||
}
|
||||
|
||||
/* Push a character in a string */
|
||||
static inline void
|
||||
string_push_back (string_t v, char c)
|
||||
{
|
||||
@@ -413,6 +450,7 @@ string_push_back (string_t v, char c)
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Concatene the string with the C string */
|
||||
static inline void
|
||||
string_cat_str(string_t v, const char str[])
|
||||
{
|
||||
@@ -426,6 +464,7 @@ string_cat_str(string_t v, const char str[])
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Concatene the string with the other string */
|
||||
static inline void
|
||||
string_cat(string_t v, const string_t v2)
|
||||
{
|
||||
@@ -442,6 +481,8 @@ string_cat(string_t v, const string_t v2)
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Compare the string to the C string and
|
||||
return the sort order (-1 if less, 0 if equal, 1 if greater) */
|
||||
static inline int
|
||||
string_cmp_str(const string_t v1, const char str[])
|
||||
{
|
||||
@@ -450,6 +491,8 @@ string_cmp_str(const string_t v1, const char str[])
|
||||
return strcmp(string_get_cstr(v1), str);
|
||||
}
|
||||
|
||||
/* Compare the string to the other string and
|
||||
return the sort order (-1 if less, 0 if equal, 1 if greater) */
|
||||
static inline int
|
||||
string_cmp(const string_t v1, const string_t v2)
|
||||
{
|
||||
@@ -458,6 +501,7 @@ string_cmp(const string_t v1, const string_t v2)
|
||||
return strcmp(string_get_cstr(v1), string_get_cstr(v2));
|
||||
}
|
||||
|
||||
/* Test if the string is equal to the given C string */
|
||||
static inline bool
|
||||
string_equal_str_p(const string_t v1, const char str[])
|
||||
{
|
||||
@@ -466,6 +510,7 @@ string_equal_str_p(const string_t v1, const char str[])
|
||||
return string_cmp_str(v1, str) == 0;
|
||||
}
|
||||
|
||||
/* Test if the string is equal to the other string */
|
||||
static inline bool
|
||||
string_equal_p(const string_t v1, const string_t v2)
|
||||
{
|
||||
@@ -475,16 +520,20 @@ string_equal_p(const string_t v1, const string_t v2)
|
||||
*/
|
||||
assert(v1 != NULL);
|
||||
assert(v2 != NULL);
|
||||
/* Optimization: both strings shall have at least the same size */
|
||||
return string_size(v1) == string_size(v2) && string_cmp(v1, v2) == 0;
|
||||
}
|
||||
|
||||
// Note: doesn't work with UTF-8 strings...
|
||||
/* Test if the string is equal to the C string
|
||||
(case insentive according to the current locale)
|
||||
Note: doesn't work with UTF-8 strings.
|
||||
*/
|
||||
static inline int
|
||||
string_cmpi_str(const string_t v1, const char p2[])
|
||||
{
|
||||
STRINGI_CONTRACT (v1);
|
||||
M_ASSUME (p2 != NULL);
|
||||
// strcasecmp is POSIX
|
||||
// strcasecmp is POSIX only
|
||||
const char *p1 = string_get_cstr(v1);
|
||||
int c1, c2;
|
||||
do {
|
||||
@@ -497,12 +546,21 @@ string_cmpi_str(const string_t v1, const char p2[])
|
||||
return c1 - c2;
|
||||
}
|
||||
|
||||
/* Test if the string is equal to the other string
|
||||
(case insentive according to the current locale)
|
||||
Note: doesn't work with UTF-8 strings.
|
||||
*/
|
||||
static inline int
|
||||
string_cmpi(const string_t v1, const string_t v2)
|
||||
{
|
||||
return string_cmpi_str(v1, string_get_cstr(v2));
|
||||
}
|
||||
|
||||
/* Search for the position of the character c
|
||||
from the position 'start' (include) in the string
|
||||
Return STRING_FAILURE if not found.
|
||||
By default, start is zero.
|
||||
*/
|
||||
static inline size_t
|
||||
string_search_char (const string_t v, char c, size_t start)
|
||||
{
|
||||
@@ -513,6 +571,11 @@ string_search_char (const string_t v, char c, size_t start)
|
||||
return p == NULL ? STRING_FAILURE : (size_t) (p-string_get_cstr(v));
|
||||
}
|
||||
|
||||
/* Reverse Search for the position of the character c
|
||||
from the position 'start' (include) in the string
|
||||
Return STRING_FAILURE if not found.
|
||||
By default, start is zero.
|
||||
*/
|
||||
static inline size_t
|
||||
string_search_rchar (const string_t v, char c, size_t start)
|
||||
{
|
||||
@@ -526,6 +589,9 @@ string_search_rchar (const string_t v, char c, size_t start)
|
||||
return p == NULL ? STRING_FAILURE : (size_t) (p-string_get_cstr(v));
|
||||
}
|
||||
|
||||
/* Search for the sub C string in the string from the position start
|
||||
Return STRING_FAILURE if not found.
|
||||
By default, start is zero. */
|
||||
static inline size_t
|
||||
string_search_str (const string_t v, const char str[], size_t start)
|
||||
{
|
||||
@@ -537,6 +603,9 @@ string_search_str (const string_t v, const char str[], size_t start)
|
||||
return p == NULL ? STRING_FAILURE : (size_t) (p-string_get_cstr(v));
|
||||
}
|
||||
|
||||
/* Search for the sub other string v2 in the string v1 from the position start
|
||||
Return STRING_FAILURE if not found.
|
||||
By default, start is zero. */
|
||||
static inline size_t
|
||||
string_search (const string_t v1, const string_t v2, size_t start)
|
||||
{
|
||||
@@ -545,6 +614,10 @@ string_search (const string_t v1, const string_t v2, size_t start)
|
||||
return string_search_str(v1, string_get_cstr(v2), start);
|
||||
}
|
||||
|
||||
/* Search for the first matching character in the given C string
|
||||
in the string v1 from the position start
|
||||
Return STRING_FAILURE if not found.
|
||||
By default, start is zero. */
|
||||
static inline size_t
|
||||
string_search_pbrk(const string_t v1, const char first_of[], size_t start)
|
||||
{
|
||||
@@ -556,6 +629,7 @@ string_search_pbrk(const string_t v1, const char first_of[], size_t start)
|
||||
return p == NULL ? STRING_FAILURE : (size_t) (p-string_get_cstr(v1));
|
||||
}
|
||||
|
||||
/* Compare the string to the C string using strcoll */
|
||||
static inline int
|
||||
string_strcoll_str(const string_t v, const char str[])
|
||||
{
|
||||
@@ -563,6 +637,7 @@ string_strcoll_str(const string_t v, const char str[])
|
||||
return strcoll(string_get_cstr(v), str);
|
||||
}
|
||||
|
||||
/* Compare the string to the other string using strcoll */
|
||||
static inline int
|
||||
string_strcoll (const string_t v1, const string_t v2)
|
||||
{
|
||||
@@ -570,6 +645,8 @@ string_strcoll (const string_t v1, const string_t v2)
|
||||
return string_strcoll_str(v1, string_get_cstr(v2));
|
||||
}
|
||||
|
||||
/* Return the number of bytes of the segment of s
|
||||
that consists entirely of bytes in accept */
|
||||
static inline size_t
|
||||
string_spn(const string_t v1, const char accept[])
|
||||
{
|
||||
@@ -578,6 +655,8 @@ string_spn(const string_t v1, const char accept[])
|
||||
return strspn(string_get_cstr(v1), accept);
|
||||
}
|
||||
|
||||
/* Return the number of bytes of the segment of s
|
||||
that consists entirely of bytes not in reject */
|
||||
static inline size_t
|
||||
string_cspn(const string_t v1, const char reject[])
|
||||
{
|
||||
@@ -586,6 +665,7 @@ string_cspn(const string_t v1, const char reject[])
|
||||
return strcspn(string_get_cstr(v1), reject);
|
||||
}
|
||||
|
||||
/* Return the string left truncated to the first 'index' bytes */
|
||||
static inline void
|
||||
string_left(string_t v, size_t index)
|
||||
{
|
||||
@@ -598,7 +678,7 @@ string_left(string_t v, size_t index)
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
// Note: this is an index, not the size to keep from the right !
|
||||
/* Return the string right truncated from the 'index' position to the last position */
|
||||
static inline void
|
||||
string_right(string_t v, size_t index)
|
||||
{
|
||||
@@ -617,6 +697,7 @@ string_right(string_t v, size_t index)
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Return the string from position index to size bytes */
|
||||
static inline void
|
||||
string_mid (string_t v, size_t index, size_t size)
|
||||
{
|
||||
@@ -624,6 +705,9 @@ string_mid (string_t v, size_t index, size_t size)
|
||||
string_left(v, size);
|
||||
}
|
||||
|
||||
/* Return in the string the C string str1 into the C string str2 from start
|
||||
By default, start is zero.
|
||||
*/
|
||||
static inline size_t
|
||||
string_replace_str (string_t v, const char str1[], const char str2[], size_t start)
|
||||
{
|
||||
@@ -646,6 +730,9 @@ string_replace_str (string_t v, const char str1[], const char str2[], size_t sta
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Return in the string the string str1 into the string str2 from start
|
||||
By default, start is zero.
|
||||
*/
|
||||
static inline size_t
|
||||
string_replace (string_t v, const string_t v1, const string_t v2, size_t start)
|
||||
{
|
||||
@@ -655,6 +742,8 @@ string_replace (string_t v, const string_t v1, const string_t v2, size_t start)
|
||||
return string_replace_str(v, string_get_cstr(v1), string_get_cstr(v2), start);
|
||||
}
|
||||
|
||||
/* Replace tin the string the sub-string at position 'pos' for 'len' bytes
|
||||
into the C string str2. */
|
||||
static inline void
|
||||
string_replace_at (string_t v, size_t pos, size_t len, const char str2[])
|
||||
{
|
||||
@@ -677,6 +766,7 @@ string_replace_at (string_t v, size_t pos, size_t len, const char str2[])
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Format in the string the given printf format */
|
||||
static inline int
|
||||
string_printf (string_t v, const char format[], ...)
|
||||
{
|
||||
@@ -706,6 +796,7 @@ string_printf (string_t v, const char format[], ...)
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Append to the string the formatted string of the given printf format */
|
||||
static inline int
|
||||
string_cat_printf (string_t v, const char format[], ...)
|
||||
{
|
||||
@@ -740,6 +831,7 @@ string_cat_printf (string_t v, const char format[], ...)
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Get a line/pureline/file from the FILE and store it in the string */
|
||||
static inline bool
|
||||
string_fgets(string_t v, FILE *f, string_fgets_t arg)
|
||||
{
|
||||
@@ -774,6 +866,10 @@ string_fgets(string_t v, FILE *f, string_fgets_t arg)
|
||||
return retcode; /* Abnormal terminaison */
|
||||
}
|
||||
|
||||
/* Get a word from the FILE and store it in the string.
|
||||
Words are supposed to be separated each other by the given list of separator
|
||||
separator shall be a CONSTANT C array.
|
||||
*/
|
||||
static inline bool
|
||||
string_fget_word (string_t v, const char separator[], FILE *f)
|
||||
{
|
||||
@@ -827,6 +923,7 @@ string_fget_word (string_t v, const char separator[], FILE *f)
|
||||
return retcode;
|
||||
}
|
||||
|
||||
/* Put the string in the given FILE without formatting */
|
||||
static inline bool
|
||||
string_fputs(FILE *f, const string_t v)
|
||||
{
|
||||
@@ -835,6 +932,7 @@ string_fputs(FILE *f, const string_t v)
|
||||
return fputs(string_get_cstr(v), f) >= 0;
|
||||
}
|
||||
|
||||
/* Test if the string starts with the given C string */
|
||||
static inline bool
|
||||
string_start_with_str_p(const string_t v, const char str[])
|
||||
{
|
||||
@@ -850,6 +948,7 @@ string_start_with_str_p(const string_t v, const char str[])
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Test if the string starts with the other string */
|
||||
static inline bool
|
||||
string_start_with_string_p(const string_t v, const string_t v2)
|
||||
{
|
||||
@@ -857,6 +956,7 @@ string_start_with_string_p(const string_t v, const string_t v2)
|
||||
return string_start_with_str_p (v, string_get_cstr(v2));
|
||||
}
|
||||
|
||||
/* Test if the string ends with the C string */
|
||||
static inline bool
|
||||
string_end_with_str_p(const string_t v, const char str[])
|
||||
{
|
||||
@@ -874,6 +974,7 @@ string_end_with_str_p(const string_t v, const char str[])
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Test if the string ends with the other string */
|
||||
static inline bool
|
||||
string_end_with_string_p(const string_t v, const string_t v2)
|
||||
{
|
||||
@@ -881,6 +982,7 @@ string_end_with_string_p(const string_t v, const string_t v2)
|
||||
return string_end_with_str_p (v, string_get_cstr(v2));
|
||||
}
|
||||
|
||||
/* Compute a hash for the string */
|
||||
static inline size_t
|
||||
string_hash(const string_t v)
|
||||
{
|
||||
@@ -899,6 +1001,8 @@ stringi_strim_char(char c, const char charac[])
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Remove any characters from charac that are present
|
||||
in the begining of the string and the end of the string. */
|
||||
static inline void
|
||||
string_strim(string_t v, const char charac[])
|
||||
{
|
||||
@@ -920,12 +1024,14 @@ string_strim(string_t v, const char charac[])
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Test if the string is equal to the OOR value */
|
||||
static inline bool
|
||||
string_oor_equal_p(const string_t s, unsigned char n)
|
||||
{
|
||||
return (s->ptr == NULL) & (s->u.heap.alloc == ~(size_t)n);
|
||||
}
|
||||
|
||||
/* Set the unitialized string to the OOR value */
|
||||
static inline void
|
||||
string_oor_set(string_t s, unsigned char n)
|
||||
{
|
||||
@@ -938,6 +1044,9 @@ string_oor_set(string_t s, unsigned char n)
|
||||
Replace " by \" within the string (and \ to \\)
|
||||
\n, \t & \r by their standard representation
|
||||
and other not printable character with \0xx */
|
||||
|
||||
/* Transform the string 'v2' into a formatted string
|
||||
and set it to (or append in) the string 'v'. */
|
||||
static inline void
|
||||
string_get_str(string_t v, const string_t v2, bool append)
|
||||
{
|
||||
@@ -988,6 +1097,8 @@ string_get_str(string_t v, const string_t v2, bool append)
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Transform the string 'v2' into a formatted string
|
||||
and output it in the given FILE */
|
||||
static inline void
|
||||
string_out_str(FILE *f, const string_t v)
|
||||
{
|
||||
@@ -1022,6 +1133,9 @@ string_out_str(FILE *f, const string_t v)
|
||||
fputc('"', f);
|
||||
}
|
||||
|
||||
/* Read the formatted string from the FILE
|
||||
and set the converted value in the string 'v'.
|
||||
Return true in case of success */
|
||||
static inline bool
|
||||
string_in_str(string_t v, FILE *f)
|
||||
{
|
||||
@@ -1066,6 +1180,11 @@ string_in_str(string_t v, FILE *f)
|
||||
return c == '"';
|
||||
}
|
||||
|
||||
/* Read the formatted string from the C string
|
||||
and set the converted value in the string 'v'.
|
||||
Return true in case of success
|
||||
If endptr is not null, update the position of the parsing.
|
||||
*/
|
||||
static inline bool
|
||||
string_parse_str(string_t v, const char str[], const char **endptr)
|
||||
{
|
||||
@@ -1114,6 +1233,10 @@ string_parse_str(string_t v, const char str[], const char **endptr)
|
||||
return success;
|
||||
}
|
||||
|
||||
/* Transform the string 'v2' into a formatted string
|
||||
and output it in the given serializer
|
||||
See serialization for return code.
|
||||
*/
|
||||
static inline m_serial_return_code_t
|
||||
string_out_serial(m_serial_write_t serial, const string_t v)
|
||||
{
|
||||
@@ -1121,6 +1244,10 @@ string_out_serial(m_serial_write_t serial, const string_t v)
|
||||
return serial->m_interface->write_string(serial, string_get_cstr(v));
|
||||
}
|
||||
|
||||
/* Read the formatted string from the serializer
|
||||
and set the converted value in the string 'v'.
|
||||
See serialization for return code.
|
||||
*/
|
||||
static inline m_serial_return_code_t
|
||||
string_in_serial(string_t v, m_serial_read_t serial)
|
||||
{
|
||||
@@ -1128,7 +1255,7 @@ string_in_serial(string_t v, m_serial_read_t serial)
|
||||
return serial->m_interface->read_string(serial, v);
|
||||
}
|
||||
|
||||
/* UTF8 Handling */
|
||||
/* State of the UTF8 decoding machine state */
|
||||
typedef enum {
|
||||
STRINGI_UTF8_STARTING = 0,
|
||||
STRINGI_UTF8_DECODING_1 = 8,
|
||||
@@ -1137,7 +1264,10 @@ typedef enum {
|
||||
STRINGI_UTF8_ERROR = 32
|
||||
} stringi_utf8_state_e;
|
||||
|
||||
/* An unicode value */
|
||||
typedef unsigned int string_unicode_t;
|
||||
|
||||
/* Error in case of decoding */
|
||||
#define STRING_UNICODE_ERROR (-1U)
|
||||
|
||||
/* UTF8 character classification:
|
||||
@@ -1158,7 +1288,8 @@ typedef unsigned int string_unicode_t;
|
||||
* 3|I2IIIIII
|
||||
* I|IIIIIIII
|
||||
*/
|
||||
/* The use of a string allows the compiler/linker to factorize it. */
|
||||
|
||||
/* The use of a string enables the compiler/linker to factorize it. */
|
||||
#define STRINGI_UTF8_STATE_TAB \
|
||||
"\000\040\010\020\030\040\040\040" \
|
||||
"\040\000\040\040\040\040\040\040" \
|
||||
@@ -1266,6 +1397,30 @@ string_it(string_it_t it, const string_t str)
|
||||
it->u = 0;
|
||||
}
|
||||
|
||||
/* Set the iterator to the end of string
|
||||
The iterator references therefore nothong.
|
||||
*/
|
||||
static inline void
|
||||
string_it_end(string_it_t it, const string_t str)
|
||||
{
|
||||
STRINGI_CONTRACT(str);
|
||||
assert(it != NULL);
|
||||
it->ptr = &string_get_cstr(str)[string_size(str)];
|
||||
it->next_ptr = 0;
|
||||
it->u = 0;
|
||||
}
|
||||
|
||||
/* Set the iterator to the same position than the other one */
|
||||
static inline void
|
||||
string_it_set(string_it_t it, const string_it_t itsrc)
|
||||
{
|
||||
assert(it != NULL && itsrc != NULL);
|
||||
it->ptr = itsrc->ptr;
|
||||
it->next_ptr = itsrc->next_ptr;
|
||||
it->u = itsrc->u;
|
||||
}
|
||||
|
||||
/* Test if the iterator has reached the end of the string */
|
||||
static inline bool
|
||||
string_end_p (string_it_t it)
|
||||
{
|
||||
@@ -1284,6 +1439,17 @@ string_end_p (string_it_t it)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Test if the iterator is equal to the other one */
|
||||
static inline bool
|
||||
string_it_equal_p(const string_it_t it1, const string_it_t it2)
|
||||
{
|
||||
assert(it1 != NULL && it2 != NULL);
|
||||
// IT1.ptr == IT2.ptr ==> IT1 == IT2 ==> All fields are equal
|
||||
assert(it1->ptr != it2->ptr || (it1->next_ptr == it2->next_ptr && it1->u == it2->u));
|
||||
return it1->ptr == it2->ptr;
|
||||
}
|
||||
|
||||
/* Advance the iterator to the next UTF8 unicode character */
|
||||
static inline void
|
||||
string_next (string_it_t it)
|
||||
{
|
||||
@@ -1291,6 +1457,7 @@ string_next (string_it_t it)
|
||||
it->ptr = it->next_ptr;
|
||||
}
|
||||
|
||||
/* Return the unicode value associated to the iterator */
|
||||
static inline string_unicode_t
|
||||
string_get_cref (const string_it_t it)
|
||||
{
|
||||
@@ -1298,6 +1465,14 @@ string_get_cref (const string_it_t it)
|
||||
return it->u;
|
||||
}
|
||||
|
||||
/* Return the unicode value associated to the iterator */
|
||||
static inline const string_unicode_t *
|
||||
string_cref (const string_it_t it)
|
||||
{
|
||||
assert (it != NULL);
|
||||
return &it->u;
|
||||
}
|
||||
|
||||
/* Push unicode into string, encoding it in UTF8 */
|
||||
static inline void
|
||||
string_push_u (string_t str, string_unicode_t u)
|
||||
@@ -1383,10 +1558,11 @@ string_utf8_p(string_t str)
|
||||
.ptr = s}})
|
||||
which produces faster code.
|
||||
Note: This code doesn't work with C++ (use of c99 feature
|
||||
of recursive struct definition). As such, there is a separate
|
||||
C++ definition.
|
||||
of recursive struct definition and compound literral).
|
||||
As such, there is a separate C++ definition.
|
||||
*/
|
||||
#ifndef __cplusplus
|
||||
/* Initialize a constant string with the given C string */
|
||||
# define STRING_CTE(s) \
|
||||
((const string_t){{.u.heap = { .size = sizeof(s)-1, .alloc = sizeof(s) } , \
|
||||
.ptr = ((struct { long long _n; char _d[sizeof (s)]; }){ 0, s })._d }})
|
||||
@@ -1408,17 +1584,34 @@ namespace m_string {
|
||||
}
|
||||
};
|
||||
}
|
||||
/* Initialize a constant string with the given C string (C++ mode) */
|
||||
#define STRING_CTE(s) \
|
||||
m_string::m_aligned_string<sizeof (s)>(s).string
|
||||
#endif
|
||||
|
||||
#define STRING_INIT_PRINTF(v, ...) \
|
||||
/* Initialize and set a string to the given formatted value. */
|
||||
#define STRINGI_INIT_PRINTF(v, ...) \
|
||||
(string_init (v), string_printf (v, __VA_ARGS__) )
|
||||
|
||||
/* NOTE: Use GCC extension FIXME: To keep? */
|
||||
/* Initialize a string with the given list of arguments.
|
||||
Check if it is a formatted input or not by counting the number of arguments.
|
||||
If there is only one argument, it can only be a set to C string.
|
||||
It is much faster in this case to call string_init_set_str.
|
||||
In C11 mode, it uses the fact that string_init_set is overloaded to handle both
|
||||
C string and string. */
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
|
||||
#define STRINGI_INIT_WITH(v, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(string_init_set, STRINGI_INIT_PRINTF)(v, __VA_ARGS__)
|
||||
#else
|
||||
#define STRINGI_INIT_WITH(v, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(string_init_set_str, STRINGI_INIT_PRINTF)(v, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* NOTE: Use GCC extension (OBSOLETE) */
|
||||
#define STRING_DECL_INIT(v) \
|
||||
string_t v __attribute__((cleanup(stringi_clear2))) = {{ 0, 0, NULL}}
|
||||
|
||||
/* NOTE: Use GCC extension (OBSOLETE) */
|
||||
#define STRING_DECL_INIT_PRINTF(v, format, ...) \
|
||||
STRING_DECL_INIT(v); \
|
||||
string_printf (v, format, __VA_ARGS__)
|
||||
@@ -1427,7 +1620,7 @@ namespace m_string {
|
||||
/* Define the OPLIST of a STRING */
|
||||
#define STRING_OPLIST \
|
||||
(INIT(string_init),INIT_SET(string_init_set), SET(string_set), \
|
||||
INIT_WITH(STRING_INIT_PRINTF), \
|
||||
INIT_WITH(STRINGI_INIT_WITH), \
|
||||
INIT_MOVE(string_init_move), MOVE(string_move), \
|
||||
SWAP(string_swap), CLEAN(string_clean), \
|
||||
TEST_EMPTY(string_empty_p), \
|
||||
@@ -1438,6 +1631,15 @@ namespace m_string {
|
||||
OUT_SERIAL(string_out_serial), IN_SERIAL(string_in_serial), \
|
||||
EXT_ALGO(STRING_SPLIT), \
|
||||
OOR_EQUAL(string_oor_equal_p), OOR_SET(string_oor_set) \
|
||||
,SUBTYPE(string_unicode_t) \
|
||||
,IT_TYPE(string_it_t) \
|
||||
,IT_FIRST(string_it) \
|
||||
,IT_END(string_it_end) \
|
||||
,IT_SET(string_it_set) \
|
||||
,IT_END_P(string_end_p) \
|
||||
,IT_EQUAL_P(string_it_equal_p) \
|
||||
,IT_NEXT(string_next) \
|
||||
,IT_CREF(string_cref) \
|
||||
)
|
||||
|
||||
/* Register the OPLIST as a global one */
|
||||
@@ -1445,27 +1647,36 @@ namespace m_string {
|
||||
|
||||
|
||||
/* Macro encapsulation to give a default value of 0 for start offset */
|
||||
|
||||
/* Search for a character in a string (string, character[, start=0]) */
|
||||
#define string_search_char(v, ...) \
|
||||
M_APPLY(string_search_char, v, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
/* Reverse Search for a character in a string (string, character[, start=0]) */
|
||||
#define string_search_rchar(v, ...) \
|
||||
M_APPLY(string_search_rchar, v, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
/* Search for a C string in a string (string, c_string[, start=0]) */
|
||||
#define string_search_str(v, ...) \
|
||||
M_APPLY(string_search_str, v, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
/* Search for a string in a string (string, string[, start=0]) */
|
||||
#define string_search(v, ...) \
|
||||
M_APPLY(string_search, v, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
/* PBRK for a string in a string (string, string[, start=0]) */
|
||||
#define string_search_pbrk(v, ...) \
|
||||
M_APPLY(string_search_pbrk, v, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
/* Replace a C string to another C string in a string (string, c_src_string, c_dst_string, [, start=0]) */
|
||||
#define string_replace_str(v, s1, ...) \
|
||||
M_APPLY(string_replace_str, v, s1, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
/* Replace a string to another string in a string (string, src_string, dst_string, [, start=0]) */
|
||||
#define string_replace(v, s1, ...) \
|
||||
M_APPLY(string_replace, v, s1, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
/* Strim a string from the given set of characters (default is " \n\r\t") */
|
||||
#define string_strim(...) \
|
||||
M_APPLY(string_strim, M_IF_DEFAULT1(" \n\r\t", __VA_ARGS__))
|
||||
|
||||
@@ -1488,20 +1699,31 @@ namespace m_string {
|
||||
default : func1 \
|
||||
)(a,b,c)
|
||||
|
||||
#define string_set(a,b) STRINGI_SELECT2(string_set, string_set_str, a, b)
|
||||
/* Init & Set the string a to the string (or C string) b (constructor) */
|
||||
#define string_init_set(a,b) STRINGI_SELECT2(string_init_set, string_init_set_str, a, b)
|
||||
|
||||
/* Set the string a to the string (or C string) b */
|
||||
#define string_set(a,b) STRINGI_SELECT2(string_set, string_set_str, a, b)
|
||||
|
||||
/* Concatene the string (or C string) b to the string a */
|
||||
#define string_cat(a,b) STRINGI_SELECT2(string_cat, string_cat_str, a, b)
|
||||
|
||||
/* Compare the string a to the string (or C string) b and return the sort order */
|
||||
#define string_cmp(a,b) STRINGI_SELECT2(string_cmp, string_cmp_str, a, b)
|
||||
|
||||
/* Compare for equality the string a to the string (or C string) b */
|
||||
#define string_equal_p(a,b) STRINGI_SELECT2(string_equal_p, string_equal_str_p, a, b)
|
||||
|
||||
/* strcoll the string a to the string (or C string) b */
|
||||
#define string_strcoll(a,b) STRINGI_SELECT2(string_strcoll, string_strcoll_str, a, b)
|
||||
|
||||
#undef string_search
|
||||
/* Search for a string in a string (or C string) (string, string[, start=0]) */
|
||||
#define string_search(v, ...) \
|
||||
M_APPLY(STRINGI_SELECT3, string_search, string_search_str, \
|
||||
v, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
/* Provide GET_STR method to default type */
|
||||
/* Internal Macro: Provide GET_STR method to default type */
|
||||
#undef M_GET_STR_METHOD_FOR_DEFAULT_TYPE
|
||||
#define M_GET_STR_METHOD_FOR_DEFAULT_TYPE GET_STR(M_GET_STRING_ARG)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - TUPLE module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -35,6 +35,7 @@
|
||||
#define TUPLE_DEF2(name, ...) \
|
||||
TUPLEI_DEF2_P1( (name, TUPLEI_INJECT_GLOBAL(__VA_ARGS__)) )
|
||||
|
||||
|
||||
/* Define the oplist of a tuple.
|
||||
USAGE: TUPLE_OPLIST(name[, oplist of the first type, ...]) */
|
||||
#define TUPLE_OPLIST(...) \
|
||||
@@ -42,7 +43,8 @@
|
||||
(TUPLEI_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST )), \
|
||||
TUPLEI_OPLIST_P1((__VA_ARGS__ )))
|
||||
|
||||
/* Return an array suitable for the _cmp_order function.
|
||||
|
||||
/* Return an array suitable for the WIP _cmp_order function.
|
||||
As compound literals are not supported in C++,
|
||||
provide a separate definition for C++ using initializer_list
|
||||
(shall be constexpr, but only supported in C++14).
|
||||
@@ -71,9 +73,18 @@ namespace m_tuple {
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Contract of a tuple. Nothing notable */
|
||||
#define TUPLEI_CONTRACT(tup) do { \
|
||||
assert(tup != NULL); \
|
||||
} while (0)
|
||||
|
||||
/* Inject the oplist within the list of arguments */
|
||||
#define TUPLEI_INJECT_GLOBAL(...) \
|
||||
M_MAP_C(TUPLEI_INJECT_OPLIST_A, __VA_ARGS__)
|
||||
|
||||
/* Transform (x, type) into (x, type, oplist) if there is global registered oplist
|
||||
or (x, type, M_DEFAULT_OPLIST) if there is no global one,
|
||||
or keep (x, type, oplist) if oplist was already present */
|
||||
#define TUPLEI_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
TUPLEI_INJECT_OPLIST_B duo_or_trio
|
||||
|
||||
@@ -83,9 +94,26 @@ namespace m_tuple {
|
||||
// Deferred evaluation
|
||||
#define TUPLEI_DEF2_P1(...) TUPLEI_DEF2_P2 __VA_ARGS__
|
||||
|
||||
#define TUPLEI_DEF2_P2(name, ...) \
|
||||
// Test if all third argument of all arguments is an oplist
|
||||
#define TUPLEI_IF_ALL_OPLIST(...) \
|
||||
M_IF(M_REDUCE(TUPLEI_IS_OPLIST_P, M_AND, __VA_ARGS__))
|
||||
// Test if the third argument is an oplist
|
||||
#define TUPLEI_IS_OPLIST_P(a) \
|
||||
M_OPLIST_P(M_RET_ARG3 a)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define TUPLEI_DEF2_P2(name, ...) \
|
||||
TUPLEI_IF_ALL_OPLIST(__VA_ARGS__)(TUPLEI_DEF2_P3, TUPLEI_DEF2_FAILURE)(name, __VA_ARGS__)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define TUPLEI_DEF2_FAILURE(name, ...) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(TUPLE_DEF2): at least one of the given argument is not a valid oplist: " #__VA_ARGS__)
|
||||
|
||||
/* Define the tuple */
|
||||
#define TUPLEI_DEF2_P3(name, ...) \
|
||||
TUPLE_DEFINE_TYPE(name, __VA_ARGS__) \
|
||||
TUPLE_DEFINE_ENUM(name, __VA_ARGS__) \
|
||||
TUPLE_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
TUPLEI_IF_ALL(INIT, __VA_ARGS__) \
|
||||
(TUPLE_DEFINE_INIT(name, __VA_ARGS__),) \
|
||||
TUPLE_DEFINE_INIT_SET(name, __VA_ARGS__) \
|
||||
@@ -188,6 +216,12 @@ namespace m_tuple {
|
||||
#define TUPLE_DEFINE_ENUM_ELE(name, a) \
|
||||
M_C4(name, _, TUPLE_GET_FIELD a, _value)
|
||||
|
||||
#define TUPLE_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(TUPLE_CONTROL_OPLIST, name, __VA_ARGS__)
|
||||
#define TUPLE_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, TUPLE_GET_FIELD a, \
|
||||
TUPLE_GET_TYPE a, TUPLE_GET_OPLIST a)
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_INIT(name, ...) \
|
||||
static inline void M_C(name, _init)(M_C(name,_t) my) { \
|
||||
@@ -199,12 +233,13 @@ namespace m_tuple {
|
||||
|
||||
#define TUPLE_DEFINE_INIT_SET(name, ...) \
|
||||
static inline void M_C(name, _init_set)(M_C(name,_t) my , M_C(name,_t) const org) { \
|
||||
TUPLEI_CONTRACT(org); \
|
||||
M_MAP(TUPLE_DEFINE_INIT_SET_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_INIT_SET_FUNC(a) \
|
||||
TUPLE_CALL_INIT_SET(a, my -> TUPLE_GET_FIELD a , org -> TUPLE_GET_FIELD a );
|
||||
|
||||
|
||||
/* NOTE: More a _init_with method */
|
||||
#define TUPLE_DEFINE_INIT_SET2(name, ...) \
|
||||
static inline void M_C(name, _init_set2)(M_C(name,_t) my \
|
||||
M_MAP(TUPLE_DEFINE_INIT_SET2_PROTO, __VA_ARGS__) \
|
||||
@@ -220,6 +255,8 @@ namespace m_tuple {
|
||||
#define TUPLE_DEFINE_SET(name, ...) \
|
||||
static inline void M_C(name, _set)(M_C(name,_t) my , \
|
||||
M_C(name,_t) const org) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
TUPLEI_CONTRACT(org); \
|
||||
M_MAP(TUPLE_DEFINE_SET_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_SET_FUNC(a) \
|
||||
@@ -230,6 +267,7 @@ namespace m_tuple {
|
||||
static inline void M_C(name, _set2)(M_C(name,_t) my \
|
||||
M_MAP(TUPLE_DEFINE_SET2_PROTO, __VA_ARGS__) \
|
||||
) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
M_MAP(TUPLE_DEFINE_SET2_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_SET2_PROTO(a) \
|
||||
@@ -240,6 +278,7 @@ namespace m_tuple {
|
||||
|
||||
#define TUPLE_DEFINE_CLEAR(name, ...) \
|
||||
static inline void M_C(name, _clear)(M_C(name,_t) my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
M_MAP(TUPLE_DEFINE_CLEAR_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_CLEAR_FUNC(a) \
|
||||
@@ -251,9 +290,11 @@ namespace m_tuple {
|
||||
#define TUPLE_DEFINE_GETTER_FIELD_PROTO(name, a) \
|
||||
static inline TUPLE_GET_TYPE a * M_C3(name, _get_at_, TUPLE_GET_FIELD a) \
|
||||
(M_C(name,_t) my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
return &(my->TUPLE_GET_FIELD a);} \
|
||||
static inline TUPLE_GET_TYPE a const * M_C3(name, _cget_at_, TUPLE_GET_FIELD a) \
|
||||
(M_C(name,_t) const my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
return &(my->TUPLE_GET_FIELD a);}
|
||||
|
||||
|
||||
@@ -262,6 +303,7 @@ namespace m_tuple {
|
||||
#define TUPLE_DEFINE_SETTER_FIELD_PROTO(name, a) \
|
||||
static inline void M_C3(name, _set_, TUPLE_GET_FIELD a) \
|
||||
(M_C(name,_t) my, TUPLE_GET_TYPE a const TUPLE_GET_FIELD a) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
TUPLE_CALL_SET(a, my ->TUPLE_GET_FIELD a, TUPLE_GET_FIELD a);}
|
||||
|
||||
|
||||
@@ -269,6 +311,8 @@ namespace m_tuple {
|
||||
static inline int M_C(name, _cmp)(M_C(name,_t) const e1 , \
|
||||
M_C(name,_t) const e2) { \
|
||||
int i; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
M_MAP(TUPLE_DEFINE_CMP_FUNC , __VA_ARGS__) \
|
||||
return 0; \
|
||||
}
|
||||
@@ -282,6 +326,8 @@ namespace m_tuple {
|
||||
M_C(name,_t) const e2, \
|
||||
const int order[]) { \
|
||||
int i, r; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
while ((i=*order++) != 0) { \
|
||||
switch (i) { \
|
||||
M_MAP2(TUPLE_DEFINE_CMP_ORDER_FUNC , name, __VA_ARGS__) \
|
||||
@@ -307,6 +353,8 @@ namespace m_tuple {
|
||||
#define TUPLE_DEFINE_CMP_FIELD_FUNC(name, field, func_cmp) \
|
||||
static inline int M_C3(name, _cmp_, field)(M_C(name,_t) const e1 , \
|
||||
M_C(name,_t) const e2) { \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
return func_cmp ( e1 -> field , e2 -> field ); \
|
||||
}
|
||||
|
||||
@@ -315,6 +363,8 @@ namespace m_tuple {
|
||||
static inline bool M_C(name, _equal_p)(M_C(name,_t) const e1 , \
|
||||
M_C(name,_t) const e2) { \
|
||||
bool b; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
M_MAP(TUPLE_DEFINE_EQUAL_FUNC , __VA_ARGS__) \
|
||||
return true; \
|
||||
}
|
||||
@@ -325,6 +375,7 @@ namespace m_tuple {
|
||||
|
||||
#define TUPLE_DEFINE_HASH(name, ...) \
|
||||
static inline size_t M_C(name, _hash)(M_C(name,_t) const e1) { \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
M_HASH_DECL(hash); \
|
||||
M_MAP(TUPLE_DEFINE_HASH_FUNC , __VA_ARGS__) \
|
||||
return M_HASH_FINAL (hash); \
|
||||
@@ -338,7 +389,8 @@ namespace m_tuple {
|
||||
M_C(name,_t) const el, \
|
||||
bool append) { \
|
||||
bool comma = false; \
|
||||
assert (str != NULL && el != NULL); \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (str != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "("); \
|
||||
M_MAP(TUPLE_DEFINE_GET_STR_FUNC , __VA_ARGS__) \
|
||||
string_push_back (str, ')'); \
|
||||
@@ -353,7 +405,8 @@ namespace m_tuple {
|
||||
static inline void M_C(name, _out_str)(FILE *f, \
|
||||
M_C(name,_t) const el) { \
|
||||
bool comma = false; \
|
||||
assert (f != NULL && el != NULL); \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (f != NULL); \
|
||||
fputc('(', f); \
|
||||
M_MAP(TUPLE_DEFINE_OUT_STR_FUNC , __VA_ARGS__) \
|
||||
fputc (')', f); \
|
||||
@@ -367,8 +420,9 @@ namespace m_tuple {
|
||||
#define TUPLE_DEFINE_IN_STR(name, ...) \
|
||||
static inline bool M_C(name, _in_str)(M_C(name,_t) el, FILE *f) { \
|
||||
bool comma = false; \
|
||||
assert (f != NULL && el != NULL); \
|
||||
int c = fgetc(f); \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (f != NULL); \
|
||||
int c = fgetc(f); \
|
||||
if (c != '(') return false; \
|
||||
M_MAP(TUPLE_DEFINE_IN_STR_FUNC , __VA_ARGS__) \
|
||||
c = fgetc(f); \
|
||||
@@ -377,7 +431,7 @@ namespace m_tuple {
|
||||
#define TUPLE_DEFINE_IN_STR_FUNC(a) \
|
||||
if (comma) { \
|
||||
c = fgetc (f); \
|
||||
if (c != ',' || c == EOF) return false; \
|
||||
if (c != ',' || c == EOF) return false; \
|
||||
} \
|
||||
comma = true; \
|
||||
if (TUPLE_CALL_IN_STR(a, el -> TUPLE_GET_FIELD a, f) == false) \
|
||||
@@ -388,10 +442,11 @@ namespace m_tuple {
|
||||
static inline bool M_C(name, _parse_str)(M_C(name,_t) el, \
|
||||
const char str[], \
|
||||
const char **endptr) { \
|
||||
assert (str != NULL && el != NULL); \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (str != NULL); \
|
||||
bool success = false; \
|
||||
bool comma = false; \
|
||||
int c = *str++; \
|
||||
int c = *str++; \
|
||||
if (c != '(') goto exit; \
|
||||
M_MAP(TUPLE_DEFINE_PARSE_STR_FUNC , __VA_ARGS__) \
|
||||
c = *str++; \
|
||||
@@ -416,17 +471,18 @@ namespace m_tuple {
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, \
|
||||
M_C(name,_t) const el) { \
|
||||
assert (f != NULL && f->m_interface != NULL && el != NULL); \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
const int field_max = M_NARGS(__VA_ARGS__); \
|
||||
static const char *const field_name[] = \
|
||||
{ M_REDUCE(TUPLE_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
int index = 0; \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
ret = f->m_interface->write_tuple_start(local, f); \
|
||||
ret = f->m_interface->write_tuple_start(local, f); \
|
||||
M_MAP(TUPLE_DEFINE_OUT_SERIAL_FUNC , __VA_ARGS__) \
|
||||
assert( index == field_max); \
|
||||
ret |= f->m_interface->write_tuple_end(local, f); \
|
||||
ret |= f->m_interface->write_tuple_end(local, f); \
|
||||
return ret & M_SERIAL_FAIL; \
|
||||
}
|
||||
#define TUPLE_DEFINE_OUT_SERIAL_FUNC(a) \
|
||||
@@ -434,17 +490,19 @@ namespace m_tuple {
|
||||
TUPLE_CALL_OUT_SERIAL(a, f, el -> TUPLE_GET_FIELD a); \
|
||||
index++; \
|
||||
|
||||
|
||||
#define TUPLE_DEFINE_IN_SERIAL(name, ...) \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(M_C(name,_t) el, m_serial_read_t f) { \
|
||||
assert (f != NULL && el != NULL); \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
int index = -1; \
|
||||
const int field_max = M_NARGS(__VA_ARGS__); \
|
||||
static const char *const field_name[] = \
|
||||
{ M_REDUCE(TUPLE_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
ret = f->m_interface->read_tuple_start(local, f); \
|
||||
ret = f->m_interface->read_tuple_start(local, f); \
|
||||
while (ret == M_SERIAL_OK_CONTINUE) { \
|
||||
ret = f->m_interface->read_tuple_id(local, f, field_name, field_max, &index); \
|
||||
if (ret == M_SERIAL_OK_CONTINUE) { \
|
||||
@@ -466,6 +524,7 @@ namespace m_tuple {
|
||||
|
||||
#define TUPLE_DEFINE_INIT_MOVE(name, ...) \
|
||||
static inline void M_C(name, _init_move)(M_C(name,_t) el, M_C(name,_t) org) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_MAP(TUPLE_DEFINE_INIT_MOVE_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_INIT_MOVE_FUNC(a) \
|
||||
@@ -474,6 +533,7 @@ namespace m_tuple {
|
||||
|
||||
#define TUPLE_DEFINE_MOVE(name, ...) \
|
||||
static inline void M_C(name, _move)(M_C(name,_t) el, M_C(name,_t) org) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_MAP(TUPLE_DEFINE_MOVE_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_MOVE_FUNC(a) \
|
||||
@@ -482,6 +542,8 @@ namespace m_tuple {
|
||||
|
||||
#define TUPLE_DEFINE_SWAP(name, ...) \
|
||||
static inline void M_C(name, _swap)(M_C(name,_t) el1, M_C(name,_t) el2) { \
|
||||
TUPLEI_CONTRACT(el1); \
|
||||
TUPLEI_CONTRACT(el2); \
|
||||
M_MAP(TUPLE_DEFINE_SWAP_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_SWAP_FUNC(a) \
|
||||
@@ -490,6 +552,7 @@ namespace m_tuple {
|
||||
|
||||
#define TUPLE_DEFINE_CLEAN(name, ...) \
|
||||
static inline void M_C(name, _clean)(M_C(name,_t) el1) { \
|
||||
TUPLEI_CONTRACT(el1); \
|
||||
M_MAP(TUPLE_DEFINE_CLEAN_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLE_DEFINE_CLEAN_FUNC(a) \
|
||||
@@ -508,7 +571,15 @@ namespace m_tuple {
|
||||
// deferred
|
||||
#define TUPLEI_OPLIST_P1(arg) TUPLEI_OPLIST_P2 arg
|
||||
|
||||
#define TUPLEI_OPLIST_P2(name, ...) \
|
||||
/* Validate the oplist before going further */
|
||||
#define TUPLEI_OPLIST_P2(name, ...) \
|
||||
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(TUPLEI_OPLIST_P3, TUPLEI_OPLIST_FAILURE)(name, __VA_ARGS__)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define TUPLEI_OPLIST_FAILURE(name, ...) \
|
||||
M_LIB_ERROR(ONE_ARGUMENT_OF_TUPLE_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_OPLIST_P3(name, ...) \
|
||||
(M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
INIT_WITH(M_C(name, _init_set2)), \
|
||||
|
||||
+86
-13
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - VARIANT module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -36,6 +36,7 @@
|
||||
#define VARIANT_DEF2(name, ...) \
|
||||
VARIANTI_DEF2_P1( (name, VARIANTI_INJECT_GLOBAL(__VA_ARGS__)) )
|
||||
|
||||
|
||||
/* Define the oplist of a variant.
|
||||
USAGE: VARIANT_OPLIST(name[, oplist of the first type, ...]) */
|
||||
#define VARIANT_OPLIST(...) \
|
||||
@@ -46,9 +47,20 @@
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Contract of a variant. */
|
||||
#define VARIANTI_CONTRACT(name, my) do { \
|
||||
assert(my != NULL); \
|
||||
assert(my->type >= M_C(name, _EMPTY)); \
|
||||
assert(my->type <= (enum M_C(name, _enum)) M_C(name, _MAX_TYPE)); \
|
||||
} while (0)
|
||||
|
||||
/* Inject the oplist within the list of arguments */
|
||||
#define VARIANTI_INJECT_GLOBAL(...) \
|
||||
M_MAP_C(VARIANTI_INJECT_OPLIST_A, __VA_ARGS__)
|
||||
|
||||
/* Transform (x, type) into (x, type, oplist) if there is global registered oplist
|
||||
or (x, type, M_DEFAULT_OPLIST) if there is no global one,
|
||||
or keep (x, type, oplist) if oplist was already present */
|
||||
#define VARIANTI_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
VARIANTI_INJECT_OPLIST_B duo_or_trio
|
||||
|
||||
@@ -58,8 +70,25 @@
|
||||
// Deferred evaluation
|
||||
#define VARIANTI_DEF2_P1(...) VARIANTI_DEF2_P2 __VA_ARGS__
|
||||
|
||||
#define VARIANTI_DEF2_P2(name, ...) \
|
||||
// Test if all third argument of all arguments is an oplist
|
||||
#define VARIANTI_IF_ALL_OPLIST(...) \
|
||||
M_IF(M_REDUCE(VARIANTI_IS_OPLIST_P, M_AND, __VA_ARGS__))
|
||||
// Test if the third argument is an oplist
|
||||
#define VARIANTI_IS_OPLIST_P(a) \
|
||||
M_OPLIST_P(M_RET_ARG3 a)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define VARIANTI_DEF2_P2(name, ...) \
|
||||
VARIANTI_IF_ALL_OPLIST(__VA_ARGS__)(VARIANTI_DEF2_P3, VARIANTI_DEF2_FAILURE)(name, __VA_ARGS__)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define VARIANTI_DEF2_FAILURE(name, ...) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(VARIANT_DEF2): at least one of the given argument is not a valid oplist: " #__VA_ARGS__)
|
||||
|
||||
/* Define the variant */
|
||||
#define VARIANTI_DEF2_P3(name, ...) \
|
||||
VARIANTI_DEFINE_TYPE(name, __VA_ARGS__) \
|
||||
VARIANTI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
VARIANTI_DEFINE_INIT(name, __VA_ARGS__) \
|
||||
VARIANTI_DEFINE_CLEAR(name, __VA_ARGS__) \
|
||||
VARIANTI_DEFINE_INIT_SET(name, __VA_ARGS__) \
|
||||
@@ -141,6 +170,9 @@
|
||||
enum M_C(name, _enum) { M_C(name, _EMPTY) \
|
||||
M_MAP2(VARIANTI_DEFINE_UNION_ELE, name, __VA_ARGS__) \
|
||||
}; \
|
||||
enum M_C(name, _enum_max) { \
|
||||
M_C(name, _MAX_TYPE) = M_NARGS(__VA_ARGS__) \
|
||||
}; \
|
||||
typedef struct M_C(name, _s) { \
|
||||
enum M_C(name, _enum) type; \
|
||||
union { \
|
||||
@@ -155,6 +187,13 @@
|
||||
VARIANTI_GET_TYPE a VARIANTI_GET_FIELD a ;
|
||||
|
||||
|
||||
#define VARIANTI_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(VARIANTI_CONTROL_OPLIST, name, __VA_ARGS__)
|
||||
#define VARIANTI_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, VARIANTI_GET_FIELD a, \
|
||||
VARIANTI_GET_TYPE a, VARIANTI_GET_OPLIST a)
|
||||
|
||||
|
||||
#define VARIANTI_DEFINE_INIT(name, ...) \
|
||||
static inline void M_C(name, _init)(M_C(name,_t) my) { \
|
||||
my->type = M_C(name, _EMPTY); \
|
||||
@@ -164,6 +203,7 @@
|
||||
#define VARIANTI_DEFINE_INIT_SET(name, ...) \
|
||||
static inline void M_C(name, _init_set)(M_C(name,_t) my , \
|
||||
M_C(name,_t) const org) { \
|
||||
VARIANTI_CONTRACT(name, org); \
|
||||
my->type = org->type; \
|
||||
switch (org->type) { \
|
||||
case M_C(name, _EMPTY): break; \
|
||||
@@ -181,6 +221,8 @@
|
||||
#define VARIANTI_DEFINE_SET(name, ...) \
|
||||
static inline void M_C(name, _set)(M_C(name,_t) my , \
|
||||
M_C(name,_t) const org) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
VARIANTI_CONTRACT(name, org); \
|
||||
if (my->type != org->type) { \
|
||||
/* Different types: clear previous one and create new */ \
|
||||
M_C(name, _clear)(my); \
|
||||
@@ -203,6 +245,7 @@
|
||||
|
||||
#define VARIANTI_DEFINE_CLEAR(name, ...) \
|
||||
static inline void M_C(name, _clear)(M_C(name,_t) my) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
switch (my->type) { \
|
||||
case M_C(name, _EMPTY): break; \
|
||||
M_MAP2(VARIANTI_DEFINE_CLEAR_FUNC, name, __VA_ARGS__) \
|
||||
@@ -218,16 +261,19 @@
|
||||
|
||||
#define VARIANTI_DEFINE_TEST_P(name, ...) \
|
||||
static inline bool M_C(name, _empty_p)(M_C(name,_t) const my) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
return my->type == M_C(name, _EMPTY); \
|
||||
} \
|
||||
static inline enum M_C(name, _enum) \
|
||||
M_C(name, _type)(M_C(name,_t) my) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
return my->type; \
|
||||
} \
|
||||
M_MAP2(VARIANTI_DEFINE_TEST_FUNC, name, __VA_ARGS__)
|
||||
#define VARIANTI_DEFINE_TEST_FUNC(name, a) \
|
||||
static inline bool \
|
||||
M_C4(name, _, VARIANTI_GET_FIELD a, _p)(M_C(name,_t) const my) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
return my->type == M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
|
||||
}
|
||||
|
||||
@@ -261,6 +307,7 @@
|
||||
static inline void \
|
||||
M_C3(name, _set_, VARIANTI_GET_FIELD a)(M_C(name,_t) my, \
|
||||
VARIANTI_GET_TYPE a const VARIANTI_GET_FIELD a ) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
if (my->type == M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \
|
||||
VARIANTI_CALL_SET(a, my -> value. VARIANTI_GET_FIELD a, \
|
||||
VARIANTI_GET_FIELD a); \
|
||||
@@ -279,6 +326,7 @@
|
||||
#define VARIANTI_DEFINE_GETTER_FIELD_FUNC(name, a) \
|
||||
static inline VARIANTI_GET_TYPE a * \
|
||||
M_C3(name, _get_, VARIANTI_GET_FIELD a)(M_C(name,_t) my) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
if (my->type != M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \
|
||||
return NULL; \
|
||||
} \
|
||||
@@ -287,6 +335,7 @@
|
||||
\
|
||||
static inline VARIANTI_GET_TYPE a const * \
|
||||
M_C3(name, _cget_, VARIANTI_GET_FIELD a)(M_C(name,_t) const my) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
if (my->type != M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \
|
||||
return NULL; \
|
||||
} \
|
||||
@@ -298,6 +347,8 @@
|
||||
static inline bool M_C(name, _equal_p)(M_C(name,_t) const e1 , \
|
||||
M_C(name,_t) const e2) { \
|
||||
bool b; \
|
||||
VARIANTI_CONTRACT(name, e1); \
|
||||
VARIANTI_CONTRACT(name, e2); \
|
||||
if (e1->type != e2->type) return false; \
|
||||
switch (e1->type) { \
|
||||
case M_C(name, _EMPTY): break; \
|
||||
@@ -316,6 +367,7 @@
|
||||
|
||||
#define VARIANTI_DEFINE_HASH(name, ...) \
|
||||
static inline size_t M_C(name, _hash)(M_C(name,_t) const e1) { \
|
||||
VARIANTI_CONTRACT(name, e1); \
|
||||
M_HASH_DECL(hash); \
|
||||
M_HASH_UP (hash, e1 -> type); \
|
||||
switch (e1->type) { \
|
||||
@@ -334,6 +386,7 @@
|
||||
#define VARIANTI_DEFINE_INIT_MOVE(name, ...) \
|
||||
static inline void \
|
||||
M_C(name, _init_move)(M_C(name,_t) el, M_C(name,_t) org) { \
|
||||
VARIANTI_CONTRACT(name, org); \
|
||||
el -> type = org -> type; \
|
||||
switch (el->type) { \
|
||||
case M_C(name, _EMPTY): break; \
|
||||
@@ -352,6 +405,8 @@
|
||||
#define VARIANTI_DEFINE_MOVE(name, ...) \
|
||||
static inline void \
|
||||
M_C(name, _move)(M_C(name,_t) el, M_C(name,_t) org) { \
|
||||
VARIANTI_CONTRACT(name, el); \
|
||||
VARIANTI_CONTRACT(name, org); \
|
||||
M_C(name, _clear)(el); \
|
||||
M_C(name, _init_move)(el , org); \
|
||||
}
|
||||
@@ -363,6 +418,7 @@
|
||||
static inline void \
|
||||
M_C3(name, _move_, VARIANTI_GET_FIELD a)(M_C(name,_t) my, \
|
||||
VARIANTI_GET_TYPE a VARIANTI_GET_FIELD a ) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
M_C(name, _clear)(my); \
|
||||
/* Reinit variable with the given value */ \
|
||||
my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
|
||||
@@ -374,6 +430,8 @@
|
||||
#define VARIANTI_DEFINE_SWAP(name, ...) \
|
||||
static inline void \
|
||||
M_C(name, _swap)(M_C(name,_t) el1, M_C(name,_t) el2) { \
|
||||
VARIANTI_CONTRACT(name, el1); \
|
||||
VARIANTI_CONTRACT(name, el2); \
|
||||
if (el1->type == el2->type) { \
|
||||
switch (el1->type) { \
|
||||
case M_C(name, _EMPTY): break; \
|
||||
@@ -407,7 +465,8 @@
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
M_C(name,_t) const el, \
|
||||
bool append) { \
|
||||
assert (str != NULL && el != NULL); \
|
||||
VARIANTI_CONTRACT(name, el); \
|
||||
assert (str != NULL); \
|
||||
void (*func)(string_t, const char *); \
|
||||
func = append ? string_cat_str : string_set_str; \
|
||||
switch (el->type) { \
|
||||
@@ -428,7 +487,8 @@
|
||||
static inline bool M_C(name, _parse_str)(M_C(name,_t) el, \
|
||||
const char str[], \
|
||||
const char **endp) { \
|
||||
assert (str != NULL && el != NULL); \
|
||||
VARIANTI_CONTRACT(name, el); \
|
||||
assert (str != NULL); \
|
||||
bool success = false; \
|
||||
char variantTypeBuf[M_MAX_IDENTIFIER_LENGTH+1]; \
|
||||
int c = *str++; \
|
||||
@@ -467,7 +527,8 @@
|
||||
#define VARIANTI_DEFINE_OUT_STR(name, ...) \
|
||||
static inline void M_C(name, _out_str)(FILE *f, \
|
||||
M_C(name,_t) const el) { \
|
||||
assert (f != NULL && el != NULL); \
|
||||
VARIANTI_CONTRACT(name, el); \
|
||||
assert (f != NULL); \
|
||||
switch (el->type) { \
|
||||
case M_C(name, _EMPTY): fprintf(f, "@EMPTY@"); break; \
|
||||
M_MAP2(VARIANTI_DEFINE_OUT_STR_FUNC , name, __VA_ARGS__) \
|
||||
@@ -485,15 +546,16 @@
|
||||
#define VARIANTI_DEFINE_IN_STR(name, ...) \
|
||||
static inline bool M_C(name, _in_str)(M_C(name,_t) el, \
|
||||
FILE *f) { \
|
||||
assert (f != NULL && el != NULL); \
|
||||
VARIANTI_CONTRACT(name, el); \
|
||||
assert (f != NULL); \
|
||||
char variantTypeBuf[M_MAX_IDENTIFIER_LENGTH+1]; \
|
||||
M_C(name, _clean)(el); \
|
||||
if (fgetc(f) != '@') return false; \
|
||||
/* First read the name of the type */ \
|
||||
bool b = true; \
|
||||
int c = fgetc(f); \
|
||||
int c = fgetc(f); \
|
||||
unsigned int i = 0; \
|
||||
while (c != '@' && c != EOF && i < sizeof(variantTypeBuf) - 1) { \
|
||||
while (c != '@' && c != EOF && i < sizeof(variantTypeBuf) - 1) { \
|
||||
variantTypeBuf[i++] = c; \
|
||||
c = fgetc(f); \
|
||||
} \
|
||||
@@ -522,10 +584,11 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, \
|
||||
M_C(name,_t) const el) { \
|
||||
VARIANTI_CONTRACT(name, el); \
|
||||
const int field_max = M_NARGS(__VA_ARGS__); \
|
||||
static const char *const field_name[] = \
|
||||
{ M_REDUCE(VARIANTI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
assert (f != NULL && f->m_interface != NULL && el != NULL); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
switch (el->type) { \
|
||||
@@ -535,7 +598,7 @@
|
||||
M_MAP2(VARIANTI_DEFINE_OUT_SERIAL_FUNC , name, __VA_ARGS__) \
|
||||
default: assert(false); break; \
|
||||
} \
|
||||
ret |= f->m_interface->write_variant_end(local, f); \
|
||||
ret |= f->m_interface->write_variant_end(local, f); \
|
||||
return ret & M_SERIAL_FAIL; \
|
||||
}
|
||||
#define VARIANTI_DEFINE_OUT_SERIAL_FUNC(name, a) \
|
||||
@@ -550,10 +613,11 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(M_C(name,_t) el, \
|
||||
m_serial_read_t f) { \
|
||||
VARIANTI_CONTRACT(name, el); \
|
||||
const int field_max = M_NARGS(__VA_ARGS__); \
|
||||
static const char *const field_name[] = \
|
||||
{ M_REDUCE(VARIANTI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
assert (f != NULL && f->m_interface != NULL && el != NULL); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
int id = -1; \
|
||||
@@ -567,7 +631,7 @@
|
||||
default: assert(false); break; \
|
||||
} \
|
||||
if (ret == M_SERIAL_OK_DONE) \
|
||||
ret = f->m_interface->read_variant_end(local, f); \
|
||||
ret = f->m_interface->read_variant_end(local, f); \
|
||||
return ret; \
|
||||
}
|
||||
#define VARIANTI_DEFINE_IN_SERIAL_FUNC(name, a) \
|
||||
@@ -580,6 +644,7 @@
|
||||
#define VARIANTI_DEFINE_CLEAN_FUNC(name, ...) \
|
||||
static inline void M_C(name, _clean)(M_C(name,_t) my) \
|
||||
{ \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
M_C(name, _clear)(my); \
|
||||
M_C(name, _init)(my); \
|
||||
} \
|
||||
@@ -588,7 +653,15 @@
|
||||
// deferred
|
||||
#define VARIANTI_OPLIST_P1(arg) VARIANTI_OPLIST_P2 arg
|
||||
|
||||
#define VARIANTI_OPLIST_P2(name, ...) \
|
||||
/* Validate the oplist before going further */
|
||||
#define VARIANTI_OPLIST_P2(name, ...) \
|
||||
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(VARIANTI_OPLIST_P3, VARIANTI_OPLIST_FAILURE)(name, __VA_ARGS__)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define VARIANTI_OPLIST_FAILURE(name, ...) \
|
||||
M_LIB_ERROR(ONE_ARGUMENT_OF_VARIANT_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)
|
||||
|
||||
#define VARIANTI_OPLIST_P3(name, ...) \
|
||||
(INIT(M_C(name,_init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
SET(M_C(name,_set)), \
|
||||
|
||||
+102
-62
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB / WORKER - Extra worker interface
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -93,16 +93,16 @@
|
||||
# error M_USE_WORKER_CPP_FUNCTION and M_USE_WORKER_CLANG_BLOCK are both defined. This is not supported.
|
||||
#endif
|
||||
|
||||
/* This type defines a work order */
|
||||
/* Definition of a work order */
|
||||
typedef struct work_order_s {
|
||||
struct worker_sync_s *block;
|
||||
void * data;
|
||||
void (*func) (void *data);
|
||||
struct worker_sync_s *block; // Reference to the shared Synchronization block
|
||||
void * data; // The work order data
|
||||
void (*func) (void *data); // The work order function (for GCC)
|
||||
#if M_USE_WORKER_CLANG_BLOCK
|
||||
void (^blockFunc)(void *data);
|
||||
void (^blockFunc)(void *data); // The work order function (block for clang)
|
||||
#endif
|
||||
#if M_USE_WORKER_CPP_FUNCTION
|
||||
std::function<void(void*)> function;
|
||||
std::function<void(void*)> function; // The work order function (for C++)
|
||||
#endif
|
||||
} worker_order_t;
|
||||
|
||||
@@ -111,42 +111,47 @@ typedef struct work_order_s {
|
||||
* * MACRO to complete the not-used fields
|
||||
*/
|
||||
#if M_USE_WORKER_CLANG_BLOCK || M_USE_WORKER_CPP_FUNCTION
|
||||
# define WORKER_EMPTY_ORDER { NULL, NULL, NULL, NULL }
|
||||
# define WORKER_EXTRA_ORDER , NULL
|
||||
# define WORKERI_EMPTY_ORDER { NULL, NULL, NULL, NULL }
|
||||
# define WORKERI_EXTRA_ORDER , NULL
|
||||
#else
|
||||
# define WORKER_EMPTY_ORDER { NULL, NULL, NULL }
|
||||
# define WORKER_EXTRA_ORDER
|
||||
# define WORKERI_EMPTY_ORDER { NULL, NULL, NULL }
|
||||
# define WORKERI_EXTRA_ORDER
|
||||
#endif
|
||||
|
||||
/* As in C++, it uses std::function, M_POD_OPLIST
|
||||
is not sufficient for initilization of the structure.
|
||||
is not sufficient for initialization of the structure.
|
||||
So let's use C++ constructor, destructor and copy constructor */
|
||||
#if M_USE_WORKER_CPP_FUNCTION
|
||||
# define WORKER_CPP_INIT(x) (new (&(x)) worker_order_t())
|
||||
# define WORKER_CPP_INIT_SET(x, y) (new (&(x)) worker_order_t(y))
|
||||
# define WORKER_CPP_SET(x, y) ((x) = (y))
|
||||
# define WORKER_CPP_CLEAR(x) ((&(x))->~worker_order_t())
|
||||
# define WORKER_CPP_INIT_MOVE(x,y) (new (&(x)) worker_order_t(y), ((&(y))->~worker_order_t()))
|
||||
# define WORKER_OPLIST (INIT(WORKER_CPP_INIT), INIT_SET(WORKER_CPP_INIT_SET), SET(WORKER_CPP_SET), CLEAR(WORKER_CPP_CLEAR),INIT_MOVE(WORKER_CPP_INIT_MOVE) )
|
||||
# define WORKERI_CPP_INIT(x) (new (&(x)) worker_order_t())
|
||||
# define WORKERI_CPP_INIT_SET(x, y) (new (&(x)) worker_order_t(y))
|
||||
# define WORKERI_CPP_SET(x, y) ((x) = (y))
|
||||
# define WORKERI_CPP_CLEAR(x) ((&(x))->~worker_order_t())
|
||||
# define WORKERI_CPP_INIT_MOVE(x,y) (new (&(x)) worker_order_t(y), ((&(y))->~worker_order_t()))
|
||||
# define WORKER_OPLIST \
|
||||
(INIT(WORKERI_CPP_INIT), INIT_SET(WORKERI_CPP_INIT_SET), \
|
||||
SET(WORKERI_CPP_SET), CLEAR(WORKERI_CPP_CLEAR), INIT_MOVE(WORKERI_CPP_INIT_MOVE) )
|
||||
#else
|
||||
# define WORKER_OPLIST M_POD_OPLIST
|
||||
#endif
|
||||
|
||||
/* This type defines a worker represented as a thread */
|
||||
/* Definition of a worker (implemented by a thread) */
|
||||
typedef struct worker_thread_s {
|
||||
m_thread_t id;
|
||||
} worker_thread_t;
|
||||
|
||||
/* Let's define the queue which will manage all work orders */
|
||||
BUFFER_DEF(worker_queue, worker_order_t, 0, BUFFER_QUEUE|BUFFER_UNBLOCKING_PUSH|BUFFER_BLOCKING_POP|BUFFER_THREAD_SAFE|BUFFER_DEFERRED_POP, WORKER_OPLIST)
|
||||
/* Definition of the queue that will record the work orders */
|
||||
BUFFER_DEF(worker_queue, worker_order_t, 0,
|
||||
BUFFER_QUEUE|BUFFER_UNBLOCKING_PUSH|BUFFER_BLOCKING_POP|BUFFER_THREAD_SAFE|BUFFER_DEFERRED_POP, WORKER_OPLIST)
|
||||
|
||||
/* This type defines the state of the workers */
|
||||
/* Definition the global pool of workers */
|
||||
typedef struct worker_s {
|
||||
/* The work order queue */
|
||||
worker_queue_t queue_g;
|
||||
|
||||
/* The table of workers */
|
||||
/* The table of available workers */
|
||||
worker_thread_t *worker;
|
||||
|
||||
/* Number of workers in the table */
|
||||
unsigned int numWorker_g;
|
||||
|
||||
/* The global reset function */
|
||||
@@ -156,15 +161,15 @@ typedef struct worker_s {
|
||||
void (*clearFunc_g)(void);
|
||||
|
||||
m_mutex_t lock;
|
||||
m_cond_t a_thread_ends;
|
||||
m_cond_t a_thread_ends; // A worker has ended
|
||||
|
||||
} worker_t[1];
|
||||
|
||||
/* This type defines a synchronization point for workers */
|
||||
/* Definition of the synchronization point for workers */
|
||||
typedef struct worker_sync_s {
|
||||
atomic_int num_spawn;
|
||||
atomic_int num_terminated_spawn;
|
||||
struct worker_s *worker;
|
||||
atomic_int num_spawn; // Number of spawned workers accord this synchronization point
|
||||
atomic_int num_terminated_spawn; // Number of terminated spawned workers
|
||||
struct worker_s *worker; // Reference to the pool of workers
|
||||
} worker_sync_t[1];
|
||||
|
||||
/* Return the number of CPU of the system */
|
||||
@@ -190,20 +195,27 @@ workeri_get_cpu_count(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Execute the registered work order synchronously */
|
||||
// (INTERNAL) Debug support for workers
|
||||
#if 1
|
||||
#define WORKERI_DEBUG(...) (void) 0
|
||||
#else
|
||||
#define WORKERI_DEBUG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* Execute the registered work order **synchronously** */
|
||||
static inline void
|
||||
workeri_exec(worker_order_t *w)
|
||||
{
|
||||
assert (w!= NULL && w->block != NULL);
|
||||
//printf ("Starting thread with data %p\n", w->data);
|
||||
WORKERI_DEBUG ("Starting thread with data %p\n", w->data);
|
||||
#if M_USE_WORKER_CLANG_BLOCK
|
||||
//printf ("Running %s f=%p b=%p\n", (w->func == NULL) ? "Blocks" : "Function", w->func, w->blockFunc);
|
||||
WORKERI_DEBUG ("Running %s f=%p b=%p\n", (w->func == NULL) ? "Blocks" : "Function", w->func, w->blockFunc);
|
||||
if (w->func == NULL)
|
||||
w->blockFunc(w->data);
|
||||
else
|
||||
#endif
|
||||
#if M_USE_WORKER_CPP_FUNCTION
|
||||
//printf ("Running %s f=%p b=%p\n", (w->function == NULL) ? "Lambda" : "Function", w->func, w->blockFunc);
|
||||
WORKERI_DEBUG ("Running %s f=%p b=%p\n", (w->function == NULL) ? "Lambda" : "Function", w->func, w->blockFunc);
|
||||
if (w->function)
|
||||
w->function(w->data);
|
||||
else
|
||||
@@ -214,29 +226,42 @@ workeri_exec(worker_order_t *w)
|
||||
}
|
||||
|
||||
|
||||
/* The worker thread */
|
||||
/* The worker thread main loop*/
|
||||
static inline void
|
||||
workeri_thread(void *arg)
|
||||
{
|
||||
// Get back the given argument
|
||||
struct worker_s *g = M_ASSIGN_CAST(struct worker_s *, arg);
|
||||
while (true) {
|
||||
worker_order_t w;
|
||||
if (g->resetFunc_g != NULL)
|
||||
// If needed, reset the global state of the worker
|
||||
if (g->resetFunc_g != NULL) {
|
||||
g->resetFunc_g();
|
||||
//printf ("Waiting for data (queue: %lu / %lu)\n", worker_queue_size(g->queue_g), worker_queue_capacity(g->queue_g));
|
||||
}
|
||||
// Waiting for data
|
||||
WORKERI_DEBUG ("Waiting for data (queue: %lu / %lu)\n", worker_queue_size(g->queue_g), worker_queue_capacity(g->queue_g));
|
||||
worker_queue_pop(&w, g->queue_g);
|
||||
// We received a work order
|
||||
// Note: that the work order is still present in the queue
|
||||
// preventing further work order to be pushed in the queue until it finishes doing the work
|
||||
// If a stop request is received, terminate the thread
|
||||
if (w.block == NULL) break;
|
||||
// Execute the work order
|
||||
workeri_exec(&w);
|
||||
// Consumme fully the work order in the queue
|
||||
worker_queue_pop_release(g->queue_g);
|
||||
// Signal that a worker has finished.
|
||||
m_mutex_lock(g->lock);
|
||||
m_cond_broadcast(g->a_thread_ends);
|
||||
m_mutex_unlock(g->lock);
|
||||
}
|
||||
if (g->clearFunc_g != NULL)
|
||||
// If needed, clear global state of the thread
|
||||
if (g->clearFunc_g != NULL) {
|
||||
g->clearFunc_g();
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialization of the worker module
|
||||
/* Initialization of the worker module (constructor)
|
||||
Input:
|
||||
@numWorker: number of worker to create (0=autodetect, -1=2*autodetect)
|
||||
@extraQueue: number of extra work order we can get if all workers are full
|
||||
@@ -247,54 +272,64 @@ static inline void
|
||||
worker_init(worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
|
||||
{
|
||||
assert (numWorker >= -1);
|
||||
// Auto compute number of workers if the argument is 0
|
||||
if (numWorker <= 0)
|
||||
numWorker = (1 + (numWorker == -1))*workeri_get_cpu_count()-1;
|
||||
//printf ("Starting queue with: %d\n", numWorker + extraQueue);
|
||||
worker_queue_init(g->queue_g, numWorker + extraQueue);
|
||||
WORKERI_DEBUG ("Starting queue with: %d\n", numWorker + extraQueue);
|
||||
// Initialization
|
||||
size_t numWorker_st = numWorker;
|
||||
g->worker = M_MEMORY_REALLOC(worker_thread_t, NULL, numWorker_st);
|
||||
if (g->worker == NULL) {
|
||||
M_MEMORY_FULL(sizeof (worker_thread_t) * numWorker_st);
|
||||
return;
|
||||
}
|
||||
worker_queue_init(g->queue_g, numWorker + extraQueue);
|
||||
g->numWorker_g = numWorker_st;
|
||||
g->resetFunc_g = resetFunc;
|
||||
g->clearFunc_g = clearFunc;
|
||||
m_mutex_init(g->lock);
|
||||
m_cond_init(g->a_thread_ends);
|
||||
|
||||
// Create & start the workers
|
||||
for(size_t i = 0; i < numWorker_st; i++) {
|
||||
m_thread_create(g->worker[i].id, workeri_thread, M_ASSIGN_CAST(void*, g));
|
||||
}
|
||||
}
|
||||
// Define function with default values.
|
||||
/* Initialization of the worker module (constructor)
|
||||
Input:
|
||||
@numWorker: number of worker to create (0=autodetect, -1=2*autodetect)
|
||||
@extraQueue: number of extra work order we can get if all workers are full
|
||||
@resetFunc: function to reset the state of a worker between work orders (optional)
|
||||
@clearFunc: function to clear the state of a worker before terminaning (optional)
|
||||
*/
|
||||
#define worker_init(...) worker_init(M_DEFAULT_ARGS(5, (0, 0, NULL, NULL), __VA_ARGS__))
|
||||
|
||||
/* Clear of the worker module */
|
||||
/* Clear of the worker module (destructor) */
|
||||
static inline void
|
||||
worker_clear(worker_t g)
|
||||
{
|
||||
assert (worker_queue_empty_p (g->queue_g));
|
||||
// Push the terminate order on the queue
|
||||
for(unsigned int i = 0; i < g->numWorker_g; i++) {
|
||||
worker_order_t w = WORKER_EMPTY_ORDER;
|
||||
worker_order_t w = WORKERI_EMPTY_ORDER;
|
||||
// Normaly all worker threads shall be waiting at this
|
||||
// stage, so all push won't block as the queue is empty.
|
||||
// But for robustness, let's wait.
|
||||
worker_queue_push_blocking (g->queue_g, w, true);
|
||||
}
|
||||
|
||||
// Wait for thread terminanison
|
||||
for(unsigned int i = 0; i < g->numWorker_g; i++) {
|
||||
m_thread_join(g->worker[i].id);
|
||||
}
|
||||
// Clear memory
|
||||
M_MEMORY_FREE(g->worker);
|
||||
|
||||
m_mutex_clear(g->lock);
|
||||
m_cond_clear(g->a_thread_ends);
|
||||
worker_queue_clear(g->queue_g);
|
||||
}
|
||||
|
||||
/* Start a new collaboration between workers
|
||||
and define the synchronization point 'block' */
|
||||
/* Start a new collaboration between workers of pool 'g'
|
||||
by defining the synchronization point 'block' */
|
||||
static inline void
|
||||
worker_start(worker_sync_t block, worker_t g)
|
||||
{
|
||||
@@ -303,20 +338,23 @@ worker_start(worker_sync_t block, worker_t g)
|
||||
block->worker = g;
|
||||
}
|
||||
|
||||
/* Spawn or not the given work order to workers,
|
||||
or do it ourself if no worker is available */
|
||||
/* Spawn the given work order to workers if possible,
|
||||
or do it ourself if no worker is available.
|
||||
The synchronization point is defined a 'block'
|
||||
The work order if composed of the function 'func' and its 'data'
|
||||
*/
|
||||
static inline void
|
||||
worker_spawn(worker_sync_t block, void (*func)(void *data), void *data)
|
||||
{
|
||||
const worker_order_t w = { block, data, func WORKER_EXTRA_ORDER };
|
||||
const worker_order_t w = { block, data, func WORKERI_EXTRA_ORDER };
|
||||
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
|
||||
&& worker_queue_push (block->worker->queue_g, w) == true) {
|
||||
//printf ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
WORKERI_DEBUG ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
atomic_fetch_add (&block->num_spawn, 1);
|
||||
return;
|
||||
}
|
||||
//printf ("Running data ourself: %p\n", data);
|
||||
/* No thread available. Call the function ourself */
|
||||
WORKERI_DEBUG ("Running data ourself: %p\n", data);
|
||||
/* No worker available. Call the function ourself */
|
||||
(*func) (data);
|
||||
}
|
||||
|
||||
@@ -329,12 +367,12 @@ worker_spawn_block(worker_sync_t block, void (^func)(void *data), void *data)
|
||||
const worker_order_t w = { block, data, NULL, func };
|
||||
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
|
||||
&& worker_queue_push (block->worker->queue_g, w) == true) {
|
||||
//printf ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
WORKERI_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
atomic_fetch_add (&block->num_spawn, 1);
|
||||
return;
|
||||
}
|
||||
//printf ("Running data ourself as block: %p\n", data);
|
||||
/* No thread available. Call the function ourself */
|
||||
WORKERI_DEBUG ("Running data ourself as block: %p\n", data);
|
||||
/* No worker available. Call the function ourself */
|
||||
func (data);
|
||||
}
|
||||
#endif
|
||||
@@ -348,17 +386,17 @@ worker_spawn_function(worker_sync_t block, std::function<void(void *data)> func,
|
||||
const worker_order_t w = { block, data, NULL, func };
|
||||
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
|
||||
&& worker_queue_push (block->worker->queue_g, w) == true) {
|
||||
//printf ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
WORKERI_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
atomic_fetch_add (&block->num_spawn, 1);
|
||||
return;
|
||||
}
|
||||
//printf ("Running data ourself as block: %p\n", data);
|
||||
/* No thread available. Call the function ourself */
|
||||
WORKERI_DEBUG ("Running data ourself as block: %p\n", data);
|
||||
/* No worker available. Call the function ourself */
|
||||
func (data);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Test if all work orders are finished */
|
||||
/* Test if all work orders of the given synchronization point are finished */
|
||||
static inline bool
|
||||
worker_sync_p(worker_sync_t block)
|
||||
{
|
||||
@@ -368,12 +406,14 @@ worker_sync_p(worker_sync_t block)
|
||||
return (atomic_load(&block->num_spawn) == atomic_load (&block->num_terminated_spawn));
|
||||
}
|
||||
|
||||
/* Wait for all work orders to be finished */
|
||||
/* Wait for all work orders of the given synchronization point to be finished */
|
||||
static inline void
|
||||
worker_sync(worker_sync_t block)
|
||||
{
|
||||
//printf ("Waiting for thread terminasion.\n");
|
||||
WORKERI_DEBUG ("Waiting for thread terminasion.\n");
|
||||
// Fast case: all workers have finished
|
||||
if (worker_sync_p(block)) return;
|
||||
// Slow case: perform a locked wait to put this thread to waiting state
|
||||
m_mutex_lock(block->worker->lock);
|
||||
while (!worker_sync_p(block)) {
|
||||
m_cond_wait(block->worker->a_thread_ends, block->worker->lock);
|
||||
@@ -381,7 +421,7 @@ worker_sync(worker_sync_t block)
|
||||
m_mutex_unlock(block->worker->lock);
|
||||
}
|
||||
|
||||
/* Flush any work order in the queue if some remains.*/
|
||||
/* Flush any work order in the queue ourself if some remains.*/
|
||||
static inline void
|
||||
worker_flush(worker_t g)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
REM Execute the test suite for Microsoft Visual Studio
|
||||
REM
|
||||
REM Load Micosoft Visual Studio environement file.
|
||||
IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" (
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
)
|
||||
IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" (
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
)
|
||||
|
||||
REM Remove previous results
|
||||
DEL *.log *.dat
|
||||
|
||||
REM List the expected failure (compiler internal error)
|
||||
set "expectedFailure=test-msnapshot.c"
|
||||
|
||||
echo "Compiler full version:"
|
||||
cl /Bv
|
||||
|
||||
echo " "
|
||||
echo "Disabled tests passed due to wrong errors C4002 C4003 preventing build"
|
||||
exit /B 0
|
||||
|
||||
REM Perform for each test
|
||||
for %%f in (test-*.c) do (
|
||||
echo Testing %%f
|
||||
REM Copy the test file as a C++ file as CL.EXE only support C++ file
|
||||
copy %%f test.cpp
|
||||
if ERRORLEVEL 1 EXIT /B 1
|
||||
REM Compile the test suite
|
||||
REM /experimental:preprocessor is mandatory to have a compliant preprocessor
|
||||
REM /Zc:__cplusplus is needed to report the real value of __cplusplus, so that M*LIB uses the C++ atomic, and not its emulation.
|
||||
echo Compiling %%f
|
||||
cl.exe /I.. /O2 /std:c++14 /Zc:__cplusplus /experimental:preprocessor test.cpp > %%f.log 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
echo *** BUILD ERROR for %%f *** >> %%f.log
|
||||
type %%f.log
|
||||
if /i "%%f" NEQ "%expectedFailure%" EXIT /B 1
|
||||
)
|
||||
REM Execute it
|
||||
echo Running %%f
|
||||
test.exe >> %%f.log 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
echo *** RUNTIME ERROR for %%f *** >> %%f.log
|
||||
type %%f.log
|
||||
if /i "%%f" NEQ "%expectedFailure%" EXIT /B 1
|
||||
) ELSE (
|
||||
echo Test OK for %%f >> %%f.log
|
||||
)
|
||||
type %%f.log
|
||||
)
|
||||
echo "All tests passed (except %expectedFailure%)"
|
||||
exit /B 0
|
||||
+37
-15
@@ -1,7 +1,7 @@
|
||||
CC=cc -std=c99
|
||||
WCFLAGS_GCC=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -ftrapv
|
||||
WCFLAGS_CLANG=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -ftrapv
|
||||
WCFLAGS_CPP=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wstrict-overflow=5 -Winline -Wundef -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wno-unused-function -ftrapv
|
||||
WCFLAGS_CPP=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wstrict-overflow=5 -Winline -Wundef -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wno-unused-function -ftrapv
|
||||
XCFLAGS=
|
||||
CFLAGS=$(WCFLAGS_GCC) $(XCFLAGS)
|
||||
CPPFLAGS=-I..
|
||||
@@ -44,7 +44,7 @@ all:
|
||||
cat $<.first.c $<.middle.c $<.end.c > $<.c
|
||||
$(CC) $(CPPFLAGS) $(LDFLAGS) -ftest-coverage -fprofile-arcs -g $<.c -o $<.exe
|
||||
$(LOG_COMPILER) ./$<.exe
|
||||
gcov $<.gcno > `basename $< .c`.synt
|
||||
LANG=C gcov $<.gcno > `basename $< .c`.synt
|
||||
cat `basename $< .c`.synt
|
||||
mv $<.c.gcov `basename $< .c`.gcov
|
||||
$(RM) $<.first.c $<.end.c $<.middle.c $<.c $<.exe
|
||||
@@ -64,7 +64,8 @@ depend:
|
||||
#####################################################################################################
|
||||
|
||||
check: depend
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'`
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'` `ls fail-*.c|$(SED) 's/\.c/\.log/g'`
|
||||
@echo All tests passed
|
||||
|
||||
clean:
|
||||
$(RM) *.exe *.s *~ *.o *.log a*.dat
|
||||
@@ -75,6 +76,26 @@ distclean: clean
|
||||
$(RM) *.depend depend
|
||||
|
||||
|
||||
#####################################################################################################
|
||||
# Proper failure generation (test if the code properly fails to compile)
|
||||
#####################################################################################################
|
||||
|
||||
# TODO: should grep failure message?
|
||||
FAIL_BASE=
|
||||
FAIL_SEQ=
|
||||
fail-generic.log:
|
||||
for i in `seq 1 $(FAIL_SEQ)` ; do \
|
||||
if $(CC) $(CFLAGS) $(CPPFLAGS) -g -c $(FAIL_BASE).c -o tmp.o -DTEST=$$i 2> $(FAIL_BASE)-$$i.log ; then echo $(FAIL_BASE) -- TEST $$i : ERROR; false; else echo $(FAIL_BASE) -- TEST $$i : OK ; fi \
|
||||
done
|
||||
|
||||
fail-no-oplist.log:
|
||||
@$(MAKE) fail-generic.log FAIL_BASE=fail-no-oplist FAIL_SEQ=44
|
||||
fail-chain-oplist.log:
|
||||
@$(MAKE) fail-generic.log FAIL_BASE=fail-chain-oplist FAIL_SEQ=23
|
||||
fail-incompatible.log:
|
||||
@$(MAKE) fail-generic.log FAIL_BASE=fail-incompatible FAIL_SEQ=24
|
||||
|
||||
|
||||
#####################################################################################################
|
||||
# Code generation analysis
|
||||
#####################################################################################################
|
||||
@@ -118,6 +139,7 @@ SYNTHESIS_DATA= M-ALGO test-malgo.c.c test-malgo.synt \
|
||||
M-CORE test-mcore.c.c test-mcore.synt \
|
||||
M-DEQUE test-mdeque.c.c test-mdeque.synt \
|
||||
M-DICT test-mdict.c.c test-mdict.synt \
|
||||
M-FUNCOBJ test-mfuncobj.c.c test-mfuncobj.synt \
|
||||
M-GENINT ../m-genint.h test-mgenint.synt \
|
||||
M-I-LIST test-milist.c.c test-milist.synt \
|
||||
M-LIST test-mlist.c.c test-mlist.synt \
|
||||
@@ -167,15 +189,15 @@ sanitize:
|
||||
#####################################################################################################
|
||||
|
||||
checkall:
|
||||
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c99"
|
||||
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c99 -m32"
|
||||
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c11"
|
||||
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c11 -m32"
|
||||
@if which clang ; then $(MAKE) clean ; $(MAKE) check CC="clang -std=c99" WCFLAGS="$(WCFLAGS_CLANG)" ; else echo "SYSTEM CLANG not found: SKIP TEST" ; fi
|
||||
@if which g++ ; then $(MAKE) clean ; $(MAKE) check CC="g++ -std=c++11" WCFLAGS="$(WCFLAGS_CPP)" ; else echo "SYSTEM G++ not found: SKIP TEST" ; fi
|
||||
@if which clang++ ; then $(MAKE) clean ; $(MAKE) check CC="clang++ -std=c++11" WCFLAGS="$(WCFLAGS_CLANG)" ; else echo "SYSTEM CLANG++ not found: SKIP TEST" ; fi
|
||||
@if which tcc ; then $(MAKE) clean ; $(MAKE) check CC="tcc -std=c99" ; else echo "SYSTEM TCC not found: SKIP TEST" ; fi
|
||||
@if which musl-gcc ; then $(MAKE) clean ; $(MAKE) check CC="musl-gcc -std=c11" ; else echo "SYSTEM MUSL-GCC not found: SKIP TEST" ; fi
|
||||
@for f in /opt/gcc* ; do if test -x "$$f/bin/gcc" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/gcc -std=c99" ; fi ; done
|
||||
@for f in /opt/clang* ; do if test -x "$$f/bin/clang" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/clang -std=c99" WCFLAGS="$(WCFLAGS_CLANG)" ; fi ; done
|
||||
@for f in /opt/tcc* ; do if test -x "$$f/bin/tcc" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/tcc -std=c99" ; fi ; done
|
||||
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c99 -Werror"
|
||||
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c99 -m32 -Werror"
|
||||
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c11 -Werror"
|
||||
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c11 -m32 -Werror"
|
||||
@if which clang ; then $(MAKE) clean ; $(MAKE) check CC="clang -std=c99 -Werror" CFLAGS="$(WCFLAGS_CLANG)" ; else echo "SYSTEM CLANG not found: SKIP TEST" ; fi
|
||||
@if which g++ ; then $(MAKE) clean ; $(MAKE) check CC="g++ -std=c++11 -Werror" CFLAGS="$(WCFLAGS_CPP)" ; else echo "SYSTEM G++ not found: SKIP TEST" ; fi
|
||||
@if which clang++ ; then $(MAKE) clean ; $(MAKE) check CC="clang++ -std=c++11" CFLAGS="$(WCFLAGS_CLANG)" ; else echo "SYSTEM CLANG++ not found: SKIP TEST" ; fi
|
||||
@if which tcc ; then $(MAKE) clean ; $(MAKE) check CC="tcc -std=c99 -Werror" ; else echo "SYSTEM TCC not found: SKIP TEST" ; fi
|
||||
@if which musl-gcc ; then $(MAKE) clean ; $(MAKE) check CC="musl-gcc -std=c11 -Werror" ; else echo "SYSTEM MUSL-GCC not found: SKIP TEST" ; fi
|
||||
@for f in /opt/gcc* ; do if test -x "$$f/bin/gcc" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/gcc -std=c99 -Werror" ; fi ; done
|
||||
@for f in /opt/clang* ; do if test -x "$$f/bin/clang" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/clang -std=c99 -Werror" CFLAGS="$(WCFLAGS_CLANG)" ; fi ; done
|
||||
@for f in /opt/tcc* ; do if test -x "$$f/bin/tcc" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/tcc -std=c99 -Werror" ; fi ; done
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* The goal of this test file is to check that invalid constructs
|
||||
are properly rejected, and that it generates a helpfull error
|
||||
message in this case.
|
||||
It tests invalid oplist in an _OPLIST constructor of a container.
|
||||
*/
|
||||
#include "m-core.h"
|
||||
|
||||
#if !defined(TEST)
|
||||
# warning Please define TEST variable to select the test to run
|
||||
|
||||
#elif TEST == 1
|
||||
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
ARRAY_DEF(array2, array_t, ARRAY_OPLIST(array, DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 2
|
||||
|
||||
#include "m-list.h"
|
||||
|
||||
LIST_DEF(list, int)
|
||||
LIST_DEF(list2, list_t, LIST_OPLIST(list, DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 3
|
||||
|
||||
#include "m-deque.h"
|
||||
|
||||
DEQUE_DEF(deque, int)
|
||||
DEQUE_DEF(deque2, deque_t, DEQUE_OPLIST(deque, DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 4
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF(bptree, 4, int)
|
||||
BPTREE_DEF(bptree2, 5, bptree_t, BPTREE_OPLIST(bptree, DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 5
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF2(bptree, 4, int, int)
|
||||
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 6
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF2(bptree, 4, int, int)
|
||||
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, M_DEFAULT_OPLIST, DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 7
|
||||
|
||||
#include "m-buffer.h"
|
||||
|
||||
BUFFER_DEF(buffer, int, 4, BUFFER_THREAD_UNSAFE)
|
||||
BUFFER_DEF(buffer2, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer, DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 8
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-concurrent.h"
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
CONCURRENT_DEF(array2, array_t, ARRAY_OPLIST(array, M_DEFAULT_OPLIST))
|
||||
ARRAY_DEF(array3, array2_t, CONCURRENT_OPLIST(array2, ARRAY_OPLIST(array, DEFAULT_OPLIST)))
|
||||
|
||||
#elif TEST == 9
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_DEF2(dict, int, int)
|
||||
DICT_DEF2(dict2, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict, DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
|
||||
|
||||
#elif TEST == 10
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_DEF2(dict, int, int)
|
||||
DICT_DEF2(dict2, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict, M_DEFAULT_OPLIST, DEFAULT_OPLIST) )
|
||||
|
||||
#elif TEST == 11
|
||||
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
|
||||
DICT_SET_DEF(dict, int)
|
||||
ARRAY_DEF(array, dict_t, DICT_SET_OPLIST(dict, DEFAULT_OPLIST) )
|
||||
|
||||
#elif TEST == 12
|
||||
|
||||
#include "m-i-list.h"
|
||||
#include "m-concurrent.h"
|
||||
|
||||
typedef struct tmp_str_s {
|
||||
ILIST_INTERFACE(tmpstr, struct tmp_str_s);
|
||||
int n;
|
||||
} tmp_str_t;
|
||||
ILIST_DEF(tmpstr, tmp_str_t, (CLEAR(M_NOTHING_DEFAULT)))
|
||||
CONCURRENT_DEF(array, tmpstr_t, ILIST_OPLIST(tmpstr, X()))
|
||||
|
||||
#elif TEST == 13
|
||||
|
||||
#include "m-i-shared.h"
|
||||
#include "m-concurrent.h"
|
||||
|
||||
typedef struct tmp_str_s {
|
||||
ISHARED_PTR_INTERFACE(tmpstr, struct tmp_str_s);
|
||||
int n;
|
||||
} tmp_str_t;
|
||||
ISHARED_PTR_DEF(tmpstr, tmp_str_t, (CLEAR(M_NOTHING_DEFAULT)))
|
||||
CONCURRENT_DEF(array, tmpstr_t, ISHARED_PTR_OPLIST(tmpstr, X()))
|
||||
|
||||
#elif TEST == 14
|
||||
|
||||
#include "m-prioqueue.h"
|
||||
|
||||
PRIOQUEUE_DEF(prioqueue, int)
|
||||
PRIOQUEUE_DEF(prioqueue2, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue, M_DEFAULT_OPLIST()))
|
||||
|
||||
#elif TEST == 15
|
||||
|
||||
#include "m-rbtree.h"
|
||||
|
||||
RBTREE_DEF(rbtree, int)
|
||||
RBTREE_DEF(rbtree2, rbtree_t, RBTREE_OPLIST(rbtree, M_DEFAULT_OPLIST2))
|
||||
|
||||
#elif TEST == 16
|
||||
|
||||
#include "m-shared.h"
|
||||
|
||||
SHARED_PTR_DEF(shared, int)
|
||||
SHARED_PTR_DEF(shared2, shared_t, SHARED_PTR_OPLIST(shared, M_DEFAULT_OPLISTop))
|
||||
|
||||
#elif TEST == 17
|
||||
|
||||
#include "m-snapshot.h"
|
||||
|
||||
SNAPSHOT_SPSC_DEF(shared, int)
|
||||
SNAPSHOT_SPSC_DEF(shared2, shared_t, SNAPSHOT_OPLIST(shared, M_DEFAULT_OPLIST x))
|
||||
|
||||
#elif TEST == 18
|
||||
|
||||
#include "m-tuple.h"
|
||||
|
||||
TUPLE_DEF2(aggregate, (x, int), (z, float))
|
||||
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, DEFAULT_OPLIST, M_DEFAULT_OPLIST)))
|
||||
|
||||
#elif TEST == 19
|
||||
|
||||
#include "m-tuple.h"
|
||||
|
||||
TUPLE_DEF2(aggregate, (x, int), (z, float))
|
||||
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST() )))
|
||||
|
||||
#elif TEST == 20
|
||||
|
||||
#include "m-variant.h"
|
||||
|
||||
VARIANT_DEF2(aggregate, (x, int), (z, float))
|
||||
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, DEFAULT_OPLIST, M_DEFAULT_OPLIST)))
|
||||
|
||||
#elif TEST == 21
|
||||
|
||||
#include "m-variant.h"
|
||||
|
||||
VARIANT_DEF2(aggregate, (x, int), (z, float))
|
||||
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, DEFAULT_OPLIST)))
|
||||
|
||||
#elif TEST == 22
|
||||
|
||||
#include "m-funcobj.h"
|
||||
|
||||
FUNC_OBJ_ITF_DEF(itf, int, int)
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_DEFAULT_OPLIST), (b, int, M_DEFAULT_OPLIST))
|
||||
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, M_DEFAULT_OPLIST, DEFAULT_OPLIST)
|
||||
|
||||
int f(void) {
|
||||
int r;
|
||||
M_LET( (f, 1, 2), ins_t)
|
||||
r = itf_call(ins_as_interface(f), 4);
|
||||
return r;
|
||||
}
|
||||
|
||||
#elif TEST == 23
|
||||
|
||||
#include "m-funcobj.h"
|
||||
|
||||
FUNC_OBJ_ITF_DEF(itf, int, int)
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_DEFAULT_OPLIST), (b, int, M_DEFAULT_OPLIST))
|
||||
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
int f(void) {
|
||||
int r;
|
||||
M_LET( (f, 1, 2), ins_t)
|
||||
r = itf_call(ins_as_interface(f), 4);
|
||||
return r;
|
||||
}
|
||||
|
||||
#else
|
||||
# warning TEST variable is out of range.
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* The goal of this test file is to check that invalid constructs
|
||||
are properly rejected, and that it generates a helpfull error
|
||||
message in this case.
|
||||
It tests incompatible type and oplist.
|
||||
*/
|
||||
#include "m-core.h"
|
||||
|
||||
// The test is only robust in C11 mode.
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
|
||||
#if !defined(TEST)
|
||||
# warning Please define TEST variable to select the test to run
|
||||
|
||||
#elif TEST == 1
|
||||
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
ARRAY_DEF(array2, int)
|
||||
ARRAY_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 2
|
||||
|
||||
#include "m-list.h"
|
||||
|
||||
LIST_DEF(list, int)
|
||||
LIST_DEF(list2, int)
|
||||
LIST_DEF(list3, list_t, LIST_OPLIST(list2, M_DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 3
|
||||
|
||||
#include "m-deque.h"
|
||||
|
||||
DEQUE_DEF(deque, int)
|
||||
DEQUE_DEF(deque2, int)
|
||||
DEQUE_DEF(deque3, deque_t, DEQUE_OPLIST(deque2, M_DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 4
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF(bptree, 4, int)
|
||||
BPTREE_DEF(bptree2, 4, int)
|
||||
BPTREE_DEF(bptree3, 5, bptree_t, BPTREE_OPLIST(bptree2, M_DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 5
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF2(bptree, 4, int, int)
|
||||
BPTREE_DEF2(bptree2, 4, int, int)
|
||||
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 6
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF2(bptree, 4, int, int)
|
||||
BPTREE_DEF2(bptree2, 4, int, int)
|
||||
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 7
|
||||
|
||||
#include "m-buffer.h"
|
||||
|
||||
BUFFER_DEF(buffer, int, 4, BUFFER_THREAD_UNSAFE)
|
||||
BUFFER_DEF(buffer2, int, 4, BUFFER_THREAD_UNSAFE)
|
||||
BUFFER_DEF(buffer3, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer2, M_DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 8
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-concurrent.h"
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
ARRAY_DEF(array2, int)
|
||||
CONCURRENT_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 9
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_DEF2(dict, int, int)
|
||||
DICT_DEF2(dict2, int, int)
|
||||
DICT_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
|
||||
|
||||
#elif TEST == 10
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_STOREHASH_DEF2(dict, int, int)
|
||||
DICT_STOREHASH_DEF2(dict2, int, int)
|
||||
DICT_STOREHASH_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
|
||||
|
||||
#elif TEST == 11
|
||||
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
ARRAY_DEF(array2, int)
|
||||
DICT_SET_DEF(dict, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST) )
|
||||
|
||||
#elif TEST == 12
|
||||
|
||||
#include "m-i-list.h"
|
||||
#include "m-concurrent.h"
|
||||
|
||||
typedef struct tmp_str_s {
|
||||
ILIST_INTERFACE(tmpstr, struct tmp_str_s);
|
||||
int n;
|
||||
} tmp_str_t;
|
||||
ILIST_DEF(tmpstr, tmp_str_t, (TYPE(struct toto), CLEAR(M_NOTHING_DEFAULT)))
|
||||
|
||||
#elif TEST == 13
|
||||
|
||||
#include "m-i-shared.h"
|
||||
#include "m-concurrent.h"
|
||||
|
||||
typedef struct tmp_str_s {
|
||||
ISHARED_PTR_INTERFACE(tmpstr, struct tmp_str_s);
|
||||
int n;
|
||||
} tmp_str_t;
|
||||
ISHARED_PTR_DEF(tmpstr, tmp_str_t, (TYPE(struct toto), CLEAR(M_NOTHING_DEFAULT)))
|
||||
|
||||
#elif TEST == 14
|
||||
|
||||
#include "m-prioqueue.h"
|
||||
|
||||
PRIOQUEUE_DEF(prioqueue, int)
|
||||
PRIOQUEUE_DEF(prioqueue2, int)
|
||||
PRIOQUEUE_DEF(prioqueue3, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue2, M_DEFAULT_OPLIST ))
|
||||
|
||||
#elif TEST == 15
|
||||
|
||||
#include "m-rbtree.h"
|
||||
|
||||
RBTREE_DEF(rbtree, int)
|
||||
RBTREE_DEF(rbtree2, int)
|
||||
RBTREE_DEF(rbtree3, rbtree_t, RBTREE_OPLIST(rbtree2, M_DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 16
|
||||
|
||||
#include "m-shared.h"
|
||||
|
||||
SHARED_PTR_DEF(shared, int)
|
||||
SHARED_PTR_DEF(shared2, int)
|
||||
SHARED_PTR_DEF(shared3, shared_t, SHARED_PTR_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 17
|
||||
|
||||
#include "m-snapshot.h"
|
||||
|
||||
SNAPSHOT_SPSC_DEF(shared, int)
|
||||
SNAPSHOT_SPSC_DEF(shared2, int)
|
||||
SNAPSHOT_SPSC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 18
|
||||
|
||||
#include "m-snapshot.h"
|
||||
|
||||
SNAPSHOT_SPMC_DEF(shared, int)
|
||||
SNAPSHOT_SPMC_DEF(shared2, int)
|
||||
SNAPSHOT_SPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 19
|
||||
|
||||
#include "m-snapshot.h"
|
||||
|
||||
SNAPSHOT_MPMC_DEF(shared, int)
|
||||
SNAPSHOT_MPMC_DEF(shared2, int)
|
||||
SNAPSHOT_MPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 20
|
||||
|
||||
#include "m-tuple.h"
|
||||
|
||||
TUPLE_DEF2(aggregate, (x, int), (z, float))
|
||||
TUPLE_DEF2(aggregate2, (x, int), (z, float))
|
||||
TUPLE_DEF2(struct2,
|
||||
(a, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
|
||||
(b, aggregate_t, TUPLE_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
)
|
||||
|
||||
#elif TEST == 21
|
||||
|
||||
#include "m-tuple.h"
|
||||
|
||||
TUPLE_DEF2(aggregate, (x, int), (z, float))
|
||||
TUPLE_DEF2(aggregate2, (x, int), (z, float))
|
||||
TUPLE_DEF2(struct2,
|
||||
(a, aggregate_t, TUPLE_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
|
||||
(b, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
)
|
||||
|
||||
#elif TEST == 22
|
||||
|
||||
#include "m-variant.h"
|
||||
|
||||
VARIANT_DEF2(aggregate, (x, int), (z, float))
|
||||
VARIANT_DEF2(aggregate2, (x, int), (z, float))
|
||||
VARIANT_DEF2(struct2,
|
||||
(a, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
|
||||
(b, aggregate_t, VARIANT_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
)
|
||||
|
||||
#elif TEST == 23
|
||||
|
||||
#include "m-variant.h"
|
||||
|
||||
VARIANT_DEF2(aggregate, (x, int), (z, float))
|
||||
VARIANT_DEF2(aggregate2, (x, int), (z, float))
|
||||
VARIANT_DEF2(struct2,
|
||||
(a, aggregate_t, VARIANT_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
|
||||
(b, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
)
|
||||
|
||||
#elif TEST == 24
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-funcobj.h"
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
ARRAY_DEF(array2, int)
|
||||
FUNC_OBJ_ITF_DEF(itf, int, int)
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), {
|
||||
return x ;
|
||||
},
|
||||
(a, array_t, ARRAY_OPLIST(array)),
|
||||
(b, array_t, ARRAY_OPLIST(array2)))
|
||||
|
||||
#else
|
||||
# warning TEST variable is out of range.
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#error Test shall be run in C11 mode.
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* The goal of this test file is to check that invalid constructs
|
||||
are properly rejected, and that it generates a helpfull error
|
||||
message in this case. */
|
||||
#include "m-core.h"
|
||||
|
||||
#if !defined(TEST)
|
||||
# warning Please define TEST variable to select the test to run
|
||||
|
||||
#elif TEST == 1
|
||||
|
||||
/* Test of the call to no default function */
|
||||
#define OP (INIT(init))
|
||||
|
||||
void f(int x, int y) {
|
||||
M_CALL_SWAP(OP, x, y);
|
||||
}
|
||||
|
||||
#elif TEST == 2
|
||||
|
||||
void f(int x, int y) {
|
||||
M_CALL_SET(M_VALID_OPLIST(DEFAULT_OPLIST), x, y);
|
||||
}
|
||||
|
||||
#elif TEST == 3
|
||||
|
||||
#include "m-array.h"
|
||||
ARRAY_DEF(array, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 4
|
||||
|
||||
#include "m-list.h"
|
||||
LIST_DEF(list, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 5
|
||||
|
||||
#include "m-list.h"
|
||||
LIST_DUAL_PUSH_DEF(list, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 6
|
||||
|
||||
#include "m-deque.h"
|
||||
DEQUE_DEF(deque, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 7
|
||||
|
||||
#include "m-i-list.h"
|
||||
typedef struct tmp_str_s {
|
||||
ILIST_INTERFACE(tmpstr, struct tmp_str_s);
|
||||
int n;
|
||||
} tmp_str_t;
|
||||
ILIST_DEF(tmpstr, tmp_str_t, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 8
|
||||
|
||||
#include "m-string.h"
|
||||
void f(void)
|
||||
{
|
||||
M_LET(x, M_STRING_OPLIST) {
|
||||
}
|
||||
}
|
||||
|
||||
#elif TEST == 9
|
||||
|
||||
#include "m-string.h"
|
||||
typedef string_t my_type;
|
||||
#define M_OPL_my_type() MSTRING_OPLIST
|
||||
void f(void)
|
||||
{
|
||||
M_LET(x, my_type) {
|
||||
}
|
||||
}
|
||||
|
||||
#elif TEST == 10
|
||||
|
||||
void f(void)
|
||||
{
|
||||
M_LET(x, () ) {
|
||||
}
|
||||
}
|
||||
|
||||
#elif TEST == 11
|
||||
|
||||
#include "m-algo.h"
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
ALGO_DEF(array, M_ARRAY_OPLIST(array))
|
||||
|
||||
#elif TEST == 12
|
||||
|
||||
#include "m-algo.h"
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
ALGO_DEF(array, (OPLIST(array)))
|
||||
|
||||
#elif TEST == 13
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF2(tree, 4, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 14
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF2(tree, 4, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 15
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF(tree, 4, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 16
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_MULTI_DEF2(tree, 4, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 17
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_MULTI_DEF(tree, 4, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 18
|
||||
|
||||
#include "m-buffer.h"
|
||||
|
||||
BUFFER_DEF(buffer, int, 0, BUFFER_QUEUE, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 19
|
||||
|
||||
#include "m-buffer.h"
|
||||
|
||||
QUEUE_MPMC_DEF(buffer, int, BUFFER_QUEUE, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 20
|
||||
|
||||
#include "m-buffer.h"
|
||||
|
||||
QUEUE_SPSC_DEF(buffer, int, BUFFER_QUEUE, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 21
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-concurrent.h"
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
CONCURRENT_DEF(lock_array, array_t, M_ARRAY_OPLIST(array))
|
||||
|
||||
#elif TEST == 22
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-concurrent.h"
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
CONCURRENT_RP_DEF(lock_array, array_t, MARRAY_OPLIST(array))
|
||||
|
||||
#elif TEST == 23
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_DEF2(array, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 24
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_DEF2(array, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 25
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_STOREHASH_DEF2(array, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 26
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_STOREHASH_DEF2(array, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 27
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_OA_DEF2(array, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 28
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_OA_DEF2(array, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 29
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_SET_DEF(array, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 30
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_OASET_DEF(array, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 31
|
||||
|
||||
#include "m-i-shared.h"
|
||||
|
||||
typedef struct tmp_s {
|
||||
ISHARED_PTR_INTERFACE(tmpi, struct_tmp_s);
|
||||
const char *s;
|
||||
} tmp_t;
|
||||
|
||||
ISHARED_PTR_DEF(tmpi, tmp_t, NOT_AN_OPLIST)
|
||||
|
||||
#elif TEST == 32
|
||||
|
||||
#include "m-prioqueue.h"
|
||||
|
||||
PRIOQUEUE_DEF(prio, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 33
|
||||
|
||||
#include "m-rbtree.h"
|
||||
|
||||
RBTREE_DEF(tree, int, M_DEFAULT_OPLIST() )
|
||||
|
||||
#elif TEST == 34
|
||||
|
||||
#include "m-shared.h"
|
||||
|
||||
SHARED_PTR_DEF(shared, int, M_DEFAULT_OPLIST2 )
|
||||
|
||||
#elif TEST == 35
|
||||
|
||||
#include "m-shared.h"
|
||||
|
||||
SHARED_RESOURCE_DEF(shared, int, M_DEFAULT_OPLIST3 )
|
||||
|
||||
#elif TEST == 36
|
||||
|
||||
#include "m-snapshot.h"
|
||||
|
||||
SNAPSHOT_SPSC_DEF(snap, int, M_DEFAULT_OPLIST2 )
|
||||
|
||||
#elif TEST == 37
|
||||
|
||||
#include "m-snapshot.h"
|
||||
|
||||
SNAPSHOT_SPMC_DEF(snap, int, M_DEFAULT_OPLIST2 )
|
||||
|
||||
#elif TEST == 38
|
||||
|
||||
#include "m-snapshot.h"
|
||||
|
||||
SNAPSHOT_MPMC_DEF(snap, int, M_DEFAULT_OPLIST8 )
|
||||
|
||||
#elif TEST == 39
|
||||
|
||||
#include "m-tuple.h"
|
||||
|
||||
TUPLE_DEF2(agregate, (x, int, M_DEFAULT_OPLIST), (y, float, DEFAULT_OPLIST) )
|
||||
|
||||
#elif TEST == 40
|
||||
|
||||
#include "m-tuple.h"
|
||||
|
||||
TUPLE_DEF2(agregate, (x, int, DEFAULT_OPLIST), (y, float) )
|
||||
|
||||
#elif TEST == 41
|
||||
|
||||
#include "m-variant.h"
|
||||
|
||||
VARIANT_DEF2(agregate, (x, int, M_DEFAULT_OPLIST), (y, float, DEFAULT_OPLIST) )
|
||||
|
||||
#elif TEST == 42
|
||||
|
||||
#include "m-variant.h"
|
||||
|
||||
VARIANT_DEF2(agregate, (x, int, DEFAULT_OPLIST), (y, float) )
|
||||
|
||||
#elif TEST == 43
|
||||
|
||||
#include "m-funcobj.h"
|
||||
|
||||
FUNC_OBJ_ITF_DEF(itf, int, int)
|
||||
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, DEFAULT_OPLIST), (b, int, M_DEFAULT_OPLIST))
|
||||
|
||||
#elif TEST == 44
|
||||
|
||||
#include "m-funcobj.h"
|
||||
|
||||
FUNC_OBJ_ITF_DEF(itf, int, int)
|
||||
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int), (b, int, M_DEFAULT_OPLIST() ))
|
||||
|
||||
|
||||
#else
|
||||
# warning TEST variable is out of range.
|
||||
#endif
|
||||
|
||||
+212
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -46,6 +46,8 @@ DEQUE_DEF(deque_obj, testobj_t, TESTOBJ_CMP_OPLIST)
|
||||
#define M_OPL_deque_obj_t() DEQUE_OPLIST(deque_obj, TESTOBJ_CMP_OPLIST)
|
||||
DICT_DEF2(dict_obj, string_t, STRING_OPLIST, testobj_t, TESTOBJ_OPLIST)
|
||||
LIST_DUAL_PUSH_DEF(dlist_int, int)
|
||||
DICT_DEF2(dict_int, string_t, int)
|
||||
#define M_OPL_dict_int_t() DICT_OPLIST(dict_int, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
#include "coverage.h"
|
||||
START_COVERAGE
|
||||
@@ -58,6 +60,12 @@ ALGO_DEF(algo_dict, DICT_OPLIST(dict_obj, STRING_OPLIST, TESTOBJ_OPLIST))
|
||||
END_COVERAGE
|
||||
ALGO_DEF(algo_dlist, LIST_OPLIST(list_int))
|
||||
|
||||
// Needs to be included ***AFTER*** so that the algorithms can be generated without Function Object before.
|
||||
#include "m-funcobj.h"
|
||||
ALGO_DEF(algo_array_fo, array_int_t)
|
||||
ALGO_DEF(algo_list_fo, LIST_OPLIST(list_int))
|
||||
|
||||
|
||||
/* Helper functions */
|
||||
int g_min, g_max, g_count;
|
||||
|
||||
@@ -99,6 +107,10 @@ static bool func_test_both_even_or_odd(int a, int b)
|
||||
return (a&1) == (b&1);
|
||||
}
|
||||
|
||||
#define start_with(pattern, item) \
|
||||
string_start_with_str_p((item).key, (pattern))
|
||||
|
||||
#define get_value(out, item) ((out) = (item).value)
|
||||
|
||||
/* Tests starts */
|
||||
static void test_list(void)
|
||||
@@ -133,6 +145,19 @@ static void test_list(void)
|
||||
assert( algo_list_count_if(l, func_test_42) == 1);
|
||||
assert( algo_list_count_if(l, func_test_101) == 0);
|
||||
|
||||
M_LET(tmp, LIST_OPLIST(list_int)) {
|
||||
g_min = 0;
|
||||
g_max = 99;
|
||||
g_count = 0;
|
||||
algo_list_transform(tmp, l, func_map);
|
||||
assert(g_count == 101);
|
||||
assert(list_int_size(tmp) == 101);
|
||||
for(int i = 0; i < 100; i++) {
|
||||
assert(*list_int_get(tmp, i) == i * i);
|
||||
}
|
||||
assert(*list_int_get(tmp, 100) == 17 * 17);
|
||||
}
|
||||
|
||||
int *p = algo_list_min(l);
|
||||
assert(p != NULL && *p == 0);
|
||||
p = algo_list_max(l);
|
||||
@@ -251,6 +276,38 @@ static void test_array(void)
|
||||
assert(g_count == 101);
|
||||
assert(n == (328350 + 17*17));
|
||||
|
||||
M_LET(tmp, array_int_t) {
|
||||
g_count = 0;
|
||||
algo_array_transform(tmp, l, func_map);
|
||||
assert(g_count == 101);
|
||||
assert(array_int_size(tmp) == 101);
|
||||
for(int i = 0; i < 100; i++) {
|
||||
assert(*array_int_get(l, i) == i);
|
||||
assert(*array_int_get(tmp, i) == i * i);
|
||||
}
|
||||
assert(*array_int_get(l, 100) == 17);
|
||||
assert(*array_int_get(tmp, 100) == 17 * 17);
|
||||
|
||||
array_int_clean(tmp);
|
||||
#define FT(d,x) ((d) = (x) + 1)
|
||||
ALGO_TRANSFORM(tmp, array_int_t, l, array_int_t, FT);
|
||||
assert(array_int_size(tmp) == 101);
|
||||
for(int i = 0; i < 100; i++) {
|
||||
assert(*array_int_get(l, i) == i);
|
||||
assert(*array_int_get(tmp, i) == i + 1);
|
||||
}
|
||||
|
||||
array_int_clean(tmp);
|
||||
#define FT2(d,x,a) ((d) = (x) + (a))
|
||||
ALGO_TRANSFORM(tmp, array_int_t, l, array_int_t, FT2, 17);
|
||||
assert(array_int_size(tmp) == 101);
|
||||
for(int i = 0; i < 100; i++) {
|
||||
assert(*array_int_get(l, i) == i);
|
||||
assert(*array_int_get(tmp, i) == i + 17);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int *min, *max;
|
||||
assert (*algo_array_min(l) == 0);
|
||||
assert (*algo_array_max(l) == 99);
|
||||
@@ -333,6 +390,36 @@ static void test_array(void)
|
||||
assert (array_int_size(arr) == 3);
|
||||
assert (algo_array_sort_p(arr) == true);
|
||||
assert (algo_array_sort_dsc_p(arr) == false);
|
||||
|
||||
algo_array_fill(arr, 1789);
|
||||
assert(*array_int_get(arr, 0) == 1789);
|
||||
assert(*array_int_get(arr, 1) == 1789);
|
||||
assert(*array_int_get(arr, 2) == 1789);
|
||||
|
||||
algo_array_fill_a(arr, 1789, 1);
|
||||
assert(*array_int_get(arr, 0) == 1789);
|
||||
assert(*array_int_get(arr, 1) == 1790);
|
||||
assert(*array_int_get(arr, 2) == 1791);
|
||||
|
||||
algo_array_fill_a(arr, 0, 2);
|
||||
assert(*array_int_get(arr, 0) == 0);
|
||||
assert(*array_int_get(arr, 1) == 2);
|
||||
assert(*array_int_get(arr, 2) == 4);
|
||||
|
||||
algo_array_fill_n(arr, 5, 1742);
|
||||
assert (array_int_size(arr) == 5);
|
||||
assert(*array_int_get(arr, 0) == 1742);
|
||||
assert(*array_int_get(arr, 1) == 1742);
|
||||
assert(*array_int_get(arr, 2) == 1742);
|
||||
assert(*array_int_get(arr, 3) == 1742);
|
||||
assert(*array_int_get(arr, 4) == 1742);
|
||||
|
||||
algo_array_fill_an(arr, 4, -1, 3);
|
||||
assert (array_int_size(arr) == 4);
|
||||
assert(*array_int_get(arr, 0) == -1);
|
||||
assert(*array_int_get(arr, 1) == 2);
|
||||
assert(*array_int_get(arr, 2) == 5);
|
||||
assert(*array_int_get(arr, 3) == 8);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,14 +466,26 @@ static void test_extract(void)
|
||||
list_int_init (l);
|
||||
for(int i = -100; i < 100; i++)
|
||||
list_int_push_back (l, i);
|
||||
list_int_reverse(l);
|
||||
array_int_t a;
|
||||
array_int_init(a);
|
||||
|
||||
ALGO_EXTRACT(a, ARRAY_OPLIST(array_int), l, LIST_OPLIST(list_int));
|
||||
assert(array_int_size(a) == 200);
|
||||
assert(*array_int_get(a, 0) == -100);
|
||||
assert(*array_int_get(a, 199) == 99);
|
||||
|
||||
#define cond(d) ((d) > 0)
|
||||
ALGO_EXTRACT(a, ARRAY_OPLIST(array_int), l, LIST_OPLIST(list_int), cond);
|
||||
assert(array_int_size(a) == 99);
|
||||
assert(*array_int_get(a, 0) == 1);
|
||||
assert(*array_int_get(a, 98) == 99);
|
||||
|
||||
#define cond2(c, d) ((d) > (c))
|
||||
ALGO_EXTRACT(a, ARRAY_OPLIST(array_int), l, LIST_OPLIST(list_int), cond2, 10);
|
||||
assert(array_int_size(a) == 89);
|
||||
assert(*array_int_get(a, 0) == 11);
|
||||
assert(*array_int_get(a, 88) == 99);
|
||||
|
||||
int dst = 0;
|
||||
#define inc(d, c) (d) += (c)
|
||||
@@ -410,8 +509,31 @@ static void test_extract(void)
|
||||
ALGO_REDUCE(dst, a, ARRAY_OPLIST(array_int), or);
|
||||
assert (dst == 127);
|
||||
|
||||
unsigned long long dst_l;
|
||||
ALGO_REDUCE( (dst_l, M_OPEXTEND(M_STANDARD_OPLIST, TYPE(unsigned long long))), a, array_int_t, sum);
|
||||
assert (dst_l == 100*99/2-10*11/2);
|
||||
|
||||
array_int_clean(a);
|
||||
for(int i = 1; i < 10; i++)
|
||||
array_int_push_back(a, i);
|
||||
ALGO_REDUCE(dst, a, ARRAY_OPLIST(array_int), product);
|
||||
assert (dst == 362880);
|
||||
|
||||
array_int_clear(a);
|
||||
list_int_clear(l);
|
||||
|
||||
M_LET(keys, array_int_t)
|
||||
M_LET( (m, (STRING_CTE("foo"), 1), (STRING_CTE("bar"), 42), (STRING_CTE("bluez"), 7), (STRING_CTE("stop"), 789) ), tmp, dict_int_t) {
|
||||
int s;
|
||||
/* Extract all elements of 'm' that starts with 'b' */
|
||||
ALGO_EXTRACT(tmp, dict_int_t, m, dict_int_t, start_with, "b");
|
||||
/* Extract the values of theses elements */
|
||||
ALGO_TRANSFORM(keys, array_int_t, tmp, dict_int_t, get_value);
|
||||
/* Sum theses values */
|
||||
ALGO_REDUCE(s, keys, array_int_t, sum);
|
||||
assert(s == 49);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ARRAY_DEF(aint, int)
|
||||
@@ -434,6 +556,93 @@ static void test_insert(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_string_utf8(void)
|
||||
{
|
||||
M_LET( (s, "H€llo René Chaînôr¬"), string_t)
|
||||
M_LET( (ref, 72, 8364, 108, 108, 111, 32, 82, 101, 110, 233, 32, 67, 104, 97, 238, 110, 244, 114, 172), a, array_int_t) {
|
||||
// Convert the string into an array of unicode.
|
||||
ALGO_EXTRACT(a, array_int_t, s, string_t);
|
||||
// Compare the converted string into the reference array
|
||||
assert(array_int_equal_p(a, ref));
|
||||
}
|
||||
}
|
||||
|
||||
/* Define some function objects */
|
||||
FUNC_OBJ_INS_DEF(fo_test, algo_array_fo_test_obj,
|
||||
(a), {
|
||||
return a == self->x;
|
||||
}, (x, int))
|
||||
#define M_OPL_fo_test_t() FUNC_OBJ_INS_OPLIST(fo_test, M_DEFAULT_OPLIST)
|
||||
|
||||
FUNC_OBJ_INS_DEF(fo_eq, algo_array_fo_eq_obj,
|
||||
(a, b), {
|
||||
return a == b && self->x != a;
|
||||
}, (x, int))
|
||||
#define M_OPL_fo_eq_t() FUNC_OBJ_INS_OPLIST(fo_eq, M_DEFAULT_OPLIST)
|
||||
|
||||
FUNC_OBJ_INS_DEF(fo_cmp, algo_array_fo_cmp_obj,
|
||||
(a, b), {
|
||||
return a < b ? -self->x : a > b ? self->x : 0;
|
||||
}, (x, int))
|
||||
#define M_OPL_fo_cmp_t() FUNC_OBJ_INS_OPLIST(fo_cmp, M_DEFAULT_OPLIST)
|
||||
|
||||
FUNC_OBJ_INS_DEF(fol_cmp, algo_list_fo_cmp_obj,
|
||||
(a, b), {
|
||||
return a < b ? -self->x : a > b ? self->x : 0;
|
||||
}, (x, int))
|
||||
#define M_OPL_fol_cmp_t() FUNC_OBJ_INS_OPLIST(fol_cmp, M_DEFAULT_OPLIST)
|
||||
|
||||
static void test_fo(void)
|
||||
{
|
||||
M_LET(tab, array_int_t) {
|
||||
for(int i = 0; i < 10; i++)
|
||||
array_int_push_back(tab, i);
|
||||
array_int_push_back(tab, 5);
|
||||
|
||||
array_int_it_t it;
|
||||
M_LET( (obj, 6), fo_test_t)
|
||||
algo_array_fo_find_fo(it, tab, fo_test_as_interface(obj));
|
||||
assert(!array_int_end_p(it));
|
||||
M_LET( (obj, 11), fo_test_t)
|
||||
algo_array_fo_find_fo(it, tab, fo_test_as_interface(obj));
|
||||
assert(array_int_end_p(it));
|
||||
|
||||
M_LET( (obj, 11), fo_test_t)
|
||||
assert( 0 == algo_array_fo_count_fo(tab, fo_test_as_interface(obj)));
|
||||
M_LET( (obj, 5), fo_test_t)
|
||||
assert( 2 == algo_array_fo_count_fo(tab, fo_test_as_interface(obj)));
|
||||
|
||||
M_LET( (obj, 3), fo_test_t)
|
||||
assert( false == algo_array_fo_all_of_fo_p(tab, fo_test_as_interface(obj)));
|
||||
M_LET( (obj, 3), fo_test_t)
|
||||
assert( true == algo_array_fo_any_of_fo_p(tab, fo_test_as_interface(obj)));
|
||||
M_LET( (obj, 3), fo_test_t)
|
||||
assert( false == algo_array_fo_none_of_fo_p(tab, fo_test_as_interface(obj)));
|
||||
M_LET( (obj, -1), fo_test_t)
|
||||
assert( true == algo_array_fo_none_of_fo_p(tab, fo_test_as_interface(obj)));
|
||||
|
||||
array_int_push_back(tab, -1);
|
||||
M_LET( (obj, 1), fo_cmp_t)
|
||||
algo_array_fo_sort_fo(tab, fo_cmp_as_interface(obj));
|
||||
M_LET ( (ref, -1, 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9), array_int_t)
|
||||
assert( array_int_equal_p(tab, ref));
|
||||
}
|
||||
|
||||
M_LET(tab, LIST_OPLIST(list_int)) {
|
||||
for(int i = 0; i < 10; i++)
|
||||
list_int_push_back(tab, i);
|
||||
list_int_push_back(tab, 5);
|
||||
list_int_push_back(tab, -1);
|
||||
M_LET( (obj, 1), fol_cmp_t)
|
||||
algo_list_fo_sort_fo(tab, fol_cmp_as_interface(obj));
|
||||
M_LET ( (ref, -1, 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9), LIST_OPLIST(list_int)) {
|
||||
// NOTE: For a list, the order is revered by default
|
||||
list_int_reverse(ref);
|
||||
assert( list_int_equal_p(tab, ref));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_list();
|
||||
@@ -441,5 +650,7 @@ int main(void)
|
||||
test_string();
|
||||
test_extract();
|
||||
test_insert();
|
||||
test_string_utf8();
|
||||
test_fo();
|
||||
exit(0);
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Test for Concurrent memory pool allocator
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+15
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -226,6 +226,9 @@ static void test_test(void)
|
||||
assert(!M_PARENTHESIS_P(a,b));
|
||||
assert(!M_PARENTHESIS_P(a));
|
||||
assert(!M_PARENTHESIS_P());
|
||||
assert(!M_PARENTHESIS_P(,));
|
||||
assert(!M_PARENTHESIS_P((),));
|
||||
assert(!M_PARENTHESIS_P(()x));
|
||||
}
|
||||
|
||||
|
||||
@@ -292,6 +295,15 @@ static void test_oplist(void)
|
||||
#define A3(op) A4(M_GET_OPLIST op)
|
||||
#define A4(op) M_GET_CLEAR op
|
||||
assert (A1);
|
||||
|
||||
#define A5 (NAME(1))
|
||||
assert (M_GET_NAME A5);
|
||||
|
||||
#define A6 (NAME(A6), INIT_WITH(API_1(M_INIT_WITH_NVAR)))
|
||||
#define A6_init_with_1(x) 1
|
||||
#define A6_init_with_2(x, y) 0
|
||||
assert (M_CALL_INIT_WITH (A6, 0));
|
||||
assert (!M_CALL_INIT_WITH (A6, 0, 0));
|
||||
}
|
||||
|
||||
static void test_cast(void)
|
||||
@@ -411,6 +423,7 @@ static void test_move_default(void)
|
||||
assert(o == 0);
|
||||
|
||||
double u, k;
|
||||
k = -1.0;
|
||||
u = 9.5;
|
||||
M_MOVE_DEFAULT(k, u);
|
||||
assert(k == 9.5);
|
||||
@@ -431,7 +444,7 @@ static void test_move_default(void)
|
||||
f_ti(x);
|
||||
assert(x[0] == 0);
|
||||
|
||||
ts y2, x2 = { .b = 2, .c = 3};
|
||||
ts y2, x2 = { 2, 3};
|
||||
M_MOVE_DEFAULT(y2, x2);
|
||||
assert(y2.b == 2 && y2.c == 3);
|
||||
assert(x2.b == 0 && x2.c == 0);
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "test-obj.h"
|
||||
#include "m-string.h"
|
||||
#include "m-funcobj.h"
|
||||
#include "coverage.h"
|
||||
|
||||
START_COVERAGE
|
||||
|
||||
/* Define one interface with some params
|
||||
and 2 instances with some data and no data*/
|
||||
FUNC_OBJ_ITF_DEF(interface1, int, int, const int *)
|
||||
|
||||
FUNC_OBJ_INS_DEF(instance11,
|
||||
interface1,
|
||||
(a, b), {
|
||||
assert(string_equal_str_p(self->c, "INIT"));
|
||||
string_set_str(self->c, "CALLED");
|
||||
return self->sort_field*(a - *b);
|
||||
},
|
||||
(sort_field, int),
|
||||
(c, string_t, STRING_OPLIST) )
|
||||
|
||||
FUNC_OBJ_INS_DEF(instance12,
|
||||
interface1,
|
||||
(a, b), {
|
||||
return a - *b;
|
||||
})
|
||||
|
||||
/* Define one interface with no param
|
||||
and 2 instances with some data and no data*/
|
||||
FUNC_OBJ_ITF_DEF(interface2, int)
|
||||
|
||||
FUNC_OBJ_INS_DEF(instance21,
|
||||
interface2,
|
||||
(), {
|
||||
return 1;
|
||||
})
|
||||
|
||||
FUNC_OBJ_INS_DEF(instance22,
|
||||
interface2,
|
||||
(), {
|
||||
self->a ++;
|
||||
return self->a;
|
||||
}, (a, int) )
|
||||
|
||||
END_COVERAGE
|
||||
|
||||
#define M_OPL_instance22_t() FUNC_OBJ_INS_OPLIST(instance22, M_DEFAULT_OPLIST)
|
||||
|
||||
static void test_instance11(void)
|
||||
{
|
||||
instance11_t cmp;
|
||||
int n = 2;
|
||||
instance11_init_with(cmp, -1, STRING_CTE("INIT") );
|
||||
int x = interface1_call(instance11_as_interface(cmp), 10, &n);
|
||||
assert(x == -8);
|
||||
assert(string_equal_str_p(cmp->c, "CALLED"));
|
||||
instance11_clear(cmp);
|
||||
|
||||
instance11_init_with(cmp, 1, STRING_CTE("INIT") );
|
||||
x = interface1_call(instance11_as_interface(cmp), 100, &n);
|
||||
assert(x == 98);
|
||||
assert(string_equal_str_p(cmp->c, "CALLED"));
|
||||
instance11_clear(cmp);
|
||||
}
|
||||
|
||||
static void test_instance12(void)
|
||||
{
|
||||
instance12_t cmp;
|
||||
int n = 0;
|
||||
instance12_init(cmp);
|
||||
int x = interface1_call(instance12_as_interface(cmp), 10, &n);
|
||||
assert(x == 10);
|
||||
instance12_clear(cmp);
|
||||
}
|
||||
|
||||
static void test_instance21(void)
|
||||
{
|
||||
instance21_t cmp;
|
||||
instance21_init(cmp);
|
||||
int x = interface2_call(instance21_as_interface(cmp));
|
||||
assert(x == 1);
|
||||
instance21_clear(cmp);
|
||||
}
|
||||
|
||||
static void test_instance22(void)
|
||||
{
|
||||
M_LET( (cmp, 1), instance22_t) {
|
||||
int x = interface2_call(instance22_as_interface(cmp));
|
||||
assert(x == 2);
|
||||
x = interface2_call(instance22_as_interface(cmp));
|
||||
assert(x == 3);
|
||||
x = interface2_call(instance22_as_interface(cmp));
|
||||
assert(x == 4);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_instance11();
|
||||
test_instance12();
|
||||
test_instance21();
|
||||
test_instance22();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MLIB - TEST module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+39
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -26,21 +26,6 @@
|
||||
|
||||
BOUNDED_STRING_DEF(string16, 16)
|
||||
|
||||
static void test1(void)
|
||||
{
|
||||
M_LET(s1, s2, string_t) {
|
||||
string_set_str(s1, "Success!");
|
||||
string_set(s2, s1);
|
||||
assert(string_equal_p(s1, s2));
|
||||
}
|
||||
M_LET((s1,"OK"),string_t) {
|
||||
assert(string_equal_str_p(s1, "OK"));
|
||||
}
|
||||
M_LET((s1,"OK S=%d", 16),string_t) {
|
||||
assert(string_equal_str_p(s1, "OK S=16"));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_utf8_basic(void)
|
||||
{
|
||||
string_t s;
|
||||
@@ -573,10 +558,47 @@ static void test_bounded_io(void)
|
||||
string16_clear(d);
|
||||
}
|
||||
|
||||
static void test_M_LET(void)
|
||||
{
|
||||
M_LET(s, string_t) {
|
||||
assert(string_empty_p(s));
|
||||
}
|
||||
M_LET(s1, s2, string_t) {
|
||||
assert(string_empty_p(s1));
|
||||
assert(string_empty_p(s2));
|
||||
string_set_str(s1, "Success!");
|
||||
string_set(s2, s1);
|
||||
assert(string_equal_p(s1, s2));
|
||||
string_set_str(s1, "Try to create a very, very, very, very big string!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
string_set(s2, s1);
|
||||
assert(string_equal_p(s1, s2));
|
||||
}
|
||||
M_LET((s1,"OK"),string_t) {
|
||||
assert(string_equal_str_p(s1, "OK"));
|
||||
}
|
||||
M_LET((s1,"OK S=%d", 16),string_t) {
|
||||
assert(string_equal_str_p(s1, "OK S=16"));
|
||||
}
|
||||
M_LET( (s1, "Hello %s", "world"), s2, (s3, "%d-%d", 42, 17), string_t) {
|
||||
assert(string_equal_str_p(s1, "Hello world"));
|
||||
assert(string_empty_p(s2));
|
||||
assert(string_equal_str_p(s3, "42-17"));
|
||||
}
|
||||
M_LET( (s1, "Hello"), string_t) {
|
||||
assert(string_equal_str_p(s1, "Hello"));
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
|
||||
// Initalization with another string is only supported in C11 mode.
|
||||
M_LET( (s2, s1), string_t) {
|
||||
// In C11 mode, string_equal_p accept also C string
|
||||
assert(string_equal_p(s2, "Hello"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
int main(void)
|
||||
{
|
||||
test0();
|
||||
test1();
|
||||
test_M_LET();
|
||||
test_utf8_basic();
|
||||
test_utf8_it();
|
||||
test_bounded1();
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -71,7 +71,7 @@ TUPLE_DEF2(rtuple,
|
||||
#define M_OPL_rtuple_t() TUPLE_OPLIST(rtuple, M_OPL_pair_str_t(), STRING_OPLIST)
|
||||
|
||||
TUPLE_DEF2(rtuple2, (name, string_t), (value, int))
|
||||
#define M_OPL_rtuple2_t() TUPLE_OPLIST(rtuple2, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_rtuple2_t() TUPLE_OPLIST(rtuple2, string_t, int)
|
||||
|
||||
TUPLE_DEF2(rtuple3, (name, string_t), (ituple2, rtuple2_t), (ituple, rtuple_t) )
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+4
-2
@@ -44,8 +44,10 @@ static void testobj_init_set(testobj_t d, const testobj_t s)
|
||||
|
||||
static void testobj_set(testobj_t d, const testobj_t s)
|
||||
{
|
||||
testobj_clear(d);
|
||||
testobj_init_set(d, s);
|
||||
if (d != s) {
|
||||
testobj_clear(d);
|
||||
testobj_init_set(d, s);
|
||||
}
|
||||
}
|
||||
|
||||
static void testobj_set_ui(testobj_t d, unsigned int v)
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Reference in new issue
Block a user