Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62c8ac3e5d | ||
|
|
1d7e93251c | ||
|
|
92fa4691d1 | ||
|
|
a20fdf4713 | ||
|
|
570dedf1c3 | ||
|
|
59e5c873ad | ||
|
|
8dbcdf9991 | ||
|
|
cd43b50068 | ||
|
|
c0413a26f9 | ||
|
|
b2d3d86e0c | ||
|
|
bc7552f4a8 | ||
|
|
28ae13092f | ||
|
|
1f561da43f | ||
|
|
ef8dcda196 | ||
|
|
cf9eb892cf | ||
|
|
ffa1e2e59c | ||
|
|
9549e82b04 | ||
|
|
50261e390e | ||
|
|
618fc99cda | ||
|
|
a9fc7e15f8 | ||
|
|
6b064870f5 | ||
|
|
d78c50be3b | ||
|
|
c96cea5a13 | ||
|
|
51d4e930f5 | ||
|
|
e650addfe4 | ||
|
|
30afcb45d8 | ||
|
|
e10c3586a3 | ||
|
|
836d892832 | ||
|
|
826d251ffe | ||
|
|
510cd062ba | ||
|
|
2695cd6f3e | ||
|
|
f6e3cbbb65 | ||
|
|
f172bbaad2 | ||
|
|
9176953a8e | ||
|
|
ae6b87d646 | ||
|
|
f719b2387a | ||
|
|
5bfa8321d0 | ||
|
|
e99fd23e69 | ||
|
|
5057366fb2 | ||
|
|
44801b8b91 | ||
|
|
9eabc86bdd | ||
|
|
fbc8f407eb | ||
|
|
09a8b93634 | ||
|
|
2caa7b77e7 | ||
|
|
c057247126 | ||
|
|
0899be21c3 | ||
|
|
c29c9f9ccd | ||
|
|
c12f698f32 | ||
|
|
d6a8a6d159 | ||
|
|
7bf325f91a | ||
|
|
fdfff0c5c5 | ||
|
|
4409f613e0 | ||
|
|
9de644b0f3 | ||
|
|
3e36363d28 | ||
|
|
4f1d1a949c | ||
|
|
e52f3b8b30 | ||
|
|
36916e7b3d | ||
|
|
ba778e9bd2 | ||
|
|
df7112489a | ||
|
|
d9c203736f | ||
|
|
2b61ffa784 | ||
|
|
ba85640172 | ||
|
|
4d21ad5050 | ||
|
|
aae14de62b | ||
|
|
70fa621745 | ||
|
|
e97f4f7f41 | ||
|
|
7a08ddce9e | ||
|
|
e19c9d31a8 | ||
|
|
51ae5f9f0c | ||
|
|
22e8133f95 | ||
|
|
c2e19fed01 | ||
|
|
274afc9978 | ||
|
|
0c337836ca | ||
|
|
1a3e694e20 | ||
|
|
a0572b63b1 | ||
|
|
1765d8ef06 | ||
|
|
1e00a102e8 | ||
|
|
61f8dcdbae | ||
|
|
39eeb3aec7 | ||
|
|
2178dcfcab | ||
|
|
f8b4f44105 | ||
|
|
9c2468c2b7 | ||
|
|
3d5cc55d0a | ||
|
|
5b9cccd2dd | ||
|
|
103b2ab79b | ||
|
|
05f1cd784c | ||
|
|
6e6754f84e | ||
|
|
33ef448a86 | ||
|
|
8ce59c2e9d | ||
|
|
85a363d325 | ||
|
|
7dc1a9dc0e | ||
|
|
983d90b731 | ||
|
|
f307762801 | ||
|
|
7924798e7a | ||
|
|
e46bbaffb9 | ||
|
|
0171c49413 | ||
|
|
a79cd9da97 | ||
|
|
408959c927 | ||
|
|
ac4d93fe29 | ||
|
|
82d224fa66 | ||
|
|
a5b6d8e391 | ||
|
|
7f79abec3f | ||
|
|
ca8d4aa97a | ||
|
|
690cef561c | ||
|
|
16ac4c556b | ||
|
|
3c175b9199 | ||
|
|
a3827cc384 | ||
|
|
353daecbd1 | ||
|
|
368392fb8f | ||
|
|
57441b2fc1 | ||
|
|
b225600238 | ||
|
|
6b361e0d0c | ||
|
|
08668aa02b | ||
|
|
3d3eb6f1d2 | ||
|
|
9bd820c652 | ||
|
|
0e960ec23f | ||
|
|
ca65d81b60 | ||
|
|
23624a1d73 | ||
|
|
3ac08b0395 | ||
|
|
dedb79dbc5 | ||
|
|
154b503bc6 | ||
|
|
5c612ce521 | ||
|
|
80582ac5ce | ||
|
|
8e6af3bfeb | ||
|
|
61671d1b18 | ||
|
|
aa3ad973d0 | ||
|
|
a19a010d1e | ||
|
|
36003b6bb3 | ||
|
|
3c83e4088c | ||
|
|
357feb9532 | ||
|
|
7e234cba65 | ||
|
|
0535ceeaeb | ||
|
|
e688f0b1df | ||
|
|
a950e15625 | ||
|
|
cf8b198dac | ||
|
|
c75d5da02d | ||
|
|
cdffb15066 | ||
|
|
cd0ad0dba9 | ||
|
|
d3be5dba96 | ||
|
|
cb94a26a9f | ||
|
|
3c8b238e75 | ||
|
|
74202d52b3 | ||
|
|
603c92cd0e | ||
|
|
e514d74f43 | ||
|
|
970161464a | ||
|
|
3e7de27c00 | ||
|
|
e28d403216 | ||
|
|
fdeb9f1322 | ||
|
|
76fad21103 | ||
|
|
5d4fa31083 | ||
|
|
c3858f4e63 | ||
|
|
2e0fc21878 | ||
|
|
4b71bbec7e | ||
|
|
052989a5a2 | ||
|
|
60cfc63c4e | ||
|
|
60ef4c7f06 | ||
|
|
58fc40d0f1 | ||
|
|
3d7e9e7c03 | ||
|
|
52e745f905 | ||
|
|
8433fc178c | ||
|
|
59807baa18 | ||
|
|
9b5b15e8cb | ||
|
|
2c54b63c51 | ||
|
|
e4d1167274 | ||
|
|
2f10aba390 | ||
|
|
a044fadec8 | ||
|
|
0edb6165b5 | ||
|
|
7d262f2450 | ||
|
|
fa30328572 | ||
|
|
b0cff7c6ac | ||
|
|
50da9e803c | ||
|
|
26252fedf5 | ||
|
|
2dcda90c7b | ||
|
|
b7d79c0a83 | ||
|
|
ae285c0a01 | ||
|
|
07db846f3b | ||
|
|
3b6907b743 | ||
|
|
82e49c6214 | ||
|
|
8e9aa9cac4 | ||
|
|
5cd6c1dd36 | ||
|
|
a98ce5ea91 | ||
|
|
a4bb0fab8f | ||
|
|
7b2e242c94 | ||
|
|
5fd6352a4e | ||
|
|
a82f2ba065 | ||
|
|
3377acd9e6 | ||
|
|
709168652a | ||
|
|
e25e9ba29b | ||
|
|
ed5eac6e9d | ||
|
|
651768f012 | ||
|
|
88c0a881da | ||
|
|
5b9dd504e5 | ||
|
|
165ec09061 | ||
|
|
6cc972bab2 | ||
|
|
333047fc4c | ||
|
|
3e4a5932c2 | ||
|
|
e2f6b81a03 | ||
|
|
0231aad947 | ||
|
|
6636800c5b | ||
|
|
d1f41de0cb | ||
|
|
c4d339cb62 | ||
|
|
56b2adc57d | ||
|
|
a73bee2650 | ||
|
|
517da1b999 | ||
|
|
25497bd96f | ||
|
|
d12b1edc39 | ||
|
|
0515cfd068 | ||
|
|
e84bc9fc0d | ||
|
|
d85df43329 | ||
|
|
16e2e07d41 | ||
|
|
57fcb4012b | ||
|
|
5be981def3 | ||
|
|
493e38abfc | ||
|
|
6e006d216b | ||
|
|
da613ad188 | ||
|
|
3dad326bea | ||
|
|
480a791f4c | ||
|
|
753c46ef14 | ||
|
|
f2d5de252b | ||
|
|
0cb1a8054f | ||
|
|
07eb5697ab | ||
|
|
e4dc06a0e2 | ||
|
|
cd2012f33d | ||
|
|
9eba30648d | ||
|
|
7e70371197 | ||
|
|
527f6d8d9a | ||
|
|
9ebc12a98f | ||
|
|
bb21d9a6ad | ||
|
|
ad39cdd393 | ||
|
|
0de771036b | ||
|
|
6d6afa4cfd | ||
|
|
7546cbedd2 | ||
|
|
8d5962eefd | ||
|
|
8597b0b8c0 | ||
|
|
c625c39883 | ||
|
|
bce86460fe | ||
|
|
f002eebc83 | ||
|
|
139da2e49f |
No files matched your search
@@ -12,13 +12,13 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make check C99
|
||||
run: make clean check CC="cc -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
run: make clean && make check -j 2 CC="cc -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C11
|
||||
working-directory: ./tests
|
||||
run: make clean check CC="cc -std=c11 -Wno-unknown-warning-option -Werror"
|
||||
run: make clean && make check -j 2 CC="cc -std=c11 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C++
|
||||
working-directory: ./tests
|
||||
run: make clean check CC="c++ -std=c++11"
|
||||
run: make clean && make check -j 2 CC="c++ -std=c++11"
|
||||
|
||||
build_linux32:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -28,13 +28,19 @@ jobs:
|
||||
- name: update package list
|
||||
run: sudo apt-get update
|
||||
- name: install multilib
|
||||
run: sudo apt-get install gcc-multilib
|
||||
run: sudo apt-get install gcc-multilib g++-multilib
|
||||
- name: make check C99 (32bits)
|
||||
working-directory: ./tests
|
||||
run: make clean check CC="gcc -m32 -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
run: make clean && make check -j 2 CC="gcc -m32 -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C11 (32bits)
|
||||
working-directory: ./tests
|
||||
run: make clean check CC="gcc -m32 -std=c11 -Wno-unknown-warning-option -Werror"
|
||||
run: make clean && make check -j 2 CC="gcc -m32 -std=c11 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C++ (32 bits)
|
||||
working-directory: ./tests
|
||||
run: make clean && make check -j 2 CC="g++ -m32 -std=c++11 -Wno-unknown-warning-option "
|
||||
- name: make check against C++ STL
|
||||
working-directory: ./tests
|
||||
run: make clean && make check-stl -j 2
|
||||
|
||||
build_linux_tcc:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -61,7 +67,7 @@ jobs:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make check
|
||||
shell: bash
|
||||
run: mingw32-make CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
run: mingw32-make -j 2 CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
|
||||
build_windows_msys2:
|
||||
runs-on: windows-latest
|
||||
@@ -76,7 +82,7 @@ jobs:
|
||||
update: true
|
||||
install: git mingw-w64-x86_64-toolchain make
|
||||
- name: make check
|
||||
run: make CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
run: make -j 2 CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
|
||||
build_windows_visual:
|
||||
runs-on: windows-latest
|
||||
|
||||
@@ -34,11 +34,6 @@ jobs:
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
|
||||
@@ -42,3 +42,4 @@ config
|
||||
.vscode
|
||||
.vs
|
||||
tmp-serial.*
|
||||
*~
|
||||
@@ -34,14 +34,14 @@ DESTDIR=
|
||||
|
||||
# Package name & version.
|
||||
PACKAGE=m_lib-$(VERSION)
|
||||
VERSION=0.5.0
|
||||
VERSION=0.6.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-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/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.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-list01.c example/ex-mph.c example/ex-multi01.c example/ex-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json 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-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/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt
|
||||
EXAMPLE=example/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.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-list01.c example/ex-mph.c example/ex-multi01.c example/ex-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json example/Makefile example/ex-defer01.c example/ex-string01.c example/ex-string02.c example/ex-astar.c example/ex-string03.c example/ex11-tstc.c
|
||||
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/tgen-mserial.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt tests/fail-chain-oplist.c tests/fail-incompatible.c tests/fail-no-oplist.c tests/test-mishared.c tests/check-array.cpp tests/check-deque.cpp tests/check-dplist.cpp tests/check-list.cpp tests/check-rbtree.cpp tests/check-uset.cpp tests/check-generic.hpp
|
||||
|
||||
.PHONY: all test check doc clean distclean depend install uninstall dist
|
||||
|
||||
@@ -58,10 +58,11 @@ checkall:
|
||||
cd tests && $(MAKE) checkall
|
||||
cd example && $(MAKE) all
|
||||
|
||||
html: doc
|
||||
doc: README.md doc/depend.png
|
||||
html: README.md
|
||||
markdown < README.md > README.html
|
||||
|
||||
doc: html doc/depend.png
|
||||
|
||||
clean:
|
||||
cd tests && $(MAKE) clean
|
||||
cd example && $(MAKE) clean
|
||||
@@ -81,7 +82,7 @@ doc/depend.png: $(HEADER)
|
||||
dot -Tpng depend.dot -o doc/depend.png
|
||||
optipng -o7 doc/depend.png
|
||||
|
||||
dist: $(HEADER) $(DOC1) $(DOC2) $(EXAMPLE) $(TEST) Makefile clean
|
||||
dist: $(HEADER) $(DOC1) $(DOC2) $(EXAMPLE) $(TEST) Makefile clean versioncheck
|
||||
$(MKDIR) '$(PACKAGE)'
|
||||
$(MKDIR) '$(PACKAGE)/doc'
|
||||
$(MKDIR) '$(PACKAGE)/tests'
|
||||
@@ -96,6 +97,14 @@ dist: $(HEADER) $(DOC1) $(DOC2) $(EXAMPLE) $(TEST) Makefile clean
|
||||
distcheck: dist
|
||||
cd '$(PACKAGE)' && make check
|
||||
|
||||
versioncheck:
|
||||
@if test "$(VERSION)." != `grep M_CORE_VERSION m-core.h |awk '{printf "%d.",$$3 } END {printf "\n"}'` ; then echo "ERROR: Version mismatch between Makefile & HEADERS" ; exit 2 ; fi
|
||||
@for i in *.h ; do echo $(HEADER) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing header $$i in Makefile" ; exit 3 ; fi ; done
|
||||
@for i in doc/* ; do echo $(DOC2) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing document $$i in Makefile" ; exit 4 ; fi ; done
|
||||
@for i in tests/*.c tests/*.txt tests/*.h ; do echo $(TEST) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing test $$i in Makefile" ; exit 5 ; fi ; done
|
||||
@for i in example/*.c example/*.json ; do echo $(EXAMPLE) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing example $$i in Makefile" ; exit 6 ; fi ; done
|
||||
@for i in tests/*.cpp tests/*.hpp ; do echo $(TEST) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing test $$i in Makefile" ; exit 7 ; fi ; done
|
||||
|
||||
install:
|
||||
$(MKDIR) $(DESTDIR)$(PREFIX)/include/m-lib
|
||||
$(INSTALL_DATA) $(HEADER) $(DESTDIR)$(PREFIX)/include/m-lib
|
||||
|
||||
+13
-1
@@ -39,7 +39,7 @@ pgo:
|
||||
|
||||
#########################################################################
|
||||
|
||||
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-cmc 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
|
||||
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-cmc 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 bench-ctl
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-rigtorp-mpmc-queue
|
||||
@@ -339,6 +339,18 @@ bench-rigtorp-mpmc-queue0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RIGTORP_MPMC_QUEUE}" bench-rigtorp-mpmcqueue.cpp common.c -DMULTI_THREAD_MEASURE -o bench-mpmcqueue.exe -lpthread
|
||||
@./bench-mpmcqueue.exe 60
|
||||
|
||||
# CTL shall point to the source directory (not where the headers are)
|
||||
bench-ctl:
|
||||
@if test -n "$${CTL}" ; then $(MAKE) bench-ctl0 ; else echo "Nothing to be done for CTL." ; fi
|
||||
|
||||
bench-ctl0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${CTL} bench-ctl.c common.c -o bench-ctl.exe
|
||||
@./bench-ctl.exe 10
|
||||
@./bench-ctl.exe 20
|
||||
@./bench-ctl.exe 30
|
||||
@./bench-ctl.exe 40
|
||||
@./bench-ctl.exe 50
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-mlib-json: bench-mlib
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "m-core.h"
|
||||
#include "common.h"
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
/********************************************************************************************/
|
||||
#define POD
|
||||
#define T uint
|
||||
#include "ctl/vector.h"
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
vec_uint a1 = vec_uint_init();
|
||||
vec_uint a2 = vec_uint_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
vec_uint_push_back(&a1, rand_get() );
|
||||
vec_uint_push_back(&a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *vec_uint_at(&a1, i ) * *vec_uint_at(&a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
vec_uint_free(&a1);
|
||||
vec_uint_free(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T uint
|
||||
#include "ctl/forward_list.h"
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
slist_uint a1 = slist_uint_init();
|
||||
slist_uint a2 = slist_uint_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
slist_uint_push_front(&a1, rand_get());
|
||||
slist_uint_push_front(&a2, rand_get());
|
||||
}
|
||||
unsigned int s = 0;
|
||||
slist_uint_it it1 = slist_uint_begin(&a1);
|
||||
slist_uint_it it2 = slist_uint_begin(&a2);
|
||||
for( ; !slist_uint_it_done(&it1) ;
|
||||
slist_uint_it_next(&it1), slist_uint_it_next(&it2)) {
|
||||
s += *slist_uint_it_ref(&it1) * *slist_uint_it_ref(&it2);
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
slist_uint_free(&a1);
|
||||
slist_uint_free(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T ulong
|
||||
#include "ctl/set.h"
|
||||
|
||||
static inline int
|
||||
int_cmp(ulong *a, ulong *b) {
|
||||
return *a < *b;
|
||||
}
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
set_ulong tree = set_ulong_init (int_cmp);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
set_ulong_insert (&tree, rand_get() );
|
||||
}
|
||||
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
if (set_ulong_find_node(&tree, j) != NULL)
|
||||
s+= j;
|
||||
}
|
||||
g_result = s;
|
||||
set_ulong_free(&tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
} pair_ulong;
|
||||
|
||||
// Use of M*LIB hash function
|
||||
static inline size_t
|
||||
pair_ulong_hash(pair_ulong *a)
|
||||
{
|
||||
return M_HASH_DEFAULT(a->key);
|
||||
}
|
||||
|
||||
static inline int
|
||||
pair_ulong_equal(pair_ulong *a, pair_ulong *b)
|
||||
{
|
||||
return a->key == b->key;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pair_ulong_free(pair_ulong *a) {
|
||||
(void) a;
|
||||
}
|
||||
|
||||
static inline pair_ulong
|
||||
pair_ulong_copy(pair_ulong *self) {
|
||||
return (pair_ulong) { .key = self->key, .value = self->value };
|
||||
}
|
||||
|
||||
#define T pair_ulong
|
||||
#include <ctl/unordered_map.h>
|
||||
|
||||
// It seems broken: it doesn't output the expected result.
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
umap_pair_ulong dict = umap_pair_ulong_init(pair_ulong_hash, pair_ulong_equal);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
umap_pair_ulong_insert(&dict, (pair_ulong) { rand_get(), rand_get() });
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
umap_pair_ulong_it it = umap_pair_ulong_find(&dict, (pair_ulong) { rand_get() , 0 } );
|
||||
if (!umap_pair_ulong_it_done(&it) )
|
||||
s += it.ref->value;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
umap_pair_ulong_free(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T float
|
||||
#include "ctl/vector.h"
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
vec_float a1 = vec_float_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
vec_float_push_back(&a1, rand_get());
|
||||
}
|
||||
vec_float_sort(&a1);
|
||||
g_result = *vec_float_at(&a1, 0);
|
||||
vec_float_free(&a1);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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},
|
||||
{ 50, "Sort", 10000000, 0, test_sort, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("CTL", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -35,10 +35,9 @@ static inline size_t my_hash(uint64_t key)
|
||||
{
|
||||
return ((key) ^ (key)>>7);
|
||||
}
|
||||
static inline void update_val(uint32_t *p, uint32_t v) { *p += v;}
|
||||
DICT_OA_DEF2(dict_oligonucleotide,
|
||||
uint64_t, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(my_oor_equal_p), OOR_SET(my_oor_set M_IPTR)),
|
||||
uint32_t, M_OPEXTEND(M_DEFAULT_OPLIST, UPDATE(update_val M_IPTR)))
|
||||
uint32_t, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_dict_oligonucleotide_t() DICT_OPLIST(dict_oligonucleotide, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(my_oor_equal_p), OOR_SET(my_oor_set M_IPTR)), M_DEFAULT_OPLIST)
|
||||
|
||||
// Define a B*TREE-21 of uint32_t --> uint64_t and register its oplist
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "../common.c"
|
||||
#define DICTI_OA_PROBING(s) 1
|
||||
#define M_USE_DICT_OA_PROBING(s) 1
|
||||
#include "m-dict.h"
|
||||
|
||||
static inline bool oor_equal_p(unsigned int k, unsigned char n)
|
||||
|
||||
+16
@@ -57,3 +57,19 @@ V0.4.*: * The order of a list initialized using M_LET is reversed
|
||||
* Rename TUPLE _init_set2 in _init_emplace & _set2 in _emplace.
|
||||
* Rename Priority Queue method _update_further in _update.
|
||||
|
||||
V0.5.*: * M_INVERT is renamed into M_REVERSE to be more coherent with the REVERSE operator.
|
||||
M_INVERT is marked as obsolete.
|
||||
* Remove _it_to_p method of B+TREE / RB-TREE as it has been deprecated.
|
||||
* Remove ALGO_INIT_VA & M_ALG0_LET_INIT_VAI of m-algo as it has been deprecated (Use of M_LET instead).
|
||||
* Some Internal name of user modifiable macros have been renamed to be properly
|
||||
customizable by the user.
|
||||
* Rename M_HASH_SEED into M_USE_HASH_SEED (as it is a user macro).
|
||||
* M_LET: for initialization of variable with arguments, if there is only one argument,
|
||||
it will default to use INIT_SET instead of INIT_WITH.
|
||||
==> Encapsulate the argument between () to force use of INIT_WITH.
|
||||
* Remove of UPDATE operator. Use of SET for RBTREE or ADD for DICT instead.
|
||||
* Make the _clean suffix for reseting the container to empty deprecated. Use new _reset suffix instead.
|
||||
* Make the _get_at suffix for always getting a value deprecated. Use new _safe_get suffix instead.
|
||||
* Rename CLEAN operator in RESET operator.
|
||||
* Rename GET_SET_KEY operator in SAFE_GET_KEY operator.
|
||||
|
||||
Binary file not shown.
+61
-16
@@ -17,23 +17,31 @@ How to make a release?
|
||||
In case of problem, open a problem report.
|
||||
|
||||
|
||||
List of tested systems
|
||||
=======================
|
||||
List of automatically tested systems
|
||||
====================================
|
||||
|
||||
* gcc 4.9, 7 & 8 on linux/x86-64
|
||||
* clang 3.5, 4 & 6 on linux/x86-64
|
||||
* g++ 7 & 8 on linux/x86-64
|
||||
* gcc on linux/x86-64 (32 bits and 64 bits)
|
||||
* g++ on linux/x86-64 (32 bits and 64 bits)
|
||||
* clang on macos/x86-64
|
||||
* clang++ on macos/x86-64
|
||||
* tcc on linux/x86-64
|
||||
* gcc 7 on windows/x86-64
|
||||
* gcc 4.9 on linux/powerpc
|
||||
* gcc 6 on linux/armv7l
|
||||
* clang 3.8 on linux/armv7l
|
||||
* gcc on windows/x86-64 (mingw)
|
||||
* msvc on windows/x86-64
|
||||
* clang on windows/x86-64
|
||||
|
||||
List of manually tested systems
|
||||
===============================
|
||||
|
||||
* clang on linux/x86-64
|
||||
* clang on linux/armv7l
|
||||
* gcc on linux/powerpc
|
||||
* gcc on linux/armv7l
|
||||
|
||||
Atomic library
|
||||
==============
|
||||
|
||||
For target, armel m68k mips mipsel powerpc powerpcspe sh4, you may need to run the test suite:
|
||||
For the targets armel, m68k, mips, mipsel, powerpc, powerpcspe or sh4,
|
||||
you may need to run the test suite by adding the atomic library:
|
||||
|
||||
make check LDFLAGS="-pthread -latomic"
|
||||
|
||||
@@ -45,7 +53,7 @@ Cross compilation
|
||||
|
||||
There is no need to cross compile the library as it is a header only library.
|
||||
|
||||
However if you want to run the test with a cross-compiler, do like the following
|
||||
However if you want to run the tests with a cross-compiler, do like the following
|
||||
command. It performs a cross-compilation of the test suite from linux to windows
|
||||
and run the test suite with wine:
|
||||
|
||||
@@ -57,9 +65,8 @@ Handling issues
|
||||
|
||||
Issues are opened in the bug tracker of the project (typically https://github.com/P-p-H-d/mlib/issues )
|
||||
|
||||
If the issue cannot be closed and taken into account in less than (typically) one month,
|
||||
or before a release,
|
||||
it shall be moved into the long term issues included in the repository:
|
||||
If the issue cannot be taken into account quickly and are long term,
|
||||
it should be moved into the long term issues included in the repository:
|
||||
https://github.com/P-p-H-d/mlib/blob/master/doc/ISSUES.org
|
||||
This is a file in ORG mode: the issues are created with the proper tags.
|
||||
|
||||
@@ -75,7 +82,7 @@ its state shall be changed to DONE (the issue shall not be removed).
|
||||
|
||||
|
||||
Debugging
|
||||
===============
|
||||
=========
|
||||
|
||||
Debugging the library can be quite difficult
|
||||
as it performs heavy preprocessing expansion
|
||||
@@ -86,7 +93,7 @@ Different strategy for debugging the library itself are still possible:
|
||||
Add printf of interresting values in the debugged function.
|
||||
|
||||
|
||||
2) Preprocess the library and then compile the preprocessed file:
|
||||
2) Preprocess the library and then compile the preprocessed file like this:
|
||||
|
||||
cc -std=c99 -E test-file.c > test-file.i
|
||||
perl -pi -e 's/;/;\n/g' test-file.i
|
||||
@@ -109,3 +116,41 @@ Run the wave driver:
|
||||
./wave ex-array01.c -I .. --c99 -t test.trace
|
||||
|
||||
The different expansion performed by the library are described in test.trace
|
||||
|
||||
Coding rules
|
||||
============
|
||||
|
||||
* Use of non standard C shall be protected under a specific compiler test,
|
||||
so that the library remains compatible with a strict C99 compiler.
|
||||
|
||||
* C11 features shall be optional.
|
||||
|
||||
* Use 'make format' to format the header files properly.
|
||||
|
||||
* External types shall be suffixed by _t and in lower case
|
||||
but shall be optional if the user doesn't want then.
|
||||
|
||||
* Internal types shall be suffixed by _ct and in lower case
|
||||
(as confidential types)
|
||||
|
||||
* External / Internal functions shall be in lower case.
|
||||
|
||||
* External / Internal macros shall be in upper case.
|
||||
|
||||
* Internal macros / functions shall be prefixed by m_<container>
|
||||
with container is the name of the container with one letter transformed:
|
||||
o --> 0
|
||||
e --> 3
|
||||
i --> 1
|
||||
y --> 4
|
||||
This prevents the automatic completion to work when the user starts writing its function.
|
||||
|
||||
* Test functions shall be predicated and be suffixed by '_p'
|
||||
|
||||
|
||||
Misc
|
||||
====
|
||||
|
||||
To put a breakpoint for the thread sanitizer in case of error, in gdb add:
|
||||
|
||||
$ set env TSAN_OPTIONS=halt_on_error=1,abort_on_error=1
|
||||
+46
-34
@@ -5,17 +5,34 @@
|
||||
|
||||
Specialize Hashmap for huge objects on supported hardware:
|
||||
|
||||
based on OA hash map with taggued pointer (needs space for tagging):
|
||||
low bits = low bits of hash
|
||||
Based on OA hash map with taggued pointer (needs space for tagging):
|
||||
low bits = high bits of hash
|
||||
pointer to object { key, hash, value }
|
||||
|
||||
Can detect collision without dereferencing object with 1/2^lowbits chances.
|
||||
Can solve collision without dereferencing object with 1/2^lowbits chances.
|
||||
NB: hash may be uneeded due to the small chances of collision.
|
||||
Reduce cache usage ==> Should be faster.
|
||||
Increase cache usage for very small object (integer).
|
||||
|
||||
Use of pointer to avoid moving object on GC.
|
||||
|
||||
On AMD64, only 48 bits of 64 bits are really used for addressing data.
|
||||
==> lowbits= 16
|
||||
Empty representation= 0 (hash can be 0. pointer cannot be it).
|
||||
Deleted representation = 1 (pointer cannot be zero)
|
||||
|
||||
<---- PTR ----><-HASH->
|
||||
|
||||
#+BEGIN_SRC C
|
||||
#define LOW_BITS 16
|
||||
#define ALIGNED_BITS 2
|
||||
void *get_ptr(int64_t x) {
|
||||
return (void*) ((x >> LOW_BITS) << ALIGNED_BITS);
|
||||
}
|
||||
unsigned get_small_hash(int64_t x) {
|
||||
return x & ((1<<LOW_BITS)-1);
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
* TODO #25 : Support of error code model for error handling. :ENHANCEMENT:
|
||||
|
||||
@@ -85,7 +102,7 @@ Open points:
|
||||
- What about M_LET/ M_EACH?
|
||||
|
||||
|
||||
* TODO #24 : Add MIN-MAX-HEAP container :ENHANCEMENT:
|
||||
* TODO #24 : New: Add MIN-MAX-HEAP container :ENHANCEMENT:
|
||||
|
||||
See https://en.wikipedia.org/wiki/Min-max_heap
|
||||
as DPRIORITY_QUEUE_DEF ?
|
||||
@@ -93,7 +110,7 @@ as DPRIORITY_QUEUE_DEF ?
|
||||
NOTE: Needs for such container?
|
||||
|
||||
|
||||
* TODO #23: Force MOVE semantic :ENHANCEMENT:
|
||||
* TODO #23: Strict MOVE semantic to clarify :ENHANCEMENT:
|
||||
|
||||
Some type may need to have a force MOVE semantic (for example, they can store
|
||||
pointer to themselves). Currently the INIT_MOVE & MOVE operators are more
|
||||
@@ -128,7 +145,7 @@ operators as it uses MOVE_DEFAULT which is not (fully compatible).
|
||||
==> Analyse limitation and possible constraint usages.
|
||||
|
||||
|
||||
* TODO #20: Bucket priority queue :ENHANCEMENT:
|
||||
* TODO #20: New: Bucket priority queue :ENHANCEMENT:
|
||||
|
||||
Add a new kind of priority queue.
|
||||
See https://en.wikipedia.org/wiki/Bucket_queue
|
||||
@@ -145,7 +162,7 @@ Check if we can use BITSET, or introduce fixed size BITSET or use ad-hock
|
||||
implementation.
|
||||
|
||||
|
||||
* TODO #19: Intrusive Red Black Tree :ENHANCEMENT:
|
||||
* TODO #19: New: Intrusive Red Black Tree :ENHANCEMENT:
|
||||
|
||||
Add intrusive red black tree.
|
||||
Look also for AVL tree (NOTE: Is there a performance difference between the two?)
|
||||
@@ -158,9 +175,9 @@ See the cells in yellow here:
|
||||
http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Container.html
|
||||
|
||||
|
||||
* TODO #17: Ressource handler :ENHANCEMENT:
|
||||
* TODO #17: New: Ressource handler :ENHANCEMENT:
|
||||
|
||||
A ressouce handler which shall associated a unique handle to a ressource.
|
||||
A global 'ressouce handler' which shall associated a unique handle to a ressource.
|
||||
The handle shall be unique for the ressource and shall not be reused.
|
||||
It is typically a 64 bits integers always incremented (even if the program
|
||||
creates one billion ressources per second, the counter won't overflow
|
||||
@@ -189,7 +206,7 @@ http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Co
|
||||
* embedded the type in the ressource handler: more work, API more complex. Memory usage seems better.
|
||||
|
||||
|
||||
* TODO #16: Lock Free List :ENHANCEMENT:
|
||||
* TODO #16: New: Lock Free List :ENHANCEMENT:
|
||||
|
||||
Implement a lock free list. Most of the difficulty is the memory reclamation part.
|
||||
Typically this lock free list shall be compatible with RCU method.
|
||||
@@ -271,7 +288,7 @@ Needs some formal operator in the oplist to support it fully and an example.
|
||||
It is a kind of object inheritance where the container inherits some extra data from its base.
|
||||
|
||||
|
||||
* TODO #12: Atomic shared pointer :ENHANCEMENT:
|
||||
* TODO #12: New: Atomic shared pointer :ENHANCEMENT:
|
||||
|
||||
Add an extension to the SHARED_PTR API:
|
||||
|
||||
@@ -347,11 +364,14 @@ Other implementation seems to have it hard to be lock-free: cf. https://github.c
|
||||
|
||||
|
||||
|
||||
* TODO #5: Concurrent dictionary Container :ENHANCEMENT:
|
||||
* TODO #5: New: Concurrent dictionary Container :ENHANCEMENT:
|
||||
|
||||
Implement a more efficient dictionary than lock + std dictionary for all operations when dealing with threads.
|
||||
See https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx
|
||||
|
||||
The best parallel algorithm is still when there is as few synchronization as possible. A concurrent dictionary will fail at this and will result in average performance at best.
|
||||
The typical best case will be in RCU context (a lot of readers, few writers), so the interface shall be compatible with such structure.
|
||||
|
||||
** Multiple locks within the dictionnary
|
||||
|
||||
A potential implementation may be to request at initialization time the number of concurrent thread N.
|
||||
@@ -372,33 +392,25 @@ See also https://github.com/simonhf/sharedhashfile
|
||||
** Lock Free dictionnary
|
||||
|
||||
Evaluate also lock-free dictionary (easier with open addressing).
|
||||
It needs a complete rewrite of the inner loop through. The hard part is the dynamic resizing of the internal array (see http://preshing.com/20160222/a-resizable-concurrent-map/ for a potential solution and http://www.cs.toronto.edu/~tomhart/papers/tomhart_thesis.pdf for memory reclamation techniques). See also https://www.research.ibm.com/people/m/michael/spaa-2002.pdf
|
||||
https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.2017.11.22a.pdf persents different techniques used by linux kernel.
|
||||
It needs a complete rewrite of the inner loop through. The hard part is the dynamic resizing of the internal array.
|
||||
Ssee http://preshing.com/20160222/a-resizable-concurrent-map/ for a potential solution
|
||||
and http://www.cs.toronto.edu/~tomhart/papers/tomhart_thesis.pdf for memory reclamation techniques).
|
||||
and https://www.research.ibm.com/people/m/michael/spaa-2002.pdf
|
||||
https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.2017.11.22a.pdf presents different techniques used by linux kernel.
|
||||
It needs before lock-free list: http://www.cse.yorku.ca/~ruppert/papers/lfll.pdf http://www.cse.yorku.ca/~ruppert/Mikhail.pdf
|
||||
|
||||
** Context
|
||||
|
||||
The best parallel algorithm is still when there is as few synchronization as possible. A concurrent dictionary will fail at this and will result in average performance at best.
|
||||
The typical best case will be in RCU context (a lot of readers, few writers), so the interface shall be compatible with such structure.
|
||||
|
||||
** Linked list
|
||||
|
||||
Another solution is to create a huge list of items which is:
|
||||
|
||||
- atomically updated,
|
||||
- in reverse order of the hash (bit 0 is highest bit, Bit 63 is the lowest bit).
|
||||
|
||||
Hash table will only give quick access to items to this list. Expanding the table won't change the order of the list (so the items will remain at the same place and always accessible by other threads) but just add sentinel in the sentinel at the right place (there won't be any reallocation of the list). Inserting will need to insert an item at the right place.
|
||||
Not sure it will really help. To analyse.
|
||||
|
||||
Concurrent dictionary is possible now with CONCURRENT_DEF + DICT_DEF.
|
||||
But it uses a global lock for all dictionary access.
|
||||
|
||||
** Open Addressing Indirect Table with a lock free node pool used as transaction pool.
|
||||
|
||||
A good way maybe Open Addessing table used only for indirection and a freelist memory reclamation container for handle the entries
|
||||
(like a transaction).
|
||||
|
||||
Solution?
|
||||
--------
|
||||
|
||||
Use of the concurrent pool (m-c-mempool) to allocate items.
|
||||
The big table will only store pointers (+ part of hash in unused bits?) to such allocate items.
|
||||
Atomic update is done by allocating a new node, update it, and atomicaly store it in the dict, putting the old one as logically deleted and to reclaim later.
|
||||
(Other threads may still read its data so we cannot free immediatly).
|
||||
|
||||
|
||||
* DONE #22: Enhanced services for SPSC Queue :ENHANCEMENT:
|
||||
|
||||
Add services:
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// -- An A* pathfinder inspired by the tutorial at Red Blob Games --
|
||||
// https://www.redblobgames.com/pathfinding/a-star/introduction.html
|
||||
// Code based on:
|
||||
// https://github.com/glouw/ctl/blob/master/examples/astar.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-prioqueue.h"
|
||||
#include "m-dict.h"
|
||||
|
||||
// Create a tuple of point, but don't use its priority field for comparison.
|
||||
TUPLE_DEF2( point, (x, int), (y, int), (priority, int, M_OPEXTEND( M_OPL_int(), CMP(0), HASH(0), EQUAL(0) ) ) )
|
||||
#define M_OPL_point_t() TUPLE_OPLIST(point, M_OPL_int(), M_OPL_int(), M_OPL_int())
|
||||
static inline int point_cmp_prio(const point_t a, const point_t b)
|
||||
{
|
||||
return a->priority < b->priority ? -1 : a->priority > b->priority;
|
||||
}
|
||||
PRIOQUEUE_DEF(prio_point, point_t, M_OPEXTEND(M_OPL_point_t(), CMP(point_cmp_prio) ) )
|
||||
#define M_OPL_prio_point_t() PRIOQUEUE_OPLIST(prio_point, M_OPL_point_t() )
|
||||
ARRAY_DEF(array_point, point_t)
|
||||
#define M_OPL_array_point_t() ARRAY_OPLIST(array_point, M_OPL_point_t() )
|
||||
DICT_DEF2(cost_point, point_t, int)
|
||||
#define M_OPL_cost_point_t() DICT_OPLIST(cost_point, M_OPL_point_t(), M_OPL_int())
|
||||
DICT_DEF2(step_point, point_t, point_t)
|
||||
#define M_OPL_step_point_t() DICT_OPLIST(step_point, M_OPL_point_t(), M_OPL_point_t())
|
||||
|
||||
static inline int point_index(const point_t p, int width)
|
||||
{
|
||||
return p->x + width * p->y;
|
||||
}
|
||||
|
||||
static inline void point_set_from(point_t p, const string_t maze, int width, const char pattern[])
|
||||
{
|
||||
size_t s = string_search_str(maze, pattern);
|
||||
point_emplace(p, s % width, s / width , 0);
|
||||
}
|
||||
|
||||
static void astar(array_point_t path, const string_t maze, int width)
|
||||
{
|
||||
M_LET(front, prio_point_t)
|
||||
M_LET(from, step_point_t)
|
||||
M_LET(costs, cost_point_t)
|
||||
M_LET(start, goal, current, next, point_t)
|
||||
{
|
||||
point_set_from(start, maze, width, "@");
|
||||
point_set_from(goal, maze, width, "!");
|
||||
cost_point_set_at(costs, start, 0);
|
||||
prio_point_push(front, start);
|
||||
while (!prio_point_empty_p(front)) {
|
||||
prio_point_pop(¤t, front);
|
||||
if (point_equal_p(current, goal))
|
||||
break;
|
||||
const struct { int x; int y; } deltas[] = {
|
||||
{ -1, +1 }, { 0, +1 }, { 1, +1 },
|
||||
{ -1, 0 }, /* ~ ~ */ { 1, 0 },
|
||||
{ -1, -1 }, { 0, -1 }, { 1, -1 },
|
||||
};
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
point_emplace(next, current->x + deltas[i].x, current->y + deltas[i].y, 0);
|
||||
if (string_get_char(maze, point_index(next, width)) != '#') {
|
||||
int *new_cost = cost_point_get(costs, current);
|
||||
int *cost = cost_point_get(costs, next);
|
||||
if (cost == NULL || *new_cost < *cost) {
|
||||
cost_point_set_at(costs, next, *new_cost);
|
||||
next->priority = *new_cost + abs(goal->x - next->x) + abs(goal->y - next->y);
|
||||
prio_point_push(front, next);
|
||||
step_point_set_at(from, next, current);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
point_set(current, goal);
|
||||
while (!point_equal_p(current, start)) {
|
||||
array_point_push_back(path, current);
|
||||
point_set(current, *step_point_get(from, current));
|
||||
}
|
||||
array_point_push_back(path, start);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET( (maze,
|
||||
("#########################################################################\n"
|
||||
"# # # # # # #\n"
|
||||
"# # ######### # ##### ######### ##### ##### ##### # ! #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"######### # ######### ######### ##### # # # ######### #\n"
|
||||
"# # # # # # # # # # #\n"
|
||||
"# # ############# # # ######### ##### # ######### # #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# ############# ##### ##### # ##### ######### # ##### #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# ##### ##### # ##### # ######### # # # #############\n"
|
||||
"# # # # # # # # # # # #\n"
|
||||
"############# # # # ######### # ##### # ##### ##### #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# ##### # ######### ##### # ##### ##### ############# #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# # ######### # ##### ######### # # ############# # #\n"
|
||||
"# # # # # # # # # # #\n"
|
||||
"# ######### # # # ##### ######### ######### # #########\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# @ # ##### ##### ##### ######### ##### # ######### # #\n"
|
||||
"# # # # # # #\n"
|
||||
"#########################################################################\n")), string_t)
|
||||
M_LET(path, array_point_t)
|
||||
{
|
||||
int width = string_search_str(maze, "\n") + 1;
|
||||
astar(path, maze, width);
|
||||
for M_EACH(it, path, array_point_t) {
|
||||
string_set_char(maze, point_index(*it, width), 'x');
|
||||
}
|
||||
printf("%s", string_get_cstr(maze));
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -34,7 +34,7 @@ int main(int argc, const char *argv[])
|
||||
// While it reads some word from the file
|
||||
while (string_fget_word(word, " \t\n\r\"(),=", f)) {
|
||||
// Get the reference to the array of this word in the dictionnary (or create it if needed)
|
||||
array_size_t *array = map_pos_get_at(positions, word);
|
||||
array_size_t *array = map_pos_safe_get(positions, word);
|
||||
// Push the new offset to this word in the associated array
|
||||
array_size_push_back(*array, (size_t)ftell(f) - string_size(word));
|
||||
}
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ CreateMinimalPerfectHash2(array_seed_t seed, array_value_t value,
|
||||
enought. */
|
||||
for(bool cont = true; cont ; ) {
|
||||
cont = false;
|
||||
array_seed_clean(slots);
|
||||
array_seed_reset(slots);
|
||||
for M_EACH(it, *b, array_cstr_t) {
|
||||
size_t s = hash(d, *it) % size;
|
||||
if (*array_value_get(value, s) != 0 || array_seed_contain_p(slots, s)){
|
||||
|
||||
@@ -48,8 +48,8 @@ static void program_init(program_t p, string_t text) {
|
||||
int left;
|
||||
array_int_pop_back(&left, leftstack);
|
||||
int right = pc;
|
||||
*array_int_get_at (p->bracket_map, left) = right;
|
||||
*array_int_get_at (p->bracket_map, right) = left;
|
||||
*array_int_safe_get (p->bracket_map, left) = right;
|
||||
*array_int_safe_get (p->bracket_map, right) = left;
|
||||
}
|
||||
|
||||
pc++;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
/* Register a dynamic seed to M*LIB hash function.
|
||||
This shall be done before any M*LIB header inclusion. */
|
||||
unsigned long long rand_seed;
|
||||
#define M_HASH_SEED rand_seed
|
||||
#define M_USE_HASH_SEED rand_seed
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-dict.h"
|
||||
|
||||
@@ -20,6 +20,9 @@ static void main_macrofree(void)
|
||||
// Overwrite element 1 of the array.
|
||||
str_array_set_at(tab_name, 1, STRING_CTE("DVD"));
|
||||
|
||||
// Finaly rewrite 1 element of the array
|
||||
string_set_str(*str_array_get(tab_name, 1), "BLU-RAY");
|
||||
|
||||
// Format some strings and push them back in the array
|
||||
string_t format;
|
||||
string_init_printf(format, "There are %d elements", str_array_size(tab_name));
|
||||
@@ -54,6 +57,9 @@ static void main_macro(void)
|
||||
// Overwrite element 1 of the array.
|
||||
str_array_set_at(tab_name, 1, STRING_CTE("DVD"));
|
||||
|
||||
// Finaly rewrite 1 element of the array
|
||||
string_set_str(*str_array_get(tab_name, 1), "BLU-RAY");
|
||||
|
||||
// Format some strings and push them back in the array
|
||||
M_LET(format, string_t) {
|
||||
string_printf(format, "There are %d elements", str_array_size(tab_name));
|
||||
@@ -67,7 +73,7 @@ static void main_macro(void)
|
||||
// Set format to a formated string
|
||||
// In C11, we can mix string_t and char *.
|
||||
// We can also use M_CSTR to create a printf formated string.
|
||||
string_sets(format, "FILE=", getenv("PWD"), "/", *str_array_get(tab_name, 2), M_CSTR("-%d.txt", str_array_size(tab_name) ));
|
||||
string_sets(format, "FILE=", getenv("PWD"), "/", *str_array_get(tab_name, 2), M_CSTR("-%zu.txt", str_array_size(tab_name) ));
|
||||
str_array_push_back(tab_name, format);
|
||||
#endif
|
||||
} // beyond this point format is cleared
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <stdio.h>
|
||||
#include "m-string.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
|
||||
/* Definition of an associative map string_t --> size_t */
|
||||
DICT_DEF2(dict_str, string_t, size_t)
|
||||
#define M_OPL_dict_str_t() DICT_OPLIST(dict_str, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
/* Definition of an array of string_t */
|
||||
ARRAY_DEF(vector_str, string_t)
|
||||
#define M_OPL_vector_str_t() ARRAY_OPLIST(vector_str, STRING_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Construct an array of string, performing a convertion of the C const char *
|
||||
// into a proper string_t at real time and push then into a dynamic array
|
||||
// that is declared, initialized and cleared.
|
||||
M_LET( (words, ("This"), ("is"), ("a"), ("useless"), ("sentence"), ("."),
|
||||
("It"), ("is"), ("used"), ("a"), ("bit"), ("to"), ("count"), ("words"), (".") ),
|
||||
vector_str_t) {
|
||||
// Print the arrays.
|
||||
printf("The words are: ");
|
||||
vector_str_out_str(stdout, words);
|
||||
printf("\n");
|
||||
|
||||
// Count the words.
|
||||
M_LET(map, dict_str_t) {
|
||||
// Count the words:
|
||||
for M_EACH(w, words, vector_str_t) {
|
||||
(*dict_str_safe_get(map, *w)) ++;
|
||||
}
|
||||
|
||||
// Print the count:
|
||||
for M_EACH(p, map, dict_str_t) {
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
|
||||
M_PRINT(p->value, " occurences of ", p->key, "\n");
|
||||
#else
|
||||
printf ("%zu occurences of %s\n", p->value, string_get_cstr(p->key));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,20 +5,21 @@
|
||||
#include "m-serial-json.h"
|
||||
#include "m-string.h"
|
||||
|
||||
/* Define the employee */
|
||||
/* Define the employee class */
|
||||
TUPLE_DEF2(employee,
|
||||
(name, string_t),
|
||||
(age, int),
|
||||
(idnum, int))
|
||||
/* Register globaly the employee_t oplist */
|
||||
#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 */
|
||||
/* Define an array of employee, register the oplist and define further 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
|
||||
* named 'compare_by' which is an instance of the interface
|
||||
/* Define the function object to select the sort order.
|
||||
* It is named 'compare_by' and is an instance of the interface
|
||||
* 'vector_employee_cmp_obj' created by ALGO_DEF.
|
||||
*/
|
||||
FUNC_OBJ_INS_DEF(compare_by /* name of the instance */,
|
||||
@@ -75,15 +76,12 @@ int main(void)
|
||||
// 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_PRINT("Employees sorted by idnum are: ", (emps, vector_employee_t), "\n" );
|
||||
|
||||
// Sort the database by employee name
|
||||
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");
|
||||
M_PRINT("Employees sorted by name are: ", (emps, vector_employee_t), "\n" );
|
||||
|
||||
// End
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/* Based on the example of STC https://github.com/tylov/STC */
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
#include "m-deque.h"
|
||||
#include "m-list.h"
|
||||
#include "m-rbtree.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-tuple.h"
|
||||
|
||||
// NOTE: After each definition of a container, we register its oplist
|
||||
// It is not mandatory, but it makes the code easier to write and read.
|
||||
|
||||
// Define a basic structure (POD structure) using a tuple to get the default functions
|
||||
TUPLE_DEF2(Point, (x, float), (y, float))
|
||||
#define M_OPL_Point_t() TUPLE_OPLIST(Point, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
// NOTE: array, list, deque don't have a native find function.
|
||||
// We'll use the algorithm header to create a find function for such containers.
|
||||
|
||||
// Define a set of int & register its oplist
|
||||
DICT_SET_DEF(cset_i, int)
|
||||
#define M_OPL_cset_i_t() DICT_SET_OPLIST(cset_i, M_DEFAULT_OPLIST)
|
||||
|
||||
// Define an array of Point, register its oplist & include some basic algorithms
|
||||
ARRAY_DEF(cvec_p, Point_t)
|
||||
#define M_OPL_cvec_p_t() ARRAY_OPLIST(cvec_p, M_OPL_Point_t())
|
||||
ALGO_DEF(cvec_p, cvec_p_t)
|
||||
|
||||
// Define a deque of int, including some basic algorithms
|
||||
DEQUE_DEF(cdeq_i, int)
|
||||
#define M_OPL_cdeq_i_t() DEQUE_OPLIST(cdeq_i, M_DEFAULT_OPLIST)
|
||||
ALGO_DEF(cdeq_i, cdeq_i_t)
|
||||
|
||||
// Define a backward list, including some basic algorithms
|
||||
LIST_DEF(clist_i, int)
|
||||
#define M_OPL_clist_i_t() LIST_OPLIST(clist_i, M_DEFAULT_OPLIST)
|
||||
ALGO_DEF(clist_i, clist_i_t)
|
||||
|
||||
// Define an unordered map of int to int
|
||||
DICT_DEF2(csmap_i, int, int)
|
||||
#define M_OPL_csmap_i_t() DICT_OPLIST(csmap_i, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Define, init & set the different containers.
|
||||
M_LET( (set, 10, 20, 30), cset_i_t)
|
||||
M_LET( (vec, (10, 1), (20, 2), (30, 3) ), cvec_p_t)
|
||||
M_LET( (deq, 10, 20, 30), cdeq_i_t)
|
||||
M_LET( (lst, 10, 20, 30), clist_i_t)
|
||||
M_LET( (map, (20, 2), (10, 1), (30,3) ), csmap_i_t) {
|
||||
|
||||
// add one more element to each container
|
||||
cset_i_push(set, 40);
|
||||
cvec_p_push_back(vec, (Point_t) {{40, 4}} );
|
||||
cdeq_i_push_front(deq, 5);
|
||||
clist_i_push_back(lst, 5);
|
||||
csmap_i_set_at(map, 40, 4);
|
||||
|
||||
M_PRINT("vec= ", (vec, cvec_p_t));
|
||||
|
||||
// Find an element (either native or through the algo header)
|
||||
int *i1 = cset_i_get(set, 20);
|
||||
cvec_p_it_t i2; cvec_p_find(i2, vec, (Point_t) {{20, 2}});
|
||||
cdeq_i_it_t i3; cdeq_i_find(i3, deq, 20);
|
||||
clist_i_it_t i4; clist_i_find(i4, lst, 20);
|
||||
int *i5 = csmap_i_get(map, 20);
|
||||
printf("\nFound: %d, (%g, %g), %d, %d, [%d: %d]\n",
|
||||
*i1,
|
||||
(*cvec_p_ref(i2))->x, (*cvec_p_ref(i2))->y,
|
||||
*cdeq_i_ref(i3),
|
||||
*clist_i_ref(i4),
|
||||
20, *i5);
|
||||
|
||||
// Erase the elements found (through key or through iterators)
|
||||
cset_i_erase(set, *i1);
|
||||
cvec_p_remove(vec, i2);
|
||||
cdeq_i_remove(deq, i3);
|
||||
clist_i_remove(lst, i4);
|
||||
csmap_i_erase(map, *i5);
|
||||
|
||||
// Display everything in one call by using the registered print functions of the different types.
|
||||
M_PRINT("After erasing elements found:\n",
|
||||
"set: ", (set, cset_i_t), "\n",
|
||||
"vec: ", (vec, cvec_p_t), "\n",
|
||||
"deq: ", (deq, cdeq_i_t), "\n",
|
||||
"map: ", (map, csmap_i_t), "\n");
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@
|
||||
ALGO_DEF(algogName, containerOplist|type if oplist has been registered) */
|
||||
#define ALGO_DEF(name, cont_oplist) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ALGOI_DEF_P1(name, M_GLOBAL_OPLIST(cont_oplist)) \
|
||||
M_ALG0_DEF_P1(name, M_GLOBAL_OPLIST(cont_oplist)) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
ALGO_FOR_EACH(container, containerOplist, function[, extra arguments of function]) */
|
||||
#define ALGO_FOR_EACH(container, cont_oplist, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ALGOI_FOR_EACH(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__), \
|
||||
ALGOI_FOR_EACH_ARG(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__ ))
|
||||
(M_ALG0_FOR_EACH(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__), \
|
||||
M_ALG0_FOR_EACH_ARG(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__ ))
|
||||
|
||||
|
||||
/* Map a function (or a macro) to all elements of a container
|
||||
@@ -53,20 +53,20 @@
|
||||
function[, extra arguments of function]) */
|
||||
#define ALGO_TRANSFORM(contD, contDop, contS, contSop, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ALGOI_TRANSFORM(contD, M_GLOBAL_OPLIST(contDop), contS, M_GLOBAL_OPLIST(contSop), __VA_ARGS__), \
|
||||
ALGOI_TRANSFORM_ARG(contD, M_GLOBAL_OPLIST(contDop), contS, M_GLOBAL_OPLIST(contSop), __VA_ARGS__ ))
|
||||
(M_ALG0_TRANSFORM(contD, M_GLOBAL_OPLIST(contDop), contS, M_GLOBAL_OPLIST(contSop), __VA_ARGS__), \
|
||||
M_ALG0_TRANSFORM_ARG(contD, M_GLOBAL_OPLIST(contDop), contS, M_GLOBAL_OPLIST(contSop), __VA_ARGS__ ))
|
||||
|
||||
|
||||
/* Extract a subset of a container to copy into another container.
|
||||
USAGE:
|
||||
ALGO_EXTRACT(contDst, contDstOplist, contSrc, contSrcOplist
|
||||
[, function [, extra arguments of function]]) */
|
||||
#define ALGO_EXTRACT(contD, contDop, contS, ...) \
|
||||
#define ALGO_EXTRACT(contD, contDop, contS, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ALGOI_EXTRACT(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__), \
|
||||
M_IF_NARGS_EQ2(__VA_ARGS__) \
|
||||
(ALGOI_EXTRACT_FUNC(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__), \
|
||||
ALGOI_EXTRACT_ARG(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__ )))
|
||||
(M_ALG0_EXTRACT(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__), \
|
||||
M_IF_NARGS_EQ2(__VA_ARGS__) \
|
||||
(M_ALG0_EXTRACT_FUNC(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__), \
|
||||
M_ALG0_EXTRACT_ARG(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Perform a Reduce operation over a container.
|
||||
@@ -75,96 +75,76 @@
|
||||
[, mapFunc[, extraParameters of map function]]) */
|
||||
#define ALGO_REDUCE(dest, cont, contOp, ...) \
|
||||
M_IF(M_PARENTHESIS_P(dest)) \
|
||||
(ALGOI_REDUCE_DISPATCH(M_PAIR_1 dest, M_GLOBAL_OPLIST(M_PAIR_2 dest), M_GLOBAL_TYPE(M_PAIR_2 dest),cont, M_GLOBAL_OPLIST(contOp), __VA_ARGS__), \
|
||||
ALGOI_REDUCE_DISPATCH(dest, M_GET_OPLIST M_GLOBAL_OPLIST(contOp), M_GET_SUBTYPE M_GLOBAL_OPLIST(contOp), cont, contOp, __VA_ARGS__)) \
|
||||
(M_ALG0_REDUCE_DISPATCH(M_PAIR_1 dest, M_GLOBAL_OPLIST(M_PAIR_2 dest), M_GLOBAL_TYPE(M_PAIR_2 dest),cont, M_GLOBAL_OPLIST(contOp), __VA_ARGS__), \
|
||||
M_ALG0_REDUCE_DISPATCH(dest, M_GET_OPLIST M_GLOBAL_OPLIST(contOp), M_GET_SUBTYPE M_GLOBAL_OPLIST(contOp), cont, contOp, __VA_ARGS__)) \
|
||||
|
||||
|
||||
/* Initialize & set a container with a variable array list.
|
||||
USAGE:
|
||||
ALGO_INIT_VA(container, containerOplist, param1[, param2[, ...]]).
|
||||
OBSOLETE: WILL BE DELETED.
|
||||
*/
|
||||
#define ALGO_INIT_VA(dest, contOp, ...) \
|
||||
ALGO_INIT_VAI(dest, M_GLOBAL_OPLIST(contOp), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define, initialize, set & clear a container with a variable array list.
|
||||
USAGE:
|
||||
ALGO_LET_INIT_VA(container, containerOplist|type, param1[, param2[, ...]]) {
|
||||
// Stuff with container
|
||||
}
|
||||
OBSOLETE: WILL BE DELETED.
|
||||
*/
|
||||
#define ALGO_LET_INIT_VA(dest, contOp, ...) \
|
||||
ALGO_LET_INIT_VAI(dest, M_GLOBAL_OPLIST(contOp), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Insert into the container 'contDst' at position 'position' all the values
|
||||
of container 'contSrc'.
|
||||
USAGE:
|
||||
ALGO_INSERT_AT(containerDst, containerDstOPLIST|containerDstType, containerDstIterator, containerSrc, containerSrcOPLIST|containerSrcType)
|
||||
*/
|
||||
#define ALGO_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) \
|
||||
ALGOI_INSERT_AT(contDst, M_GLOBAL_OPLIST(contDstOp), position, contSrc, M_GLOBAL_OPLIST(contSrcOp) )
|
||||
M_ALG0_INSERT_AT(contDst, M_GLOBAL_OPLIST(contDstOp), position, contSrc, M_GLOBAL_OPLIST(contSrcOp) )
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Try to expand the algorithms */
|
||||
#define ALGOI_DEF_P1(name, cont_oplist) \
|
||||
ALGOI_DEF_P2(name, M_GET_TYPE cont_oplist, cont_oplist, \
|
||||
#define M_ALG0_DEF_P1(name, cont_oplist) \
|
||||
M_ALG0_DEF_P2(name, M_GET_TYPE cont_oplist, cont_oplist, \
|
||||
M_GET_SUBTYPE cont_oplist, M_GET_OPLIST cont_oplist, \
|
||||
M_GET_IT_TYPE cont_oplist)
|
||||
|
||||
/* First validate the first oplist */
|
||||
#define ALGOI_DEF_P2(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_IF_OPLIST(cont_oplist)(ALGOI_DEF_P3, ALGOI_DEF_FAILURE)(name, container_t, cont_oplist, type_t, type_oplist, it_t)
|
||||
#define M_ALG0_DEF_P2(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_IF_OPLIST(cont_oplist)(M_ALG0_DEF_P3, M_ALG0_DEF_FAILURE)(name, container_t, cont_oplist, type_t, type_oplist, it_t)
|
||||
|
||||
/* Then validate the second oplist */
|
||||
#define ALGOI_DEF_P3(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_IF_OPLIST(type_oplist)(ALGOI_DEF_P4, ALGOI_DEF_FAILURE)(name, container_t, cont_oplist, type_t, type_oplist, it_t)
|
||||
#define M_ALG0_DEF_P3(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_IF_OPLIST(type_oplist)(M_ALG0_DEF_P4, M_ALG0_DEF_FAILURE)(name, container_t, cont_oplist, type_t, type_oplist, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure if an oplist was invalid */
|
||||
#define ALGOI_DEF_FAILURE(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_DEF_FAILURE(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ALGO_DEF): one of the given argument is not a valid oplist: " M_AS_STR(cont_oplist) " / " M_AS_STR(type_oplist) )
|
||||
|
||||
|
||||
/* Expand all algorithms */
|
||||
#define ALGOI_DEF_P4(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_DEF_P4(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 10, container_t, cont_oplist) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 11, type_t, type_oplist) \
|
||||
\
|
||||
ALGOI_CALLBACK_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_IF_FUNCOBJ(ALGOI_FUNCOBJ_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t)) \
|
||||
M_ALG0_CALLBACK_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_IF_FUNCOBJ(M_ALG0_FUNCOBJ_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t)) \
|
||||
\
|
||||
M_IF_METHOD(EQUAL, type_oplist)( \
|
||||
ALGOI_FIND_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_FIND_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
, /* NO EQUAL */) \
|
||||
\
|
||||
ALGOI_FIND_IF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, if, M_C(name, _test_cb_ct), M_C(name, _eq_cb_ct), M_APPLY, M_APPLY) \
|
||||
M_IF_FUNCOBJ(ALGOI_FIND_IF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, fo, M_C(name, _test_obj_t), M_C(name, _eq_obj_t), M_C(name, _test_obj_call), M_C(name, _eq_obj_call))) \
|
||||
M_ALG0_FIND_IF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, if, M_C(name, _test_cb_ct), M_C(name, _eq_cb_ct), M_APPLY, M_APPLY) \
|
||||
M_IF_FUNCOBJ(M_ALG0_FIND_IF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, fo, M_C(name, _test_obj_t), M_C(name, _eq_obj_t), M_C(name, _test_obj_call), M_C(name, _eq_obj_call))) \
|
||||
\
|
||||
ALGOI_MAP_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_MAP_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
ALGOI_ALL_OF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, _, M_C(name, _test_cb_ct), M_APPLY) \
|
||||
M_IF_FUNCOBJ(ALGOI_ALL_OF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, _fo_, M_C(name, _test_obj_t), M_C(name, _test_obj_call)) ) \
|
||||
M_ALG0_ALL_OF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, _, M_C(name, _test_cb_ct), M_APPLY) \
|
||||
M_IF_FUNCOBJ(M_ALG0_ALL_OF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, _fo_, M_C(name, _test_obj_t), M_C(name, _test_obj_call)) ) \
|
||||
\
|
||||
/* If there is a IT_REF method, we consider the container as modifiable through iterator */ \
|
||||
/* If there is a IT_REF method, we consider the container as modifiable through iterator */ \
|
||||
M_IF_METHOD(IT_REF, cont_oplist)( \
|
||||
ALGOI_FILL_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
ALGOI_VECTOR_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_FILL_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_VECTOR_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
M_IF_METHOD(CMP, type_oplist)( \
|
||||
ALGOI_MINMAX_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
ALGOI_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, +, _sort) \
|
||||
ALGOI_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, -, _sort_dsc) \
|
||||
M_ALG0_MINMAX_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, +, _sort) \
|
||||
M_ALG0_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, -, _sort_dsc) \
|
||||
M_IF_METHOD(IT_REMOVE, cont_oplist)( \
|
||||
ALGOI_REMOVE_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_REMOVE_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
, /* No IT_REMOVE method */) \
|
||||
, /* No CMP method */) \
|
||||
\
|
||||
M_IF_FUNCOBJ(ALGOI_SORT_DEF_P6(name, container_t, cont_oplist, type_t, type_oplist, it_t, _sort_fo, ALGOI_SORT_CALL_OBJ_P4, ALGOI_SORT_PARAM_OBJ_P4, ALGOI_SORT_ARG_OBJ_P4) ) \
|
||||
M_IF_FUNCOBJ(M_ALG0_SORT_DEF_P6(name, container_t, cont_oplist, type_t, type_oplist, it_t, _sort_fo, M_ALG0_SORT_CALL_OBJ_P4, M_ALG0_SORT_PARAM_OBJ_P4, M_ALG0_SORT_ARG_OBJ_P4) ) \
|
||||
, /* No IT_REF method */) \
|
||||
\
|
||||
M_IF_METHOD(EXT_ALGO, type_oplist)( \
|
||||
@@ -174,7 +154,7 @@
|
||||
|
||||
/* Define the types of the callbacks associated to the algorithms.
|
||||
* Types remain internal */
|
||||
#define ALGOI_CALLBACK_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_CALLBACK_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
typedef bool (*M_C(name, _test_cb_ct))(type_t const); \
|
||||
typedef bool (*M_C(name, _eq_cb_ct))(type_t const, type_t const); \
|
||||
@@ -185,7 +165,7 @@
|
||||
|
||||
/* Define the function objects associated to the algorithms.
|
||||
* Created Function objects are part of the public interface */
|
||||
#define ALGOI_FUNCOBJ_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_FUNCOBJ_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
FUNC_OBJ_ITF_DEF(M_C(name, _test_obj), bool, type_t const) \
|
||||
FUNC_OBJ_ITF_DEF(M_C(name, _eq_obj), bool, type_t const, type_t const ) \
|
||||
@@ -195,7 +175,7 @@
|
||||
|
||||
|
||||
/* Define the sort functions with the CMP operator using the order selected */
|
||||
#define ALGOI_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, order, sort_name) \
|
||||
#define M_ALG0_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, order, sort_name) \
|
||||
\
|
||||
/* Define the encapsulation function that perform the selected order */ \
|
||||
static inline int M_C3(name,sort_name,_cmp)(type_t const*a,type_t const*b) \
|
||||
@@ -203,19 +183,19 @@
|
||||
return order M_CALL_CMP(type_oplist, *a, *b); \
|
||||
} \
|
||||
\
|
||||
ALGOI_SORT_DEF_P6(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, ALGOI_SORT_CALL_CMP_P4, M_EAT, /*empty*/ )
|
||||
M_ALG0_SORT_DEF_P6(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, M_ALG0_SORT_CALL_CMP_P4, M_EAT, /*empty*/ )
|
||||
|
||||
// Call the comparaison function of the type oplist (Using CMP operator)
|
||||
#define ALGOI_SORT_CALL_CMP_P4(name, sort_name, ref1, ref2) \
|
||||
#define M_ALG0_SORT_CALL_CMP_P4(name, sort_name, ref1, ref2) \
|
||||
M_C3(name, sort_name,_cmp)(ref1, ref2)
|
||||
|
||||
|
||||
// Call the created function object
|
||||
#define ALGOI_SORT_CALL_OBJ_P4(name, sort_name, ref1, ref2) \
|
||||
#define M_ALG0_SORT_CALL_OBJ_P4(name, sort_name, ref1, ref2) \
|
||||
M_C(name, _cmp_obj_call)(funcobj, *ref1, *ref2)
|
||||
// Adding a parameter named 'funcobj' to the algorithm functions
|
||||
#define ALGOI_SORT_PARAM_OBJ_P4(name) M_DEFERRED_COMMA M_C(name, _cmp_obj_t) funcobj
|
||||
#define ALGOI_SORT_ARG_OBJ_P4 M_DEFERRED_COMMA funcobj
|
||||
#define M_ALG0_SORT_PARAM_OBJ_P4(name) M_DEFERRED_COMMA M_C(name, _cmp_obj_t) funcobj
|
||||
#define M_ALG0_SORT_ARG_OBJ_P4 M_DEFERRED_COMMA funcobj
|
||||
|
||||
|
||||
/* Define the sort funtions using either the CMP operator or a function object
|
||||
@@ -231,7 +211,7 @@
|
||||
It is needed to add another argument to the function.
|
||||
- cmp_arg: Name of such argument.
|
||||
*/
|
||||
#define ALGOI_SORT_DEF_P6(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, cmp_func, cmp_param, cmp_arg) \
|
||||
#define M_ALG0_SORT_DEF_P6(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, cmp_func, cmp_param, cmp_arg) \
|
||||
\
|
||||
/* Test if the container is sorted */ \
|
||||
static inline bool \
|
||||
@@ -246,7 +226,7 @@
|
||||
while (!M_CALL_IT_END_P(cont_oplist, it2)) { \
|
||||
type_t const *ref1 = M_CALL_IT_CREF(cont_oplist, it1); \
|
||||
type_t const *ref2 = M_CALL_IT_CREF(cont_oplist, it2); \
|
||||
if (!(cmp_func(name, sort_name, ref1, ref2) <= 0)) { \
|
||||
if (!(cmp_func(name, sort_name, ref1, ref2) <= 0)) { \
|
||||
return false; \
|
||||
} \
|
||||
M_CALL_IT_SET(cont_oplist, it1, it2); \
|
||||
@@ -260,11 +240,11 @@
|
||||
/* - an unstable merge sort (need 'splice_back' method) */ \
|
||||
/* - an insertion sort (need 'previous' method) */ \
|
||||
/* - a selection sort */ \
|
||||
M_IF(M_AND(M_TEST_METHOD_P(SORT, cont_oplist), M_EMPTY_P(cmp_arg)))( \
|
||||
/******** OPTIMIZED SORT FOR CONTAINER *********/ \
|
||||
M_IF(M_AND(M_TEST_METHOD_P(SORT, cont_oplist), M_EMPTY_P(cmp_arg)))( \
|
||||
/******** OPTIMIZED SORT FOR CONTAINER *********/ \
|
||||
static inline void M_C(name,sort_name)(container_t l) \
|
||||
{ \
|
||||
M_CALL_SORT(cont_oplist, l, M_C3(name, sort_name,_cmp)); \
|
||||
M_CALL_SORT(cont_oplist, l, M_C3(name, sort_name,_cmp)); \
|
||||
} \
|
||||
, \
|
||||
\
|
||||
@@ -279,7 +259,7 @@
|
||||
{ \
|
||||
it_t it; \
|
||||
bool b = false; \
|
||||
/* Split 'l' into 'l1' and 'l2' */ \
|
||||
/* Split 'l' into 'l1' and 'l2' */ \
|
||||
for (M_CALL_IT_FIRST(cont_oplist,it, l); \
|
||||
!M_CALL_IT_END_P(cont_oplist, it);) { \
|
||||
M_CALL_SPLICE_BACK(cont_oplist, (b ? l1 : l2), l, it); \
|
||||
@@ -300,14 +280,14 @@
|
||||
M_CALL_IT_FIRST(cont_oplist,it1, l1); \
|
||||
M_CALL_IT_FIRST(cont_oplist,it2, l2); \
|
||||
while (true) { \
|
||||
/* Compare current elements of the containers l1 and l2 */ \
|
||||
/* Compare current elements of the containers l1 and l2 */ \
|
||||
int c = cmp_func(name, sort_name, M_CALL_IT_CREF(cont_oplist, it1), \
|
||||
M_CALL_IT_CREF(cont_oplist, it2)); \
|
||||
M_CALL_IT_CREF(cont_oplist, it2)); \
|
||||
if (c <= 0) { \
|
||||
/* Move the element of l1 in the new container */ \
|
||||
/* Move the element of l1 in the new container */ \
|
||||
M_CALL_SPLICE_AT(cont_oplist, l, it, l1, it1); \
|
||||
if (M_UNLIKELY (M_CALL_IT_END_P(cont_oplist, it1))) { \
|
||||
/* Move all remaining elements of l2 in 'l' */ \
|
||||
/* Move all remaining elements of l2 in 'l' */ \
|
||||
while (!M_CALL_IT_END_P(cont_oplist, it2)) { \
|
||||
M_CALL_SPLICE_AT(cont_oplist, l, it, l2, it2); \
|
||||
} \
|
||||
@@ -330,7 +310,7 @@
|
||||
\
|
||||
/* Sort the container 'l' */ \
|
||||
static inline void \
|
||||
M_C(name,sort_name)(container_t l cmp_param(name)) \
|
||||
M_C(name,sort_name)(container_t l cmp_param(name)) \
|
||||
{ \
|
||||
container_t l1; \
|
||||
container_t l2; \
|
||||
@@ -350,8 +330,8 @@
|
||||
if (M_UNLIKELY (M_CALL_IT_END_P(cont_oplist, it))) { \
|
||||
/* Two elements */ \
|
||||
int c = cmp_func(name, sort_name, \
|
||||
M_CALL_IT_CREF(cont_oplist, it1), \
|
||||
M_CALL_IT_CREF(cont_oplist, it2)); \
|
||||
M_CALL_IT_CREF(cont_oplist, it1), \
|
||||
M_CALL_IT_CREF(cont_oplist, it2)); \
|
||||
if (c > 0) { \
|
||||
/* SWAP */ \
|
||||
M_CALL_SPLICE_BACK(cont_oplist, l, l, it2); \
|
||||
@@ -391,8 +371,8 @@
|
||||
M_CALL_IT_SET(cont_oplist, it2p1, it1); \
|
||||
while (!M_CALL_IT_END_P(cont_oplist, it2) \
|
||||
&& !(cmp_func(name, sort_name, \
|
||||
M_CALL_IT_CREF(cont_oplist, it2), \
|
||||
M_CONST_CAST(type_t, &x)) <= 0)) { \
|
||||
M_CALL_IT_CREF(cont_oplist, it2), \
|
||||
M_CONST_CAST(type_t, &x)) <= 0)) { \
|
||||
/* TAB[jp1=j+1] := TAB[j] */ \
|
||||
memcpy(M_CALL_IT_REF(cont_oplist, it2p1), \
|
||||
M_CALL_IT_CREF(cont_oplist, it2), sizeof (type_t) ); \
|
||||
@@ -422,8 +402,8 @@
|
||||
for(M_CALL_IT_NEXT(cont_oplist, it2) ; \
|
||||
!M_CALL_IT_END_P(cont_oplist, it2); \
|
||||
M_CALL_IT_NEXT(cont_oplist, it2)) { \
|
||||
if (cmp_func(name, sort_name, M_CALL_IT_CREF(cont_oplist, it2), \
|
||||
M_CALL_IT_CREF(cont_oplist, it_min)) < 0) { \
|
||||
if (cmp_func(name, sort_name, M_CALL_IT_CREF(cont_oplist, it2), \
|
||||
M_CALL_IT_CREF(cont_oplist, it_min)) < 0) { \
|
||||
M_CALL_IT_SET(cont_oplist, it_min, it2); \
|
||||
} \
|
||||
} \
|
||||
@@ -463,23 +443,23 @@
|
||||
if (cmp <= 0) { \
|
||||
/* The element of dst is before. Go to next element of dst */ \
|
||||
M_CALL_IT_SET(cont_oplist, itIns, itDst); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itDst); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itDst); \
|
||||
if (cmp == 0) { \
|
||||
/* Skip same arguments in both lists */ \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
} \
|
||||
} else { \
|
||||
/* The element of src is before. */ \
|
||||
/* insert objSrc before */ \
|
||||
/* insert objSrc before */ \
|
||||
/* NOTE: IT_INSERT insert after ==> Need of another iterator */ \
|
||||
M_CALL_IT_INSERT(cont_oplist, dst, itIns, *objSrc); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
M_CALL_IT_INSERT(cont_oplist, dst, itIns, *objSrc); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
} \
|
||||
} \
|
||||
while (!M_CALL_IT_END_P(cont_oplist, itSrc)) { \
|
||||
/* Finish inserting the element of src in dst */ \
|
||||
type_t *objSrc = M_CALL_IT_REF(cont_oplist, itSrc); \
|
||||
M_CALL_IT_INSERT(cont_oplist, dst, itIns, *objSrc); \
|
||||
M_CALL_IT_INSERT(cont_oplist, dst, itIns, *objSrc); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
} \
|
||||
} \
|
||||
@@ -501,7 +481,7 @@
|
||||
&& !M_CALL_IT_END_P(cont_oplist, itDst)) { \
|
||||
type_t const *objSrc = M_CALL_IT_CREF(cont_oplist, itSrc); \
|
||||
type_t const *objDst = M_CALL_IT_CREF(cont_oplist, itDst); \
|
||||
int cmp = cmp_func(name, sort_name, objDst, objSrc); \
|
||||
int cmp = cmp_func(name, sort_name, objDst, objSrc); \
|
||||
if (cmp == 0) { \
|
||||
/* Keep it */ \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
@@ -523,7 +503,7 @@
|
||||
TODO: Define _find_sorted that find in a sorted random access container
|
||||
(binary search)
|
||||
*/
|
||||
#define ALGOI_FIND_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_FIND_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
/* It supposes that the container is not sorted */ \
|
||||
/* Find the next occurence from it (included) of data */ \
|
||||
static inline void \
|
||||
@@ -631,7 +611,7 @@
|
||||
TODO: Define _find_sorted that find in a sorted random access container
|
||||
(binary search)
|
||||
*/
|
||||
#define ALGOI_FIND_IF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, test_t, eq_t, call_test, call_eq) \
|
||||
#define M_ALG0_FIND_IF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, test_t, eq_t, call_test, call_eq) \
|
||||
\
|
||||
/* Find the next occurence that matches the condition */ \
|
||||
static inline void \
|
||||
@@ -677,7 +657,7 @@
|
||||
M_CALL_IT_NEXT(cont_oplist, it1), \
|
||||
M_CALL_IT_NEXT(cont_oplist, it2)) { \
|
||||
if (!call_eq(func, *M_CALL_IT_CREF(cont_oplist, it1), \
|
||||
*M_CALL_IT_CREF(cont_oplist, it2))) \
|
||||
*M_CALL_IT_CREF(cont_oplist, it2))) \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
@@ -694,7 +674,7 @@
|
||||
|
||||
|
||||
/* Define the FILL algorithms */
|
||||
#define ALGOI_FILL_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_FILL_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
/* Fill all the container with value (overwritten) */ \
|
||||
static inline void \
|
||||
@@ -710,7 +690,7 @@
|
||||
static inline void \
|
||||
M_C(name, _fill_n) (container_t l, size_t n, type_t const value) \
|
||||
{ \
|
||||
M_CALL_CLEAN(cont_oplist, l); \
|
||||
M_CALL_RESET(cont_oplist, l); \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_PUSH(cont_oplist, l, value); \
|
||||
} \
|
||||
@@ -738,7 +718,7 @@
|
||||
{ \
|
||||
type_t tmp; \
|
||||
M_CALL_INIT_SET(type_oplist, tmp, value); \
|
||||
M_CALL_CLEAN(cont_oplist, l); \
|
||||
M_CALL_RESET(cont_oplist, l); \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_PUSH(cont_oplist, l, tmp); \
|
||||
M_CALL_ADD(type_oplist, tmp, tmp, inc); \
|
||||
@@ -750,7 +730,7 @@
|
||||
|
||||
|
||||
/* Define MAP algorithms */
|
||||
#define ALGOI_MAP_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_MAP_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
/* Apply func for all elements of the container */ \
|
||||
static inline void \
|
||||
@@ -771,7 +751,7 @@
|
||||
M_C(name, _transform_cb_ct) func) \
|
||||
{ \
|
||||
M_ASSERT(dst != src); \
|
||||
M_CALL_CLEAN(cont_oplist, dst); \
|
||||
M_CALL_RESET(cont_oplist, dst); \
|
||||
for M_EACH(item, src, cont_oplist) { \
|
||||
type_t tmp; \
|
||||
M_CALL_INIT(type_oplist, tmp); \
|
||||
@@ -806,7 +786,7 @@
|
||||
void M_C(name, _map_reduce) (type_t *dest, \
|
||||
const container_t l, \
|
||||
M_C(name, _transform_cb_ct) redFunc, \
|
||||
M_C(name, _transform_cb_ct) mapFunc) \
|
||||
M_C(name, _transform_cb_ct) mapFunc) \
|
||||
{ \
|
||||
bool initDone = false; \
|
||||
type_t tmp; \
|
||||
@@ -826,7 +806,7 @@
|
||||
|
||||
|
||||
/* Define ALL_OF algorithms */
|
||||
#define ALGOI_ALL_OF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, func_t, call) \
|
||||
#define M_ALG0_ALL_OF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, func_t, call) \
|
||||
\
|
||||
static inline bool \
|
||||
M_C4(name, _any_of, suffix, p) (container_t const l, \
|
||||
@@ -841,7 +821,7 @@
|
||||
\
|
||||
static inline bool \
|
||||
M_C4(name, _all_of, suffix, p) (container_t const l, \
|
||||
func_t func ) \
|
||||
func_t func ) \
|
||||
{ \
|
||||
for M_EACH(item, l, cont_oplist) { \
|
||||
if (!call(func, *item)) \
|
||||
@@ -863,7 +843,7 @@
|
||||
|
||||
|
||||
/* Define MIN / MAX algorithms */
|
||||
#define ALGOI_MINMAX_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_MINMAX_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
static inline type_t * \
|
||||
M_C(name, _min) (const container_t l) \
|
||||
@@ -912,7 +892,7 @@
|
||||
} \
|
||||
|
||||
|
||||
#define ALGOI_REMOVE_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_REMOVE_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _uniq)(container_t l) \
|
||||
@@ -967,7 +947,7 @@
|
||||
} \
|
||||
|
||||
|
||||
#define ALGOI_VECTOR_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_VECTOR_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
M_IF_METHOD(ADD, type_oplist)( \
|
||||
static inline void M_C(name, _add) (container_t dst, const container_t src) \
|
||||
@@ -1051,21 +1031,21 @@
|
||||
// _flatten (takes a set of containers and returns a new container containing all flatten objects)
|
||||
|
||||
|
||||
#define ALGOI_FOR_EACH(container, cont_oplist, func) do { \
|
||||
#define M_ALG0_FOR_EACH(container, cont_oplist, func) do { \
|
||||
for M_EACH(_item, container, cont_oplist) { \
|
||||
func(*_item); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_FOR_EACH_ARG(container, cont_oplist, func, ...) do { \
|
||||
#define M_ALG0_FOR_EACH_ARG(container, cont_oplist, func, ...) do { \
|
||||
for M_EACH(_item, container, cont_oplist) { \
|
||||
func(__VA_ARGS__, *_item); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ALGOI_TRANSFORM(contD, contDop, contS, contSop, func) do { \
|
||||
M_CALL_CLEAN(contDop, contD); \
|
||||
#define M_ALG0_TRANSFORM(contD, contDop, contS, contSop, func) do { \
|
||||
M_CALL_RESET(contDop, contD); \
|
||||
for M_EACH(_item, contS, contSop) { \
|
||||
M_GET_SUBTYPE contDop _tmp; \
|
||||
M_CALL_INIT(M_GET_OPLIST contDop, _tmp); \
|
||||
@@ -1075,8 +1055,8 @@
|
||||
M_IF_METHOD(REVERSE, contDop) (M_CALL_REVERSE(contDop, contD);, ) \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_TRANSFORM_ARG(contD, contDop, contS, contSop, func, ...) do { \
|
||||
M_CALL_CLEAN(contDop, contD); \
|
||||
#define M_ALG0_TRANSFORM_ARG(contD, contDop, contS, contSop, func, ...) do { \
|
||||
M_CALL_RESET(contDop, contD); \
|
||||
for M_EACH(_item, contS, contSop) { \
|
||||
M_GET_SUBTYPE contDop _tmp; \
|
||||
M_CALL_INIT(M_GET_OPLIST contDop, _tmp); \
|
||||
@@ -1087,9 +1067,9 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ALGOI_EXTRACT(contDst, contDstOplist, \
|
||||
#define M_ALG0_EXTRACT(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist) do { \
|
||||
M_CALL_CLEAN(contDstOplist, contDst); \
|
||||
M_CALL_RESET(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
M_IF_METHOD(PUSH, contDstOplist)( \
|
||||
M_CALL_PUSH(contDstOplist, contDst, *_item); \
|
||||
@@ -1100,10 +1080,10 @@
|
||||
M_IF_METHOD(REVERSE, contDstOplist) (M_CALL_REVERSE(contDstOplist, contDst);, ) \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_EXTRACT_FUNC(contDst, contDstOplist, \
|
||||
#define M_ALG0_EXTRACT_FUNC(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist, \
|
||||
condFunc) do { \
|
||||
M_CALL_CLEAN(contDstOplist, contDst); \
|
||||
M_CALL_RESET(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
if (condFunc (*_item)) { \
|
||||
M_IF_METHOD(PUSH, contDstOplist)( \
|
||||
@@ -1116,10 +1096,10 @@
|
||||
M_IF_METHOD(REVERSE, contDstOplist) (M_CALL_REVERSE(contDstOplist, contDst);, ) \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_EXTRACT_ARG(contDst, contDstOplist, \
|
||||
#define M_ALG0_EXTRACT_ARG(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist, \
|
||||
condFunc, ...) do { \
|
||||
M_CALL_CLEAN(contDstOplist, contDst); \
|
||||
M_CALL_RESET(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
if (condFunc (__VA_ARGS__, *_item)) { \
|
||||
M_IF_METHOD(PUSH, contDstOplist)( \
|
||||
@@ -1133,41 +1113,41 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ALGOI_REDUCE_DISPATCH(dest, destOp, dest_t, cont, contOp, ...) \
|
||||
#define M_ALG0_REDUCE_DISPATCH(dest, destOp, dest_t, cont, contOp, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ALGOI_REDUCE_BASIC(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
|
||||
(M_ALG0_REDUCE_BASIC(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
|
||||
M_IF_NARGS_EQ2(__VA_ARGS__) \
|
||||
(ALGOI_REDUCE_FOR_EACH(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
|
||||
ALGOI_REDUCE_FOR_EACH_ARG(dest, dest_t, destOp, cont, contOp, __VA_ARGS__) ) )
|
||||
(M_ALG0_REDUCE_FOR_EACH(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
|
||||
M_ALG0_REDUCE_FOR_EACH_ARG(dest, dest_t, destOp, cont, contOp, __VA_ARGS__) ) )
|
||||
|
||||
/* The special functions handled by ALGO_REDUCE */
|
||||
#define ALGOI_REDUCE_AND(a,b) ((a) &= (b))
|
||||
#define ALGOI_REDUCE_OR(a,b) ((a) |= (b))
|
||||
#define ALGOI_REDUCE_SUM(a,b) ((a) += (b))
|
||||
#define ALGOI_REDUCE_PRODUCT(a,b) ((a) *= (b))
|
||||
#define M_ALG0_REDUCE_AND(a,b) ((a) &= (b))
|
||||
#define M_ALG0_REDUCE_OR(a,b) ((a) |= (b))
|
||||
#define M_ALG0_REDUCE_SUM(a,b) ((a) += (b))
|
||||
#define M_ALG0_REDUCE_PRODUCT(a,b) ((a) *= (b))
|
||||
|
||||
/* Return the method associated to a reduce operation.
|
||||
It returns the special function handler if function is and, or, sum or add.
|
||||
Otherwise it returns the original function */
|
||||
#define ALGOI_REDUCE_FUNC(reduceFunc) \
|
||||
#define M_ALG0_REDUCE_FUNC(reduceFunc) \
|
||||
M_IF(M_KEYWORD_P(and, reduceFunc)) \
|
||||
(ALGOI_REDUCE_AND, \
|
||||
(M_ALG0_REDUCE_AND, \
|
||||
M_IF(M_KEYWORD_P(or, reduceFunc)) \
|
||||
(ALGOI_REDUCE_OR, \
|
||||
(M_ALG0_REDUCE_OR, \
|
||||
M_IF(M_KEYWORD_P(sum, reduceFunc)) \
|
||||
(ALGOI_REDUCE_SUM, \
|
||||
(M_ALG0_REDUCE_SUM, \
|
||||
M_IF(M_KEYWORD_P(product, reduceFunc)) \
|
||||
(ALGOI_REDUCE_PRODUCT, \
|
||||
(M_ALG0_REDUCE_PRODUCT, \
|
||||
reduceFunc) \
|
||||
) \
|
||||
) \
|
||||
)
|
||||
|
||||
#define ALGOI_REDUCE_BASIC(dest, dest_t, destOp, cont, cont_oplist, reduceFunc) do { \
|
||||
#define M_ALG0_REDUCE_BASIC(dest, dest_t, destOp, cont, cont_oplist, reduceFunc) do { \
|
||||
bool _init_done = false; \
|
||||
for M_EACH(_item, cont, cont_oplist) { \
|
||||
if (_init_done) { \
|
||||
ALGOI_REDUCE_FUNC(reduceFunc) (dest, *_item); \
|
||||
M_ALG0_REDUCE_FUNC(reduceFunc) (dest, *_item); \
|
||||
} else { \
|
||||
M_CALL_SET(destOp, dest, *_item); \
|
||||
_init_done = true; \
|
||||
@@ -1175,14 +1155,14 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_REDUCE_FOR_EACH(dest, dest_t, destOp, cont, cont_oplist, reduceFunc, mapFunc) do { \
|
||||
#define M_ALG0_REDUCE_FOR_EACH(dest, dest_t, destOp, cont, cont_oplist, reduceFunc, mapFunc) do { \
|
||||
bool _init_done = false; \
|
||||
dest_t _tmp; \
|
||||
M_CALL_INIT(destOp, _tmp); \
|
||||
for M_EACH(_item, cont, cont_oplist) { \
|
||||
mapFunc(_tmp, *_item); \
|
||||
if (_init_done) { \
|
||||
ALGOI_REDUCE_FUNC(reduceFunc) (dest, _tmp); \
|
||||
M_ALG0_REDUCE_FUNC(reduceFunc) (dest, _tmp); \
|
||||
} else { \
|
||||
M_CALL_SET(destOp, dest, _tmp); \
|
||||
_init_done = true; \
|
||||
@@ -1191,14 +1171,14 @@
|
||||
M_CALL_CLEAR(destOp, _tmp); \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_REDUCE_FOR_EACH_ARG(dest, dest_t, destOp, cont, cont_oplist, reduceFunc, mapFunc, ...) do { \
|
||||
#define M_ALG0_REDUCE_FOR_EACH_ARG(dest, dest_t, destOp, cont, cont_oplist, reduceFunc, mapFunc, ...) do { \
|
||||
bool _init_done = false; \
|
||||
dest_t _tmp; \
|
||||
M_CALL_INIT(destOp, _tmp); \
|
||||
for M_EACH(_item, cont, cont_oplist) { \
|
||||
mapFunc(_tmp, __VA_ARGS__, *_item); \
|
||||
if (_init_done) { \
|
||||
ALGOI_REDUCE_FUNC(reduceFunc) (dest, _tmp); \
|
||||
M_ALG0_REDUCE_FUNC(reduceFunc) (dest, _tmp); \
|
||||
} else { \
|
||||
M_CALL_SET(destOp, dest, _tmp); \
|
||||
_init_done = true; \
|
||||
@@ -1208,26 +1188,7 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ALGOI_INIT_VA_FUNC(d, a) \
|
||||
M_RET_ARG2 d (M_RET_ARG1 d, a) M_DEFERRED_COMMA
|
||||
|
||||
#define ALGO_INIT_VAI(dest, contOp, ...) \
|
||||
(void)(M_CALL_INIT(contOp, dest) M_DEFERRED_COMMA \
|
||||
M_MAP2(ALGOI_INIT_VA_FUNC, (dest, M_GET_PUSH contOp, ) , __VA_ARGS__) \
|
||||
true)
|
||||
|
||||
|
||||
#define ALGO_LET_INIT_VAI(dest, ...) \
|
||||
ALGOI_LET_INIT_VAI(M_C3(m_cont_, __LINE__, dest), dest, __VA_ARGS__)
|
||||
|
||||
#define ALGOI_LET_INIT_VAI(cont, dest, contOp, ...) \
|
||||
for(bool cont = true; cont ; /* unused */) \
|
||||
for(M_GET_TYPE contOp dest; \
|
||||
cont && (ALGO_INIT_VAI (dest, contOp, __VA_ARGS__), true); \
|
||||
(M_CALL_CLEAR(contOp, dest), cont = false))
|
||||
|
||||
|
||||
#define ALGOI_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) do { \
|
||||
#define M_ALG0_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) do { \
|
||||
M_GET_IT_TYPE contSrcOp _itSrc; \
|
||||
M_GET_IT_TYPE contDstOp _itDst; \
|
||||
M_CALL_IT_SET(contDstOp, _itDst, position); \
|
||||
|
||||
@@ -30,11 +30,7 @@
|
||||
/* Define a dynamic array of the given type and its associated functions.
|
||||
USAGE: ARRAY_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define ARRAY_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ARRAYI_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)))) \
|
||||
M_END_PROTECTED_CODE
|
||||
ARRAY_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a dynamic array of the given type and its associated functions
|
||||
@@ -42,7 +38,7 @@
|
||||
USAGE: ARRAY_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define ARRAY_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ARRAYI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_ARRA4_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -52,11 +48,17 @@
|
||||
If no oplist is given it is assumed to be M_DEFAULT_OPLIST
|
||||
USAGE: ARRAY_OPLIST(name[, oplist of the type]) */
|
||||
#define ARRAY_OPLIST(...) \
|
||||
ARRAYI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_ARRA4_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define an init value to init global variables of type array.
|
||||
USAGE:
|
||||
array_t global_variable = ARRAY_INIT_VALUE();
|
||||
*/
|
||||
#define ARRAY_INIT_VALUE() \
|
||||
{ { 0, 0, NULL } }
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************** INTERNAL ************************************/
|
||||
@@ -64,29 +66,30 @@
|
||||
|
||||
/* Deferred evaluation for the oplist definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define ARRAYI_OPLIST_P1(arg) ARRAYI_OPLIST_P2 arg
|
||||
#define M_ARRA4_OPLIST_P1(arg) M_ARRA4_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)
|
||||
#define M_ARRA4_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_ARRA4_OPLIST_P3, M_ARRA4_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define ARRAYI_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_ARRA4_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_P3(name, oplist) \
|
||||
#define M_ARRA4_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,M_IF_METHOD2(INIT_SET,SET, oplist)(INIT_SET(M_C(name, _init_set)),) \
|
||||
,M_IF_METHOD(INIT_SET, oplist)(INIT_WITH(API_1(M_INIT_VAI)),) \
|
||||
,M_IF_METHOD(INIT_SET, oplist)(INIT_WITH(API_1(M_INIT_WITH_VAI)),) \
|
||||
,M_IF_METHOD2(INIT_SET,SET, oplist)(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,_ct)) \
|
||||
,NAME(name) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,EMPTY_P(M_C(name,_empty_p)) \
|
||||
,IT_TYPE(M_C(name,_it_ct)), \
|
||||
@@ -103,14 +106,14 @@
|
||||
,IT_CREF(M_C(name,_cref)) \
|
||||
,M_IF_METHOD(INIT_SET, oplist)(IT_INSERT(M_C(name,_insert)) ,) \
|
||||
,M_IF_AT_LEAST_METHOD(SET,INIT_MOVE,oplist)(IT_REMOVE(M_C(name,_remove)),) \
|
||||
,CLEAN(M_C(name,_clean)) \
|
||||
,RESET(M_C(name,_reset)) \
|
||||
,KEY_TYPE(size_t) \
|
||||
,VALUE_TYPE(M_C(name, _subtype_ct)) \
|
||||
,KEY_OPLIST(M_DEFAULT_OPLIST) \
|
||||
,VALUE_OPLIST(oplist) \
|
||||
,M_IF_METHOD(SET, oplist)(SET_KEY(M_C(name, _set_at)) ,) \
|
||||
,GET_KEY(M_C(name, _get)) \
|
||||
,M_IF_METHOD(INIT, oplist)(GET_SET_KEY(M_C(name, _get_at)) ,) \
|
||||
,M_IF_METHOD(INIT, oplist)(SAFE_GET_KEY(M_C(name, _safe_get)) ,) \
|
||||
,M_IF_AT_LEAST_METHOD(SET,INIT_MOVE,oplist)(ERASE_KEY(M_C(name, _erase)),) \
|
||||
,GET_SIZE(M_C(name, _size)) \
|
||||
,M_IF_METHOD(INIT_SET, oplist)(PUSH(M_C(name,_push_back)) ,) \
|
||||
@@ -133,22 +136,23 @@
|
||||
)
|
||||
|
||||
/* Define the internal contract of an array */
|
||||
#define ARRAYI_CONTRACT(a) do { \
|
||||
#define M_ARRA4_CONTRACT(a) do { \
|
||||
M_ASSERT (a != NULL); \
|
||||
M_ASSERT (a->size <= a->alloc); \
|
||||
M_ASSERT (a->size == 0 || a->ptr != NULL); \
|
||||
M_ASSERT (a->alloc == 0 || a->ptr != NULL); \
|
||||
} while (0)
|
||||
|
||||
/* Deferred evaluation for the array definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define ARRAYI_DEF_P1(arg) ARRAYI_DEF_P2 arg
|
||||
#define M_ARRA4_DEF_P1(arg) M_ARRA4_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)
|
||||
#define M_ARRA4_DEF_P2(name, type, oplist, array_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(M_ARRA4_DEF_P3, M_ARRA4_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) \
|
||||
#define M_ARRA4_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:
|
||||
@@ -158,7 +162,7 @@
|
||||
- array_t: alias for the type of the array
|
||||
- it_t: alias for the iterator of the array
|
||||
*/
|
||||
#define ARRAYI_DEF_P3(name, type, oplist, array_t, it_t) \
|
||||
#define M_ARRA4_DEF_P3(name, type, oplist, array_t, it_t) \
|
||||
\
|
||||
/* Define a dynamic array */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
@@ -190,26 +194,33 @@
|
||||
v->size = 0; \
|
||||
v->alloc = 0; \
|
||||
v->ptr = NULL; \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(array_t v) \
|
||||
M_C(name, _reset)(array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
for(size_t i = 0; i < v->size; i++) \
|
||||
M_CALL_CLEAR(oplist, v->ptr[i]); \
|
||||
v->size = 0; \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(array_t v) \
|
||||
{ \
|
||||
M_C(name, _reset)(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_C(name, _clean)(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_C(name, _reset)(v); \
|
||||
M_CALL_FREE(oplist, v->ptr); \
|
||||
v->alloc = 0; \
|
||||
/* This is so reusing the object implies an assertion failure */ \
|
||||
v->alloc = 1; \
|
||||
v->ptr = NULL; \
|
||||
} \
|
||||
\
|
||||
@@ -217,8 +228,8 @@
|
||||
static inline void \
|
||||
M_C(name, _set)(array_t d, const array_t s) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(d); \
|
||||
ARRAYI_CONTRACT(s); \
|
||||
M_ARRA4_CONTRACT(d); \
|
||||
M_ARRA4_CONTRACT(s); \
|
||||
if (M_UNLIKELY (d == s)) return; \
|
||||
if (s->size > d->alloc) { \
|
||||
const size_t alloc = s->size; \
|
||||
@@ -239,7 +250,7 @@
|
||||
for( ; i < d->size; i++) \
|
||||
M_CALL_CLEAR(oplist, d->ptr[i]); \
|
||||
d->size = s->size; \
|
||||
ARRAYI_CONTRACT(d); \
|
||||
M_ARRA4_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -255,13 +266,14 @@
|
||||
M_C(name, _init_move)(array_t d, array_t s) \
|
||||
{ \
|
||||
M_ASSERT (d != s); \
|
||||
ARRAYI_CONTRACT(s); \
|
||||
M_ARRA4_CONTRACT(s); \
|
||||
d->size = s->size; \
|
||||
d->alloc = s->alloc; \
|
||||
d->ptr = s->ptr; \
|
||||
s->alloc = 0; \
|
||||
/* Robustness */ \
|
||||
s->alloc = 1; \
|
||||
s->ptr = NULL; \
|
||||
ARRAYI_CONTRACT(d); \
|
||||
M_ARRA4_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -276,26 +288,26 @@
|
||||
static inline void \
|
||||
M_C(name, _set_at)(array_t v, size_t i, type const x) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT(v->size > 0 && v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(i, v->size); \
|
||||
M_CALL_SET(oplist, v->ptr[i], x); \
|
||||
} \
|
||||
, /* No SET */) \
|
||||
\
|
||||
static inline type const * \
|
||||
static inline type * \
|
||||
M_C(name, _back)(array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT(v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(0, v->size); \
|
||||
return M_CONST_CAST(type, &v->ptr[v->size-1]); \
|
||||
return &v->ptr[v->size-1]; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_raw)(array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
if (M_UNLIKELY (v->size >= v->alloc)) { \
|
||||
M_ASSERT(v->size == v->alloc); \
|
||||
size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \
|
||||
@@ -315,7 +327,7 @@
|
||||
M_ASSERT(v->ptr != NULL); \
|
||||
type *ret = &v->ptr[v->size]; \
|
||||
v->size++; \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSUME(ret != NULL); \
|
||||
return ret; \
|
||||
} \
|
||||
@@ -359,7 +371,7 @@
|
||||
static inline void \
|
||||
M_C(name, _push_at)(array_t v, size_t key, type const x) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT_INDEX(key, v->size+1); \
|
||||
if (M_UNLIKELY (v->size >= v->alloc) ) { \
|
||||
M_ASSERT(v->size == v->alloc); \
|
||||
@@ -381,7 +393,7 @@
|
||||
memmove(&v->ptr[key+1], &v->ptr[key], (v->size-key)*sizeof(type)); \
|
||||
v->size++; \
|
||||
M_CALL_INIT_SET(oplist, v->ptr[key], x); \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
, /* No INIT_SET */ ) \
|
||||
\
|
||||
@@ -389,7 +401,7 @@
|
||||
static inline void \
|
||||
M_C(name, _resize)(array_t v, size_t size) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
if (v->size > size) { \
|
||||
/* Decrease size of array */ \
|
||||
for(size_t i = size ; i < v->size; i++) \
|
||||
@@ -411,14 +423,14 @@
|
||||
M_CALL_INIT(oplist, v->ptr[i]); \
|
||||
v->size = size; \
|
||||
} \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
, /* No INIT */ ) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reserve)(array_t v, size_t alloc) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
/* NOTE: Reserve below needed size to perform a shrink to fit */ \
|
||||
if (v->size > alloc) { \
|
||||
alloc = v->size; \
|
||||
@@ -436,14 +448,14 @@
|
||||
v->ptr = ptr; \
|
||||
v->alloc = alloc; \
|
||||
} \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
static inline type * \
|
||||
M_C(name, _get_at)(array_t v, size_t idx) \
|
||||
M_C(name, _safe_get)(array_t v, size_t idx) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
const size_t size = idx + 1; \
|
||||
/* resize if needed */ \
|
||||
if (v->size <= size) { \
|
||||
@@ -468,16 +480,21 @@
|
||||
v->size = size; \
|
||||
} \
|
||||
M_ASSERT (idx < v->size); \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
return &v->ptr[idx]; \
|
||||
} \
|
||||
static inline M_ATTR_DEPRECATED type * \
|
||||
M_C(name, _get_at)(array_t v, size_t idx) \
|
||||
{ \
|
||||
return M_C(name, _safe_get)(v, idx); \
|
||||
} \
|
||||
, /* No INIT */) \
|
||||
\
|
||||
M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _pop_back)(type *dest, array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(0, v->size); \
|
||||
v->size--; \
|
||||
@@ -486,7 +503,7 @@
|
||||
} else { \
|
||||
M_CALL_CLEAR(oplist, v->ptr[v->size]); \
|
||||
} \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
, /* SET | INIT_MOVE */ ) \
|
||||
\
|
||||
@@ -494,13 +511,13 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_move)(type *dest, array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(0, v->size); \
|
||||
M_ASSERT (dest != NULL); \
|
||||
v->size--; \
|
||||
M_DO_INIT_MOVE (oplist, *dest, v->ptr[v->size]); \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
, /* INIT_SET | INIT_MOVE */ ) \
|
||||
\
|
||||
@@ -508,7 +525,7 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_until)(array_t v, it_t pos) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (v == pos->array); \
|
||||
M_ASSERT_INDEX(pos->index, v->size+1); \
|
||||
M_C(name, _resize)(v, pos->index); \
|
||||
@@ -518,21 +535,21 @@
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
return v->size == 0; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
return v->size; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _capacity)(const array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
return v->alloc; \
|
||||
} \
|
||||
\
|
||||
@@ -540,22 +557,22 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_at)(type *dest, array_t v, size_t i) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (v->size > 0 && v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(i, v->size); \
|
||||
if (dest) \
|
||||
M_DO_MOVE (oplist, *dest, v->ptr[i]); \
|
||||
else \
|
||||
M_CALL_CLEAR(oplist, v->ptr[i]); \
|
||||
memmove(&v->ptr[i], &v->ptr[i+1], sizeof(type)*(v->size - i) ); \
|
||||
memmove(&v->ptr[i], &v->ptr[i+1], sizeof(type)*(v->size-1-i)); \
|
||||
v->size--; \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _erase)(array_t a, size_t i) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(a); \
|
||||
M_ARRA4_CONTRACT(a); \
|
||||
if (i >= a->size) return false; \
|
||||
M_C(name, _pop_at)(NULL, a, i); \
|
||||
return true; \
|
||||
@@ -566,7 +583,7 @@
|
||||
static inline void \
|
||||
M_C(name, _insert_v)(array_t v, size_t i, size_t num) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT_INDEX(i, v->size+1); \
|
||||
size_t size = v->size + num; \
|
||||
/* Test for overflow of variable size */ \
|
||||
@@ -595,14 +612,14 @@
|
||||
for(size_t k = i ; k < i+num; k++) \
|
||||
M_CALL_INIT(oplist, v->ptr[k]); \
|
||||
v->size = size; \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
, /* No INIT */) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _remove_v)(array_t v, size_t i, size_t j) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT(i < j && v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(i, v->size); \
|
||||
M_ASSERT_INDEX(j, v->size+1); \
|
||||
@@ -610,32 +627,26 @@
|
||||
M_CALL_CLEAR(oplist, v->ptr[k]); \
|
||||
memmove(&v->ptr[i], &v->ptr[j], sizeof(type)*(v->size - j) ); \
|
||||
v->size -= (j-i); \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(array_t v1, array_t v2) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v1); \
|
||||
ARRAYI_CONTRACT(v2); \
|
||||
size_t tmp = v1->size; \
|
||||
v1->size = v2->size; \
|
||||
v2->size = tmp; \
|
||||
tmp = v1->alloc; \
|
||||
v1->alloc = v2->alloc; \
|
||||
v2->alloc = tmp; \
|
||||
type *p = v1->ptr; \
|
||||
v1->ptr = v2->ptr; \
|
||||
v2->ptr = p; \
|
||||
ARRAYI_CONTRACT(v1); \
|
||||
ARRAYI_CONTRACT(v2); \
|
||||
M_ARRA4_CONTRACT(v1); \
|
||||
M_ARRA4_CONTRACT(v2); \
|
||||
M_SWAP(size_t, v1->size, v2->size); \
|
||||
M_SWAP(size_t, v1->alloc, v2->alloc); \
|
||||
M_SWAP(type *, v1->ptr, v2->ptr); \
|
||||
M_ARRA4_CONTRACT(v1); \
|
||||
M_ARRA4_CONTRACT(v2); \
|
||||
} \
|
||||
\
|
||||
M_IF_AT_LEAST_METHOD(INIT_SET,INIT_MOVE,oplist) ( \
|
||||
static inline void \
|
||||
M_C(name, _swap_at)(array_t v, size_t i, size_t j) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT(v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(i, v->size); \
|
||||
M_ASSERT_INDEX(j, v->size); \
|
||||
@@ -643,14 +654,14 @@
|
||||
M_DO_INIT_MOVE(oplist, tmp, v->ptr[i]); \
|
||||
M_DO_INIT_MOVE(oplist, v->ptr[i], v->ptr[j]); \
|
||||
M_DO_INIT_MOVE(oplist, v->ptr[j], tmp); \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
, /* INIT_SET | INIT_MOVE */ ) \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _get)(const array_t v, size_t i) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(i, v->size); \
|
||||
return &v->ptr[i]; \
|
||||
@@ -659,24 +670,24 @@
|
||||
static inline type const * \
|
||||
M_C(name, _cget)(const array_t v, size_t i) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(i, v->size); \
|
||||
return M_CONST_CAST(type, &v->ptr[i]); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
static inline type * \
|
||||
M_C(name, _front)(const array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT_INDEX(0, v->size); \
|
||||
return M_C(name, _cget)(v, 0); \
|
||||
return M_C(name, _get)(v, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->index = 0; \
|
||||
it->array = v; \
|
||||
@@ -685,7 +696,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, const array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (it != NULL); \
|
||||
/* If size is 0, index is -1 as unsigned, so it is greater than end */ \
|
||||
it->index = v->size - 1; \
|
||||
@@ -695,7 +706,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, const array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->index = v->size; \
|
||||
it->array = v; \
|
||||
@@ -707,7 +718,7 @@
|
||||
M_ASSERT (it != NULL && org != NULL); \
|
||||
it->index = org->index; \
|
||||
it->array = org->array; \
|
||||
ARRAYI_CONTRACT(it->array); \
|
||||
M_ARRA4_CONTRACT(it->array); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
@@ -769,8 +780,9 @@
|
||||
M_C(name, _insert)(array_t a, it_t it, type const x) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && a == it->array); \
|
||||
M_C(name, _push_at)(a, it->index + 1, x); \
|
||||
it->index ++; \
|
||||
size_t index = M_C(name, _end_p)(it) ? 0 : it->index+1; \
|
||||
M_C(name, _push_at)(a, index, x); \
|
||||
it->index = index; \
|
||||
} \
|
||||
, /* End of INIT_SET */ ) \
|
||||
\
|
||||
@@ -799,7 +811,7 @@
|
||||
\
|
||||
M_IF_METHOD2(SWAP, SET, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _special_stable_sort_noalloc) (type tab[], size_t size, type tmp[]) \
|
||||
M_C3(m_arra4_,name,_stable_sort_noalloc)(type tab[], size_t size, type tmp[]) \
|
||||
{ \
|
||||
size_t th = 4; \
|
||||
M_IF_DEBUG(type *org_tab = tab;) \
|
||||
@@ -881,7 +893,7 @@
|
||||
M_MEMORY_FULL(sizeof (type) * l->size); \
|
||||
return ; \
|
||||
} \
|
||||
M_C(name, _special_stable_sort_noalloc)(l->ptr, l->size, temp); \
|
||||
M_C3(m_arra4_,name,_stable_sort_noalloc)(l->ptr, l->size, temp); \
|
||||
M_CALL_FREE(oplist, temp); \
|
||||
} \
|
||||
,) /* IF SWAP & SET methods */ \
|
||||
@@ -894,8 +906,7 @@
|
||||
M_C(name, _get_str)(string_t str, array_t const array, \
|
||||
bool append) \
|
||||
{ \
|
||||
STRINGI_CONTRACT(str); \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
it_t it; \
|
||||
for (M_C(name, _it)(it, array) ; \
|
||||
@@ -907,7 +918,6 @@
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
STRINGI_CONTRACT(str); \
|
||||
} \
|
||||
, /* no GET_STR */ ) \
|
||||
\
|
||||
@@ -915,7 +925,7 @@
|
||||
static inline void \
|
||||
M_C(name, _out_str)(FILE *file, const array_t array) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
M_ASSERT (file != NULL); \
|
||||
fputc ('[', file); \
|
||||
for (size_t i = 0; i < array->size; i++) { \
|
||||
@@ -932,9 +942,9 @@
|
||||
static inline bool \
|
||||
M_C(name, _parse_str)(array_t array, const char str[], const char**endp) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
M_ASSERT (str != NULL); \
|
||||
M_C(name,_clean)(array); \
|
||||
M_C(name,_reset)(array); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
@@ -950,7 +960,7 @@
|
||||
if (b == false || c == 0) { goto exit_clear; } \
|
||||
M_C(name, _push_back)(array, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
success = (c == ']'); \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
@@ -964,9 +974,9 @@
|
||||
static inline bool \
|
||||
M_C(name, _in_str)(array_t array, FILE *file) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
M_ASSERT (file != NULL); \
|
||||
M_C(name,_clean)(array); \
|
||||
M_C(name,_reset)(array); \
|
||||
int c = fgetc(file); \
|
||||
if (M_UNLIKELY (c != '[')) return false; \
|
||||
c = fgetc(file); \
|
||||
@@ -982,7 +992,7 @@
|
||||
M_C(name, _push_back)(array, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
return c == ']'; \
|
||||
} \
|
||||
, /* no IN_STR & INIT */ ) \
|
||||
@@ -991,7 +1001,7 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, const array_t array) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_return_code_t ret; \
|
||||
m_serial_local_t local; \
|
||||
@@ -1012,12 +1022,12 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(array_t array, m_serial_read_t f) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_return_code_t ret; \
|
||||
m_serial_local_t local; \
|
||||
size_t estimated_size = 0; \
|
||||
M_C(name,_clean)(array); \
|
||||
M_C(name,_reset)(array); \
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) { \
|
||||
return ret; \
|
||||
@@ -1035,7 +1045,7 @@
|
||||
ret = f->m_interface->read_array_next(local, f); \
|
||||
} while (ret == M_SERIAL_OK_CONTINUE); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
return ret; \
|
||||
} \
|
||||
, /* no IN_SERIAL & INIT */ ) \
|
||||
@@ -1045,8 +1055,8 @@
|
||||
M_C(name, _equal_p)(const array_t array1, \
|
||||
const array_t array2) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array1); \
|
||||
ARRAYI_CONTRACT(array2); \
|
||||
M_ARRA4_CONTRACT(array1); \
|
||||
M_ARRA4_CONTRACT(array2); \
|
||||
if (array1->size != array2->size) return false; \
|
||||
size_t i; \
|
||||
for(i = 0; i < array1->size; i++) { \
|
||||
@@ -1063,7 +1073,7 @@
|
||||
static inline size_t \
|
||||
M_C(name, _hash)(const array_t array) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
M_HASH_DECL(hash); \
|
||||
for(size_t i = 0 ; i < array->size; i++) { \
|
||||
size_t hi = M_CALL_HASH(oplist, array->ptr[i]); \
|
||||
@@ -1076,8 +1086,8 @@
|
||||
static inline void \
|
||||
M_C(name, _splice)(array_t a1, array_t a2) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(a1); \
|
||||
ARRAYI_CONTRACT(a2); \
|
||||
M_ARRA4_CONTRACT(a1); \
|
||||
M_ARRA4_CONTRACT(a2); \
|
||||
if (M_LIKELY (a2->size > 0)) { \
|
||||
size_t newSize = a1->size + a2->size; \
|
||||
if (newSize > a1->alloc) { \
|
||||
|
||||
+224
-161
@@ -35,25 +35,26 @@ M_BEGIN_PROTECTED_CODE
|
||||
// Define the basic limb of a bitset
|
||||
typedef uint64_t bitset_limb_ct;
|
||||
// And its size in bits
|
||||
#define BITSET_LIMB_BIT (sizeof(bitset_limb_ct) * CHAR_BIT)
|
||||
#define M_B1TSET_LIMB_BIT (sizeof(bitset_limb_ct) * CHAR_BIT)
|
||||
|
||||
// bitset grow policy. n is limb size
|
||||
#define BITSETI_INC_ALLOC_SIZE(n) ((n) < 4 ? 4 : (n) * 2)
|
||||
#define M_B1TSET_INC_ALLOC_SIZE(n) ((n) < 4 ? 4 : (n) * 2)
|
||||
|
||||
// Compute the number of allocated limbs needed to handle 'n' bits.
|
||||
#define BITSETI_TO_ALLOC(n) (((n) + BITSET_LIMB_BIT - 1) / BITSET_LIMB_BIT)
|
||||
#define M_B1TSET_TO_ALLOC(n) (((n) + M_B1TSET_LIMB_BIT - 1) / M_B1TSET_LIMB_BIT)
|
||||
|
||||
// Compute the number of bits available from the allocated size in limbs
|
||||
#define BITSETI_FROM_ALLOC(n) ((n) * BITSET_LIMB_BIT)
|
||||
#define M_B1TSET_FROM_ALLOC(n) ((n) * M_B1TSET_LIMB_BIT)
|
||||
|
||||
// Contract of a bitset
|
||||
#define BITSETI_CONTRACT(t) do { \
|
||||
#define M_B1TSET_CONTRACT(t) do { \
|
||||
M_ASSERT (t != NULL); \
|
||||
M_ASSERT (t->size <= BITSETI_FROM_ALLOC (t->alloc)); \
|
||||
M_ASSERT (t->alloc <= ((size_t)-1) / BITSET_LIMB_BIT); \
|
||||
M_ASSERT (t->size < ((size_t)-1) - BITSET_LIMB_BIT); \
|
||||
M_ASSERT (t->size <= M_B1TSET_FROM_ALLOC (t->alloc)); \
|
||||
M_ASSERT (t->alloc <= ((size_t)-1) / M_B1TSET_LIMB_BIT); \
|
||||
M_ASSERT (t->size < ((size_t)-1) - M_B1TSET_LIMB_BIT); \
|
||||
M_ASSERT (t->size == 0 || t->ptr != NULL); \
|
||||
M_ASSERT (t->alloc == 0 || t->ptr != NULL); \
|
||||
M_ASSERT ((t->size % M_B1TSET_LIMB_BIT) == 0 || (t->ptr[ (t->size-1) / M_B1TSET_LIMB_BIT] & ~(((((bitset_limb_ct)1)<<(t->size % M_B1TSET_LIMB_BIT))<<1)-1)) == 0); \
|
||||
} while (0)
|
||||
|
||||
|
||||
@@ -84,26 +85,32 @@ static inline void
|
||||
bitset_init(bitset_t t)
|
||||
{
|
||||
M_ASSERT (t != NULL);
|
||||
M_STATIC_ASSERT (M_POWEROF2_P(BITSET_LIMB_BIT), MLIB_INTERNAL, "M*LIB: BITSET LIMB shall be a power of 2.");
|
||||
M_STATIC_ASSERT (M_POWEROF2_P(M_B1TSET_LIMB_BIT), MLIB_INTERNAL, "M*LIB: BITSET LIMB shall be a power of 2.");
|
||||
t->size = 0;
|
||||
t->alloc = 0;
|
||||
t->ptr = NULL;
|
||||
BITSETI_CONTRACT(t);
|
||||
M_B1TSET_CONTRACT(t);
|
||||
}
|
||||
|
||||
/* Clean a bitset */
|
||||
static inline void
|
||||
bitset_reset(bitset_t t)
|
||||
{
|
||||
M_B1TSET_CONTRACT(t);
|
||||
t->size = 0;
|
||||
}
|
||||
|
||||
static inline void M_ATTR_DEPRECATED
|
||||
bitset_clean(bitset_t t)
|
||||
{
|
||||
BITSETI_CONTRACT(t);
|
||||
t->size = 0;
|
||||
bitset_reset(t);
|
||||
}
|
||||
|
||||
/* Clear a bitset (DESTRUCTOR) */
|
||||
static inline void
|
||||
bitset_clear(bitset_t t)
|
||||
{
|
||||
bitset_clean(t);
|
||||
bitset_reset(t);
|
||||
M_MEMORY_FREE(t->ptr);
|
||||
// This is not really needed, but is safer
|
||||
// This representation is invalid and will be detected by the contract.
|
||||
@@ -116,11 +123,11 @@ bitset_clear(bitset_t t)
|
||||
static inline void
|
||||
bitset_set(bitset_t d, const bitset_t s)
|
||||
{
|
||||
BITSETI_CONTRACT(d);
|
||||
BITSETI_CONTRACT(s);
|
||||
M_B1TSET_CONTRACT(d);
|
||||
M_B1TSET_CONTRACT(s);
|
||||
if (M_UNLIKELY (d == s)) return;
|
||||
const size_t needAlloc = BITSETI_TO_ALLOC (s->size);
|
||||
if (s->size > BITSETI_FROM_ALLOC (d->alloc)) {
|
||||
const size_t needAlloc = M_B1TSET_TO_ALLOC (s->size);
|
||||
if (s->size > M_B1TSET_FROM_ALLOC (d->alloc)) {
|
||||
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, d->ptr, needAlloc);
|
||||
if (M_UNLIKELY (ptr == NULL)) {
|
||||
M_MEMORY_FULL(needAlloc);
|
||||
@@ -131,7 +138,7 @@ bitset_set(bitset_t d, const bitset_t s)
|
||||
}
|
||||
memcpy (d->ptr, s->ptr, needAlloc * sizeof(bitset_limb_ct) );
|
||||
d->size = s->size;
|
||||
BITSETI_CONTRACT(d);
|
||||
M_B1TSET_CONTRACT(d);
|
||||
}
|
||||
|
||||
/* Initialize & set a bitset to another one (CONSTRUCTOR) */
|
||||
@@ -147,13 +154,14 @@ bitset_init_set(bitset_t d, const bitset_t s)
|
||||
static inline void
|
||||
bitset_init_move(bitset_t d, bitset_t s)
|
||||
{
|
||||
BITSETI_CONTRACT(s);
|
||||
M_B1TSET_CONTRACT(s);
|
||||
d->size = s->size;
|
||||
d->alloc = s->alloc;
|
||||
d->ptr = s->ptr;
|
||||
s->alloc = 0;
|
||||
// Illegal representation of a bitset, to be detectable
|
||||
s->alloc = 1;
|
||||
s->ptr = NULL;
|
||||
BITSETI_CONTRACT(d);
|
||||
M_B1TSET_CONTRACT(d);
|
||||
}
|
||||
|
||||
/* Move a bitset from another one (DESTRUCTOR) */
|
||||
@@ -168,38 +176,38 @@ bitset_move(bitset_t d, bitset_t s)
|
||||
static inline void
|
||||
bitset_set_at(bitset_t v, size_t i, bool x)
|
||||
{
|
||||
BITSETI_CONTRACT(v);
|
||||
M_B1TSET_CONTRACT(v);
|
||||
M_ASSERT (v->ptr != NULL);
|
||||
M_ASSERT_INDEX(i, v->size);
|
||||
const size_t offset = i / BITSET_LIMB_BIT;
|
||||
const size_t index = i % BITSET_LIMB_BIT;
|
||||
const size_t offset = i / M_B1TSET_LIMB_BIT;
|
||||
const size_t index = i % M_B1TSET_LIMB_BIT;
|
||||
// This is a branchless version as x can only be 0 or 1 with only one variable shift.
|
||||
const bitset_limb_ct mask = ((bitset_limb_ct)1)<<index;
|
||||
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (0-(bitset_limb_ct)x));
|
||||
BITSETI_CONTRACT (v);
|
||||
M_B1TSET_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Flip the bit 'i' in the bitset */
|
||||
static inline void
|
||||
bitset_flip_at(bitset_t v, size_t i)
|
||||
{
|
||||
BITSETI_CONTRACT(v);
|
||||
M_B1TSET_CONTRACT(v);
|
||||
M_ASSERT (v->ptr != NULL);
|
||||
M_ASSERT_INDEX(i, v->size);
|
||||
size_t offset = i / BITSET_LIMB_BIT;
|
||||
size_t index = i % BITSET_LIMB_BIT;
|
||||
size_t offset = i / M_B1TSET_LIMB_BIT;
|
||||
size_t index = i % M_B1TSET_LIMB_BIT;
|
||||
v->ptr[offset] ^= ((bitset_limb_ct)1)<<index;
|
||||
BITSETI_CONTRACT (v);
|
||||
M_B1TSET_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Push back the boolean 'x' in the bitset (increasing the bitset) */
|
||||
static inline void
|
||||
bitset_push_back (bitset_t v, bool x)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
if (v->size >= BITSETI_FROM_ALLOC (v->alloc)) {
|
||||
M_B1TSET_CONTRACT (v);
|
||||
if (M_UNLIKELY (v->size >= M_B1TSET_FROM_ALLOC (v->alloc))) {
|
||||
// Compute the needed allocation.
|
||||
const size_t needAlloc = BITSETI_INC_ALLOC_SIZE(v->alloc);
|
||||
const size_t needAlloc = M_B1TSET_INC_ALLOC_SIZE(v->alloc);
|
||||
// Check for integer overflow
|
||||
if (M_UNLIKELY (needAlloc <= v->alloc)) {
|
||||
M_MEMORY_FULL(needAlloc * sizeof(bitset_limb_ct));
|
||||
@@ -212,31 +220,39 @@ bitset_push_back (bitset_t v, bool x)
|
||||
M_MEMORY_FULL(needAlloc * sizeof(bitset_limb_ct));
|
||||
return;
|
||||
}
|
||||
// Clear allocated memory
|
||||
// FIXME: Why?
|
||||
for(size_t a = v->alloc; a < needAlloc; a++)
|
||||
ptr[a] = 0;
|
||||
v->ptr = ptr;
|
||||
v->alloc = needAlloc;
|
||||
}
|
||||
M_ASSERT(v->ptr != NULL);
|
||||
|
||||
const size_t i = v->size;
|
||||
const size_t offset = i / M_B1TSET_LIMB_BIT;
|
||||
const size_t index = i % M_B1TSET_LIMB_BIT;
|
||||
if (M_UNLIKELY(index == 0)) {
|
||||
// A new limb if used. Clear it before using it.
|
||||
v->ptr[offset] = 0;
|
||||
}
|
||||
// This is a branchless version as x can only be 0 or 1 with only one variable shift.
|
||||
const bitset_limb_ct mask = ((bitset_limb_ct)1)<<index;
|
||||
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (0-(bitset_limb_ct)x));
|
||||
v->size ++;
|
||||
bitset_set_at (v, v->size - 1, x);
|
||||
M_B1TSET_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Resize the bitset to have exactly 'size' bits */
|
||||
static inline void
|
||||
bitset_resize (bitset_t v, size_t size)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
M_B1TSET_CONTRACT (v);
|
||||
// Check for overflow
|
||||
if (M_UNLIKELY (size >= ((size_t)-1) - BITSET_LIMB_BIT)) {
|
||||
if (M_UNLIKELY (size >= ((size_t)-1) - M_B1TSET_LIMB_BIT)) {
|
||||
M_MEMORY_FULL((size_t) -1);
|
||||
return;
|
||||
}
|
||||
// Compute the needed allocation.
|
||||
size_t newAlloc = BITSETI_TO_ALLOC (size);
|
||||
size_t newAlloc = M_B1TSET_TO_ALLOC (size);
|
||||
if (newAlloc > v->alloc) {
|
||||
// Allocate more limbs to store the bitset.
|
||||
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, v->ptr, newAlloc);
|
||||
if (M_UNLIKELY (ptr == NULL) ) {
|
||||
M_MEMORY_FULL(newAlloc * sizeof(bitset_limb_ct));
|
||||
@@ -245,30 +261,50 @@ bitset_resize (bitset_t v, size_t size)
|
||||
v->ptr = ptr;
|
||||
v->alloc = newAlloc;
|
||||
}
|
||||
//FIXME: Last bit are not cleared if new size is lower than org size. Needed?
|
||||
//TODO: Implement a more efficient version when needed.
|
||||
size_t i = v->size;
|
||||
// Resize the bitsets
|
||||
const size_t old_size = v->size;
|
||||
const size_t offset = size / M_B1TSET_LIMB_BIT;
|
||||
const size_t index = size % M_B1TSET_LIMB_BIT;
|
||||
const bitset_limb_ct mask = (((bitset_limb_ct)1)<<index)-1;
|
||||
if (size < old_size) {
|
||||
// Resize down the bitset: clear unused bits
|
||||
if (M_LIKELY(index != 0)) {
|
||||
// Mask the last limb to clear the last bits
|
||||
v->ptr[offset] &= mask;
|
||||
}
|
||||
} else if (size > old_size) {
|
||||
// Resize up the bitset: set to 0 new bits.
|
||||
const size_t old_offset = old_size / M_B1TSET_LIMB_BIT;
|
||||
for(size_t i = old_offset+1 ; i < offset; i++) {
|
||||
v->ptr[i] = 0;
|
||||
}
|
||||
if (M_LIKELY(index != 0)) {
|
||||
// Mask the last limb to clear the last bits
|
||||
v->ptr[offset] = 0;
|
||||
}
|
||||
}
|
||||
v->size = size;
|
||||
for( ; i < size; i++)
|
||||
bitset_set_at(v, i, 0);
|
||||
BITSETI_CONTRACT (v);
|
||||
M_B1TSET_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Reserve allocation in the bitset to accomodate at least 'size' bits without reallocation */
|
||||
static inline void
|
||||
bitset_reserve (bitset_t v, size_t size)
|
||||
bitset_reserve (bitset_t v, size_t alloc)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
size_t oldAlloc = BITSETI_TO_ALLOC (v->size);
|
||||
size_t newAlloc = BITSETI_TO_ALLOC (size);
|
||||
M_B1TSET_CONTRACT (v);
|
||||
size_t oldAlloc = M_B1TSET_TO_ALLOC (v->size);
|
||||
size_t newAlloc = M_B1TSET_TO_ALLOC (alloc);
|
||||
// We refuse to reduce allocation below current size
|
||||
if (oldAlloc > newAlloc) {
|
||||
newAlloc = oldAlloc;
|
||||
}
|
||||
if (M_UNLIKELY (newAlloc == 0)) {
|
||||
// Free all memory used by the bitsets
|
||||
M_MEMORY_FREE (v->ptr);
|
||||
v->size = v->alloc = 0;
|
||||
v->ptr = NULL;
|
||||
} else {
|
||||
// Allocate more memory or reduce memory usage
|
||||
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, v->ptr, newAlloc);
|
||||
if (M_UNLIKELY (ptr == NULL) ) {
|
||||
M_MEMORY_FULL(newAlloc * sizeof(bitset_limb_ct));
|
||||
@@ -277,7 +313,7 @@ bitset_reserve (bitset_t v, size_t size)
|
||||
v->ptr = ptr;
|
||||
v->alloc = newAlloc;
|
||||
}
|
||||
BITSETI_CONTRACT (v);
|
||||
M_B1TSET_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Return the value of the boolean at index 'i'.
|
||||
@@ -287,11 +323,11 @@ bitset_reserve (bitset_t v, size_t size)
|
||||
static inline bool
|
||||
bitset_get(const bitset_t v, size_t i)
|
||||
{
|
||||
BITSETI_CONTRACT(v);
|
||||
M_B1TSET_CONTRACT(v);
|
||||
M_ASSERT (v->ptr != NULL);
|
||||
M_ASSERT_INDEX(i, v->size);
|
||||
size_t offset = i / BITSET_LIMB_BIT;
|
||||
size_t index = i % BITSET_LIMB_BIT;
|
||||
size_t offset = i / M_B1TSET_LIMB_BIT;
|
||||
size_t index = i % M_B1TSET_LIMB_BIT;
|
||||
return ( v->ptr[offset] & (((bitset_limb_ct)1) << index) ) != 0;
|
||||
}
|
||||
|
||||
@@ -302,21 +338,27 @@ bitset_get(const bitset_t v, size_t i)
|
||||
static inline void
|
||||
bitset_pop_back(bool *dest, bitset_t v)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
M_B1TSET_CONTRACT (v);
|
||||
M_ASSERT_INDEX (0, v->size);
|
||||
if (dest) {
|
||||
*dest = bitset_get (v, v->size - 1);
|
||||
}
|
||||
// Remove one item from the bitset
|
||||
v->size--;
|
||||
// Last popped bit is not cleared
|
||||
BITSETI_CONTRACT (v);
|
||||
// Prepare clearing popped bit
|
||||
const size_t offset = v->size / M_B1TSET_LIMB_BIT;
|
||||
const size_t index = v->size % M_B1TSET_LIMB_BIT;
|
||||
const bitset_limb_ct mask = ((bitset_limb_ct)1)<<index;
|
||||
if (dest) {
|
||||
// Read popped bit
|
||||
*dest = (v->ptr[offset] & mask) != 0;
|
||||
}
|
||||
v->ptr[offset] &= mask-1;
|
||||
M_B1TSET_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Return the front bit value in the bitset */
|
||||
static inline bool
|
||||
bitset_front(bitset_t v)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
M_B1TSET_CONTRACT (v);
|
||||
M_ASSERT_INDEX (0, v->size);
|
||||
return bitset_get(v, 0);
|
||||
}
|
||||
@@ -325,7 +367,7 @@ bitset_front(bitset_t v)
|
||||
static inline bool
|
||||
bitset_back(bitset_t v)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
M_B1TSET_CONTRACT (v);
|
||||
M_ASSERT_INDEX (0, v->size);
|
||||
return bitset_get(v, v->size-1);
|
||||
}
|
||||
@@ -334,7 +376,7 @@ bitset_back(bitset_t v)
|
||||
static inline bool
|
||||
bitset_empty_p(bitset_t v)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
M_B1TSET_CONTRACT (v);
|
||||
return v->size == 0;
|
||||
}
|
||||
|
||||
@@ -342,7 +384,7 @@ bitset_empty_p(bitset_t v)
|
||||
static inline size_t
|
||||
bitset_size(bitset_t v)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
M_B1TSET_CONTRACT (v);
|
||||
return v->size;
|
||||
}
|
||||
|
||||
@@ -350,15 +392,14 @@ bitset_size(bitset_t v)
|
||||
static inline size_t
|
||||
bitset_capacity(bitset_t v)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
return BITSETI_FROM_ALLOC (v->alloc);
|
||||
M_B1TSET_CONTRACT (v);
|
||||
return M_B1TSET_FROM_ALLOC (v->alloc);
|
||||
}
|
||||
|
||||
/* Swap the bit at index i and j of the bitset */
|
||||
static inline void
|
||||
bitset_swap_at (bitset_t v, size_t i, size_t j)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
M_ASSERT_INDEX(i, v->size);
|
||||
M_ASSERT_INDEX(j, v->size);
|
||||
|
||||
@@ -366,18 +407,19 @@ bitset_swap_at (bitset_t v, size_t i, size_t j)
|
||||
bool j_val = bitset_get(v, j);
|
||||
bitset_set_at (v, i, j_val);
|
||||
bitset_set_at (v, j, i_val);
|
||||
BITSETI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Swap the bitsets */
|
||||
static inline void
|
||||
bitset_swap (bitset_t v1, bitset_t v2)
|
||||
{
|
||||
BITSETI_CONTRACT (v1);
|
||||
BITSETI_CONTRACT (v2);
|
||||
M_B1TSET_CONTRACT (v1);
|
||||
M_B1TSET_CONTRACT (v2);
|
||||
M_SWAP (size_t, v1->size, v2->size);
|
||||
M_SWAP (size_t, v1->alloc, v2->alloc);
|
||||
M_SWAP (bitset_limb_ct *, v1->ptr, v2->ptr);
|
||||
M_B1TSET_CONTRACT (v1);
|
||||
M_B1TSET_CONTRACT (v2);
|
||||
}
|
||||
|
||||
/* (INTERNAL) Left shift of the bitset (ptr+size) by 1 bit,
|
||||
@@ -385,12 +427,12 @@ bitset_swap (bitset_t v1, bitset_t v2)
|
||||
* Return the new carry.
|
||||
*/
|
||||
static inline bitset_limb_ct
|
||||
bitseti_lshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
|
||||
m_b1tset_lshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
bitset_limb_ct v = ptr[i];
|
||||
ptr[i] = (v << 1) | carry;
|
||||
carry = (v >> (BITSET_LIMB_BIT-1) );
|
||||
carry = (v >> (M_B1TSET_LIMB_BIT-1) );
|
||||
}
|
||||
return carry;
|
||||
}
|
||||
@@ -400,40 +442,42 @@ bitseti_lshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
|
||||
* Return the new carry.
|
||||
*/
|
||||
static inline bitset_limb_ct
|
||||
bitseti_rshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
|
||||
m_b1tset_rshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
|
||||
{
|
||||
for(size_t i = n - 1; i < n; i--) {
|
||||
bitset_limb_ct v = ptr[i];
|
||||
v = (v >> 1) | (carry << (BITSET_LIMB_BIT-1) );
|
||||
ptr[i] = (v >> 1) | (carry << (M_B1TSET_LIMB_BIT-1) );
|
||||
carry = v & 1;
|
||||
}
|
||||
return carry;
|
||||
}
|
||||
|
||||
/* Insert a new bit at position 'key' of value 'value' in the bitset */
|
||||
/* Insert a new bit at position 'key' of value 'value' in the bitset 'set'
|
||||
shifting the set accordingly */
|
||||
static inline void
|
||||
bitset_push_at(bitset_t set, size_t key, bool value)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
M_B1TSET_CONTRACT (set);
|
||||
// First push another value to extend the array to the right size
|
||||
bitset_push_back(set, false);
|
||||
M_ASSERT (set->ptr != NULL);
|
||||
M_ASSERT_INDEX(key, set->size);
|
||||
|
||||
// Then shift it
|
||||
size_t offset = key / BITSET_LIMB_BIT;
|
||||
size_t index = key % BITSET_LIMB_BIT;
|
||||
size_t offset = key / M_B1TSET_LIMB_BIT;
|
||||
size_t index = key % M_B1TSET_LIMB_BIT;
|
||||
bitset_limb_ct v = set->ptr[offset];
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1)<<index)-1;
|
||||
bitset_limb_ct carry = (v >> (BITSET_LIMB_BIT-1) );
|
||||
bitset_limb_ct carry = (v >> (M_B1TSET_LIMB_BIT-1) );
|
||||
v = (v & mask) | ((unsigned int) value << index) | ((v & ~mask) << 1);
|
||||
set->ptr[offset] = v;
|
||||
size_t size = (set->size + BITSET_LIMB_BIT - 1) / BITSET_LIMB_BIT;
|
||||
size_t size = (set->size + M_B1TSET_LIMB_BIT - 1) / M_B1TSET_LIMB_BIT;
|
||||
M_ASSERT (size >= offset + 1);
|
||||
v = bitseti_lshift(&set->ptr[offset+1], size - offset - 1, carry);
|
||||
// v is unused.
|
||||
v = m_b1tset_lshift(&set->ptr[offset+1], size - offset - 1, carry);
|
||||
// v is unused as it should be zero.
|
||||
M_ASSERT(v == 0);
|
||||
(void) v;
|
||||
BITSETI_CONTRACT (set);
|
||||
M_B1TSET_CONTRACT (set);
|
||||
}
|
||||
|
||||
/* Pop a new bit at position 'key' in the bitset
|
||||
@@ -441,49 +485,42 @@ bitset_push_at(bitset_t set, size_t key, bool value)
|
||||
static inline void
|
||||
bitset_pop_at(bool *dest, bitset_t set, size_t key)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
M_B1TSET_CONTRACT (set);
|
||||
M_ASSERT (set->ptr != NULL);
|
||||
M_ASSERT_INDEX(key, set->size);
|
||||
|
||||
if (dest) {
|
||||
*dest = bitset_get (set, key);
|
||||
}
|
||||
// Shift it
|
||||
size_t offset = key / BITSET_LIMB_BIT;
|
||||
size_t index = key % BITSET_LIMB_BIT;
|
||||
size_t size = (set->size + BITSET_LIMB_BIT - 1) / BITSET_LIMB_BIT;
|
||||
// Shift it
|
||||
size_t offset = key / M_B1TSET_LIMB_BIT;
|
||||
size_t index = key % M_B1TSET_LIMB_BIT;
|
||||
size_t size = (set->size + M_B1TSET_LIMB_BIT - 1) / M_B1TSET_LIMB_BIT;
|
||||
bitset_limb_ct v, mask, carry;
|
||||
carry = bitseti_rshift(&set->ptr[offset+1], size - offset - 1, false);
|
||||
carry = m_b1tset_rshift(&set->ptr[offset+1], size - offset - 1, false);
|
||||
v = set->ptr[offset];
|
||||
mask = (((bitset_limb_ct)1)<<index)-1;
|
||||
v = (v & mask) | ((v>>1) & ~mask) | (carry << (BITSET_LIMB_BIT-1)) ;
|
||||
v = (v & mask) | ((v>>1) & ~mask) | (carry << (M_B1TSET_LIMB_BIT-1)) ;
|
||||
set->ptr[offset] = v;
|
||||
// Decrease size
|
||||
set->size --;
|
||||
BITSETI_CONTRACT (set);
|
||||
M_B1TSET_CONTRACT (set);
|
||||
}
|
||||
|
||||
/* Test if two bitsets are equal */
|
||||
static inline bool
|
||||
bitset_equal_p (const bitset_t set1, const bitset_t set2)
|
||||
{
|
||||
BITSETI_CONTRACT (set1);
|
||||
BITSETI_CONTRACT (set2);
|
||||
M_B1TSET_CONTRACT (set1);
|
||||
M_B1TSET_CONTRACT (set2);
|
||||
if (set1->size != set2->size)
|
||||
return false;
|
||||
/* We won't compare each bit individualy,
|
||||
but instead compare them per limb */
|
||||
const size_t limbSize = (set1->size) / BITSET_LIMB_BIT;
|
||||
const size_t limbSize = (set1->size + M_B1TSET_LIMB_BIT -1) / M_B1TSET_LIMB_BIT;
|
||||
for(size_t i = 0 ; i < limbSize;i++)
|
||||
if (set1->ptr[i] != set2->ptr[i])
|
||||
return false;
|
||||
/* Compare the last limb if needed */
|
||||
const size_t index = set1->size % BITSET_LIMB_BIT;
|
||||
if (index > 0) {
|
||||
const bitset_limb_ct mask = (((bitset_limb_ct)1) << index) - 1;
|
||||
if ((set1->ptr[limbSize] & mask) != (set2->ptr[limbSize] & mask))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -491,7 +528,7 @@ bitset_equal_p (const bitset_t set1, const bitset_t set2)
|
||||
static inline void
|
||||
bitset_it(bitset_it_t it, bitset_t set)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
M_B1TSET_CONTRACT (set);
|
||||
it->index = 0;
|
||||
it->set = set;
|
||||
}
|
||||
@@ -509,7 +546,7 @@ bitset_it_set(bitset_it_t it, const bitset_it_t itorg)
|
||||
static inline void
|
||||
bitset_it_last(bitset_it_t it, bitset_t set)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
M_B1TSET_CONTRACT (set);
|
||||
it->index = set->size-1;
|
||||
it->set = set;
|
||||
}
|
||||
@@ -518,7 +555,7 @@ bitset_it_last(bitset_it_t it, bitset_t set)
|
||||
static inline void
|
||||
bitset_it_end(bitset_it_t it, bitset_t set)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
M_B1TSET_CONTRACT (set);
|
||||
it->index = set->size;
|
||||
it->set = set;
|
||||
}
|
||||
@@ -581,7 +618,7 @@ bitset_cref(bitset_it_t it)
|
||||
static inline void
|
||||
bitset_out_str(FILE *file, const bitset_t set)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
M_B1TSET_CONTRACT (set);
|
||||
M_ASSERT(file != NULL);
|
||||
fputc ('[', file);
|
||||
for(size_t i = 0; i < set->size; i++) {
|
||||
@@ -596,18 +633,18 @@ bitset_out_str(FILE *file, const bitset_t set)
|
||||
static inline bool
|
||||
bitset_in_str(bitset_t set, FILE *file)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
M_B1TSET_CONTRACT (set);
|
||||
M_ASSERT(file != NULL);
|
||||
bitset_clean(set);
|
||||
bitset_reset(set);
|
||||
int c = fgetc(file);
|
||||
if (c != '[') return false;
|
||||
if (M_UNLIKELY (c != '[')) return false;
|
||||
c = fgetc(file);
|
||||
while (c == '0' || c == '1') {
|
||||
const bool b = (c == '1');
|
||||
bitset_push_back (set, b);
|
||||
c = fgetc(file);
|
||||
}
|
||||
BITSETI_CONTRACT (set);
|
||||
M_B1TSET_CONTRACT (set);
|
||||
return c == ']';
|
||||
}
|
||||
|
||||
@@ -615,20 +652,20 @@ bitset_in_str(bitset_t set, FILE *file)
|
||||
static inline bool
|
||||
bitset_parse_str(bitset_t set, const char str[], const char **endptr)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
M_B1TSET_CONTRACT (set);
|
||||
M_ASSERT(str != NULL);
|
||||
bool success = false;
|
||||
bitset_clean(set);
|
||||
bitset_reset(set);
|
||||
char c = *str++;
|
||||
if (c != '[') goto exit;
|
||||
if (M_UNLIKELY(c != '[')) goto exit;
|
||||
c = *str++;
|
||||
do {
|
||||
if (c != '0' && c != '1') goto exit;
|
||||
if (M_UNLIKELY(c != '0' && c != '1')) goto exit;
|
||||
const bool b = (c == '1');
|
||||
bitset_push_back (set, b);
|
||||
c = *str++;
|
||||
} while (c != ']' && c != 0);
|
||||
BITSETI_CONTRACT (set);
|
||||
M_B1TSET_CONTRACT (set);
|
||||
success = (c == ']');
|
||||
exit:
|
||||
if (endptr) *endptr = str;
|
||||
@@ -647,19 +684,15 @@ bitset_set_str(bitset_t dest, const char str[])
|
||||
static inline void
|
||||
bitset_and(bitset_t dest, const bitset_t src)
|
||||
{
|
||||
BITSETI_CONTRACT(dest);
|
||||
BITSETI_CONTRACT(src);
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
M_B1TSET_CONTRACT(src);
|
||||
size_t s = M_MIN(dest->size, src->size);
|
||||
size_t n = s / BITSET_LIMB_BIT;
|
||||
size_t m = s % BITSET_LIMB_BIT;
|
||||
size_t n = (s + M_B1TSET_LIMB_BIT -1) / M_B1TSET_LIMB_BIT;
|
||||
for(size_t i = 0 ; i < n; i++)
|
||||
dest->ptr[i] &= src->ptr[i];
|
||||
if (m) {
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
dest->ptr[n] = (dest->ptr[n] & src->ptr[n]) & mask;
|
||||
}
|
||||
// Reduce the dest size to the minimum size between both
|
||||
dest->size = s;
|
||||
BITSETI_CONTRACT(dest);
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
}
|
||||
|
||||
/* Perform an OR operation between the bitsets,
|
||||
@@ -667,19 +700,15 @@ bitset_and(bitset_t dest, const bitset_t src)
|
||||
static inline void
|
||||
bitset_or(bitset_t dest, const bitset_t src)
|
||||
{
|
||||
BITSETI_CONTRACT(dest);
|
||||
BITSETI_CONTRACT(src);
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
M_B1TSET_CONTRACT(src);
|
||||
size_t s = M_MIN(dest->size, src->size);
|
||||
size_t n = s / BITSET_LIMB_BIT;
|
||||
size_t m = s % BITSET_LIMB_BIT;
|
||||
size_t n = (s + M_B1TSET_LIMB_BIT - 1) / M_B1TSET_LIMB_BIT;
|
||||
for(size_t i = 0 ; i < n; i++)
|
||||
dest->ptr[i] |= src->ptr[i];
|
||||
if (m) {
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
dest->ptr[n] = (dest->ptr[n] | src->ptr[n]) & mask;
|
||||
}
|
||||
// Reduce the dest size to the minimum size between both
|
||||
dest->size = s;
|
||||
BITSETI_CONTRACT(dest);
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
}
|
||||
|
||||
/* Perform an XOR operation between the bitsets,
|
||||
@@ -687,54 +716,51 @@ bitset_or(bitset_t dest, const bitset_t src)
|
||||
static inline void
|
||||
bitset_xor(bitset_t dest, const bitset_t src)
|
||||
{
|
||||
BITSETI_CONTRACT(dest);
|
||||
BITSETI_CONTRACT(src);
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
M_B1TSET_CONTRACT(src);
|
||||
size_t s = M_MIN(dest->size, src->size);
|
||||
size_t n = s / BITSET_LIMB_BIT;
|
||||
size_t m = s % BITSET_LIMB_BIT;
|
||||
size_t n = s / M_B1TSET_LIMB_BIT;
|
||||
size_t m = s % M_B1TSET_LIMB_BIT;
|
||||
for(size_t i = 0 ; i < n; i++)
|
||||
dest->ptr[i] ^= src->ptr[i];
|
||||
if (m) {
|
||||
if (M_LIKELY(m)) {
|
||||
// Last limb needs to be masked too
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
dest->ptr[n] = (dest->ptr[n] ^ src->ptr[n]) & mask;
|
||||
}
|
||||
// Reduce the dest size to the minimum size between both
|
||||
dest->size = s;
|
||||
BITSETI_CONTRACT(dest);
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
}
|
||||
|
||||
/* Perform a NOT operation of the bitset */
|
||||
static inline void
|
||||
bitset_not(bitset_t dest)
|
||||
{
|
||||
BITSETI_CONTRACT(dest);
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
size_t s = dest->size;
|
||||
size_t n = s / BITSET_LIMB_BIT;
|
||||
size_t m = s % BITSET_LIMB_BIT;
|
||||
size_t n = s / M_B1TSET_LIMB_BIT;
|
||||
size_t m = s % M_B1TSET_LIMB_BIT;
|
||||
for(size_t i = 0 ; i < n; i++)
|
||||
dest->ptr[i] = ~ (dest->ptr[i]);
|
||||
if (m) {
|
||||
if (M_LIKELY(m)) {
|
||||
// Last limb needs to be masked too
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
dest->ptr[n] = (~ dest->ptr[n]) & mask;
|
||||
}
|
||||
dest->size = s;
|
||||
BITSETI_CONTRACT(dest);
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
}
|
||||
|
||||
/* Copute a hash of the bitset */
|
||||
static inline size_t
|
||||
bitset_hash(const bitset_t set)
|
||||
{
|
||||
BITSETI_CONTRACT(set);
|
||||
M_B1TSET_CONTRACT(set);
|
||||
size_t s = set->size;
|
||||
size_t n = s / BITSET_LIMB_BIT;
|
||||
size_t m = s % BITSET_LIMB_BIT;
|
||||
size_t n = (s + M_B1TSET_LIMB_BIT-1) / M_B1TSET_LIMB_BIT;
|
||||
M_HASH_DECL(hash);
|
||||
for(size_t i = 0 ; i < n; i++)
|
||||
M_HASH_UP(hash, set->ptr[i]);
|
||||
if (m) {
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
M_HASH_UP(hash, (set->ptr[n] & mask));
|
||||
}
|
||||
return M_HASH_FINAL (hash);
|
||||
}
|
||||
|
||||
@@ -742,25 +768,57 @@ bitset_hash(const bitset_t set)
|
||||
static inline size_t
|
||||
bitset_clz(const bitset_t set)
|
||||
{
|
||||
BITSETI_CONTRACT(set);
|
||||
M_B1TSET_CONTRACT(set);
|
||||
size_t s = set->size;
|
||||
M_ASSERT_INDEX (0, s); // TBC: Special case to handle?
|
||||
size_t n = (s -1) / BITSET_LIMB_BIT;
|
||||
size_t m = s % BITSET_LIMB_BIT;
|
||||
if (M_UNLIKELY (s == 0)) {
|
||||
return 0;
|
||||
}
|
||||
size_t n = (s -1) / M_B1TSET_LIMB_BIT;
|
||||
size_t m = s % M_B1TSET_LIMB_BIT;
|
||||
bitset_limb_ct limb = set->ptr[n];
|
||||
if (m) {
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
limb &= mask;
|
||||
} else {
|
||||
m = BITSET_LIMB_BIT;
|
||||
m = M_B1TSET_LIMB_BIT;
|
||||
}
|
||||
s = 0;
|
||||
while (limb == 0 && n > 0) {
|
||||
s += m;
|
||||
limb = set->ptr[--n];
|
||||
m = BITSET_LIMB_BIT;
|
||||
m = M_B1TSET_LIMB_BIT;
|
||||
}
|
||||
s += m_core_clz64(limb) - (BITSET_LIMB_BIT - m);
|
||||
s += m_core_clz64(limb) - (M_B1TSET_LIMB_BIT - m);
|
||||
return s;
|
||||
}
|
||||
|
||||
// For GCC or CLANG or ICC
|
||||
#if defined(__GNUC__)
|
||||
static inline size_t m_b1tset_popcount64(bitset_limb_ct limb)
|
||||
{
|
||||
return (size_t) __builtin_popcountll(limb);
|
||||
}
|
||||
#else
|
||||
// MSVC __popcnt64 may not exist on the target architecture (no emulation layer)
|
||||
// Use emulation layer: https://en.wikipedia.org/wiki/Hamming_weight
|
||||
static inline size_t m_b1tset_popcount64(bitset_limb_ct limb)
|
||||
{
|
||||
limb = limb - ((limb >> 1) & 0x5555555555555555ULL);
|
||||
limb = (limb & 0x3333333333333333ULL) + ((limb >> 2) & 0x3333333333333333ULL);
|
||||
limb = (limb + (limb >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
|
||||
return (limb * 0x0101010101010101ULL) >> 56;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Count the number of 1 */
|
||||
static inline size_t
|
||||
bitset_popcount(const bitset_t set)
|
||||
{
|
||||
M_B1TSET_CONTRACT(set);
|
||||
size_t s = 0;
|
||||
size_t n = (set->size + M_B1TSET_LIMB_BIT - 1) / M_B1TSET_LIMB_BIT;
|
||||
for(size_t i = 0 ; i < n; i++)
|
||||
s += m_b1tset_popcount64(set->ptr[i]);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -789,7 +847,7 @@ bitset_clz(const bitset_t set)
|
||||
,IT_NEXT(bitset_next) \
|
||||
,IT_PREVIOUS(bitset_previous) \
|
||||
,IT_CREF(bitset_cref) \
|
||||
,CLEAN(bitset_clean) \
|
||||
,RESET(bitset_reset) \
|
||||
,PUSH(bitset_push_back) \
|
||||
,POP(bitset_pop_back) \
|
||||
,HASH(bitset_hash) \
|
||||
@@ -805,17 +863,22 @@ bitset_clz(const bitset_t set)
|
||||
|
||||
// TODO: set_at2, insert_v, remove_v
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
|
||||
// NOTE: Define this function only if m-string has been included
|
||||
#if !defined(MSTARLIB_BITSET_STRING_H) && defined(MSTARLIB_STRING_H)
|
||||
#define MSTARLIB_BITSET_STRING_H
|
||||
|
||||
/* Output to a string_t the formatted text representation of a bitset */
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Output to a string_t 'str' the formatted text representation of the bitset 'set'
|
||||
or append it to the strinf (append=true) */
|
||||
static inline void
|
||||
bitset_get_str(string_t str, const bitset_t set, bool append)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
M_B1TSET_CONTRACT (set);
|
||||
M_ASSERT(str != NULL);
|
||||
(append ? string_cat_str : string_set_str) (str, "[");
|
||||
for(size_t i = 0; i < set->size; i++) {
|
||||
|
||||
+134
-121
@@ -35,11 +35,7 @@
|
||||
BPTREE_DEF2(name, N, key_t, value_t)
|
||||
*/
|
||||
#define BPTREE_DEF2(name, N, key_type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 1, 0, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ), \
|
||||
(name, N, key_type, __VA_ARGS__, 1, 0, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
BPTREE_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name, _itref_t), N, key_type, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a B+tree of size 'N' that maps a 'key' to a 'value'
|
||||
@@ -51,7 +47,7 @@
|
||||
*/
|
||||
#define BPTREE_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_BPTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 1, 0, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, itref_t ), \
|
||||
(name, N, key_type, __VA_ARGS__, 1, 0, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, itref_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -61,11 +57,7 @@
|
||||
with its associated functions
|
||||
USAGE: BPTREE_DEF(name, N, type, [, oplist_of_the_type]) */
|
||||
#define BPTREE_DEF(name, N, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 0, 0, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ), \
|
||||
(name, N, __VA_ARGS__, __VA_ARGS__, 0, 0, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
BPTREE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), N, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a B+tree of a given type, of size N.
|
||||
@@ -73,7 +65,7 @@
|
||||
USAGE: BPTREE_DEF_AS(name, name_t, it_t, N, type, [, oplist_of_the_type]) */
|
||||
#define BPTREE_DEF_AS(name, name_t, it_t, N, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_BPTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 0, 0, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, M_C(name, _itref_ct) ), \
|
||||
(name, N, __VA_ARGS__, __VA_ARGS__, 0, 0, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, M_C(name, _itref_ct) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -88,11 +80,7 @@
|
||||
BPTREE_MULTI_DEF2(name, N, key_t, value_t)
|
||||
*/
|
||||
#define BPTREE_MULTI_DEF2(name, N, key_type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 1, 1, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ), \
|
||||
(name, N, key_type, __VA_ARGS__, 1, 1, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
BPTREE_MULTI_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), N, key_type, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a B+tree of size 'N' that maps a 'key' to a 'value',
|
||||
@@ -105,7 +93,7 @@
|
||||
*/
|
||||
#define BPTREE_MULTI_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_BPTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 1, 1, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, itref_t ), \
|
||||
(name, N, key_type, __VA_ARGS__, 1, 1, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, itref_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -116,11 +104,7 @@
|
||||
with its associated functions
|
||||
USAGE: BPTREE_MULTI_DEF(name, N, type, [, oplist_of_the_type]) */
|
||||
#define BPTREE_MULTI_DEF(name, N, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 0, 1, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ), \
|
||||
(name, N, __VA_ARGS__, __VA_ARGS__, 0, 1, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ))) \
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
BPTREE_MULTI_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), N, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a B+tree of a given type, of size N.
|
||||
@@ -129,7 +113,7 @@
|
||||
USAGE: BPTREE_MULTI_DEF_AS(name, name_t, it_t, N, type, [, oplist_of_the_type]) */
|
||||
#define BPTREE_MULTI_DEF_AS(name, name_t, it_t, N, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_BPTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 0, 1, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, M_C(name, _itref_ct) ), \
|
||||
(name, N, __VA_ARGS__, __VA_ARGS__, 0, 1, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, M_C(name, _itref_ct) ))) \
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
@@ -138,7 +122,7 @@
|
||||
/* Define the oplist of a B+TREE used as a set of type (from BPTREE_DEF).
|
||||
USAGE: BPTREE_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define BPTREE_OPLIST(...) \
|
||||
BPTREEI_KEY_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_BPTR33_KEY_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
@@ -149,7 +133,7 @@
|
||||
by algorithm.
|
||||
*/
|
||||
#define BPTREE_OPLIST2(...) \
|
||||
BPTREEI_OPLIST2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_BPTR33_OPLIST2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
@@ -159,18 +143,18 @@
|
||||
|
||||
/* Deferred evaluation for the oplist definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define BPTREEI_KEY_OPLIST_P1(arg) BPTREEI_KEY_OPLIST_P2 arg
|
||||
#define M_BPTR33_KEY_OPLIST_P1(arg) M_BPTR33_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)
|
||||
#define M_BPTR33_KEY_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_BPTR33_KEY_OPLIST_P3, M_BPTR33_KEY_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define BPTREEI_KEY_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_BPTR33_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_P3(name, oplist) \
|
||||
/* OPLIST definition of a b+tree (global tree) */
|
||||
#define M_BPTR33_KEY_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
INIT_WITH(API_1(M_INIT_VAI)), \
|
||||
@@ -179,6 +163,7 @@
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(name, _swap)), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
SUBTYPE(M_C(name, _subtype_ct)), \
|
||||
IT_TYPE(M_C(name, _it_ct)), \
|
||||
@@ -190,7 +175,7 @@
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_REF(M_C(name,_ref)), \
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
CLEAN(M_C(name,_clean)), \
|
||||
RESET(M_C(name,_reset)), \
|
||||
PUSH(M_C(name,_push)), \
|
||||
GET_MIN(M_C(name,_min)), \
|
||||
GET_MAX(M_C(name,_max)), \
|
||||
@@ -208,20 +193,20 @@
|
||||
)
|
||||
|
||||
/* Deferred evaluation */
|
||||
#define BPTREEI_OPLIST2_P1(arg) BPTREEI_OPLIST2_P2 arg
|
||||
#define M_BPTR33_OPLIST2_P1(arg) M_BPTR33_OPLIST2_P2 arg
|
||||
|
||||
/* Validation of the given oplists (first the key oplist, then the value oplist) */
|
||||
#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)
|
||||
#define M_BPTR33_OPLIST2_P2(name, key_oplist, value_oplist) \
|
||||
M_IF_OPLIST(key_oplist)(M_BPTR33_OPLIST2_P3, M_BPTR33_OPLIST2_FAILURE)(name, key_oplist, value_oplist)
|
||||
#define M_BPTR33_OPLIST2_P3(name, key_oplist, value_oplist) \
|
||||
M_IF_OPLIST(value_oplist)(M_BPTR33_OPLIST2_P4, M_BPTR33_OPLIST2_FAILURE)(name, key_oplist, value_oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define BPTREEI_OPLIST2_FAILURE(name, key_oplist, value_oplist) \
|
||||
#define M_BPTR33_OPLIST2_FAILURE(name, key_oplist, value_oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, key_oplist, value_oplist)))
|
||||
|
||||
/* Final definition of the oplist */
|
||||
#define BPTREEI_OPLIST2_P4(name, key_oplist, value_oplist) \
|
||||
/* Final definition of the oplist (associative array) */
|
||||
#define M_BPTR33_OPLIST2_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)), \
|
||||
@@ -230,6 +215,7 @@
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(name, _swap)), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
SUBTYPE(M_C(name, _subtype_ct)), \
|
||||
EMPTY_P(M_C(name,_empty_p)), \
|
||||
@@ -241,17 +227,17 @@
|
||||
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)), \
|
||||
RESET(M_C(name,_reset)), \
|
||||
GET_MIN(M_C(name,_min)), \
|
||||
GET_MAX(M_C(name,_max)), \
|
||||
KEY_TYPE(M_C(name, _key_ct)), \
|
||||
VALUE_TYPE(M_C(name, _value_ct)), \
|
||||
SET_KEY(M_C(name, _set_at)), \
|
||||
GET_KEY(M_C(name, _get)), \
|
||||
SAFE_GET_KEY(M_C(name, _safe_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)),), \
|
||||
@@ -268,9 +254,9 @@
|
||||
|
||||
/* Internal contract of a B+TREE of size 'N' for a node 'node' or root 'root' */
|
||||
#ifdef NDEBUG
|
||||
# define BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, node, root) do { } while (0)
|
||||
# define M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, node, root) do { } while (0)
|
||||
#else
|
||||
# define BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, node, root) do { \
|
||||
# define M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, node, root) do { \
|
||||
M_ASSERT ((node) != NULL); \
|
||||
M_ASSERT ((root) != NULL); \
|
||||
int num2 = (node)->num; \
|
||||
@@ -299,9 +285,9 @@
|
||||
#endif
|
||||
|
||||
/* Contract for a B+TREE of size N named 'b' */
|
||||
#define BPTREEI_CONTRACT(N, isMulti, key_oplist, b) do { \
|
||||
#define M_BPTR33_CONTRACT(N, isMulti, key_oplist, b) do { \
|
||||
M_ASSERT (N >= 3); /* TBC: 2 instead ? */ \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, (b)->root, (b)->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, (b)->root, (b)->root); \
|
||||
M_ASSERT ((b)->root->next == NULL); \
|
||||
if ((b)->root->num <= 0) M_ASSERT (-(b)->root->num == (int) (b)->size); \
|
||||
} while (0)
|
||||
@@ -314,22 +300,22 @@
|
||||
Ceil(Log2(2 ^ (CHAR_BIT*sizeof (size_t)))) + 1
|
||||
"+ 1" due to final line composed of nodes.
|
||||
*/
|
||||
#define BPTREEI_MAX_STACK ((int)(1 + CHAR_BIT*sizeof (size_t)))
|
||||
#define M_BPTR33_MAX_STACK ((int)(1 + CHAR_BIT*sizeof (size_t)))
|
||||
|
||||
/* Deferred evaluation for the b+tree definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define BPTREEI_DEF_P1(arg) BPTREEI_DEF_P2 arg
|
||||
#define M_BPTR33_DEF_P1(arg) M_BPTR33_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, subtype_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, subtype_t)
|
||||
#define M_BPTR33_DEF_P2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
M_IF_OPLIST(key_oplist)(M_BPTR33_DEF_P3, M_BPTR33_DEF_FAILURE)(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_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, subtype_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, subtype_t)
|
||||
#define M_BPTR33_DEF_P3(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
M_IF_OPLIST(value_oplist)(M_BPTR33_DEF_P4, M_BPTR33_DEF_FAILURE)(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_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, subtype_t) \
|
||||
#define M_BPTR33_DEF_FAILURE(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_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
|
||||
@@ -347,14 +333,14 @@
|
||||
- pit_t: alias for internal parent iterator
|
||||
- subtype_t: alias for the type referenced by the iterator
|
||||
*/
|
||||
#define BPTREEI_DEF_P4(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
#define M_BPTR33_DEF_P4(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
\
|
||||
M_IF(isMap)( \
|
||||
/* Type returned by the iterator. Due to having key and value \
|
||||
separated in their own array in the node, it is pointers to \
|
||||
the objects, not a global pointer to both objects. */ \
|
||||
typedef struct M_C(name, _pair_s) { \
|
||||
key_t *key_ptr; \
|
||||
key_t *key_ptr; \
|
||||
value_t *value_ptr; \
|
||||
} subtype_t; \
|
||||
, \
|
||||
@@ -393,7 +379,7 @@
|
||||
/* Define the Parent Tree Iterator */ \
|
||||
typedef struct M_C(name, _parent_it_s) { \
|
||||
int num; \
|
||||
node_t parent[BPTREEI_MAX_STACK]; \
|
||||
node_t parent[M_BPTR33_MAX_STACK]; \
|
||||
} pit_t[1]; \
|
||||
\
|
||||
/* Define the Iterator */ \
|
||||
@@ -411,6 +397,8 @@
|
||||
/* TODO: Can be specialized to alloc for leaf or for non leaf */ \
|
||||
static inline node_t M_C(name, _new_node)(void) \
|
||||
{ \
|
||||
M_STATIC_ASSERT(N >= 2, M_LIB_ILLEGAL_PARAM, \
|
||||
"Number of items per node shall be >= 2."); \
|
||||
node_t n = M_CALL_NEW(key_oplist, struct M_C(name, _node_s)); \
|
||||
if (M_UNLIKELY (n == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (node_t)); \
|
||||
@@ -425,7 +413,7 @@
|
||||
{ \
|
||||
b->root = M_C(name, _new_node)(); \
|
||||
b->size = 0; \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
static inline bool M_C(name, _is_leaf)(const node_t n) \
|
||||
@@ -444,9 +432,9 @@
|
||||
return num; \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _clean)(tree_t b) \
|
||||
static inline void M_C(name, _reset)(tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
node_t next, n = b->root; \
|
||||
pit_t pit; \
|
||||
/* np is the heigh of the tree */ \
|
||||
@@ -454,11 +442,11 @@
|
||||
/* Scan down the nodes to the left down node */ \
|
||||
while (!M_C(name, _is_leaf)(n)) { \
|
||||
pit->parent[np++] = n; \
|
||||
M_ASSERT (np <= BPTREEI_MAX_STACK); \
|
||||
M_ASSERT (np <= M_BPTR33_MAX_STACK); \
|
||||
n = n->kind.node[0]; \
|
||||
} \
|
||||
pit->parent[np++] = n; \
|
||||
M_ASSERT (np <= BPTREEI_MAX_STACK); \
|
||||
M_ASSERT (np <= M_BPTR33_MAX_STACK); \
|
||||
/* Clean & free non root */ \
|
||||
for(int i = 0; i < np; i++) { \
|
||||
n = pit->parent[i]; \
|
||||
@@ -484,13 +472,18 @@
|
||||
/* Clean root */ \
|
||||
b->root->num = 0; \
|
||||
b->size = 0; \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED M_C(name, _clean)(tree_t b) \
|
||||
{ \
|
||||
M_C(name, _reset)(b); \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _clear)(tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_C(name, _clean)(b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_C(name, _reset)(b); \
|
||||
/* Once the tree is clean, only the root remains */ \
|
||||
M_CALL_DEL(key_oplist, b->root); \
|
||||
b->root = NULL; \
|
||||
@@ -539,18 +532,18 @@
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, (o==root) ? n : root); \
|
||||
M_BPTR33_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) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, o); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, o); \
|
||||
M_ASSERT (b != NULL); \
|
||||
/* Just copy recursively the root node */ \
|
||||
b->root = M_C(name, _copy_node)(o->root, o->root); \
|
||||
b->size = o->size; \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _set)(tree_t b, const tree_t o) \
|
||||
@@ -563,14 +556,14 @@
|
||||
\
|
||||
static inline bool M_C(name, _empty_p)(const tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
/* root shall be an empty leaf */ \
|
||||
return b->size == 0; \
|
||||
} \
|
||||
\
|
||||
static inline size_t M_C(name, _size)(const tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
return b->size; \
|
||||
} \
|
||||
\
|
||||
@@ -578,10 +571,10 @@
|
||||
{ \
|
||||
node_t n = b->root; \
|
||||
int np = 0; \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
/* Go down the tree while searching for key */ \
|
||||
while (!M_C(name, _is_leaf)(n)) { \
|
||||
M_ASSERT (np <= BPTREEI_MAX_STACK); \
|
||||
M_ASSERT (np <= M_BPTR33_MAX_STACK); \
|
||||
int i, hi = n->num; \
|
||||
M_ASSERT (hi > 0); \
|
||||
/* Linear search is usually faster than binary search for \
|
||||
@@ -597,7 +590,7 @@
|
||||
/* Select the new node to go down to */ \
|
||||
n = n->kind.node[i]; \
|
||||
M_ASSERT (n != NULL); \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
} \
|
||||
pit->num = np; \
|
||||
return n; \
|
||||
@@ -605,12 +598,12 @@
|
||||
\
|
||||
static inline value_t *M_C(name, _get)(const tree_t b, key_t const key) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_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); \
|
||||
M_BPTR33_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]); \
|
||||
@@ -688,7 +681,7 @@
|
||||
M_IF(isMap)(M_DEFERRED_COMMA value_t const value,)) \
|
||||
{ \
|
||||
pit_t pit; \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
node_t leaf = M_C(name, _search_for_leaf)(pit, b, key); \
|
||||
/* Insert key into the leaf.*/ \
|
||||
/* NOTE: Even if there is N elements, we can still add one more.*/ \
|
||||
@@ -696,7 +689,7 @@
|
||||
if (i < 0) { \
|
||||
/* Nothing to do anymore. key already exists in the tree. \
|
||||
value has been updated if needed */ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
return; \
|
||||
} \
|
||||
b->size ++; \
|
||||
@@ -705,7 +698,7 @@
|
||||
M_ASSERT (num > 0); \
|
||||
if (M_LIKELY (num <= N)) { \
|
||||
/* nothing more to do */ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
return; \
|
||||
} \
|
||||
M_ASSERT (num == N+1); \
|
||||
@@ -722,8 +715,8 @@
|
||||
nleaf->num = -nnum; \
|
||||
nleaf->next = leaf->next; \
|
||||
leaf->next = nleaf; \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, leaf, b->root); \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, nleaf, b->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, leaf, b->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, nleaf, b->root); \
|
||||
/* Update parent to inject *key_ptr that splits between (leaf, nleaf) */ \
|
||||
key_t *key_ptr = &leaf->key[num-1]; \
|
||||
while (true) { \
|
||||
@@ -736,7 +729,7 @@
|
||||
parent->kind.node[0] = leaf; \
|
||||
parent->kind.node[1] = nleaf; \
|
||||
b->root = parent; \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
return; \
|
||||
} \
|
||||
/* Non root node. Get the parent node */ \
|
||||
@@ -747,7 +740,7 @@
|
||||
parent->kind.node[i+1] = nleaf; \
|
||||
/* Test if parent node is full? */ \
|
||||
if (M_LIKELY (parent->num <= N)) { \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
return; /* No need to split parent.*/ \
|
||||
} \
|
||||
M_ASSERT (parent->num == N+1); \
|
||||
@@ -764,8 +757,8 @@
|
||||
nparent->num = nnp; \
|
||||
nparent->next = parent->next; \
|
||||
parent->next = nparent; \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, parent, b->root); \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, nparent, b->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, parent, b->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, nparent, b->root); \
|
||||
/* Prepare for the next step */ \
|
||||
key_ptr = &parent->key[np]; \
|
||||
leaf = parent; \
|
||||
@@ -773,6 +766,29 @@
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline value_t *M_C(name, _safe_get)(tree_t b, key_t const key) \
|
||||
{ \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
/* Not optimized implementation */ \
|
||||
value_t *ret = M_C(name, _get)(b, key); \
|
||||
if (ret == NULL) { \
|
||||
M_IF(isMap)( \
|
||||
value_t v; \
|
||||
M_CALL_INIT(value_oplist, v); \
|
||||
M_C(name, _set_at)(b, key, v); \
|
||||
, \
|
||||
M_C(name, _push)(b, key); \
|
||||
) \
|
||||
ret = M_C(name, _get)(b, key); \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
static inline M_ATTR_DEPRECATED value_t * \
|
||||
M_C(name, _get_at)(tree_t b, key_t const key) \
|
||||
{ \
|
||||
return M_C(name, _safe_get)(b, key); \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
M_C(name, _search_and_remove_in_leaf)(node_t n, key_t const key) \
|
||||
{ \
|
||||
@@ -912,7 +928,7 @@
|
||||
\
|
||||
static inline bool M_C(name, _erase)(tree_t b, key_t const key) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
pit_t pit; \
|
||||
node_t leaf = M_C(name, _search_for_leaf)(pit, b, key); \
|
||||
int k = M_C(name, _search_and_remove_in_leaf)(leaf, key); \
|
||||
@@ -981,7 +997,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_ASSERT (it != NULL); \
|
||||
node_t n = b->root; \
|
||||
/* Scan down the nodes */ \
|
||||
@@ -995,7 +1011,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, const tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_ASSERT (it != NULL); \
|
||||
node_t n = b->root; \
|
||||
/* Scan down the nodes */ \
|
||||
@@ -1032,6 +1048,7 @@
|
||||
M_C(name, _next)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->node != NULL); \
|
||||
M_ASSERT (M_C(name, _is_leaf)(it->node)); \
|
||||
it->idx ++; \
|
||||
if (it->idx >= -it->node->num && it->node->next != NULL) { \
|
||||
it->node = it->node->next; \
|
||||
@@ -1043,6 +1060,7 @@
|
||||
M_C(name, _ref)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->node != NULL); \
|
||||
M_ASSERT (M_C(name, _is_leaf)(it->node)); \
|
||||
M_ASSERT (it->idx <= -it->node->num); \
|
||||
M_IF(isMap)( \
|
||||
it->pair.key_ptr = &it->node->key[it->idx]; \
|
||||
@@ -1063,13 +1081,13 @@
|
||||
static inline void \
|
||||
M_C(name, _it_from)(it_t it, const tree_t b, key_t const key) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_ASSERT (it != NULL); \
|
||||
pit_t pit; \
|
||||
node_t n = M_C(name, _search_for_leaf)(pit, b, key); \
|
||||
it->node = n; \
|
||||
int i; \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
M_BPTR33_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; \
|
||||
@@ -1101,17 +1119,11 @@
|
||||
return (cmp <= 0); \
|
||||
} \
|
||||
\
|
||||
static inline bool M_ATTR_DEPRECATED \
|
||||
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) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_ASSERT (b->size > 0); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
if (M_UNLIKELY (b->size == 0)) return NULL; \
|
||||
node_t n = b->root; \
|
||||
/* Scan down the nodes */ \
|
||||
while (!M_C(name, _is_leaf)(n)) { \
|
||||
@@ -1123,7 +1135,8 @@
|
||||
static inline value_t * \
|
||||
M_C(name, _max)(const tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
if (M_UNLIKELY (b->size == 0)) return NULL; \
|
||||
node_t n = b->root; \
|
||||
/* Scan down the nodes */ \
|
||||
while (!M_C(name, _is_leaf)(n)) { \
|
||||
@@ -1147,47 +1160,47 @@
|
||||
static inline void \
|
||||
M_C(name, _init_move)(tree_t b, tree_t ref) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, ref); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, ref); \
|
||||
M_ASSERT (b != NULL && b != ref); \
|
||||
b->size = ref->size; \
|
||||
b->root = ref->root; \
|
||||
ref->root = NULL; \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(tree_t b, tree_t ref) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, ref); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, ref); \
|
||||
M_ASSERT (b != ref); \
|
||||
M_C(name,_clear)(b); \
|
||||
M_C(name,_init_move)(b, ref); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
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_BPTR33_CONTRACT(N, isMulti, key_oplist, tree1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, tree2); \
|
||||
M_SWAP(size_t, tree1->size, tree2->size); \
|
||||
M_SWAP(node_t, tree1->root, tree2->root); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, tree1); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, tree2); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, tree1); \
|
||||
M_BPTR33_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, subtype_t)
|
||||
M_BPTR33_FUNC_ADDITIONAL_DEF2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t)
|
||||
|
||||
|
||||
/* Define additional functions.
|
||||
Do not used any fields but the already defined methods */
|
||||
#define BPTREEI_FUNC_ADDITIONAL_DEF2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
#define M_BPTR33_FUNC_ADDITIONAL_DEF2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
\
|
||||
M_IF_METHOD_BOTH(EQUAL, key_oplist, value_oplist)( \
|
||||
static inline bool M_C(name,_equal_p)(const tree_t t1, const tree_t t2) { \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t2); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t2); \
|
||||
if (t1->size != t2->size) return false; \
|
||||
if (t1->size == 0) return true; \
|
||||
/* Slow comparaison */ \
|
||||
@@ -1222,7 +1235,7 @@
|
||||
\
|
||||
M_IF_METHOD_BOTH(HASH, key_oplist, value_oplist)( \
|
||||
static inline size_t M_C(name,_hash)(const tree_t t1) { \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_HASH_DECL(hash); \
|
||||
/* NOTE: We can't compute the hash directly for the same reason \
|
||||
than for EQUAL operator. */ \
|
||||
@@ -1245,7 +1258,7 @@
|
||||
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
const tree_t t1, bool append) { \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT(str != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
/* NOTE: The print is really naive, and not really efficient */ \
|
||||
@@ -1274,7 +1287,7 @@
|
||||
static inline void \
|
||||
M_C(name, _out_str)(FILE *file, tree_t const t1) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT (file != NULL); \
|
||||
fputc ('[', file); \
|
||||
bool commaToPrint = false; \
|
||||
@@ -1302,9 +1315,9 @@
|
||||
static inline bool \
|
||||
M_C(name, _parse_str)(tree_t t1, const char str[], const char **endp) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT (str != NULL); \
|
||||
M_C(name,_clean)(t1); \
|
||||
M_C(name,_reset)(t1); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
@@ -1344,9 +1357,9 @@
|
||||
static inline bool \
|
||||
M_C(name, _in_str)(tree_t t1, FILE *file) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT (file != NULL); \
|
||||
M_C(name,_clean)(t1); \
|
||||
M_C(name,_reset)(t1); \
|
||||
int c = fgetc(file); \
|
||||
if (M_UNLIKELY (c != '[')) return false; \
|
||||
c = fgetc(file); \
|
||||
@@ -1382,7 +1395,7 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, tree_t const t1) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_return_code_t ret; \
|
||||
m_serial_local_t local; \
|
||||
@@ -1426,13 +1439,13 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(tree_t t1, m_serial_read_t f) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
size_t estimated_size = 0; \
|
||||
key_t key; \
|
||||
M_C(name,_clean)(t1); \
|
||||
M_C(name,_reset)(t1); \
|
||||
M_IF(isMap)( \
|
||||
value_t value; \
|
||||
ret = f->m_interface->read_map_start(local, f, &estimated_size); \
|
||||
|
||||
+357
-249
File diff suppressed because it is too large.
Load diff
+31
-31
@@ -32,19 +32,19 @@
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Minimum number of nodes per group of nodes */
|
||||
#define C_MEMPOOL_MIN_NODE_PER_GROUP 16
|
||||
#define M_CMEMP00L_MIN_NODE_PER_GROUP 16
|
||||
|
||||
#define C_MEMPOOL_DEF(name, type_t) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
C_MEMPOOL_DEF_SINGLY_LIST(name, type_t) \
|
||||
C_MEMPOOL_DEF_LF_QUEUE(name, type_t) \
|
||||
C_MEMPOOL_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
|
||||
C_MEMPOOL_DEF_SYSTEM_ALLOC(name, type_t) \
|
||||
C_MEMPOOL_DEF_LF_MEMPOOL(name, type_t) \
|
||||
M_CMEMP00L_DEF_SINGLY_LIST(name, type_t) \
|
||||
M_CMEMP00L_DEF_LF_QUEUE(name, type_t) \
|
||||
M_CMEMP00L_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
|
||||
M_CMEMP00L_DEF_SYSTEM_ALLOC(name, type_t) \
|
||||
M_CMEMP00L_DEF_LF_MEMPOOL(name, type_t) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
/* Classic internal Singly List without allocation */
|
||||
#define C_MEMPOOL_DEF_SINGLY_LIST(name, type_t) \
|
||||
#define M_CMEMP00L_DEF_SINGLY_LIST(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _slist_node_s) { \
|
||||
struct M_C(name, _slist_node_s) *next; \
|
||||
@@ -123,7 +123,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
*/
|
||||
/* TODO: Optimize alignement to reduce memory consumption. NIL object can use []
|
||||
to reduce memory consumption too (non compatible with C++ ...) */
|
||||
#define C_MEMPOOL_DEF_LF_QUEUE(name, type_t) \
|
||||
#define M_CMEMP00L_DEF_LF_QUEUE(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _lf_node_s) { \
|
||||
M_ATTR_EXTENSION _Atomic(struct M_C(name, _lf_node_s) *) next; \
|
||||
@@ -304,7 +304,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* System node allocator: request memory to the system.
|
||||
As such it is a non Lock-Free path. */
|
||||
#define C_MEMPOOL_DEF_SYSTEM_ALLOC(name, type_t) \
|
||||
#define M_CMEMP00L_DEF_SYSTEM_ALLOC(name, type_t) \
|
||||
\
|
||||
static inline M_C(name, _lf_node_t) * \
|
||||
M_C(name, _alloc_node)(unsigned int initial) \
|
||||
@@ -386,7 +386,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
As such it won't support more than ULONG_MAX sleep for all threads.
|
||||
*/
|
||||
#define C_MEMPOOL_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
|
||||
#define M_CMEMP00L_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _lfmp_thread_s) { \
|
||||
M_C(name, _slist_ct) free; \
|
||||
@@ -410,7 +410,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
|
||||
/* NOTE: once a node is deleted, its data are kept readable until the future GC */
|
||||
#define C_MEMPOOL_DEF_LF_MEMPOOL(name, type_t) \
|
||||
#define M_CMEMP00L_DEF_LF_MEMPOOL(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
unsigned initial; \
|
||||
@@ -418,18 +418,18 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_C(name, _lflist_ct) free; \
|
||||
M_C(name, _lflist_ct) to_be_reclaimed; \
|
||||
M_C(name, _lflist_ct) empty; \
|
||||
m_gc_mempool_list_ct mempool_node; \
|
||||
m_gM_CMEMP00L_list_ct mempool_node; \
|
||||
struct m_gc_s *gc_mem; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
/* Garbage collect of the nodes of the mempool on sleep */ \
|
||||
static inline void \
|
||||
M_C(name, _int_gc_on_sleep)(m_gc_t gc_mem, m_gc_mempool_list_ct *data, \
|
||||
M_C3(m_cmemp00l_,name,_gc_on_sleep)(m_gc_t gc_mem, m_gM_CMEMP00L_list_ct *data, \
|
||||
m_gc_tid_t id, m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket) \
|
||||
{ \
|
||||
/* Get back the mempool from the node */ \
|
||||
struct M_C(name, _s) *mempool = \
|
||||
M_TYPE_FROM_FIELD(struct M_C(name, _s), data, m_gc_mempool_list_ct, mempool_node); \
|
||||
M_TYPE_FROM_FIELD(struct M_C(name, _s), data, m_gM_CMEMP00L_list_ct, mempool_node); \
|
||||
\
|
||||
/* Move the local nodes of the mempool to be reclaimed to the thread into the global pool */ \
|
||||
if (!M_C(name, _slist_empty_p)(mempool->thread_data[id].to_be_reclaimed)) { \
|
||||
@@ -473,7 +473,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_C(name, _lfmp_thread_init)(&mem->thread_data[i]); \
|
||||
} \
|
||||
/* Preallocate some group of nodes for the mempool */ \
|
||||
mem->initial = M_MAX(C_MEMPOOL_MIN_NODE_PER_GROUP, init_node_count); \
|
||||
mem->initial = M_MAX(M_CMEMP00L_MIN_NODE_PER_GROUP, init_node_count); \
|
||||
M_C(name, _lflist_init)(mem->free, M_C(name, _alloc_node)(init_node_count)); \
|
||||
M_C(name, _lflist_init)(mem->to_be_reclaimed, M_C(name, _alloc_node)(init_node_count)); \
|
||||
M_C(name, _lflist_init)(mem->empty, M_C(name, _alloc_node)(0)); \
|
||||
@@ -484,7 +484,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
gc_mem->thread_data[0].bkoff); \
|
||||
} \
|
||||
/* Register the mempool in the GC */ \
|
||||
mem->mempool_node.gc_on_sleep = M_C(name, _int_gc_on_sleep); \
|
||||
mem->mempool_node.gc_on_sleep = M_C3(m_cmemp00l_,name,_gc_on_sleep); \
|
||||
mem->mempool_node.next = gc_mem->mempool_list; \
|
||||
gc_mem->mempool_list = &mem->mempool_node; \
|
||||
mem->gc_mem = gc_mem; \
|
||||
@@ -555,13 +555,13 @@ typedef atomic_ulong m_gc_atomic_ticket_ct;
|
||||
|
||||
/* Define the Linked List of mempools that are registered in the GC */
|
||||
struct m_gc_s;
|
||||
typedef struct m_gc_mempool_list_s {
|
||||
struct m_gc_mempool_list_s *next;
|
||||
typedef struct m_gM_CMEMP00L_list_s {
|
||||
struct m_gM_CMEMP00L_list_s *next;
|
||||
void (*gc_on_sleep)(struct m_gc_s *gc_mem,
|
||||
struct m_gc_mempool_list_s *data, m_gc_tid_t id,
|
||||
struct m_gM_CMEMP00L_list_s *data, m_gc_tid_t id,
|
||||
m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket);
|
||||
void *data;
|
||||
} m_gc_mempool_list_ct;
|
||||
} m_gM_CMEMP00L_list_ct;
|
||||
|
||||
/* Define the Garbage collector thread data */
|
||||
typedef struct m_gc_lfmp_thread_s {
|
||||
@@ -576,7 +576,7 @@ typedef struct m_gc_s {
|
||||
m_gc_tid_t max_thread;
|
||||
genint_t thread_alloc;
|
||||
m_gc_lfmp_thread_ct *thread_data;
|
||||
m_gc_mempool_list_ct *mempool_list;
|
||||
m_gM_CMEMP00L_list_ct *mempool_list;
|
||||
} m_gc_t[1];
|
||||
|
||||
static inline void
|
||||
@@ -644,7 +644,7 @@ m_gc_awake(m_gc_t gc_mem, m_gc_tid_t id)
|
||||
}
|
||||
|
||||
static inline m_gc_ticket_ct
|
||||
m_gc_int_min_ticket(m_gc_t gc_mem)
|
||||
m_cmemp00l_gc_min_ticket(m_gc_t gc_mem)
|
||||
{
|
||||
m_gc_ticket_ct min = atomic_load(&gc_mem->thread_data[0].ticket);
|
||||
for(m_gc_tid_t i = 1; i < gc_mem->max_thread; i++) {
|
||||
@@ -660,9 +660,9 @@ m_gc_sleep(m_gc_t gc_mem, m_gc_tid_t id)
|
||||
/* Increase life time of the thread */
|
||||
m_gc_ticket_ct t = atomic_fetch_add(&gc_mem->ticket, 1UL);
|
||||
atomic_store(&gc_mem->thread_data[id].ticket, t+1);
|
||||
const m_gc_ticket_ct min_ticket = m_gc_int_min_ticket(gc_mem);
|
||||
const m_gc_ticket_ct min_ticket = m_cmemp00l_gc_min_ticket(gc_mem);
|
||||
/* Iterate over all registered mempools */
|
||||
m_gc_mempool_list_ct *it = gc_mem->mempool_list;
|
||||
m_gM_CMEMP00L_list_ct *it = gc_mem->mempool_list;
|
||||
|
||||
while (it) {
|
||||
/* Perform a garbage collect of the mempool */
|
||||
@@ -681,9 +681,9 @@ m_gc_sleep(m_gc_t gc_mem, m_gc_tid_t id)
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
|
||||
C_MEMPOOL_DEF_SINGLY_LIST(m_vlapool, char)
|
||||
C_MEMPOOL_DEF_LF_QUEUE(m_vlapool, char)
|
||||
C_MEMPOOL_DEF_SYSTEM_ALLOC(m_vlapool, char)
|
||||
M_CMEMP00L_DEF_SINGLY_LIST(m_vlapool, char)
|
||||
M_CMEMP00L_DEF_LF_QUEUE(m_vlapool, char)
|
||||
M_CMEMP00L_DEF_SYSTEM_ALLOC(m_vlapool, char)
|
||||
|
||||
typedef struct m_vlapool_lfmp_thread_s {
|
||||
m_vlapool_slist_ct to_be_reclaimed;
|
||||
@@ -707,18 +707,18 @@ typedef struct m_vlapool_s {
|
||||
m_vlapool_lflist_ct to_be_reclaimed;
|
||||
m_vlapool_lflist_ct empty;
|
||||
m_vlapool_lfmp_thread_ct *thread_data;
|
||||
m_gc_mempool_list_ct mvla_node;
|
||||
m_gM_CMEMP00L_list_ct mvla_node;
|
||||
struct m_gc_s *gc_mem;
|
||||
} m_vlapool_t[1];
|
||||
|
||||
/* Garbage collect of the nodes of the vla mempool on sleep */
|
||||
static inline void
|
||||
m_vlapool_int_gc_on_sleep(m_gc_t gc_mem, m_gc_mempool_list_ct *data,
|
||||
m_cmemp00l_vlapool_on_sleep(m_gc_t gc_mem, m_gM_CMEMP00L_list_ct *data,
|
||||
m_gc_tid_t id, m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket)
|
||||
{
|
||||
/* Get back the mempool from the node */
|
||||
struct m_vlapool_s *vlapool =
|
||||
M_TYPE_FROM_FIELD(struct m_vlapool_s, data, m_gc_mempool_list_ct, mvla_node);
|
||||
M_TYPE_FROM_FIELD(struct m_vlapool_s, data, m_gM_CMEMP00L_list_ct, mvla_node);
|
||||
|
||||
/* Move the local nodes of the vlapool to be reclaimed to the thread into the global pool */
|
||||
if (!m_vlapool_slist_empty_p(vlapool->thread_data[id].to_be_reclaimed)) {
|
||||
@@ -771,7 +771,7 @@ m_vlapool_init(m_vlapool_t mem, m_gc_t gc_mem)
|
||||
m_vlapool_lflist_init(mem->empty, m_vlapool_alloc_node(0));
|
||||
|
||||
/* Register the mempool in the GC */
|
||||
mem->mvla_node.gc_on_sleep = m_vlapool_int_gc_on_sleep;
|
||||
mem->mvla_node.gc_on_sleep = m_cmemp00l_vlapool_on_sleep;
|
||||
mem->mvla_node.next = gc_mem->mempool_list;
|
||||
gc_mem->mempool_list = &mem->mvla_node;
|
||||
mem->gc_mem = gc_mem;
|
||||
|
||||
+104
-101
@@ -33,11 +33,7 @@
|
||||
based on the given container.
|
||||
USAGE: CONCURRENT_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define CONCURRENT_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
CONCURRENTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
CONCURRENT_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a protected concurrent container and its associated functions
|
||||
@@ -45,30 +41,18 @@
|
||||
USAGE: CONCURRENT_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
|
||||
#define CONCURRENT_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
CONCURRENTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_C0NCURRENT_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__, name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the oplist of a protected concurrent container given its name and its oplist.
|
||||
USAGE: CONCURRENT_OPLIST(name[, oplist of the type]) */
|
||||
#define CONCURRENT_OPLIST(...) \
|
||||
CONCURRENTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define a protected concurrent container and its associated functions
|
||||
based on its given container. Operations that perform only read of the container
|
||||
can be done in parallel.
|
||||
USAGE: CONCURRENT_RP_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define CONCURRENT_RP_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
CONCURRENTI_RP_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
CONCURRENT_RP_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a protected concurrent container and its associated functions
|
||||
@@ -78,24 +62,32 @@
|
||||
USAGE: CONCURRENT_RP_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
|
||||
#define CONCURRENT_RP_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
CONCURRENTI_RP_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_C0NCURRENT_RP_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__, name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the oplist of a protected concurrent container given its name and its oplist.
|
||||
USAGE: CONCURRENT_OPLIST(name[, oplist of the type]) */
|
||||
#define CONCURRENT_OPLIST(...) \
|
||||
M_C0NCURRENT_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Deferred evaluation for the oplist definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define CONCURRENTI_OPLIST_P1(arg) CONCURRENTI_OPLIST_P2 arg
|
||||
#define M_C0NCURRENT_OPLIST_P1(arg) M_C0NCURRENT_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)
|
||||
#define M_C0NCURRENT_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_C0NCURRENT_OPLIST_P3, M_C0NCURRENT_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define CONCURRENTI_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_C0NCURRENT_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_CONCURRENT_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
/* OPLIST definition
|
||||
@@ -103,7 +95,7 @@
|
||||
container (_get returns a pointer to an internal data, data that may be
|
||||
destroyed by another thread).
|
||||
*/
|
||||
#define CONCURRENTI_OPLIST_P3(name, oplist) \
|
||||
#define M_C0NCURRENT_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)),) \
|
||||
@@ -111,12 +103,13 @@
|
||||
,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(M_C(name, _init_move)),) \
|
||||
,M_IF_METHOD(MOVE, oplist)(MOVE(M_C(name, _move)),) \
|
||||
,M_IF_METHOD(SWAP,oplist)(SWAP(M_C(name, _swap)),) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_C(name,_ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,OPLIST(oplist) \
|
||||
,M_IF_METHOD(EMPTY_P, oplist)(EMPTY_P(M_C(name,_empty_p)),) \
|
||||
,M_IF_METHOD(GET_SIZE, oplist)(GET_SIZE(M_C(name,_size)),) \
|
||||
,M_IF_METHOD(CLEAN, oplist)(CLEAN(M_C(name,_clean)),) \
|
||||
,M_IF_METHOD(RESET, oplist)(RESET(M_C(name,_reset)),) \
|
||||
,M_IF_METHOD(KEY_TYPE, oplist)(KEY_TYPE(M_GET_KEY_TYPE oplist),) \
|
||||
,M_IF_METHOD(VALUE_TYPE, oplist)(VALUE_TYPE(M_GET_VALUE_TYPE oplist),) \
|
||||
,M_IF_METHOD(KEY_TYPE, oplist)(KEY_OPLIST(M_GET_KEY_OPLIST oplist),) \
|
||||
@@ -143,21 +136,21 @@
|
||||
/* Internal contract
|
||||
NOTE: Can't check too much without locking the container itself
|
||||
*/
|
||||
#define CONCURRENTI_CONTRACT(c) do { \
|
||||
#define M_C0NCURRENT_CONTRACT(c) do { \
|
||||
M_ASSERT ((c) != NULL); \
|
||||
M_ASSERT ( (c)->self == (c)); \
|
||||
} while (0)
|
||||
|
||||
/* Deferred evaluation for the concurrent definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define CONCURRENTI_DEF_P1(arg) CONCURRENTI_DEF_P2 arg
|
||||
#define M_C0NCURRENT_DEF_P1(arg) M_C0NCURRENT_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)
|
||||
#define M_C0NCURRENT_DEF_P2(name, type, oplist, concurrent_t) \
|
||||
M_IF_OPLIST(oplist)(M_C0NCURRENT_DEF_P3, M_C0NCURRENT_DEF_FAILURE)(name, type, oplist, concurrent_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define CONCURRENTI_DEF_FAILURE(name, type, oplist, concurrent_t) \
|
||||
#define M_C0NCURRENT_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
|
||||
@@ -166,7 +159,7 @@
|
||||
- oplist: oplist of the type of the sub container
|
||||
- concurrent_t: alias for M_C(name, _t) [ type of the container ]
|
||||
*/
|
||||
#define CONCURRENTI_DEF_P3(name, type, oplist, concurrent_t) \
|
||||
#define M_C0NCURRENT_DEF_P3(name, type, oplist, concurrent_t) \
|
||||
\
|
||||
/* Define a concurrent container using a lock */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
@@ -197,7 +190,7 @@
|
||||
m_mutex_init(out->lock); \
|
||||
m_cond_init(out->there_is_data); \
|
||||
out->self = out; \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
\
|
||||
/* Clear the fields of the concurrent object not associated to the \
|
||||
@@ -205,7 +198,7 @@
|
||||
static inline void \
|
||||
M_C(name, _internal_clear)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_clear(out->lock); \
|
||||
m_cond_clear(out->there_is_data); \
|
||||
out->self = NULL; \
|
||||
@@ -218,7 +211,7 @@
|
||||
static inline void \
|
||||
M_C(name, _read_lock)(const concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->self->lock); \
|
||||
} \
|
||||
\
|
||||
@@ -228,7 +221,7 @@
|
||||
static inline void \
|
||||
M_C(name, _read_unlock)(const concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_unlock (out->self->lock); \
|
||||
} \
|
||||
\
|
||||
@@ -237,7 +230,7 @@
|
||||
static inline void \
|
||||
M_C(name, _read_wait)(const concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_cond_wait(out->self->there_is_data, out->self->lock); \
|
||||
} \
|
||||
\
|
||||
@@ -248,7 +241,7 @@
|
||||
static inline void \
|
||||
M_C(name, _write_lock)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->lock); \
|
||||
} \
|
||||
\
|
||||
@@ -258,7 +251,7 @@
|
||||
static inline void \
|
||||
M_C(name, _write_unlock)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_unlock (out->lock); \
|
||||
} \
|
||||
\
|
||||
@@ -267,7 +260,7 @@
|
||||
static inline void \
|
||||
M_C(name, _write_wait)(const concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_cond_wait(out->self->there_is_data, out->self->lock); \
|
||||
} \
|
||||
\
|
||||
@@ -276,13 +269,13 @@
|
||||
static inline void \
|
||||
M_C(name, _write_signal)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
/* We need to signal this to ALL waiting threads as multiple threads \
|
||||
may wait on a some data of this container. */ \
|
||||
m_cond_broadcast(out->there_is_data); \
|
||||
} \
|
||||
\
|
||||
CONCURRENTI_DEF_FUNC_P3(name, type, oplist, concurrent_t)
|
||||
M_C0NCURRENT_DEF_FUNC_P3(name, type, oplist, concurrent_t)
|
||||
|
||||
|
||||
/* Internal definition of the functions commons to concurrent and rp-concurrent
|
||||
@@ -293,7 +286,7 @@
|
||||
A function is defined only if the underlying container exports the needed
|
||||
services. It is usually one service declared per service exported.
|
||||
*/
|
||||
#define CONCURRENTI_DEF_FUNC_P3(name, type, oplist, concurrent_t) \
|
||||
#define M_C0NCURRENT_DEF_FUNC_P3(name, type, oplist, concurrent_t) \
|
||||
\
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
static inline void \
|
||||
@@ -301,7 +294,7 @@
|
||||
{ \
|
||||
M_C(name, _internal_init)(out); \
|
||||
M_CALL_INIT(oplist, out->data); \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
@@ -309,13 +302,13 @@
|
||||
static inline void \
|
||||
M_C(name, _init_set)(concurrent_t out, concurrent_t const src) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(src); \
|
||||
M_C0NCURRENT_CONTRACT(src); \
|
||||
M_ASSERT (out != src); \
|
||||
M_C(name, _internal_init)(out); \
|
||||
M_C(name, _read_lock)(src); \
|
||||
M_CALL_INIT_SET(oplist, out->data, src->data); \
|
||||
M_C(name, _read_unlock)(src); \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
@@ -323,7 +316,7 @@
|
||||
static inline void \
|
||||
M_C(name, _set)(concurrent_t out, concurrent_t const src) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
if (M_UNLIKELY (out == src)) return; \
|
||||
/* Need to order the locks in a total way to avoid lock deadlock. \
|
||||
Indeed, two call to _set can be done in two threads with : \
|
||||
@@ -350,7 +343,7 @@
|
||||
M_C(name, _write_unlock)(out); \
|
||||
M_C(name, _read_unlock)(src); \
|
||||
} \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
@@ -358,7 +351,7 @@
|
||||
static inline void \
|
||||
M_C(name, _clear)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
/* No need to lock. A clear is supposed to be called when all operations \
|
||||
of the container in other threads are terminated */ \
|
||||
M_CALL_CLEAR(oplist, out->data); \
|
||||
@@ -370,13 +363,13 @@
|
||||
static inline void \
|
||||
M_C(name, _init_move)(concurrent_t out, concurrent_t src) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(src); \
|
||||
M_C0NCURRENT_CONTRACT(src); \
|
||||
M_ASSERT (out != src); \
|
||||
/* No need to lock 'src' ? */ \
|
||||
M_C(name, _internal_init)(out); \
|
||||
M_CALL_INIT_MOVE(oplist, out->data, src->data); \
|
||||
M_C(name, _internal_clear)(src); \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
@@ -384,14 +377,14 @@
|
||||
static inline void \
|
||||
M_C(name, _move)(concurrent_t out, concurrent_t src) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
CONCURRENTI_CONTRACT(src); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(src); \
|
||||
/* No need to lock 'src' ? */ \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_MOVE(oplist, out->data, src->data); \
|
||||
M_C(name, _write_unlock)(out); \
|
||||
M_C(name, _internal_clear)(src); \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
@@ -399,8 +392,8 @@
|
||||
static inline void \
|
||||
M_C(name, _swap)(concurrent_t out, concurrent_t src) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
CONCURRENTI_CONTRACT(src); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(src); \
|
||||
if (M_UNLIKELY (out == src)) return; \
|
||||
/* See comment above */ \
|
||||
if (out < src) { \
|
||||
@@ -421,14 +414,19 @@
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
M_IF_METHOD(CLEAN, oplist)( \
|
||||
M_IF_METHOD(RESET, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _reset)(concurrent_t out) \
|
||||
{ \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_RESET(oplist, out->data); \
|
||||
M_C(name, _write_unlock)(out); \
|
||||
} \
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_CLEAN(oplist, out->data); \
|
||||
M_C(name, _write_unlock)(out); \
|
||||
M_C(name,_reset)(out); \
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
@@ -436,7 +434,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(concurrent_t const out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
bool b = M_CALL_EMPTY_P(oplist, out->data); \
|
||||
M_C(name, _read_unlock)(out); \
|
||||
@@ -448,7 +446,7 @@
|
||||
static inline size_t \
|
||||
M_C(name, _size)(concurrent_t const out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
size_t r = M_CALL_GET_SIZE(oplist, out->data); \
|
||||
M_C(name, _read_unlock)(out); \
|
||||
@@ -460,7 +458,7 @@
|
||||
static inline void \
|
||||
M_C(name, _set_at)(concurrent_t out, M_GET_KEY_TYPE oplist const key, M_GET_VALUE_TYPE oplist const data) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_SET_KEY(oplist, out->data, key, data); \
|
||||
M_C(name, _write_signal)(out); \
|
||||
@@ -472,7 +470,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _get_copy)(M_GET_VALUE_TYPE oplist *out_data, const concurrent_t out, M_GET_KEY_TYPE oplist const key) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_ASSERT (out_data != NULL); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
M_GET_VALUE_TYPE oplist *p = M_CALL_GET_KEY(oplist, out->data, key); \
|
||||
@@ -484,25 +482,30 @@
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
M_IF_METHOD(GET_SET_KEY, oplist)( \
|
||||
M_IF_METHOD(SAFE_GET_KEY, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_at_copy)(M_GET_VALUE_TYPE oplist *out_data, concurrent_t out, M_GET_KEY_TYPE oplist const key) \
|
||||
M_C(name, _safe_get_copy)(M_GET_VALUE_TYPE oplist *out_data, concurrent_t out, M_GET_KEY_TYPE oplist const key) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_ASSERT (out_data != NULL); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_GET_VALUE_TYPE oplist *p = M_CALL_GET_SET_KEY(oplist, out->data, key); \
|
||||
M_GET_VALUE_TYPE oplist *p = M_CALL_SAFE_GET_KEY(oplist, out->data, key); \
|
||||
M_ASSERT (p != NULL); \
|
||||
M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \
|
||||
M_C(name, _write_unlock)(out); \
|
||||
} \
|
||||
static inline M_ATTR_DEPRECATED void \
|
||||
M_C(name, _get_at_copy)(M_GET_VALUE_TYPE oplist *out_data, concurrent_t out, M_GET_KEY_TYPE oplist const key) \
|
||||
{ \
|
||||
M_C(name, _safe_get_copy)(out_data, out, key); \
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
M_IF_METHOD(ERASE_KEY, oplist)( \
|
||||
static inline bool \
|
||||
M_C(name, _erase)(concurrent_t out, M_GET_KEY_TYPE oplist const key) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
bool b = M_CALL_ERASE_KEY(oplist, out->data, key); \
|
||||
/* We suppose that the container has 'infinite' capacity, so \
|
||||
@@ -516,7 +519,7 @@
|
||||
static inline void \
|
||||
M_C(name, _push)(concurrent_t out, M_GET_SUBTYPE oplist const data) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_PUSH(oplist, out->data, data); \
|
||||
M_C(name, _write_signal)(out); \
|
||||
@@ -528,7 +531,7 @@
|
||||
static inline void \
|
||||
M_C(name, _pop)(M_GET_SUBTYPE oplist *p, concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_POP(oplist, p, out->data); \
|
||||
/* See comment above */ \
|
||||
@@ -540,7 +543,7 @@
|
||||
static inline void \
|
||||
M_C(name, _push_move)(concurrent_t out, M_GET_SUBTYPE oplist *data) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_PUSH_MOVE(oplist, out->data, data); \
|
||||
M_C(name, _write_signal)(out); \
|
||||
@@ -552,7 +555,7 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_move)(M_GET_SUBTYPE oplist *p, concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_POP_MOVE(oplist, p, out->data); \
|
||||
/* See comment above */ \
|
||||
@@ -564,7 +567,7 @@
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, concurrent_t const out, bool a) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
M_CALL_GET_STR(oplist, str, out->data, a); \
|
||||
M_C(name, _read_unlock)(out); \
|
||||
@@ -575,7 +578,7 @@
|
||||
static inline void \
|
||||
M_C(name, _out_str)(FILE *f, concurrent_t const out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
M_CALL_OUT_STR(oplist, f, out->data); \
|
||||
M_C(name, _read_unlock)(out); \
|
||||
@@ -586,7 +589,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _parse_str)(concurrent_t out, const char str[], const char **e) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
bool b = M_CALL_PARSE_STR(oplist, out->data, str, e); \
|
||||
M_C(name, _write_signal)(out); \
|
||||
@@ -599,7 +602,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _in_str)(concurrent_t out, FILE *f) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
bool b = M_CALL_IN_STR(oplist, out->data, f); \
|
||||
M_C(name, _write_signal)(out); \
|
||||
@@ -612,7 +615,7 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, concurrent_t const out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
m_serial_return_code_t r = M_CALL_OUT_SERIAL(oplist, f, out->data); \
|
||||
M_C(name, _read_unlock)(out); \
|
||||
@@ -624,7 +627,7 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(concurrent_t out, m_serial_read_t f) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
m_serial_return_code_t r = M_CALL_IN_SERIAL(oplist, out->data, f); \
|
||||
M_C(name, _write_signal)(out); \
|
||||
@@ -637,8 +640,8 @@
|
||||
static inline bool \
|
||||
M_C(name, _equal_p)(concurrent_t const out1, concurrent_t const out2) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out1); \
|
||||
CONCURRENTI_CONTRACT(out2); \
|
||||
M_C0NCURRENT_CONTRACT(out1); \
|
||||
M_C0NCURRENT_CONTRACT(out2); \
|
||||
if (M_UNLIKELY (out1 == out2)) return true; \
|
||||
/* See comment above on mutal mutexs */ \
|
||||
if (out1 < out2) { \
|
||||
@@ -664,7 +667,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _get_blocking)(M_GET_VALUE_TYPE oplist *out_data, const concurrent_t out, M_GET_KEY_TYPE oplist const key, bool blocking) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_ASSERT (out_data != NULL); \
|
||||
bool ret = false; \
|
||||
M_C(name, _read_lock)(out); \
|
||||
@@ -688,7 +691,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _pop_blocking)(M_GET_SUBTYPE oplist *p, concurrent_t out, bool blocking) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_ASSERT (p != NULL); \
|
||||
bool ret = false; \
|
||||
M_C(name, _write_lock)(out); \
|
||||
@@ -711,7 +714,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _pop_move_blocking)(M_GET_SUBTYPE oplist *p, concurrent_t out, bool blocking) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_ASSERT (p != NULL); \
|
||||
bool ret = false; \
|
||||
M_C(name, _write_lock)(out); \
|
||||
@@ -734,7 +737,7 @@
|
||||
static inline size_t \
|
||||
M_C(name, _hash)(concurrent_t const out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
size_t h = M_CALL_HASH(oplist, out->data); \
|
||||
M_C(name, _read_unlock)(out); \
|
||||
@@ -747,14 +750,14 @@
|
||||
|
||||
/* Deferred evaluation for the RP concurrent definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define CONCURRENTI_RP_DEF_P1(arg) CONCURRENTI_RP_DEF_P2 arg
|
||||
#define M_C0NCURRENT_RP_DEF_P1(arg) M_C0NCURRENT_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)
|
||||
#define M_C0NCURRENT_RP_DEF_P2(name, type, oplist, concurrent_t) \
|
||||
M_IF_OPLIST(oplist)(M_C0NCURRENT_RP_DEF_P3, M_C0NCURRENT_RP_DEF_FAILURE)(name, type, oplist, concurrent_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define CONCURRENTI_RP_DEF_FAILURE(name, type, oplist, concurrent_t) \
|
||||
#define M_C0NCURRENT_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
|
||||
@@ -763,7 +766,7 @@
|
||||
- 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_P3(name, type, oplist, concurrent_t) \
|
||||
#define M_C0NCURRENT_RP_DEF_P3(name, type, oplist, concurrent_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
struct M_C(name, _s) *self; \
|
||||
@@ -790,13 +793,13 @@
|
||||
out->self = out; \
|
||||
out->read_count = 0; \
|
||||
out->writer_waiting = false; \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _internal_clear)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_clear(out->lock); \
|
||||
m_cond_clear(out->rw_done); \
|
||||
m_cond_clear(out->there_is_data); \
|
||||
@@ -806,7 +809,7 @@
|
||||
static inline void \
|
||||
M_C(name, _read_lock)(const concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
struct M_C(name, _s) *self = out->self; \
|
||||
m_mutex_lock (self->lock); \
|
||||
while (self->writer_waiting == true) { \
|
||||
@@ -819,7 +822,7 @@
|
||||
static inline void \
|
||||
M_C(name, _read_unlock)(const concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
struct M_C(name, _s) *self = out->self; \
|
||||
m_mutex_lock (self->lock); \
|
||||
self->read_count --; \
|
||||
@@ -832,7 +835,7 @@
|
||||
static inline void \
|
||||
M_C(name, _write_lock)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->lock); \
|
||||
while (out->writer_waiting == true) { \
|
||||
m_cond_wait(out->rw_done, out->lock); \
|
||||
@@ -847,7 +850,7 @@
|
||||
static inline void \
|
||||
M_C(name, _write_unlock)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->lock); \
|
||||
out->writer_waiting = false; \
|
||||
m_cond_broadcast (out->rw_done); \
|
||||
@@ -857,7 +860,7 @@
|
||||
static inline void \
|
||||
M_C(name, _read_wait)(const concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
struct M_C(name, _s) *self = out->self; \
|
||||
M_ASSERT (self == out); \
|
||||
m_mutex_lock (out->self->lock); \
|
||||
@@ -876,7 +879,7 @@
|
||||
static inline void \
|
||||
M_C(name, _write_wait)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->lock); \
|
||||
out->writer_waiting = false; \
|
||||
m_cond_broadcast (out->rw_done); \
|
||||
@@ -894,13 +897,13 @@
|
||||
static inline void \
|
||||
M_C(name, _write_signal)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->lock); \
|
||||
m_cond_broadcast(out->there_is_data); \
|
||||
m_mutex_unlock (out->lock); \
|
||||
} \
|
||||
\
|
||||
CONCURRENTI_DEF_FUNC_P3(name, type, oplist, concurrent_t)
|
||||
M_C0NCURRENT_DEF_FUNC_P3(name, type, oplist, concurrent_t)
|
||||
|
||||
|
||||
#endif
|
||||
@@ -30,11 +30,7 @@
|
||||
/* Define a deque of a given type and its associated functions.
|
||||
USAGE: DEQUE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define DEQUE_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
DEQUEI_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), M_C(name, _node_ct) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t), M_C(name, _node_ct)))) \
|
||||
M_END_PROTECTED_CODE
|
||||
DEQUE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a deque of a given type and its associated functions.
|
||||
@@ -42,7 +38,7 @@
|
||||
USAGE: DEQUE_DEF(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define DEQUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
DEQUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_D3QU3_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t, M_C(name, _node_ct) ), \
|
||||
(name, __VA_ARGS__, name_t, it_t, M_C(name, _node_ct)))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -51,21 +47,21 @@
|
||||
/* Define the oplist of a deque of a type.
|
||||
USAGE: DEQUE_OPLIST(name[, oplist of the type]) */
|
||||
#define DEQUE_OPLIST(...) \
|
||||
DEQUEI_OPLIST_P1 (M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_D3QU3_OPLIST_P1 (M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Default initial size of a bucket of items */
|
||||
#ifndef DEQUEUI_DEFAULT_SIZE
|
||||
#define DEQUEUI_DEFAULT_SIZE 8
|
||||
#ifndef M_USE_DEQUE_DEFAULT_SIZE
|
||||
#define M_USE_DEQUE_DEFAULT_SIZE 8
|
||||
#endif
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Define the internal contract of a deque */
|
||||
#define DEQUEI_CONTRACT(d) do { \
|
||||
#define M_D3QU3_CONTRACT(d) do { \
|
||||
M_ASSERT ((d) != NULL); \
|
||||
M_ASSERT ((d)->default_size >= DEQUEUI_DEFAULT_SIZE); \
|
||||
M_ASSERT ((d)->default_size >= M_USE_DEQUE_DEFAULT_SIZE); \
|
||||
M_ASSERT ((d)->front->node != NULL); \
|
||||
M_ASSERT ((d)->front->index <= (d)->front->node->size); \
|
||||
M_ASSERT ((d)->back->node != NULL); \
|
||||
@@ -78,14 +74,14 @@
|
||||
|
||||
/* Deferred evaluation for the deque definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define DEQUEI_DEF_P1(arg) DEQUEI_DEF_P2 arg
|
||||
#define M_D3QU3_DEF_P1(arg) M_D3QU3_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)
|
||||
#define M_D3QU3_DEF_P2(name, type, oplist, deque_t, it_t, node_t) \
|
||||
M_IF_OPLIST(oplist)(M_D3QU3_DEF_P3, M_D3QU3_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) \
|
||||
#define M_D3QU3_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
|
||||
@@ -96,7 +92,7 @@
|
||||
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
|
||||
- node_t: alias for node_t [ node ]
|
||||
*/
|
||||
#define DEQUEI_DEF_P3(name, type, oplist, deque_t, it_t, node_t) \
|
||||
#define M_D3QU3_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 \
|
||||
@@ -129,7 +125,8 @@
|
||||
\
|
||||
/* Define the deque type: \
|
||||
- 'list' if the list of buckets containing the objects. \
|
||||
- 'front' and 'back' are iterators to the first and last elements. \
|
||||
- 'front' is a pseudo-iterator to the first \
|
||||
- 'back' is a pseudo-iterator to the one after last element \
|
||||
- 'default_size' is the size used for the creation of a new bucket \
|
||||
- 'count' is the number of elements in the container. \
|
||||
*/ \
|
||||
@@ -159,8 +156,9 @@
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
/* Allocate a new node for a deque */ \
|
||||
static inline node_t* \
|
||||
M_C(name, _int_new_node)(deque_t d) \
|
||||
M_C3(m_d3qu3_,name,_new_node)(deque_t d) \
|
||||
{ \
|
||||
size_t def = d->default_size; \
|
||||
/* Test for overflow of the size computation */ \
|
||||
@@ -168,7 +166,7 @@
|
||||
M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \
|
||||
return NULL; \
|
||||
} \
|
||||
/* Alloc a new node */ \
|
||||
/* Alloc a new node with dynamic size */ \
|
||||
node_t*n = (node_t*) (void*) \
|
||||
M_CALL_REALLOC(oplist, char, NULL, \
|
||||
sizeof(node_t) + def * sizeof(type) ); \
|
||||
@@ -191,22 +189,22 @@
|
||||
M_C(name, _init)(deque_t d) \
|
||||
{ \
|
||||
M_C(name, _node_list_init)(d->list); \
|
||||
d->default_size = DEQUEUI_DEFAULT_SIZE; \
|
||||
d->default_size = M_USE_DEQUE_DEFAULT_SIZE; \
|
||||
d->count = 0; \
|
||||
node_t *n = M_C(name, _int_new_node)(d); \
|
||||
node_t *n = M_C3(m_d3qu3_,name,_new_node)(d); \
|
||||
if (n == NULL) return; \
|
||||
M_C(name, _node_list_push_back)(d->list, n); \
|
||||
d->front->node = n; \
|
||||
d->front->index = DEQUEUI_DEFAULT_SIZE/2; \
|
||||
d->front->index = M_USE_DEQUE_DEFAULT_SIZE/2; \
|
||||
d->back->node = n; \
|
||||
d->back->index = DEQUEUI_DEFAULT_SIZE/2; \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
d->back->index = M_USE_DEQUE_DEFAULT_SIZE/2; \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(deque_t d) \
|
||||
M_C(name, _reset)(deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
node_t *min_node = NULL; \
|
||||
for(node_t *n = d->front->node; \
|
||||
n != NULL ; \
|
||||
@@ -225,14 +223,20 @@
|
||||
d->back->node = min_node; \
|
||||
d->back->index = min_node->size / 2; \
|
||||
d->count = 0; \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(deque_t d) \
|
||||
{ \
|
||||
M_C(name, _reset)(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_C(name, _clean)(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_C(name, _reset)(d); \
|
||||
/* We have registered the delete operator to clear all objects */ \
|
||||
M_C(name, _node_list_clear)(d->list); \
|
||||
/* It is safer to clean some variables */ \
|
||||
@@ -244,7 +248,7 @@
|
||||
static inline type * \
|
||||
M_C(name, _push_back_raw)(deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
node_t *n = d->back->node; \
|
||||
size_t index = d->back->index; \
|
||||
if (M_UNLIKELY (n->size <= index)) { \
|
||||
@@ -252,7 +256,7 @@
|
||||
n = M_C(name, _node_list_next_obj)(d->list, n); \
|
||||
if (n == NULL) { \
|
||||
/* No node exists, allocate a new one */ \
|
||||
n = M_C(name, _int_new_node)(d); \
|
||||
n = M_C3(m_d3qu3_,name,_new_node)(d); \
|
||||
if (M_UNLIKELY (n == NULL)) return NULL; \
|
||||
M_C(name, _node_list_push_back)(d->list, n); \
|
||||
} \
|
||||
@@ -263,10 +267,17 @@
|
||||
index++; \
|
||||
d->count ++; \
|
||||
d->back->index = index; \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
/* Internal, for INIT_WITH */ \
|
||||
static inline type * \
|
||||
M_C(name, _push_raw)(deque_t d) \
|
||||
{ \
|
||||
return M_C(name, _push_back_raw)(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push_back)(deque_t d, type const x) \
|
||||
{ \
|
||||
@@ -301,7 +312,7 @@
|
||||
static inline type* \
|
||||
M_C(name, _push_front_raw)(deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
node_t *n = d->front->node; \
|
||||
size_t index = d->front->index; \
|
||||
index --; \
|
||||
@@ -309,7 +320,7 @@
|
||||
if (M_UNLIKELY (n->size <= index)) { \
|
||||
n = M_C(name, _node_list_previous_obj)(d->list, n); \
|
||||
if (n == NULL) { \
|
||||
n = M_C(name, _int_new_node)(d); \
|
||||
n = M_C3(m_d3qu3_,name,_new_node)(d); \
|
||||
if (M_UNLIKELY (n == NULL)) return NULL; \
|
||||
M_C(name, _node_list_push_front)(d->list, n); \
|
||||
} \
|
||||
@@ -319,7 +330,7 @@
|
||||
type *ret = &n->data[index]; \
|
||||
d->count ++; \
|
||||
d->front->index = index; \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
@@ -357,7 +368,7 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_back)(type *ptr, deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT(d->count > 0); \
|
||||
node_t *n = d->back->node; \
|
||||
size_t index = d->back->index; \
|
||||
@@ -386,7 +397,7 @@
|
||||
M_CALL_CLEAR(oplist, n->data[index]); \
|
||||
d->count --; \
|
||||
d->back->index = index; \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
@@ -403,25 +414,10 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_front)(type *ptr, deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT(d->count > 0); \
|
||||
node_t *n = d->front->node; \
|
||||
size_t index = d->front->index; \
|
||||
if (M_UNLIKELY (n->size <= index)) { \
|
||||
/* If there is a previous node, \
|
||||
pop the front node and push it back to the back. This \
|
||||
reduce the used memory if the deque is used as a FIFO queue.*/ \
|
||||
node_t *prev = M_C(name, _node_list_previous_obj)(d->list, n); \
|
||||
if (prev != NULL) { \
|
||||
prev = M_C(name, _node_list_pop_front)(d->list); \
|
||||
M_ASSERT (prev != n); \
|
||||
M_C(name, _node_list_push_back)(d->list, prev); \
|
||||
} \
|
||||
n = M_C(name, _node_list_next_obj)(d->list, n); \
|
||||
M_ASSERT (n != NULL); \
|
||||
d->front->node = n; \
|
||||
index = 0; \
|
||||
} \
|
||||
if (ptr != NULL) \
|
||||
M_IF_METHOD(MOVE, oplist) ( \
|
||||
M_CALL_MOVE(oplist, *ptr, n->data[index]); else \
|
||||
@@ -430,8 +426,34 @@
|
||||
) \
|
||||
M_CALL_CLEAR(oplist, n->data[index]); \
|
||||
index++; \
|
||||
if (M_UNLIKELY (n->size <= index)) { \
|
||||
/* If there is a previous node, \
|
||||
pop the front node and push it back to the back. This \
|
||||
recycles the used memory if the deque is used as a FIFO queue.*/ \
|
||||
node_t *prev = M_C(name, _node_list_previous_obj)(d->list, n); \
|
||||
if (prev != NULL) { \
|
||||
prev = M_C(name, _node_list_pop_front)(d->list); \
|
||||
M_ASSERT (prev != n); \
|
||||
M_C(name, _node_list_push_back)(d->list, prev); \
|
||||
} \
|
||||
/* Update front iterator to point to the next object */ \
|
||||
n = M_C(name, _node_list_next_obj)(d->list, n); \
|
||||
if (M_UNLIKELY(n == NULL)) { \
|
||||
/* No next obj. \
|
||||
It is only possible if there was only 1 element */ \
|
||||
M_ASSERT(d->count == 1); \
|
||||
/* Reset the deque to the midle of the current node */ \
|
||||
d->back->node = d->front->node; \
|
||||
index = d->front->node->size/2; \
|
||||
d->back->index = d->front->node->size/2; \
|
||||
} else { \
|
||||
d->front->node = n; \
|
||||
index = 0; \
|
||||
} \
|
||||
} \
|
||||
d->count --; \
|
||||
d->front->index = index; \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
@@ -448,7 +470,7 @@
|
||||
static inline type * \
|
||||
M_C(name, _back)(const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT (d->count > 0); \
|
||||
size_t i = d->back->index; \
|
||||
node_t *n = d->back->node; \
|
||||
@@ -463,29 +485,24 @@
|
||||
static inline type * \
|
||||
M_C(name, _front)(const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT (d->count > 0); \
|
||||
size_t i = d->front->index; \
|
||||
node_t *n = d->front->node; \
|
||||
if (M_UNLIKELY (n->size <= i)) { \
|
||||
n = M_C(name, _node_list_next_obj)(d->list, n); \
|
||||
M_ASSERT (n != NULL); \
|
||||
i = 0; \
|
||||
} \
|
||||
return &n->data[i]; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
return d->count; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _capacity_back)(const deque_t v) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(v); \
|
||||
M_D3QU3_CONTRACT(v); \
|
||||
size_t s = 0; \
|
||||
for(node_t *n = M_C(name, _node_list_back)(v->list); \
|
||||
n != NULL ; \
|
||||
@@ -499,7 +516,7 @@
|
||||
static inline size_t \
|
||||
M_C(name, _capacity_front)(const deque_t v) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(v); \
|
||||
M_D3QU3_CONTRACT(v); \
|
||||
size_t s = 0; \
|
||||
for(node_t *n = M_C(name, _node_list_front)(v->list); \
|
||||
n != NULL ; \
|
||||
@@ -519,14 +536,14 @@
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
return d->count == 0; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->node = d->front->node; \
|
||||
it->index = d->front->index; \
|
||||
@@ -536,7 +553,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->node = d->back->node; \
|
||||
it->index = d->back->index - 1; \
|
||||
@@ -551,7 +568,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->node = d->back->node; \
|
||||
it->index = d->back->index; \
|
||||
@@ -586,7 +603,7 @@
|
||||
it->index ++; \
|
||||
if (M_UNLIKELY (it->index >= n->size)) { \
|
||||
n = M_C(name, _node_list_next_obj)(it->deque->list, n); \
|
||||
if (M_UNLIKELY (n == NULL)) { \
|
||||
if (M_UNLIKELY (n == NULL || it->node == it->deque->back->node)) { \
|
||||
/* Point to 'end' (can't undo it) */ \
|
||||
it->node = it->deque->back->node; \
|
||||
it->index = it->deque->back->node->size; \
|
||||
@@ -605,14 +622,14 @@
|
||||
it->index --; \
|
||||
if (M_UNLIKELY (it->index >= n->size)) { \
|
||||
n = M_C(name, _node_list_previous_obj)(it->deque->list, n); \
|
||||
if (M_UNLIKELY (n == NULL)) { \
|
||||
if (M_UNLIKELY (n == NULL || it->node == it->deque->front->node)) { \
|
||||
/* Point to 'end' (can't undo it) */ \
|
||||
it->node = it->deque->back->node; \
|
||||
it->index = it->deque->back->node->size; \
|
||||
return; \
|
||||
} \
|
||||
it->node = n; \
|
||||
it->index = 0; \
|
||||
it->index = n->size - 1; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
@@ -653,30 +670,93 @@
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _remove)(deque_t d, it_t it) \
|
||||
{ \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT (it != NULL && it->node != NULL); \
|
||||
M_ASSERT (d->count >= 1); \
|
||||
M_ASSERT_INDEX(it->index, it->node->size); \
|
||||
\
|
||||
node_t *n = it->node; \
|
||||
M_CALL_CLEAR(oplist, n->data[it->index]); \
|
||||
if (n == d->back->node) { \
|
||||
/* back index points to the element after the end */ \
|
||||
M_ASSERT (d->back->index != 0); \
|
||||
M_ASSERT (it->index < d->back->index); \
|
||||
/* We cannot have a node deletion in this case */ \
|
||||
memmove(&n->data[it->index], &n->data[it->index+1], \
|
||||
sizeof(type) * (d->back->index - it->index - 1)); \
|
||||
d->back->index --; \
|
||||
/* The iterator points to the next element */ \
|
||||
} else if (n == d->front->node) { \
|
||||
/* front index points to the first element */ \
|
||||
if (M_UNLIKELY (d->front->index == n->size -1)) { \
|
||||
/* Node 'smart' deletion (single element) */ \
|
||||
/* Update front iterator to point to the next object */ \
|
||||
n = M_C(name, _node_list_next_obj)(d->list, n); \
|
||||
/* We must have a next element, as we have a different back node \
|
||||
than the front node. */ \
|
||||
M_ASSERT (n != NULL); \
|
||||
d->front->node = n; \
|
||||
d->front->index = 0; \
|
||||
/* The iterator references this element */ \
|
||||
it->node = n; \
|
||||
it->index = 0; \
|
||||
} else { \
|
||||
memmove(&n->data[d->front->index+1], &n->data[d->front->index], \
|
||||
sizeof(type) * (it->index - d->front->index)); \
|
||||
d->front->index ++; \
|
||||
/* The iterator shall reference the next element */ \
|
||||
M_C(name, _next)(it); \
|
||||
} \
|
||||
} else { \
|
||||
/* Nether front or end node */ \
|
||||
if (M_UNLIKELY(n->size == 1)) { \
|
||||
/* The iterator shall reference the next element */ \
|
||||
M_C(name, _next)(it); \
|
||||
/* Node deletion */ \
|
||||
M_ASSERT(d->count > 1); \
|
||||
M_C(name, _node_list_unlink)(n); \
|
||||
M_CALL_FREE(oplist, n); \
|
||||
} else { \
|
||||
memmove(&n->data[it->index], &n->data[it->index+1], \
|
||||
sizeof(type) * (it->node->size - it->index - 1)); \
|
||||
/* We lose capacity of the node... */ \
|
||||
n->size --; \
|
||||
/* The iterator points to the next element \
|
||||
except if it was the last one*/ \
|
||||
if (M_UNLIKELY(it->index >= n->size)) M_C(name, _next)(it); \
|
||||
} \
|
||||
} \
|
||||
d->count--; \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(deque_t d, const deque_t src) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(src); \
|
||||
M_D3QU3_CONTRACT(src); \
|
||||
M_ASSERT (d != NULL); \
|
||||
M_C(name, _node_list_init)(d->list); \
|
||||
d->default_size = DEQUEUI_DEFAULT_SIZE + src->count; \
|
||||
d->default_size = M_USE_DEQUE_DEFAULT_SIZE + src->count; \
|
||||
d->count = src->count; \
|
||||
node_t *n = M_C(name, _int_new_node)(d); \
|
||||
node_t *n = M_C3(m_d3qu3_,name,_new_node)(d); \
|
||||
if (n == NULL) return; \
|
||||
d->default_size /= 2; \
|
||||
M_C(name, _node_list_push_back)(d->list, n); \
|
||||
d->front->node = n; \
|
||||
d->front->index = DEQUEUI_DEFAULT_SIZE/2; \
|
||||
d->front->index = M_USE_DEQUE_DEFAULT_SIZE/2; \
|
||||
d->back->node = n; \
|
||||
d->back->index = DEQUEUI_DEFAULT_SIZE/2 + src->count; \
|
||||
d->back->index = M_USE_DEQUE_DEFAULT_SIZE/2 + src->count; \
|
||||
it_t it; \
|
||||
size_t i = DEQUEUI_DEFAULT_SIZE/2; \
|
||||
size_t i = M_USE_DEQUE_DEFAULT_SIZE/2; \
|
||||
for(M_C(name, _it)(it, src); !M_C(name, _end_p)(it) ; M_C(name, _next)(it)) { \
|
||||
type const *obj = M_C(name, _cref)(it); \
|
||||
M_CALL_INIT_SET(oplist, n->data[i], *obj); \
|
||||
i++; \
|
||||
M_ASSERT (i <= d->back->index); \
|
||||
} \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -692,7 +772,7 @@
|
||||
static inline void \
|
||||
M_C(name, _init_move)(deque_t d, deque_t src) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(src); \
|
||||
M_D3QU3_CONTRACT(src); \
|
||||
M_ASSERT (d!= NULL); \
|
||||
M_C(name,_node_list_init_move)(d->list, src->list); \
|
||||
d->front->node = src->front->node; \
|
||||
@@ -702,24 +782,24 @@
|
||||
d->default_size = src->default_size; \
|
||||
d->count = src->count; \
|
||||
memset(src, 0, sizeof(deque_t)); \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(deque_t d, deque_t src) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
DEQUEI_CONTRACT(src); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(src); \
|
||||
M_C(name, _clear)(d); \
|
||||
M_C(name, _init_move)(d, src); \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(deque_t d, deque_t e) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
DEQUEI_CONTRACT(e); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(e); \
|
||||
M_C(name, _node_list_swap) (d->list, e->list); \
|
||||
M_SWAP(node_t *, d->front->node, e->front->node); \
|
||||
M_SWAP(node_t *, d->back->node, e->back->node); \
|
||||
@@ -727,14 +807,14 @@
|
||||
M_SWAP(size_t, d->back->index, e->back->index); \
|
||||
M_SWAP(size_t, d->default_size, e->default_size); \
|
||||
M_SWAP(size_t, d->count, e->count); \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
DEQUEI_CONTRACT(e); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(e); \
|
||||
} \
|
||||
\
|
||||
static inline type* \
|
||||
M_C(name, _get)(deque_t d, size_t key) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT_INDEX (key, d->count); \
|
||||
const size_t index0 = d->front->index; \
|
||||
size_t count = 0; \
|
||||
@@ -761,19 +841,19 @@
|
||||
static inline void \
|
||||
M_C(name, _set_at)(deque_t d, size_t key, type const x) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT_INDEX (key, d->count); \
|
||||
type *p = M_C(name, _get)(d, key); \
|
||||
M_CALL_SET(oplist, *p, x); \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(EQUAL, oplist)( \
|
||||
static inline bool \
|
||||
M_C(name, _equal_p)(const deque_t d1, const deque_t d2) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d1); \
|
||||
DEQUEI_CONTRACT(d2); \
|
||||
M_D3QU3_CONTRACT(d1); \
|
||||
M_D3QU3_CONTRACT(d2); \
|
||||
if (d1->count != d2->count) \
|
||||
return false; \
|
||||
it_t it1; \
|
||||
@@ -795,7 +875,7 @@
|
||||
static inline size_t \
|
||||
M_C(name, _hash)(const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_HASH_DECL(hash); \
|
||||
it_t it; \
|
||||
for(M_C(name, _it)(it, d); !M_C(name, _end_p)(it); M_C(name, _next)(it)) { \
|
||||
@@ -810,13 +890,13 @@
|
||||
static inline void \
|
||||
M_C(name, _swap_at)(deque_t d, size_t i, size_t j) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT_INDEX (i, d->count); \
|
||||
M_ASSERT_INDEX (j, d->count); \
|
||||
type *obj1 = M_C(name, _get)(d, i); \
|
||||
type *obj2 = M_C(name, _get)(d, j); \
|
||||
M_CALL_SWAP(oplist, *obj1, *obj2); \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
, /* NO SWAP */) \
|
||||
\
|
||||
@@ -824,8 +904,7 @@
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, deque_t const deque, bool append) \
|
||||
{ \
|
||||
STRINGI_CONTRACT(str); \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
it_t it; \
|
||||
for (M_C(name, _it)(it, deque) ; \
|
||||
@@ -837,7 +916,6 @@
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
STRINGI_CONTRACT(str); \
|
||||
} \
|
||||
, /* no GET_STR */ ) \
|
||||
\
|
||||
@@ -845,7 +923,7 @@
|
||||
static inline void \
|
||||
M_C(name, _out_str)(FILE *file, const deque_t deque) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
M_ASSERT (file != NULL); \
|
||||
fputc ('[', file); \
|
||||
it_t it; \
|
||||
@@ -865,9 +943,9 @@
|
||||
static inline bool \
|
||||
M_C(name, _parse_str)(deque_t deque, const char str[], const char **endp) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
M_ASSERT (str != NULL); \
|
||||
M_C(name,_clean)(deque); \
|
||||
M_C(name,_reset)(deque); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
@@ -883,7 +961,7 @@
|
||||
if (b == false || c == 0) { goto exit_clear; } \
|
||||
M_C(name, _push_back)(deque, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
success = (c == ']'); \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
@@ -897,9 +975,9 @@
|
||||
static inline bool \
|
||||
M_C(name, _in_str)(deque_t deque, FILE *file) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
M_ASSERT (file != NULL); \
|
||||
M_C(name,_clean)(deque); \
|
||||
M_C(name,_reset)(deque); \
|
||||
int c = fgetc(file); \
|
||||
if (M_UNLIKELY (c != '[')) return false; \
|
||||
c = fgetc(file); \
|
||||
@@ -915,7 +993,7 @@
|
||||
M_C(name, _push_back)(deque, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
return c == ']'; \
|
||||
} \
|
||||
, /* no IN_STR */ ) \
|
||||
@@ -924,7 +1002,7 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, const deque_t deque) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
@@ -949,12 +1027,12 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(deque_t deque, m_serial_read_t f) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
size_t estimated_size = 0; \
|
||||
M_C(name,_clean)(deque); \
|
||||
M_C(name,_reset)(deque); \
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
|
||||
type item; \
|
||||
@@ -973,26 +1051,27 @@
|
||||
|
||||
/* Deferred evaluation for the oplist definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define DEQUEI_OPLIST_P1(arg) DEQUEI_OPLIST_P2 arg
|
||||
#define M_D3QU3_OPLIST_P1(arg) M_D3QU3_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define DEQUEI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(DEQUEI_OPLIST_P3, DEQUEI_OPLIST_FAILURE)(name, oplist)
|
||||
#define M_D3QU3_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_D3QU3_OPLIST_P3, M_D3QU3_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define DEQUEI_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_D3QU3_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) \
|
||||
#define M_D3QU3_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
,INIT_WITH(API_1(M_INIT_WITH_VAI)) \
|
||||
,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)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_C(name,_ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,EMPTY_P(M_C(name,_empty_p)) \
|
||||
@@ -1008,7 +1087,8 @@
|
||||
,IT_PREVIOUS(M_C(name,_previous)) \
|
||||
,IT_REF(M_C(name,_ref)) \
|
||||
,IT_CREF(M_C(name,_cref)) \
|
||||
,CLEAN(M_C(name,_clean)) \
|
||||
,IT_REMOVE(M_C(name,_remove)) \
|
||||
,RESET(M_C(name,_reset)) \
|
||||
,GET_SIZE(M_C(name, _size)) \
|
||||
,PUSH(M_C(name,_push_back)) \
|
||||
,POP(M_C(name,_pop_back)) \
|
||||
|
||||
+57
-60
@@ -33,9 +33,7 @@
|
||||
* FUNC_OBJ_ITF_DEF(name, retcode type, type of param1, type of param 2, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_ITF_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_ITF_NO_PARAM_DEF, FUNCOBJI_ITF_PARAM_DEF)(name, M_C(name, _t), __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
FUNC_OBJ_ITF_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a function object interface of name 'name'
|
||||
@@ -45,7 +43,7 @@
|
||||
*/
|
||||
#define FUNC_OBJ_ITF_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_ITF_NO_PARAM_DEF, FUNCOBJI_ITF_PARAM_DEF)(name, name_t, __VA_ARGS__) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(M_FUNC0BJ_ITF_NO_PARAM_DEF, M_FUNC0BJ_ITF_PARAM_DEF)(name, name_t, __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
@@ -68,9 +66,7 @@
|
||||
* 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_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_DEF, FUNCOBJI_INS_ATTR_DEF)(name, M_C(name, _t), base_name, param_list, __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
FUNC_OBJ_INS_DEF_AS(name, M_C(name,_t), base_name, param_list, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a function object instance of name 'name' based on the interface 'base_name'
|
||||
@@ -82,7 +78,7 @@
|
||||
*/
|
||||
#define FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, param_list, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_DEF, FUNCOBJI_INS_ATTR_DEF)(name, name_t, base_name, param_list, __VA_ARGS__) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(M_FUNC0BJ_INS_NO_ATTR_DEF, M_FUNC0BJ_INS_ATTR_DEF)(name, name_t, base_name, param_list, __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
@@ -91,7 +87,7 @@
|
||||
* 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__)
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(M_FUNC0BJ_INS_NO_ATTR_OPLIST, M_FUNC0BJ_INS_ATTR_OPLIST_P1)( __VA_ARGS__)
|
||||
|
||||
|
||||
|
||||
@@ -113,7 +109,7 @@
|
||||
*/
|
||||
|
||||
/* Specialization of the OPLIST in function if there is at least one member or not */
|
||||
#define FUNCOBJI_INS_NO_ATTR_OPLIST(name) ( \
|
||||
#define M_FUNC0BJ_INS_NO_ATTR_OPLIST(name) ( \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
@@ -121,20 +117,21 @@
|
||||
)
|
||||
|
||||
/* 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__)
|
||||
#define M_FUNC0BJ_INS_ATTR_OPLIST_P1(name, ...) \
|
||||
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(M_FUNC0BJ_INS_ATTR_OPLIST_P3, M_FUNC0BJ_INS_ATTR_OPLIST_FAILURE)(name, __VA_ARGS__)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_FAILURE(name, ...) \
|
||||
#define M_FUNC0BJ_INS_ATTR_OPLIST_FAILURE(name, ...) \
|
||||
((M_LIB_ERROR(ONE_ARGUMENT_OF_FUNC_OBJ_INS_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)))
|
||||
|
||||
/* Define the oplist of the instance */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_P3(name, ...) ( \
|
||||
#define M_FUNC0BJ_INS_ATTR_OPLIST_P3(name, ...) ( \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
INIT_WITH(M_C(name, _init_with)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
|
||||
PROPERTIES(( LET_AS_INIT_WITH(1) )) \
|
||||
)
|
||||
|
||||
|
||||
@@ -145,7 +142,7 @@
|
||||
* - M_C(name, _callback_ct): internal type of the callback.
|
||||
* - M_C(name, _ct): synonym of main type used by oplist.
|
||||
*/
|
||||
#define FUNCOBJI_ITF_NO_PARAM_DEF(name, interface_t, retcode) \
|
||||
#define M_FUNC0BJ_ITF_NO_PARAM_DEF(name, interface_t, retcode) \
|
||||
\
|
||||
/* Forward declaration */ \
|
||||
struct M_C(name, _s); \
|
||||
@@ -179,7 +176,7 @@
|
||||
* - M_C4(name, _param_, num, _ct) for each parameter defined
|
||||
* - M_C(name, _ct): synonym of main type used by oplist.
|
||||
*/
|
||||
#define FUNCOBJI_ITF_PARAM_DEF(name, interface_t, retcode, ...) \
|
||||
#define M_FUNC0BJ_ITF_PARAM_DEF(name, interface_t, retcode, ...) \
|
||||
\
|
||||
/* Forward declaration */ \
|
||||
struct M_C(name, _s); \
|
||||
@@ -187,7 +184,7 @@
|
||||
/* Internal types for instance */ \
|
||||
typedef retcode M_C(name, _retcode_ct); \
|
||||
/* Define types for all parameters */ \
|
||||
M_MAP3(FUNCOBJI_BASE_TYPE, name, __VA_ARGS__) \
|
||||
M_MAP3(M_FUNC0BJ_BASE_TYPE, name, __VA_ARGS__) \
|
||||
/* Define callback type with all parameters */ \
|
||||
typedef retcode(*M_C(name, _callback_ct))(struct M_C(name, _s) *, __VA_ARGS__); \
|
||||
\
|
||||
@@ -200,18 +197,18 @@
|
||||
\
|
||||
static inline retcode \
|
||||
M_C(name, _call)(interface_t funcobj \
|
||||
M_MAP3(FUNCOBJI_BASE_ARGLIST, name, __VA_ARGS__) ) \
|
||||
M_MAP3(M_FUNC0BJ_BASE_ARGLIST, name, __VA_ARGS__) ) \
|
||||
{ \
|
||||
/* If the retcode is 'void', don't return the value of the callback */ \
|
||||
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
|
||||
funcobj->callback(funcobj M_MAP3(FUNCOBJI_BASE_ARGCALL, name, __VA_ARGS__) ); \
|
||||
funcobj->callback(funcobj M_MAP3(M_FUNC0BJ_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, instance_t, base_name, param_list, callback_core) \
|
||||
#define M_FUNC0BJ_INS_NO_ATTR_DEF(name, instance_t, base_name, param_list, callback_core) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(base_name, _callback_ct) callback; \
|
||||
} instance_t[1]; \
|
||||
@@ -223,7 +220,7 @@
|
||||
M_C(name, _callback)(M_C(base_name, _ct) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list) \
|
||||
M_MAP3(M_FUNC0BJ_INS_ARGLIST, base_name, M_OPFLAT param_list) \
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
@@ -261,55 +258,55 @@
|
||||
* with mandatory member attribute.
|
||||
* First inject oplist in member attributes.
|
||||
*/
|
||||
#define FUNCOBJI_INS_ATTR_DEF(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
FUNCOBJI_INS_ATTR_DEF_P2(name, instance_t, base_name, param_list, callback_core, FUNCOBJI_INJECT_GLOBAL(__VA_ARGS__) )
|
||||
#define M_FUNC0BJ_INS_ATTR_DEF(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
M_FUNC0BJ_INS_ATTR_DEF_P2(name, instance_t, base_name, param_list, callback_core, M_FUNC0BJ_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__)
|
||||
#define M_FUNC0BJ_INJECT_GLOBAL(...) \
|
||||
M_MAP_C(M_FUNC0BJ_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, ... ) \
|
||||
#define M_FUNC0BJ_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
M_FUNC0BJ_INJECT_OPLIST_B duo_or_trio
|
||||
#define M_FUNC0BJ_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__))
|
||||
#define M_FUNC0BJ_IF_ALL_OPLIST(...) \
|
||||
M_IF(M_REDUCE(M_FUNC0BJ_IS_OPLIST_P, M_AND, __VA_ARGS__))
|
||||
// Test if the third argument is an oplist. a is a trio (name, type, oplist)
|
||||
#define FUNCOBJI_IS_OPLIST_P(a) \
|
||||
#define M_FUNC0BJ_IS_OPLIST_P(a) \
|
||||
M_OPLIST_P(M_RET_ARG3 a)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define FUNCOBJI_INS_ATTR_DEF_P2(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
FUNCOBJI_IF_ALL_OPLIST(__VA_ARGS__)(FUNCOBJI_INS_ATTR_DEF_P3, FUNCOBJI_INS_ATTR_DEF_FAILURE)(name, instance_t, base_name, param_list, callback_core, __VA_ARGS__)
|
||||
#define M_FUNC0BJ_INS_ATTR_DEF_P2(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
M_FUNC0BJ_IF_ALL_OPLIST(__VA_ARGS__)(M_FUNC0BJ_INS_ATTR_DEF_P3, M_FUNC0BJ_INS_ATTR_DEF_FAILURE)(name, instance_t, base_name, param_list, callback_core, __VA_ARGS__)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define FUNCOBJI_INS_ATTR_DEF_FAILURE(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
#define M_FUNC0BJ_INS_ATTR_DEF_FAILURE(name, instance_t, 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, instance_t, base_name, param_list, callback_core, ...) \
|
||||
#define M_FUNC0BJ_INS_ATTR_DEF_P3(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
/* Callback is the mandatory first argument */ \
|
||||
M_C(base_name, _callback_ct) callback; \
|
||||
/* All the member attribute of the Function Object */ \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_STRUCT, __VA_ARGS__) \
|
||||
M_MAP(M_FUNC0BJ_INS_ATTR_STRUCT, __VA_ARGS__) \
|
||||
} instance_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef instance_t M_C(name, _ct); \
|
||||
\
|
||||
FUNCOBJI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
M_FUNC0BJ_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
\
|
||||
static inline M_C(base_name, _retcode_ct) \
|
||||
M_C(name, _callback)(M_C(base_name, _ct) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list) \
|
||||
M_MAP3(M_FUNC0BJ_INS_ARGLIST, base_name, M_OPFLAT param_list) \
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
@@ -319,16 +316,16 @@
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_with)(instance_t obj M_MAP(FUNCOBJI_INS_ATTR_LIST, __VA_ARGS__)) \
|
||||
M_C(name, _init_with)(instance_t obj M_MAP(M_FUNC0BJ_INS_ATTR_LIST, __VA_ARGS__)) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_INIT_SET, __VA_ARGS__); \
|
||||
M_MAP(M_FUNC0BJ_INS_ATTR_INIT_SET, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(instance_t obj) \
|
||||
{ \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_CLEAR, __VA_ARGS__); \
|
||||
M_MAP(M_FUNC0BJ_INS_ATTR_CLEAR, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(base_name, _s) * \
|
||||
@@ -337,65 +334,65 @@
|
||||
return (struct M_C(base_name, _s) *) obj; \
|
||||
} \
|
||||
\
|
||||
M_IF(FUNCOBJI_TEST_METHOD_P(INIT, __VA_ARGS)) \
|
||||
M_IF(M_FUNC0BJ_TEST_METHOD_P(INIT, __VA_ARGS)) \
|
||||
( \
|
||||
static inline void \
|
||||
M_C(name, _init)(instance_t obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_INIT, __VA_ARGS__); \
|
||||
M_MAP(M_FUNC0BJ_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) \
|
||||
#define M_FUNC0BJ_BASE_TYPE(name, num, type) \
|
||||
typedef type M_C4(name, _param_, num, _ct);
|
||||
|
||||
/* Define a list of the type of arguments for a function definition */
|
||||
#define FUNCOBJI_BASE_ARGLIST(name, num, type) \
|
||||
#define M_FUNC0BJ_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) \
|
||||
#define M_FUNC0BJ_BASE_ARGCALL(name, num, type) \
|
||||
M_DEFERRED_COMMA M_C(param_, num)
|
||||
|
||||
|
||||
/* Helper macros */
|
||||
/* arg = (name, type [, oplist]) */
|
||||
#define FUNCOBJI_INS_ATTR_STRUCT(arg) \
|
||||
#define M_FUNC0BJ_INS_ATTR_STRUCT(arg) \
|
||||
M_RET_ARG2 arg M_RET_ARG1 arg;
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_LIST(arg) \
|
||||
#define M_FUNC0BJ_INS_ATTR_LIST(arg) \
|
||||
M_DEFERRED_COMMA M_RET_ARG2 arg const M_RET_ARG1 arg
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_INIT(arg) \
|
||||
#define M_FUNC0BJ_INS_ATTR_INIT(arg) \
|
||||
M_CALL_INIT(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg);
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_INIT_SET(arg) \
|
||||
#define M_FUNC0BJ_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) \
|
||||
#define M_FUNC0BJ_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) \
|
||||
#define M_FUNC0BJ_INS_ARGLIST(name, num, param) \
|
||||
M_DEFERRED_COMMA M_C4(name, _param_, num, _ct) param
|
||||
|
||||
|
||||
/* Macros for testing for a method presence in all the attributes */
|
||||
#define FUNCOBJI_TEST_METHOD2_P(method, op) \
|
||||
#define M_FUNC0BJ_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__))
|
||||
#define M_FUNC0BJ_TEST_METHOD1_P(method, arg) \
|
||||
M_APPLY(M_FUNC0BJ_TEST_METHOD2_P, method, M_RET_ARG3 arg)
|
||||
#define M_FUNC0BJ_TEST_METHOD_P(method, ...) \
|
||||
M_IF(M_REDUCE2(M_FUNC0BJ_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) \
|
||||
#define M_FUNC0BJ_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(M_FUNC0BJ_CONTROL_OPLIST, name, __VA_ARGS__)
|
||||
#define M_FUNC0BJ_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, M_RET_ARG1 a, M_RET_ARG2 a, M_RET_ARG3 a)
|
||||
|
||||
|
||||
|
||||
+48
-48
@@ -30,7 +30,7 @@
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* GENINT is a container providing unique integers.
|
||||
/* GENINT is an internal container providing unique integers.
|
||||
It has the following properties:
|
||||
- it stores integer from [0..N) (N is fixed).
|
||||
- an integer can have only one occurrence in the container.
|
||||
@@ -39,7 +39,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
- there are no order (like FIFO or stack)
|
||||
|
||||
This can be used to map integers to index of resources in a table.
|
||||
At most we can support N = 2048 with the master limb usage.
|
||||
At most we can support N = 32*64 = 2048 with the master limb usage.
|
||||
For the typical usage of this container
|
||||
(mapping hardware or software limited resources), this should be
|
||||
enough.
|
||||
@@ -60,24 +60,24 @@ typedef struct genint_s {
|
||||
atomic_ullong *data; // the bitfield which informs if an integer is used or not
|
||||
} genint_t[1];
|
||||
|
||||
// Define the max absolute supported value
|
||||
#define GENINT_MAX_ALLOC (GENINT_LIMBSIZE * (GENINT_LIMBSIZE - GENINT_ABA_CPT))
|
||||
// Define the max absolute supported value. It should be 2048 on most implementations.
|
||||
#define GENINT_MAX_ALLOC (M_GEN1NT_LIMBSIZE * (M_GEN1NT_LIMBSIZE - M_GEN1NT_ABA_CPT))
|
||||
|
||||
// Define the size of a limb in bits.
|
||||
#define GENINT_LIMBSIZE ((unsigned)(sizeof(genint_limb_ct) * CHAR_BIT))
|
||||
#define M_GEN1NT_LIMBSIZE ((unsigned)(sizeof(genint_limb_ct) * CHAR_BIT))
|
||||
|
||||
// Define the contract of a genint
|
||||
#define GENINT_CONTRACT(s) do { \
|
||||
#define M_GEN1NT_CONTRACT(s) do { \
|
||||
M_ASSERT (s != NULL); \
|
||||
M_ASSERT (s->n > 0 && s->n <= GENINT_MAX_ALLOC); \
|
||||
M_ASSERT ((s->max+1) * GENINT_LIMBSIZE >= s->n); \
|
||||
M_ASSERT ((s->max+1) * M_GEN1NT_LIMBSIZE >= s->n); \
|
||||
M_ASSERT (s->data != NULL); \
|
||||
} while (0)
|
||||
|
||||
// Define the limb one
|
||||
#define GENINT_ONE ((genint_limb_ct)1)
|
||||
#define M_GEN1NT_ONE ((genint_limb_ct)1)
|
||||
|
||||
#define GENINT_FULL_MASK ULLONG_MAX
|
||||
#define M_GEN1NT_FULL_MASK ULLONG_MAX
|
||||
|
||||
// Value returned in case of error (not integer available).
|
||||
#define GENINT_ERROR (UINT_MAX)
|
||||
@@ -85,18 +85,18 @@ typedef struct genint_s {
|
||||
/* 32 bits of the master mask are kept for handling the ABA problem.
|
||||
* NOTE: May be too much. 16 bits should be more than enough. TBC
|
||||
*/
|
||||
#define GENINT_ABA_CPT 32
|
||||
#define GENINT_ABA_CPT_T uint32_t
|
||||
#define M_GEN1NT_ABA_CPT 32
|
||||
#define M_GEN1NT_ABA_CPT_T uint32_t
|
||||
|
||||
// Set the bit 'i' of the master limb, and increase ABA counter.
|
||||
#define GENINT_MASTER_SET(master, i) \
|
||||
((((master)& (~((GENINT_ONE<< GENINT_ABA_CPT)-1))) | (GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \
|
||||
|((GENINT_ABA_CPT_T)((master) + 1)))
|
||||
#define M_GEN1NT_MASTER_SET(master, i) \
|
||||
((((master)& (~((M_GEN1NT_ONE<< M_GEN1NT_ABA_CPT)-1))) | (M_GEN1NT_ONE << (M_GEN1NT_LIMBSIZE - 1 - i))) \
|
||||
|((M_GEN1NT_ABA_CPT_T)((master) + 1)))
|
||||
|
||||
// Reset the bit i of the master limb, and increase ABA counter.
|
||||
#define GENINT_MASTER_RESET(master, i) \
|
||||
(((master) & (~((GENINT_ONE<< GENINT_ABA_CPT)-1)) & ~(GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \
|
||||
|((GENINT_ABA_CPT_T)((master) + 1)))
|
||||
#define M_GEN1NT_MASTER_RESET(master, i) \
|
||||
(((master) & (~((M_GEN1NT_ONE<< M_GEN1NT_ABA_CPT)-1)) & ~(M_GEN1NT_ONE << (M_GEN1NT_LIMBSIZE - 1 - i))) \
|
||||
|((M_GEN1NT_ABA_CPT_T)((master) + 1)))
|
||||
|
||||
/* Initialize an integer generator (CONSTRUCTOR).
|
||||
* Initialy, the container is full of all the integers up to 'n-1'
|
||||
@@ -109,8 +109,8 @@ static inline void
|
||||
genint_init(genint_t s, unsigned int n)
|
||||
{
|
||||
M_ASSERT (s != NULL && n > 0 && n <= GENINT_MAX_ALLOC);
|
||||
const size_t alloc = (n + GENINT_LIMBSIZE - 1) / GENINT_LIMBSIZE;
|
||||
const unsigned int index = n % GENINT_LIMBSIZE;
|
||||
const size_t alloc = (n + M_GEN1NT_LIMBSIZE - 1) / M_GEN1NT_LIMBSIZE;
|
||||
const unsigned int index = n % M_GEN1NT_LIMBSIZE;
|
||||
atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, alloc);
|
||||
if (M_UNLIKELY (ptr == NULL)) {
|
||||
M_MEMORY_FULL(alloc);
|
||||
@@ -119,19 +119,19 @@ genint_init(genint_t s, unsigned int n)
|
||||
s->n = n;
|
||||
s->data = ptr;
|
||||
s->max = (unsigned int) (alloc-1);
|
||||
s->mask0 = (index == 0) ? GENINT_FULL_MASK : ~((GENINT_ONE<<(GENINT_LIMBSIZE-index))-1);
|
||||
s->mask_master = (((GENINT_ONE << alloc) - 1) << (GENINT_LIMBSIZE-alloc)) >> GENINT_ABA_CPT;
|
||||
s->mask0 = (index == 0) ? M_GEN1NT_FULL_MASK : ~((M_GEN1NT_ONE<<(M_GEN1NT_LIMBSIZE-index))-1);
|
||||
s->mask_master = (((M_GEN1NT_ONE << alloc) - 1) << (M_GEN1NT_LIMBSIZE-alloc)) >> M_GEN1NT_ABA_CPT;
|
||||
atomic_init (&s->master, (genint_limb_ct)0);
|
||||
for(unsigned int i = 0; i < alloc; i++)
|
||||
atomic_init(&s->data[i], (genint_limb_ct)0);
|
||||
GENINT_CONTRACT(s);
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
}
|
||||
|
||||
/* Clear an integer generator (Destructor) */
|
||||
static inline void
|
||||
genint_clear(genint_t s)
|
||||
{
|
||||
GENINT_CONTRACT(s);
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
M_MEMORY_FREE(s->data);
|
||||
s->data = NULL;
|
||||
}
|
||||
@@ -140,7 +140,7 @@ genint_clear(genint_t s)
|
||||
static inline size_t
|
||||
genint_size(genint_t s)
|
||||
{
|
||||
GENINT_CONTRACT(s);
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
return s->n;
|
||||
}
|
||||
|
||||
@@ -149,17 +149,17 @@ genint_size(genint_t s)
|
||||
static inline unsigned int
|
||||
genint_pop(genint_t s)
|
||||
{
|
||||
GENINT_CONTRACT(s);
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
// First read master to see which limb is not full.
|
||||
genint_limb_ct master = atomic_load(&s->master);
|
||||
// While master is not full
|
||||
while ((master >> GENINT_ABA_CPT) != s->mask_master) {
|
||||
while ((master >> M_GEN1NT_ABA_CPT) != s->mask_master) {
|
||||
// Let's get the index i of the first not full limb according to master.
|
||||
unsigned int i = m_core_clz64(~master);
|
||||
M_ASSERT (i < GENINT_LIMBSIZE);
|
||||
M_ASSERT (i < M_GEN1NT_LIMBSIZE);
|
||||
// Let's compute the mask of this limb representing the limb as being full
|
||||
genint_limb_ct mask = s->mask0;
|
||||
mask = (i == s->max) ? mask : GENINT_FULL_MASK;
|
||||
mask = (i == s->max) ? mask : M_GEN1NT_FULL_MASK;
|
||||
unsigned int bit;
|
||||
// Let's load this limb,
|
||||
genint_limb_ct next, org = atomic_load(&s->data[i]);
|
||||
@@ -167,14 +167,14 @@ genint_pop(genint_t s)
|
||||
// If it is now full, we have been preempted by another.
|
||||
if (M_UNLIKELY (org == mask))
|
||||
goto next_element;
|
||||
M_ASSERT (org != GENINT_FULL_MASK);
|
||||
M_ASSERT (org != M_GEN1NT_FULL_MASK);
|
||||
// At least one bit is free in the limb. Find one.
|
||||
bit = GENINT_LIMBSIZE - 1 - m_core_clz64(~org);
|
||||
M_ASSERT (bit < GENINT_LIMBSIZE);
|
||||
M_ASSERT ((org & (GENINT_ONE<<bit)) == 0);
|
||||
M_ASSERT (i * GENINT_LIMBSIZE + GENINT_LIMBSIZE - 1 - bit < s->n);
|
||||
bit = M_GEN1NT_LIMBSIZE - 1 - m_core_clz64(~org);
|
||||
M_ASSERT (bit < M_GEN1NT_LIMBSIZE);
|
||||
M_ASSERT ((org & (M_GEN1NT_ONE<<bit)) == 0);
|
||||
M_ASSERT (i * M_GEN1NT_LIMBSIZE + M_GEN1NT_LIMBSIZE - 1 - bit < s->n);
|
||||
// Set the integer as being used.
|
||||
next = org | (GENINT_ONE << bit);
|
||||
next = org | (M_GEN1NT_ONE << bit);
|
||||
// Try to reserve the integer
|
||||
} while (!atomic_compare_exchange_weak (&s->data[i], &org, next));
|
||||
// We have reserved the integer.
|
||||
@@ -183,9 +183,9 @@ genint_pop(genint_t s)
|
||||
while (true) {
|
||||
genint_limb_ct newMaster;
|
||||
if (next == mask) {
|
||||
newMaster = GENINT_MASTER_SET(master, i);
|
||||
newMaster = M_GEN1NT_MASTER_SET(master, i);
|
||||
} else {
|
||||
newMaster = GENINT_MASTER_RESET(master, i);
|
||||
newMaster = M_GEN1NT_MASTER_RESET(master, i);
|
||||
}
|
||||
if (atomic_compare_exchange_weak (&s->master, &master, newMaster))
|
||||
break;
|
||||
@@ -194,13 +194,13 @@ genint_pop(genint_t s)
|
||||
}
|
||||
}
|
||||
// Return the new number
|
||||
GENINT_CONTRACT(s);
|
||||
return i * GENINT_LIMBSIZE + GENINT_LIMBSIZE - 1 - bit;
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
return i * M_GEN1NT_LIMBSIZE + M_GEN1NT_LIMBSIZE - 1 - bit;
|
||||
next_element:
|
||||
// Reload master
|
||||
master = atomic_load(&s->master);
|
||||
}
|
||||
GENINT_CONTRACT(s);
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
return GENINT_ERROR; // No more resource available
|
||||
}
|
||||
|
||||
@@ -209,31 +209,31 @@ genint_pop(genint_t s)
|
||||
static inline void
|
||||
genint_push(genint_t s, unsigned int n)
|
||||
{
|
||||
GENINT_CONTRACT(s);
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
M_ASSERT (n < s->n);
|
||||
const unsigned int i = n / GENINT_LIMBSIZE;
|
||||
const unsigned int bit = GENINT_LIMBSIZE - 1 - (n % GENINT_LIMBSIZE);
|
||||
const unsigned int i = n / M_GEN1NT_LIMBSIZE;
|
||||
const unsigned int bit = M_GEN1NT_LIMBSIZE - 1 - (n % M_GEN1NT_LIMBSIZE);
|
||||
genint_limb_ct master = atomic_load(&s->master);
|
||||
// Load the limb
|
||||
genint_limb_ct next, org = atomic_load(&s->data[i]);
|
||||
do {
|
||||
M_ASSERT ((org & (GENINT_ONE << bit)) != 0);
|
||||
M_ASSERT ((org & (M_GEN1NT_ONE << bit)) != 0);
|
||||
// Reset it
|
||||
next = org & (~(GENINT_ONE << bit));
|
||||
next = org & (~(M_GEN1NT_ONE << bit));
|
||||
// Try to unreserve it.
|
||||
} while (!atomic_compare_exchange_weak (&s->data[i], &org, next));
|
||||
// if the limb was marked as full by master
|
||||
genint_limb_ct mask = s->mask0;
|
||||
mask = (i == s->max) ? mask : GENINT_FULL_MASK;
|
||||
mask = (i == s->max) ? mask : M_GEN1NT_FULL_MASK;
|
||||
if (M_UNLIKELY (next != mask)) {
|
||||
// Let's compute the mask of this limb representing the limb as being full
|
||||
// Let's try to update master to say that this limb is not full
|
||||
while (true) {
|
||||
genint_limb_ct newMaster;
|
||||
if (next == mask) {
|
||||
newMaster = GENINT_MASTER_SET(master, i);
|
||||
newMaster = M_GEN1NT_MASTER_SET(master, i);
|
||||
} else {
|
||||
newMaster = GENINT_MASTER_RESET(master, i);
|
||||
newMaster = M_GEN1NT_MASTER_RESET(master, i);
|
||||
}
|
||||
if (atomic_compare_exchange_weak (&s->master, &master, newMaster))
|
||||
break;
|
||||
@@ -241,7 +241,7 @@ genint_push(genint_t s, unsigned int n)
|
||||
next = atomic_load(&s->data[i]);
|
||||
}
|
||||
}
|
||||
GENINT_CONTRACT(s);
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
}
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
+118
-113
@@ -26,7 +26,7 @@
|
||||
#define MSTARLIB_I_LIST_H
|
||||
|
||||
#include "m-core.h"
|
||||
#include "m-list.h" // For LISTI_ITBASE_DEF
|
||||
#include "m-list.h" // For M_L1ST_ITBASE_DEF
|
||||
|
||||
/* Interface to add to a structure to enable intrusive doubly-linked support.
|
||||
name: name of the intrusive list.
|
||||
@@ -39,7 +39,7 @@
|
||||
} tmp_str_t;
|
||||
*/
|
||||
#define ILIST_INTERFACE(name, type) \
|
||||
struct ilist_head_s name
|
||||
struct m_ilist_head_s name
|
||||
|
||||
|
||||
/* Define a doubly-linked intrusive list of a given type.
|
||||
@@ -47,11 +47,7 @@
|
||||
USAGE:
|
||||
ILIST_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define ILIST_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ILISTI_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) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
ILIST_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a doubly-linked intrusive list of a given type
|
||||
@@ -61,7 +57,7 @@
|
||||
ILIST_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define ILIST_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ILISTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_IL1ST_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -71,7 +67,7 @@
|
||||
USAGE:
|
||||
ILIST_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define ILIST_OPLIST(...) \
|
||||
ILISTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_IL1ST_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
@@ -79,30 +75,31 @@
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Define the basic structure to be added in all objects. */
|
||||
typedef struct ilist_head_s {
|
||||
struct ilist_head_s *next;
|
||||
struct ilist_head_s *prev;
|
||||
} ilist_head_ct;
|
||||
typedef struct m_ilist_head_s {
|
||||
struct m_ilist_head_s *next;
|
||||
struct m_ilist_head_s *prev;
|
||||
} m_ilist_head_ct;
|
||||
|
||||
/* Indirection call to allow expanding all arguments */
|
||||
#define ILISTI_OPLIST_P1(arg) ILISTI_OPLIST_P2 arg
|
||||
#define M_IL1ST_OPLIST_P1(arg) M_IL1ST_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)
|
||||
#define M_IL1ST_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_IL1ST_OPLIST_P3, M_IL1ST_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define ILISTI_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_IL1ST_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_P3(name, oplist) \
|
||||
#define M_IL1ST_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
CLEAN(M_C(name,_clean)), \
|
||||
RESET(M_C(name,_reset)), \
|
||||
SUBTYPE(M_C(name,_subtype_ct)), \
|
||||
EMPTY_P(M_C(name,_empty_p)), \
|
||||
IT_TYPE(M_C(name,_it_ct)), \
|
||||
@@ -126,7 +123,7 @@ typedef struct ilist_head_s {
|
||||
)
|
||||
|
||||
/* Contract respected by all intrusive lists */
|
||||
#define ILISTI_CONTRACT(name, list) do { \
|
||||
#define M_IL1ST_CONTRACT(name, list) do { \
|
||||
M_ASSERT(list != NULL); \
|
||||
M_ASSERT(list->name.prev != NULL); \
|
||||
M_ASSERT(list->name.next != NULL); \
|
||||
@@ -135,7 +132,7 @@ typedef struct ilist_head_s {
|
||||
M_ASSERT(!(list->name.prev == &list->name) || list->name.prev == list->name.next); \
|
||||
} while (0)
|
||||
|
||||
#define ILISTI_NODE_CONTRACT(node) do { \
|
||||
#define M_IL1ST_NODE_CONTRACT(node) do { \
|
||||
M_ASSERT((node) != NULL); \
|
||||
M_ASSERT((node)->prev != NULL); \
|
||||
M_ASSERT((node)->next != NULL); \
|
||||
@@ -144,14 +141,14 @@ typedef struct ilist_head_s {
|
||||
} while (0)
|
||||
|
||||
/* Indirection call to allow expanding all arguments (TBC) */
|
||||
#define ILISTI_DEF_P1(arg) ILISTI_DEF_P2 arg
|
||||
#define M_IL1ST_DEF_P1(arg) M_IL1ST_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)
|
||||
#define M_IL1ST_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(M_IL1ST_DEF_P3, M_IL1ST_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) \
|
||||
#define M_IL1ST_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.
|
||||
@@ -162,12 +159,12 @@ 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_P3(name, type, oplist, list_t, it_t) \
|
||||
#define M_IL1ST_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
/* Define the list as a structure containing pointers \
|
||||
* to the front & back nodes */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
struct ilist_head_s name; \
|
||||
struct m_ilist_head_s name; \
|
||||
} list_t[1]; \
|
||||
\
|
||||
/* Define internal types pointers to such a list */ \
|
||||
@@ -176,10 +173,10 @@ typedef struct ilist_head_s {
|
||||
\
|
||||
/* Define iterator of such a list */ \
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
struct ilist_head_s *head; \
|
||||
struct ilist_head_s *previous; \
|
||||
struct ilist_head_s *current; \
|
||||
struct ilist_head_s *next; \
|
||||
struct m_ilist_head_s *head; \
|
||||
struct m_ilist_head_s *previous; \
|
||||
struct m_ilist_head_s *current; \
|
||||
struct m_ilist_head_s *next; \
|
||||
} it_t[1]; \
|
||||
\
|
||||
/* Define types used by oplist */ \
|
||||
@@ -195,18 +192,18 @@ typedef struct ilist_head_s {
|
||||
M_ASSERT (list != NULL); \
|
||||
list->name.next = &list->name; \
|
||||
list->name.prev = &list->name; \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(list_t list) \
|
||||
M_C(name, _reset)(list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
for(struct ilist_head_s *it = list->name.next, *next ; \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
for(struct m_ilist_head_s *it = list->name.next, *next ; \
|
||||
it != &list->name; it = next) { \
|
||||
/* Cannot check node contract as previous node may be deleted */ \
|
||||
type *obj = M_TYPE_FROM_FIELD(type, it, \
|
||||
struct ilist_head_s, name); \
|
||||
struct m_ilist_head_s, name); \
|
||||
/* Read next now before the object is destroyed */ \
|
||||
next = it->next; \
|
||||
M_ASSERT (next != NULL); \
|
||||
@@ -217,14 +214,20 @@ typedef struct ilist_head_s {
|
||||
/* Nothing remains in the list anymore */ \
|
||||
list->name.next = &list->name; \
|
||||
list->name.prev = &list->name; \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(list_t list) \
|
||||
{ \
|
||||
M_C(name,_reset)(list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(list_t list) \
|
||||
{ \
|
||||
/* Nothing to do more than clean the list itself */ \
|
||||
M_C(name, _clean)(list); \
|
||||
M_C(name, _reset)(list); \
|
||||
/* For safety purpose (create invalid represenation of object) */ \
|
||||
list->name.next = NULL; \
|
||||
list->name.prev = NULL; \
|
||||
@@ -233,7 +236,7 @@ typedef struct ilist_head_s {
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
return list->name.next == &list->name; \
|
||||
} \
|
||||
\
|
||||
@@ -241,7 +244,7 @@ typedef struct ilist_head_s {
|
||||
static inline void \
|
||||
M_C(name, _init_move)(list_t list, list_t ref) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, ref); \
|
||||
M_IL1ST_CONTRACT(name, ref); \
|
||||
M_ASSERT (list != ref); \
|
||||
M_C(name,_init)(list); \
|
||||
if (!M_C(name,_empty_p)(ref)) { \
|
||||
@@ -252,7 +255,7 @@ typedef struct ilist_head_s {
|
||||
} \
|
||||
ref->name.next = NULL; \
|
||||
ref->name.prev = NULL; \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -265,12 +268,12 @@ typedef struct ilist_head_s {
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
size_t s = 0; \
|
||||
/* Scan the full list to count the number of elements */ \
|
||||
for(const struct ilist_head_s *it = list->name.next ; \
|
||||
for(const struct m_ilist_head_s *it = list->name.next ; \
|
||||
it != &list->name; it = it->next) { \
|
||||
ILISTI_NODE_CONTRACT(it); \
|
||||
M_IL1ST_NODE_CONTRACT(it); \
|
||||
s++; \
|
||||
} \
|
||||
return s; \
|
||||
@@ -279,27 +282,27 @@ typedef struct ilist_head_s {
|
||||
static inline void \
|
||||
M_C(name, _push_back)(list_t list, type *obj) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (obj != NULL); \
|
||||
struct ilist_head_s *prev = list->name.prev; \
|
||||
struct m_ilist_head_s *prev = list->name.prev; \
|
||||
list->name.prev = &obj->name; \
|
||||
obj->name.prev = prev; \
|
||||
obj->name.next = &list->name; \
|
||||
prev->next = &obj->name; \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push_front)(list_t list, type *obj) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (obj != NULL); \
|
||||
struct ilist_head_s *next = list->name.next; \
|
||||
struct m_ilist_head_s *next = list->name.next; \
|
||||
list->name.next = &obj->name; \
|
||||
obj->name.next = next; \
|
||||
obj->name.prev = &list->name; \
|
||||
next->prev = &obj->name; \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -307,8 +310,8 @@ typedef struct ilist_head_s {
|
||||
{ \
|
||||
M_ASSERT (obj_pos != NULL && obj != NULL); \
|
||||
/* We don't have the list, so we have no contract at list level */ \
|
||||
ILISTI_NODE_CONTRACT(&obj_pos->name); \
|
||||
struct ilist_head_s *next = obj_pos->name.next; \
|
||||
M_IL1ST_NODE_CONTRACT(&obj_pos->name); \
|
||||
struct m_ilist_head_s *next = obj_pos->name.next; \
|
||||
obj_pos->name.next = &obj->name; \
|
||||
obj->name.next = next; \
|
||||
obj->name.prev = &obj_pos->name; \
|
||||
@@ -329,9 +332,9 @@ typedef struct ilist_head_s {
|
||||
{ \
|
||||
M_ASSERT (obj != NULL); \
|
||||
/* We don't have the list, so we have no contract at list level */ \
|
||||
ILISTI_NODE_CONTRACT(&obj->name); \
|
||||
struct ilist_head_s *next = obj->name.next; \
|
||||
struct ilist_head_s *prev = obj->name.prev; \
|
||||
M_IL1ST_NODE_CONTRACT(&obj->name); \
|
||||
struct m_ilist_head_s *next = obj->name.next; \
|
||||
struct m_ilist_head_s *prev = obj->name.prev; \
|
||||
next->prev = prev; \
|
||||
prev->next = next; \
|
||||
/* Note: not really needed, but safer */ \
|
||||
@@ -342,53 +345,53 @@ typedef struct ilist_head_s {
|
||||
static inline type * \
|
||||
M_C(name, _back)(const list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT(!M_C(name, _empty_p)(list)); \
|
||||
return M_TYPE_FROM_FIELD(type, list->name.prev, \
|
||||
struct ilist_head_s, name); \
|
||||
struct m_ilist_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _front)(const list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT(!M_C(name, _empty_p)(list)); \
|
||||
return M_TYPE_FROM_FIELD(type, list->name.next, \
|
||||
struct ilist_head_s, name); \
|
||||
struct m_ilist_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _next_obj)(const list_t list, type const *obj) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (obj != NULL); \
|
||||
ILISTI_NODE_CONTRACT(&obj->name); \
|
||||
M_IL1ST_NODE_CONTRACT(&obj->name); \
|
||||
return obj->name.next == &list->name ? NULL : \
|
||||
M_TYPE_FROM_FIELD(type, obj->name.next, \
|
||||
struct ilist_head_s, name); \
|
||||
struct m_ilist_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _previous_obj)(const list_t list, type const *obj) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (obj != NULL); \
|
||||
ILISTI_NODE_CONTRACT(&obj->name); \
|
||||
M_IL1ST_NODE_CONTRACT(&obj->name); \
|
||||
return obj->name.prev == &list->name ? NULL : \
|
||||
M_TYPE_FROM_FIELD(type, obj->name.prev, \
|
||||
struct ilist_head_s, name); \
|
||||
struct m_ilist_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->head = list->name.next->prev; \
|
||||
it->current = list->name.next; \
|
||||
it->next = list->name.next->next; \
|
||||
it->previous = it->head; \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -399,19 +402,19 @@ typedef struct ilist_head_s {
|
||||
it->current = cit->current; \
|
||||
it->next = cit->next; \
|
||||
it->previous = cit->previous; \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, list_t const list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->head = list->name.next->prev; \
|
||||
it->current = list->name.prev; \
|
||||
it->next = it->head; \
|
||||
it->previous = list->name.prev->prev; \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -422,14 +425,14 @@ typedef struct ilist_head_s {
|
||||
it->current = it->head; \
|
||||
it->next = list->name.next; \
|
||||
it->previous = list->name.prev; \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
return it->current == it->head; \
|
||||
} \
|
||||
\
|
||||
@@ -437,7 +440,7 @@ typedef struct ilist_head_s {
|
||||
M_C(name, _last_p)(const it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
return it->next == it->head || it->current == it->head; \
|
||||
} \
|
||||
\
|
||||
@@ -453,7 +456,7 @@ typedef struct ilist_head_s {
|
||||
it->next = it->current->next; \
|
||||
it->previous = it->current->prev; \
|
||||
M_ASSERT (it->next != NULL && it->previous != NULL); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -468,7 +471,7 @@ typedef struct ilist_head_s {
|
||||
it->next = it->current->next; \
|
||||
it->previous = it->current->prev; \
|
||||
M_ASSERT (it->next != NULL && it->previous != NULL); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
@@ -483,13 +486,13 @@ typedef struct ilist_head_s {
|
||||
M_C(name, _ref)(const it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->current != NULL); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
/* check if 'it' was not deleted */ \
|
||||
M_ASSERT (it->current->next == it->next); \
|
||||
M_ASSERT (it->current->prev == it->previous); \
|
||||
M_ASSERT (!M_C(name, _end_p)(it)); \
|
||||
return M_TYPE_FROM_FIELD(type, it->current, \
|
||||
struct ilist_head_s, name); \
|
||||
struct m_ilist_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
@@ -502,11 +505,11 @@ typedef struct ilist_head_s {
|
||||
static inline void \
|
||||
M_C(name, _remove)(list_t list, it_t it) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
(void)list; /* list param is not used */ \
|
||||
type *obj = M_TYPE_FROM_FIELD(type, it->current, \
|
||||
struct ilist_head_s, name); \
|
||||
struct m_ilist_head_s, name); \
|
||||
M_C(name, _unlink)(obj); \
|
||||
M_CALL_CLEAR(oplist, obj); \
|
||||
M_IF_METHOD(DEL, oplist)(M_CALL_DEL(oplist, obj), (void) 0); \
|
||||
@@ -517,8 +520,8 @@ typedef struct ilist_head_s {
|
||||
static inline void \
|
||||
M_C(name, _insert)(list_t list, it_t it, type x) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
type *p = M_CALL_NEW(oplist, type); \
|
||||
if (M_UNLIKELY (p == NULL)) { \
|
||||
M_MEMORY_FULL (sizeof (type)); \
|
||||
@@ -529,14 +532,14 @@ typedef struct ilist_head_s {
|
||||
M_C(name, _push_after)(obj, p); \
|
||||
it->current = p; \
|
||||
(void) list; \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
, /* NEW not defined */) \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _pop_back)(list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (!M_C(name, _empty_p)(list)); \
|
||||
type *obj = M_C(name, _back)(list); \
|
||||
list->name.prev = list->name.prev->prev; \
|
||||
@@ -547,7 +550,7 @@ typedef struct ilist_head_s {
|
||||
static inline type * \
|
||||
M_C(name, _pop_front)(list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (!M_C(name, _empty_p)(list)); \
|
||||
type *obj = M_C(name, _front)(list); \
|
||||
list->name.next = list->name.next->next; \
|
||||
@@ -558,52 +561,52 @@ typedef struct ilist_head_s {
|
||||
static inline void \
|
||||
M_C(name, _splice)(list_t list1, list_t list2) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list1); \
|
||||
ILISTI_CONTRACT(name, list2); \
|
||||
struct ilist_head_s *midle1 = list1->name.prev; \
|
||||
struct ilist_head_s *midle2 = list2->name.next; \
|
||||
M_IL1ST_CONTRACT(name, list1); \
|
||||
M_IL1ST_CONTRACT(name, list2); \
|
||||
struct m_ilist_head_s *midle1 = list1->name.prev; \
|
||||
struct m_ilist_head_s *midle2 = list2->name.next; \
|
||||
midle1->next = midle2; \
|
||||
midle2->prev = midle1; \
|
||||
list1->name.prev = list2->name.prev; \
|
||||
list2->name.prev->next = &list1->name; \
|
||||
list2->name.next = &list2->name; \
|
||||
list2->name.prev = &list2->name; \
|
||||
ILISTI_CONTRACT(name, list1); \
|
||||
ILISTI_CONTRACT(name, list2); \
|
||||
M_IL1ST_CONTRACT(name, list1); \
|
||||
M_IL1ST_CONTRACT(name, list2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice_back)(list_t nv, list_t ov, it_t it) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, nv); \
|
||||
ILISTI_CONTRACT(name, ov); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_CONTRACT(name, nv); \
|
||||
M_IL1ST_CONTRACT(name, ov); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
M_ASSERT (it != NULL); \
|
||||
(void) ov; \
|
||||
type *obj = M_C(name, _ref)(it); \
|
||||
M_C(name, _unlink)(obj); \
|
||||
M_C(name, _push_back)(nv, obj); \
|
||||
M_C(name, _next)(it); \
|
||||
ILISTI_CONTRACT(name, nv); \
|
||||
ILISTI_CONTRACT(name, ov); \
|
||||
M_IL1ST_CONTRACT(name, nv); \
|
||||
M_IL1ST_CONTRACT(name, ov); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice_at)(list_t nlist, it_t npos, \
|
||||
list_t olist, it_t opos) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, nlist); \
|
||||
ILISTI_CONTRACT(name, olist); \
|
||||
M_IL1ST_CONTRACT(name, nlist); \
|
||||
M_IL1ST_CONTRACT(name, olist); \
|
||||
M_ASSERT (npos != NULL && opos != NULL); \
|
||||
M_ASSERT (!M_C(name, _end_p)(opos)); \
|
||||
/* npos may be end */ \
|
||||
(void) olist, (void) nlist; \
|
||||
type *obj = M_C(name, _ref)(opos); \
|
||||
struct ilist_head_s *ref = npos->current; \
|
||||
struct m_ilist_head_s *ref = npos->current; \
|
||||
/* Remove object */ \
|
||||
M_C(name, _unlink)(obj); \
|
||||
/* Push 'obj' after 'ref' */ \
|
||||
struct ilist_head_s *next = ref->next; \
|
||||
struct m_ilist_head_s *next = ref->next; \
|
||||
ref->next = &obj->name; \
|
||||
obj->name.next = next; \
|
||||
obj->name.prev = ref; \
|
||||
@@ -614,17 +617,19 @@ typedef struct ilist_head_s {
|
||||
npos->previous = ref; \
|
||||
npos->current = &obj->name; \
|
||||
npos->next = next; \
|
||||
ILISTI_CONTRACT(name, nlist); \
|
||||
ILISTI_CONTRACT(name, olist); \
|
||||
M_IL1ST_CONTRACT(name, nlist); \
|
||||
M_IL1ST_CONTRACT(name, olist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(list_t d, list_t e) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, d); \
|
||||
ILISTI_CONTRACT(name, e); \
|
||||
struct ilist_head_s *d_item = d->name.next; \
|
||||
struct ilist_head_s *e_item = e->name.next; \
|
||||
M_IL1ST_CONTRACT(name, d); \
|
||||
M_IL1ST_CONTRACT(name, e); \
|
||||
struct m_ilist_head_s *d_item = d->name.next; \
|
||||
struct m_ilist_head_s *e_item = e->name.next; \
|
||||
/* it is more complicated than other swap functions since \
|
||||
we need to detect "cyclic" loop */ \
|
||||
d->name.next = e_item == &e->name ? &d->name : e_item; \
|
||||
e->name.next = d_item == &d->name ? &e->name : d_item; \
|
||||
d_item = d->name.prev; \
|
||||
@@ -635,15 +640,15 @@ typedef struct ilist_head_s {
|
||||
d->name.prev->next = &d->name; \
|
||||
e->name.next->prev = &e->name; \
|
||||
e->name.prev->next = &e->name; \
|
||||
ILISTI_CONTRACT(name, d); \
|
||||
ILISTI_CONTRACT(name, e); \
|
||||
M_IL1ST_CONTRACT(name, d); \
|
||||
M_IL1ST_CONTRACT(name, e); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reverse)(list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
struct ilist_head_s *next, *it; \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
struct m_ilist_head_s *next, *it; \
|
||||
for(it = list->name.next ; it != &list->name; it = next) { \
|
||||
next = it->next; \
|
||||
it->next = it->prev; \
|
||||
@@ -652,11 +657,11 @@ typedef struct ilist_head_s {
|
||||
next = it->next; \
|
||||
it->next = it->prev; \
|
||||
it->prev = next; \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
/* Used of macro from m-list */ \
|
||||
LISTI_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
/* Used of internal macro from m-list */ \
|
||||
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
#endif
|
||||
+22
-19
@@ -33,7 +33,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define the oplist of a intrusive shared pointer.
|
||||
USAGE: ISHARED_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define ISHARED_PTR_OPLIST(...) \
|
||||
ISHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_ISHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
@@ -58,11 +58,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define the intrusive shared pointer type and its static inline functions.
|
||||
USAGE: ISHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define ISHARED_PTR_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
ISHARED_PTR_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define the intrusive shared pointer type and its static inline functions
|
||||
@@ -70,7 +66,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
USAGE: ISHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
|
||||
#define ISHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_ISHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__ , name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -79,23 +75,24 @@ M_BEGIN_PROTECTED_CODE
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
// Deferred evaluation
|
||||
#define ISHAREDI_PTR_OPLIST_P1(arg) ISHAREDI_PTR_OPLIST_P2 arg
|
||||
#define M_ISHAR3D_PTR_OPLIST_P1(arg) M_ISHAR3D_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)
|
||||
#define M_ISHAR3D_PTR_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_ISHAR3D_PTR_OPLIST_P3, M_ISHAR3D_PTR_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define ISHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_ISHAR3D_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_P3(name, oplist) ( \
|
||||
#define M_ISHAR3D_PTR_OPLIST_P3(name, oplist) ( \
|
||||
INIT(M_INIT_DEFAULT), \
|
||||
INIT_SET(API_4(M_C(name, _init_set))), \
|
||||
SET(M_C(name, _set) M_IPTR), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
CLEAN(M_C(name, _clean) M_IPTR), \
|
||||
RESET(M_C(name, _reset) M_IPTR), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
OPLIST(oplist), \
|
||||
SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
@@ -105,17 +102,17 @@ M_BEGIN_PROTECTED_CODE
|
||||
)
|
||||
|
||||
// Deferred evaluatioin
|
||||
#define ISHAREDI_PTR_DEF_P1(arg) ISHAREDI_PTR_DEF_P2 arg
|
||||
#define M_ISHAR3D_PTR_DEF_P1(arg) M_ISHAR3D_PTR_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define ISHAREDI_PTR_DEF_P2(name, type, oplist, shared_t) \
|
||||
M_IF_OPLIST(oplist)(ISHAREDI_PTR_DEF_P3, ISHAREDI_PTR_DEF_FAILURE)(name, type, oplist, shared_t)
|
||||
#define M_ISHAR3D_PTR_DEF_P2(name, type, oplist, shared_t) \
|
||||
M_IF_OPLIST(oplist)(M_ISHAR3D_PTR_DEF_P3, M_ISHAR3D_PTR_DEF_FAILURE)(name, type, oplist, shared_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define ISHAREDI_PTR_DEF_FAILURE(name, type, oplist, shared_t) \
|
||||
#define M_ISHAR3D_PTR_DEF_FAILURE(name, type, oplist, shared_t) \
|
||||
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, shared_t) \
|
||||
#define M_ISHAR3D_PTR_DEF_P3(name, type, oplist, shared_t) \
|
||||
\
|
||||
/* The shared pointer is only a pointer to the type */ \
|
||||
typedef type *shared_t; \
|
||||
@@ -216,12 +213,18 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(shared_t *shared) \
|
||||
M_C(name, _reset)(shared_t *shared) \
|
||||
{ \
|
||||
M_C(name, _clear)(*shared); \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(shared_t *shared) \
|
||||
{ \
|
||||
M_C(name, _reset)(shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(shared_t *ptr, shared_t shared) \
|
||||
{ \
|
||||
|
||||
@@ -30,11 +30,7 @@
|
||||
/* Define a singly linked list of a given type.
|
||||
USAGE: LIST_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define LIST_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
LISTI_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) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
LIST_DEF_AS(name, M_C(name, _t), M_C(name, _it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a singly linked list of a given type
|
||||
@@ -42,7 +38,7 @@
|
||||
USAGE: LIST_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define LIST_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
LISTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_L1ST_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -51,11 +47,7 @@
|
||||
/* Define a singly linked list of a given type allowing both push.
|
||||
USAGE: LIST_DUAL_PUSH_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
|
||||
#define LIST_DUAL_PUSH_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
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) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
LIST_DUAL_PUSH_DEF_AS(name, M_C(name,_t), M_C(name, _it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a singly linked list of a given type allowing both push.
|
||||
@@ -63,7 +55,7 @@
|
||||
USAGE: LIST_DUAL_PUSH_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define LIST_DUAL_PUSH_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
LISTI_DUAL_PUSH_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_L1ST_DUAL_PUSH_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -72,35 +64,51 @@
|
||||
/* Define the oplist of a list of the given type.
|
||||
USAGE: LIST_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define LIST_OPLIST(...) \
|
||||
LISTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_L1ST_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
/* Define an init value to init global variables of type list.
|
||||
USAGE:
|
||||
list_t global_variable = LIST_INIT_VALUE();
|
||||
*/
|
||||
#define LIST_INIT_VALUE() \
|
||||
{ NULL }
|
||||
|
||||
|
||||
/* Define an init value to init global variables of type dual push list.
|
||||
USAGE:
|
||||
list_t global_variable = LIST_DUAL_PUSH_INIT_VALUE();
|
||||
*/
|
||||
#define LIST_DUAL_PUSH_INIT_VALUE() \
|
||||
{ { NULL, NULL } }
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Deferred evaluation for the oplist definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define LISTI_OPLIST_P1(arg) LISTI_OPLIST_P2 arg
|
||||
#define M_L1ST_OPLIST_P1(arg) M_L1ST_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)
|
||||
#define M_L1ST_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_L1ST_OPLIST_P3, M_L1ST_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define LISTI_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_L1ST_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_P3(name, oplist) \
|
||||
#define M_L1ST_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
INIT_WITH(API_1(M_INIT_VAI)), \
|
||||
INIT_WITH(API_1(M_INIT_WITH_VAI)), \
|
||||
SET(M_C(name, _set)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
SWAP(M_C(name, _swap)), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
SUBTYPE(M_C(name,_subtype_ct)), \
|
||||
EMPTY_P(M_C(name,_empty_p)), \
|
||||
@@ -116,7 +124,7 @@
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
IT_INSERT(M_C(name, _insert)), \
|
||||
IT_REMOVE(M_C(name,_remove)), \
|
||||
CLEAN(M_C(name,_clean)), \
|
||||
RESET(M_C(name,_reset)), \
|
||||
PUSH(M_C(name,_push_back)), \
|
||||
POP(M_C(name,_pop_back)), \
|
||||
PUSH_MOVE(M_C(name,_push_move)), \
|
||||
@@ -140,35 +148,35 @@
|
||||
|
||||
/* Deferred evaluation for the list definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define LISTI_DEF_P1(arg) LISTI_DEF_P2 arg
|
||||
#define M_L1ST_DEF_P1(arg) M_L1ST_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)
|
||||
#define M_L1ST_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(M_L1ST_DEF_P3, M_L1ST_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) \
|
||||
#define M_L1ST_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) \
|
||||
#define M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, list_it_t) \
|
||||
M_IF_METHOD(MEMPOOL, oplist)( \
|
||||
\
|
||||
MEMPOOL_DEF(M_C(name, _mempool), struct M_C(name, _s)) \
|
||||
M_GET_MEMPOOL_LINKAGE oplist M_C(name, _mempool_t) M_GET_MEMPOOL oplist; \
|
||||
static inline struct M_C(name, _s) *M_C(name, _int_new)(void) { \
|
||||
static inline struct M_C(name, _s) *M_C3(m_l1st_,name,_new)(void) { \
|
||||
return M_C(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \
|
||||
} \
|
||||
static inline void M_C(name,_int_del)(struct M_C(name, _s) *ptr) { \
|
||||
static inline void M_C3(m_l1st_,name,_del)(struct M_C(name, _s) *ptr) { \
|
||||
M_C(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \
|
||||
} \
|
||||
\
|
||||
, /* No mempool allocation */ \
|
||||
\
|
||||
static inline struct M_C(name, _s) *M_C(name, _int_new)(void) { \
|
||||
static inline struct M_C(name, _s) *M_C3(m_l1st_,name,_new)(void) { \
|
||||
return M_CALL_NEW(oplist, struct M_C(name, _s)); \
|
||||
} \
|
||||
static inline void M_C(name,_int_del)(struct M_C(name, _s) *ptr) { \
|
||||
static inline void M_C3(m_l1st_,name,_del)(struct M_C(name, _s) *ptr) { \
|
||||
M_CALL_DEL(oplist, ptr); \
|
||||
} \
|
||||
) \
|
||||
@@ -182,7 +190,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_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
#define M_L1ST_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
/* Define the node of a list, and the list as a pointer to a node */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
@@ -205,14 +213,14 @@
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
LISTI_MEMPOOL_DEF(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)
|
||||
M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
/* Define the internal contract of a list
|
||||
(there is nothing worthy to be checked) */
|
||||
#define LISTI_CONTRACT(v) do { \
|
||||
#define M_L1ST_CONTRACT(v) do { \
|
||||
M_ASSERT (v != NULL); \
|
||||
} while (0)
|
||||
|
||||
@@ -224,7 +232,7 @@
|
||||
- list_t: alias for type of the container
|
||||
- it_t: alias for iterator of the container
|
||||
*/
|
||||
#define LISTI_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
#define M_L1ST_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(list_t v) \
|
||||
@@ -234,40 +242,46 @@
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(list_t v) \
|
||||
M_C(name, _reset)(list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
struct M_C(name, _s) *it = *v; \
|
||||
*v = NULL; \
|
||||
while (it != NULL) { \
|
||||
struct M_C(name, _s) *next = it->next; \
|
||||
M_CALL_CLEAR(oplist, it->data); \
|
||||
M_C(name,_int_del)(it); \
|
||||
M_C3(m_l1st_,name,_del)(it); \
|
||||
it = next; \
|
||||
} \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(list_t v) \
|
||||
{ \
|
||||
M_C(name, _reset)(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(list_t v) \
|
||||
{ \
|
||||
M_C(name, _clean)(v); \
|
||||
M_C(name, _reset)(v); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
static inline type * \
|
||||
M_C(name, _back)(const list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
M_ASSERT(*v != NULL); \
|
||||
return M_CONST_CAST(type, &((*v)->data)); \
|
||||
return &((*v)->data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_raw)(list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next; \
|
||||
next = M_C(name, _int_new)(); \
|
||||
next = M_C3(m_l1st_,name,_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return NULL; \
|
||||
@@ -275,7 +289,7 @@
|
||||
type *ret = &next->data; \
|
||||
next->next = *v; \
|
||||
*v = next; \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
@@ -303,7 +317,7 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_back)(type *data, list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
M_ASSERT(*v != NULL); \
|
||||
if (data != NULL) { \
|
||||
M_DO_MOVE (oplist, *data, (*v)->data); \
|
||||
@@ -312,8 +326,8 @@
|
||||
} \
|
||||
struct M_C(name, _s) *tofree = *v; \
|
||||
*v = (*v)->next; \
|
||||
M_C(name,_int_del)(tofree); \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_C3(m_l1st_,name,_del)(tofree); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -329,38 +343,36 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_move)(type *data, list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
M_ASSERT(*v != NULL && data != NULL); \
|
||||
M_DO_INIT_MOVE (oplist, *data, (*v)->data); \
|
||||
struct M_C(name, _s) *tofree = *v; \
|
||||
*v = (*v)->next; \
|
||||
M_C(name,_int_del)(tofree); \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_C3(m_l1st_,name,_del)(tofree); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
return *v == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(list_t l, list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(l); \
|
||||
LISTI_CONTRACT(v); \
|
||||
struct M_C(name, _s) *tmp = *l; \
|
||||
*l = *v; \
|
||||
*v = tmp; \
|
||||
LISTI_CONTRACT(l); \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(l); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
M_SWAP(struct M_C(name, _s) *, *l, *v); \
|
||||
M_L1ST_CONTRACT(l); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->current = *v; \
|
||||
it->previous = NULL; \
|
||||
@@ -377,7 +389,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it1, const list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
M_ASSERT (it1 != NULL); \
|
||||
(void)v; /* unused */ \
|
||||
it1->current = NULL; \
|
||||
@@ -430,7 +442,7 @@
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const list_t list) \
|
||||
{ \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
size_t size = 0; \
|
||||
struct M_C(name, _s) *it = *list; \
|
||||
while (it != NULL) { \
|
||||
@@ -443,7 +455,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _sublist_p)(const list_t list, const it_t itsub) \
|
||||
{ \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
M_ASSERT (itsub != NULL); \
|
||||
struct M_C(name, _s) *it = *list; \
|
||||
while (it != NULL) { \
|
||||
@@ -457,7 +469,7 @@
|
||||
static inline type * \
|
||||
M_C(name, _get)(const list_t list, size_t i) \
|
||||
{ \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
struct M_C(name, _s) *it = *list; \
|
||||
/* FIXME: How to avoid the double iteration over the list? */ \
|
||||
size_t len = M_C(name,_size)(list); \
|
||||
@@ -481,10 +493,10 @@
|
||||
M_C(name, _insert)(list_t list, it_t insertion_point, \
|
||||
type const x) \
|
||||
{ \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
M_ASSERT (insertion_point != NULL); \
|
||||
M_ASSERT(M_C(name, _sublist_p)(list, insertion_point)); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
struct M_C(name, _s) *next = M_C3(m_l1st_,name,_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return; \
|
||||
@@ -500,13 +512,13 @@
|
||||
} \
|
||||
/* Update insertion_point to this element */ \
|
||||
insertion_point->current = next; \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _remove)(list_t list, it_t removing_point) \
|
||||
{ \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
M_ASSERT (removing_point != NULL); \
|
||||
M_ASSERT (removing_point->current != NULL); \
|
||||
M_ASSERT(M_C(name, _sublist_p)(list, removing_point)); \
|
||||
@@ -517,21 +529,21 @@
|
||||
removing_point->previous->next = next; \
|
||||
} \
|
||||
M_CALL_CLEAR(oplist, removing_point->current->data); \
|
||||
M_C(name,_int_del) (removing_point->current); \
|
||||
M_C3(m_l1st_,name,_del) (removing_point->current); \
|
||||
removing_point->current = next; \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(list_t list, const list_t org) \
|
||||
{ \
|
||||
LISTI_CONTRACT(org); \
|
||||
M_L1ST_CONTRACT(org); \
|
||||
struct M_C(name, _s) *next, *it_org; \
|
||||
struct M_C(name, _s) **update_list; \
|
||||
update_list = list; \
|
||||
it_org = *org; \
|
||||
while (it_org != NULL) { \
|
||||
next = M_C(name, _int_new)(); \
|
||||
next = M_C3(m_l1st_,name,_new)(); \
|
||||
*update_list = next; \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
@@ -543,7 +555,7 @@
|
||||
it_org = it_org->next; \
|
||||
} \
|
||||
*update_list = NULL; \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -557,7 +569,7 @@
|
||||
static inline void \
|
||||
M_C(name, _init_move)(list_t list, list_t org) \
|
||||
{ \
|
||||
LISTI_CONTRACT(org); \
|
||||
M_L1ST_CONTRACT(org); \
|
||||
M_ASSERT (list != NULL && list != org); \
|
||||
*list = *org; \
|
||||
*org = NULL; /* safer */ \
|
||||
@@ -574,8 +586,8 @@
|
||||
static inline void \
|
||||
M_C(name, _splice_back)(list_t nv, list_t ov, it_t it) \
|
||||
{ \
|
||||
LISTI_CONTRACT(nv); \
|
||||
LISTI_CONTRACT(ov); \
|
||||
M_L1ST_CONTRACT(nv); \
|
||||
M_L1ST_CONTRACT(ov); \
|
||||
M_ASSERT (it != NULL); \
|
||||
M_ASSERT (it->current != NULL); \
|
||||
M_ASSERT (M_C(name, _sublist_p)(ov, it)); \
|
||||
@@ -599,8 +611,8 @@
|
||||
M_C(name, _splice_at)(list_t nlist, it_t npos, \
|
||||
list_t olist, it_t opos) \
|
||||
{ \
|
||||
LISTI_CONTRACT(nlist); \
|
||||
LISTI_CONTRACT(olist); \
|
||||
M_L1ST_CONTRACT(nlist); \
|
||||
M_L1ST_CONTRACT(olist); \
|
||||
M_ASSERT (npos != NULL); \
|
||||
M_ASSERT (opos != NULL); \
|
||||
M_ASSERT (M_C(name, _sublist_p)(nlist, npos)); \
|
||||
@@ -627,15 +639,15 @@
|
||||
/* Update 'npos' to point to the new current element */ \
|
||||
npos->previous = npos->current; \
|
||||
npos->current = current; \
|
||||
LISTI_CONTRACT(nlist); \
|
||||
LISTI_CONTRACT(olist); \
|
||||
M_L1ST_CONTRACT(nlist); \
|
||||
M_L1ST_CONTRACT(olist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice)(list_t list1, list_t list2) \
|
||||
{ \
|
||||
LISTI_CONTRACT(list1); \
|
||||
LISTI_CONTRACT(list2); \
|
||||
M_L1ST_CONTRACT(list1); \
|
||||
M_L1ST_CONTRACT(list2); \
|
||||
M_ASSERT (list1 != list2); \
|
||||
struct M_C(name, _s) **update_list = list1; \
|
||||
struct M_C(name, _s) *it = *list1; \
|
||||
@@ -650,7 +662,7 @@
|
||||
static inline void \
|
||||
M_C(name, _reverse)(list_t list) \
|
||||
{ \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
struct M_C(name, _s) *previous = NULL, *it = *list, *next; \
|
||||
while (it != NULL) { \
|
||||
next = it->next; \
|
||||
@@ -672,7 +684,7 @@
|
||||
- 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 ]
|
||||
*/
|
||||
#define LISTI_ITBASE_DEF(name, type, oplist, list_t, it_t) \
|
||||
#define M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
@@ -718,7 +730,7 @@
|
||||
M_C(name, _parse_str)(list_t list, const char str[], const char **endp) \
|
||||
{ \
|
||||
M_ASSERT (str != NULL && list != NULL); \
|
||||
M_C(name,_clean)(list); \
|
||||
M_C(name,_reset)(list); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
@@ -749,7 +761,7 @@
|
||||
M_C(name, _in_str)(list_t list, FILE *file) \
|
||||
{ \
|
||||
M_ASSERT (file != NULL && list != NULL); \
|
||||
M_C(name,_clean)(list); \
|
||||
M_C(name,_reset)(list); \
|
||||
int c = fgetc(file); \
|
||||
if (M_UNLIKELY (c != '[')) return false; \
|
||||
c = fgetc(file); \
|
||||
@@ -804,7 +816,7 @@
|
||||
m_serial_return_code_t ret; \
|
||||
m_serial_local_t local; \
|
||||
size_t estimated_size = 0; \
|
||||
M_C(name,_clean)(list); \
|
||||
M_C(name,_reset)(list); \
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
|
||||
type item; \
|
||||
@@ -866,14 +878,14 @@
|
||||
|
||||
/* Deferred evaluation for the dual-push list definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define LISTI_DUAL_PUSH_DEF_P1(arg) LISTI_DUAL_PUSH_DEF_P2 arg
|
||||
#define M_L1ST_DUAL_PUSH_DEF_P1(arg) M_L1ST_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)
|
||||
#define M_L1ST_DUAL_PUSH_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(M_L1ST_DUAL_PUSH_DEF_P3, M_L1ST_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) \
|
||||
#define M_L1ST_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
|
||||
@@ -883,7 +895,7 @@
|
||||
- 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 ]
|
||||
*/
|
||||
#define LISTI_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
#define M_L1ST_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
/* Node of a list (it is liked the singly linked list) */ \
|
||||
struct M_C(name, _s) { \
|
||||
@@ -916,13 +928,13 @@
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
LISTI_MEMPOOL_DEF(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)
|
||||
M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_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 { \
|
||||
#define M_L1ST_DUAL_PUSH_CONTRACT(l) do { \
|
||||
M_ASSERT (l != NULL); \
|
||||
M_ASSERT ( (l->back == NULL && l->front == NULL) \
|
||||
|| (l->back != NULL && l->front != NULL)); \
|
||||
@@ -935,7 +947,7 @@
|
||||
- list_t: alias for type of the container
|
||||
- it_t: alias for iterator of the container
|
||||
*/
|
||||
#define LISTI_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
#define M_L1ST_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(list_t v) \
|
||||
@@ -943,44 +955,50 @@
|
||||
M_ASSERT( v != NULL); \
|
||||
v->front = NULL; \
|
||||
v->back = NULL; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(list_t v) \
|
||||
M_C(name, _reset)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *it = v->back; \
|
||||
while (it != NULL) { \
|
||||
struct M_C(name, _s) *next = it->next; \
|
||||
M_CALL_CLEAR(oplist, it->data); \
|
||||
M_C(name,_int_del)(it); \
|
||||
M_C3(m_l1st_,name,_del)(it); \
|
||||
it = next; \
|
||||
} \
|
||||
v->front = NULL; \
|
||||
v->back = NULL; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(list_t v) \
|
||||
{ \
|
||||
M_C(name, _reset)(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(list_t v) \
|
||||
{ \
|
||||
M_C(name, _clean)(v); \
|
||||
M_C(name, _reset)(v); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
static inline type * \
|
||||
M_C(name, _back)(const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
M_ASSERT (v->back != NULL); \
|
||||
return M_CONST_CAST(type, &(v->back->data)); \
|
||||
return &(v->back->data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_back_raw)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next = M_C3(m_l1st_,name,_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return NULL; \
|
||||
@@ -993,10 +1011,17 @@
|
||||
struct M_C(name, _s) *front = v->front; \
|
||||
front = (front == NULL) ? next : front; \
|
||||
v->front = front; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
/* Internal, for INIT_WITH */ \
|
||||
static inline type * \
|
||||
M_C(name, _push_raw)(list_t d) \
|
||||
{ \
|
||||
return M_C(name, _push_back_raw)(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push_back)(list_t v, type const x) \
|
||||
{ \
|
||||
@@ -1037,7 +1062,7 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_back)(type *data, list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
M_ASSERT (v->back != NULL); \
|
||||
struct M_C(name, _s) *tofree = v->back; \
|
||||
if (data != NULL) { \
|
||||
@@ -1046,46 +1071,46 @@
|
||||
M_CALL_CLEAR(oplist, tofree->data); \
|
||||
} \
|
||||
v->back = tofree->next; \
|
||||
M_C(name,_int_del)(tofree); \
|
||||
M_C3(m_l1st_,name,_del)(tofree); \
|
||||
/* Update front too if the list became empty */ \
|
||||
/* This C code shall generate branchless code */ \
|
||||
struct M_C(name, _s) *front = v->front; \
|
||||
front = (front == tofree) ? NULL : front; \
|
||||
v->front = front; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _pop_move)(type *data, list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
M_ASSERT (v->back != NULL); \
|
||||
M_ASSERT (data != NULL); \
|
||||
struct M_C(name, _s) *tofree = v->back; \
|
||||
M_DO_INIT_MOVE (oplist, *data, tofree->data); \
|
||||
v->back = tofree->next; \
|
||||
M_C(name,_int_del)(tofree); \
|
||||
M_C3(m_l1st_,name,_del)(tofree); \
|
||||
/* Update front too if the list became empty */ \
|
||||
/* This C code shall generate branchless code */ \
|
||||
struct M_C(name, _s) *front = v->front; \
|
||||
front = (front == tofree) ? NULL : front; \
|
||||
v->front = front; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
static inline type * \
|
||||
M_C(name, _front)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
M_ASSERT (v->front != NULL); \
|
||||
return M_CONST_CAST(type, &(v->front->data)); \
|
||||
return &(v->front->data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_front_raw)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next = M_C3(m_l1st_,name,_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return NULL; \
|
||||
@@ -1099,7 +1124,7 @@
|
||||
v->back = next; \
|
||||
} \
|
||||
v->front = next; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
@@ -1137,15 +1162,15 @@
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
return v->back == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(list_t l, list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(l); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(l); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
M_SWAP(struct M_C(name, _s) *, l->front, v->front); \
|
||||
M_SWAP(struct M_C(name, _s) *, l->back, v->back); \
|
||||
} \
|
||||
@@ -1153,7 +1178,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->current = v->back; \
|
||||
it->previous = NULL; \
|
||||
@@ -1171,7 +1196,7 @@
|
||||
M_C(name, _it_end)(it_t it1, const list_t v) \
|
||||
{ \
|
||||
M_ASSERT (it1 != NULL); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
(void)v; /* unused */ \
|
||||
it1->current = NULL; \
|
||||
it1->previous = NULL; \
|
||||
@@ -1223,7 +1248,7 @@
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
size_t size = 0; \
|
||||
struct M_C(name, _s) *it = v->back; \
|
||||
while (it != NULL) { \
|
||||
@@ -1237,9 +1262,9 @@
|
||||
M_C(name, _insert)(list_t list, it_t insertion_point, \
|
||||
type const x) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
M_ASSERT (insertion_point != NULL); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
struct M_C(name, _s) *next = M_C3(m_l1st_,name,_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return; \
|
||||
@@ -1265,7 +1290,7 @@
|
||||
static inline void \
|
||||
M_C(name, _remove)(list_t list, it_t removing_point) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
M_ASSERT (removing_point != NULL); \
|
||||
M_ASSERT(removing_point->current != NULL); \
|
||||
struct M_C(name, _s) *next = removing_point->current->next; \
|
||||
@@ -1281,24 +1306,24 @@
|
||||
list->front = front; \
|
||||
/* Remove node */ \
|
||||
M_CALL_CLEAR(oplist, removing_point->current->data); \
|
||||
M_C(name,_int_del) (removing_point->current); \
|
||||
M_C3(m_l1st_,name,_del) (removing_point->current); \
|
||||
removing_point->current = next; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(list_t list, const list_t org) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(org); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(org); \
|
||||
struct M_C(name, _s) *next = NULL; \
|
||||
struct M_C(name, _s) *it_org; \
|
||||
struct M_C(name, _s) **update_list; \
|
||||
if (M_UNLIKELY (list == org)) return; \
|
||||
M_C(name, _clean)(list); \
|
||||
M_C(name, _reset)(list); \
|
||||
update_list = &list->back; \
|
||||
it_org = org->back; \
|
||||
while (it_org != NULL) { \
|
||||
next = M_C(name, _int_new)(); \
|
||||
next = M_C3(m_l1st_,name,_new)(); \
|
||||
*update_list = next; \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
@@ -1340,8 +1365,8 @@
|
||||
static inline void \
|
||||
M_C(name, _splice_back)(list_t list1, list_t list2, it_t it) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list1); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list2); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list1); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list2); \
|
||||
M_ASSERT (it->current != NULL); \
|
||||
/* First remove the item 'it' from the list 'list2' */ \
|
||||
struct M_C(name, _s) *current = it->current; \
|
||||
@@ -1365,16 +1390,16 @@
|
||||
front = list1->front; \
|
||||
front = (front == NULL) ? current : front; \
|
||||
list1->front = front; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list1); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list2); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list1); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice_at)(list_t nlist, it_t npos, \
|
||||
list_t olist, it_t opos) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(nlist); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(olist); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(nlist); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(olist); \
|
||||
M_ASSERT (npos != NULL && opos != NULL); \
|
||||
/* First remove the item 'opos' from the list 'olist' */ \
|
||||
struct M_C(name, _s) *current = opos->current; \
|
||||
@@ -1411,15 +1436,15 @@
|
||||
/* Update 'npos' to point to 'current'. */ \
|
||||
npos->previous = npos_current; \
|
||||
npos->current = current; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(nlist); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(olist); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(nlist); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(olist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice)(list_t list1, list_t list2) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list1); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list2); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list1); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list2); \
|
||||
M_ASSERT (list1 != list2); \
|
||||
if (M_LIKELY (list1->front != NULL)) { \
|
||||
list1->front->next = list2->back; \
|
||||
@@ -1431,14 +1456,14 @@
|
||||
} \
|
||||
list2->back = NULL; \
|
||||
list2->front = NULL; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list1); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list2); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list1); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reverse)(list_t list) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
list->front = list->back; \
|
||||
struct M_C(name, _s) *previous = NULL, *it = list->back, *next; \
|
||||
while (it != NULL) { \
|
||||
@@ -1448,7 +1473,7 @@
|
||||
it = next; \
|
||||
} \
|
||||
list->back = previous; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
} \
|
||||
|
||||
#endif
|
||||
+15
-17
@@ -40,9 +40,7 @@
|
||||
NOTE: Can not use m-list since it may be expanded from LIST_DEF
|
||||
*/
|
||||
#define MEMPOOL_DEF(name, type) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
MEMPOOL_DEF_P2(name, type, M_C(name, _t) ) \
|
||||
M_END_PROTECTED_CODE
|
||||
MEMPOOL_DEF_AS(name, M_C(name,_t), type)
|
||||
|
||||
|
||||
/* Fast Fixed Size thread unsafe allocator based on memory region.
|
||||
@@ -51,7 +49,7 @@
|
||||
*/
|
||||
#define MEMPOOL_DEF_AS(name, name_t, type) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
MEMPOOL_DEF_P2(name, type, name_t ) \
|
||||
M_M3MPOOL_DEF_P2(name, type, name_t ) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
@@ -59,15 +57,15 @@
|
||||
the minimun number of elements.
|
||||
The default is the number of elements that fits in 16KB.
|
||||
*/
|
||||
#ifndef MEMPOOL_MAX_PER_SEGMENT
|
||||
#define MEMPOOL_MAX_PER_SEGMENT(type) \
|
||||
#ifndef M_USE_MEMPOOL_MAX_PER_SEGMENT
|
||||
#define M_USE_MEMPOOL_MAX_PER_SEGMENT(type) \
|
||||
M_MAX((16*1024-sizeof(unsigned int) - 2*sizeof(void*)) / sizeof (type), 256U)
|
||||
#endif
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
#define MEMPOOL_DEF_P2(name, type, name_t) \
|
||||
#define M_M3MPOOL_DEF_P2(name, type, name_t) \
|
||||
\
|
||||
/* Define the type of element in a segment of the mempool. \
|
||||
Either it is the basic type or a pointer to another one. */ \
|
||||
@@ -81,7 +79,7 @@
|
||||
typedef struct M_C(name,_segment_s) { \
|
||||
unsigned int count; \
|
||||
struct M_C(name,_segment_s) *next; \
|
||||
M_C(name,_union_ct) tab[MEMPOOL_MAX_PER_SEGMENT(type)]; \
|
||||
M_C(name,_union_ct) tab[M_USE_MEMPOOL_MAX_PER_SEGMENT(type)]; \
|
||||
} M_C(name,_segment_ct); \
|
||||
\
|
||||
/* Define a mempool. \
|
||||
@@ -103,13 +101,13 @@
|
||||
} \
|
||||
mem->current_segment->next = NULL; \
|
||||
mem->current_segment->count = 0; \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_clear)(name_t mem) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
M_C(name,_segment_ct) *segment = mem->current_segment; \
|
||||
while (segment != NULL) { \
|
||||
M_C(name,_segment_ct) *next = segment->next; \
|
||||
@@ -124,7 +122,7 @@
|
||||
static inline type * \
|
||||
M_C(name,_alloc)(name_t mem) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
/* Test if one object is in the free list */ \
|
||||
M_C(name,_union_ct) *ret = mem->free_list; \
|
||||
if (ret != NULL) { \
|
||||
@@ -137,7 +135,7 @@
|
||||
M_ASSERT(segment != NULL); \
|
||||
unsigned int count = segment->count; \
|
||||
/* If segment is full, allocate a new one from the system */ \
|
||||
if (M_UNLIKELY (count >= MEMPOOL_MAX_PER_SEGMENT(type))) { \
|
||||
if (M_UNLIKELY (count >= M_USE_MEMPOOL_MAX_PER_SEGMENT(type))) { \
|
||||
M_C(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (M_C(name,_segment_ct)); \
|
||||
if (M_UNLIKELY (new_segment == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (M_C(name,_segment_ct))); \
|
||||
@@ -152,14 +150,14 @@
|
||||
/* Return the object as the last element of the current segment */ \
|
||||
ret = &segment->tab[count]; \
|
||||
segment->count = count + 1; \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
return &ret->t; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_free)(name_t mem, type *ptr) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
/* NOTE: Unsafe cast: suppose that the given pointer \
|
||||
was allocated by the previous alloc function. */ \
|
||||
M_C(name,_union_ct) *ret = (M_C(name,_union_ct) *)(uintptr_t)ptr; \
|
||||
@@ -168,14 +166,14 @@
|
||||
mem->free_list = ret; \
|
||||
/* NOTE: the objects are NOT given back to the system until the mempool \
|
||||
is fully cleared */ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
} \
|
||||
|
||||
/* MEMPOOL contract */
|
||||
#define MEMPOOLI_CONTRACT(mempool, type) do { \
|
||||
#define M_M3MPOOL_CONTRACT(mempool, type) do { \
|
||||
M_ASSERT((mempool) != NULL); \
|
||||
M_ASSERT((mempool)->current_segment != NULL); \
|
||||
M_ASSERT((mempool)->current_segment->count <= MEMPOOL_MAX_PER_SEGMENT(type)); \
|
||||
M_ASSERT((mempool)->current_segment->count <= M_USE_MEMPOOL_MAX_PER_SEGMENT(type)); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
+22
-19
@@ -33,11 +33,7 @@
|
||||
/* Define a prioqueue of a given type and its associated functions.
|
||||
USAGE: PRIOQUEUE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define PRIOQUEUE_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
PRIOQUEUEI_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)))) \
|
||||
M_END_PROTECTED_CODE
|
||||
PRIOQUEUE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a prioqueue of a given type and its associated functions.
|
||||
@@ -45,7 +41,7 @@
|
||||
USAGE: PRIOQUEUE_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define PRIOQUEUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
PRIOQUEUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_PR1OQUEUE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -54,7 +50,7 @@
|
||||
/* Define the oplist of a prioqueue of type.
|
||||
USAGE: PRIOQUEUE_OPLIST(name[, oplist of the type]) */
|
||||
#define PRIOQUEUE_OPLIST(...) \
|
||||
PRIOQUEUEI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_PR1OQUEUE_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
@@ -64,18 +60,18 @@
|
||||
|
||||
/* Deferred evaluation for the definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define PRIOQUEUEI_OPLIST_P1(arg) PRIOQUEUEI_OPLIST_P2 arg
|
||||
#define M_PR1OQUEUE_OPLIST_P1(arg) M_PR1OQUEUE_OPLIST_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)
|
||||
#define M_PR1OQUEUE_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_PR1OQUEUE_OPLIST_P3, M_PR1OQUEUE_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define PRIOQUEUEI_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_PR1OQUEUE_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_P3(name, oplist) \
|
||||
#define M_PR1OQUEUE_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
@@ -84,9 +80,10 @@
|
||||
,INIT_MOVE(M_C(name, _init_move)) \
|
||||
,MOVE(M_C(name, _move)) \
|
||||
,SWAP(M_C(name, _swap)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_C(name,_ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,CLEAN(M_C(name,_clean)) \
|
||||
,RESET(M_C(name,_reset)) \
|
||||
,PUSH(M_C(name,_push)) \
|
||||
,POP(M_C(name,_pop)) \
|
||||
,OPLIST(oplist) \
|
||||
@@ -106,14 +103,14 @@
|
||||
|
||||
/* Deferred evaluation for the definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define PRIOQUEUEI_DEF_P1(arg) PRIOQUEUEI_DEF_P2 arg
|
||||
#define M_PR1OQUEUE_DEF_P1(arg) M_PR1OQUEUE_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)
|
||||
#define M_PR1OQUEUE_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(M_PR1OQUEUE_DEF_P3, M_PR1OQUEUE_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) \
|
||||
#define M_PR1OQUEUE_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:
|
||||
@@ -123,7 +120,7 @@
|
||||
- prioqueue_t: type of the container,
|
||||
- it_t: iterator of the container
|
||||
*/
|
||||
#define PRIOQUEUEI_DEF_P3(name, type, oplist, prioqueue_t, it_t) \
|
||||
#define M_PR1OQUEUE_DEF_P3(name, type, oplist, prioqueue_t, it_t) \
|
||||
\
|
||||
/* Definition of the internal array used to construct the priority queue */ \
|
||||
ARRAY_DEF(M_C(name, _array), type, oplist) \
|
||||
@@ -189,9 +186,15 @@
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reset)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_reset)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_clean)(p->array); \
|
||||
M_C(name,_reset)(p); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
|
||||
+236
-211
File diff suppressed because it is too large.
Load diff
+6
-4
@@ -345,7 +345,8 @@ static inline void m_serial_bin_write_clear(m_serial_write_t serial)
|
||||
/* Define a synonym of m_serial_read_t to the BIN serializer with its proper OPLIST */
|
||||
typedef m_serial_write_t m_serial_bin_write_t;
|
||||
#define M_OPL_m_serial_bin_write_t() \
|
||||
(INIT_WITH(m_serial_bin_write_init), CLEAR(m_serial_bin_write_clear), TYPE(m_serial_bin_write_t) )
|
||||
(INIT_WITH(m_serial_bin_write_init), CLEAR(m_serial_bin_write_clear), \
|
||||
TYPE(m_serial_bin_write_t), PROPERTIES(( LET_AS_INIT_WITH(1) )) )
|
||||
|
||||
|
||||
/* Read from the stream 'serial' a boolean.
|
||||
@@ -429,8 +430,8 @@ m_serial_bin_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
size_t length;
|
||||
if (m_serial_bin_read_size(f, &length) != true) return m_core_serial_fail();
|
||||
// Use of internal string interface to dimension the string
|
||||
char *p = stringi_fit2size(s, length + 1);
|
||||
stringi_set_size(s, length);
|
||||
char *p = m_str1ng_fit2size(s, length + 1);
|
||||
m_str1ng_set_size(s, length);
|
||||
// Read the characters excluding the final null one.
|
||||
// NOTE: fread supports length == 0.
|
||||
size_t n = fread(M_ASSIGN_CAST(void*, p), 1, length, f);
|
||||
@@ -586,7 +587,8 @@ static inline void m_serial_bin_read_clear(m_serial_read_t serial)
|
||||
/* Define a synonym of m_serial_read_t to the BIN serializer with its proper OPLIST */
|
||||
typedef m_serial_read_t m_serial_bin_read_t;
|
||||
#define M_OPL_m_serial_bin_read_t() \
|
||||
(INIT_WITH(m_serial_bin_read_init), CLEAR(m_serial_bin_read_clear), TYPE(m_serial_bin_read_t) )
|
||||
(INIT_WITH(m_serial_bin_read_init), CLEAR(m_serial_bin_read_clear), \
|
||||
TYPE(m_serial_bin_read_t), PROPERTIES(( LET_AS_INIT_WITH(1) )) )
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
+627
-11
@@ -30,6 +30,10 @@
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/********************************************************************************/
|
||||
/*************************** FILE / WRITE / JSON ********************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/* Write the boolean 'data' into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
@@ -236,7 +240,8 @@ m_serial_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* The internal exported interface of m_serial_write_json. */
|
||||
/* The internal exported interface of m_serial_write_json
|
||||
If it is not used, it will be optimized away by the compiler. */
|
||||
static const m_serial_write_interface_t m_serial_write_json_interface = {
|
||||
m_serial_json_write_boolean,
|
||||
m_serial_json_write_integer,
|
||||
@@ -272,10 +277,16 @@ static inline void m_serial_json_write_clear(m_serial_write_t serial)
|
||||
/* 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) )
|
||||
(INIT_WITH(m_serial_json_write_init), CLEAR(m_serial_json_write_clear), \
|
||||
TYPE(m_serial_json_write_t), PROPERTIES(( LET_AS_INIT_WITH(1) )) )
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/*************************** FILE / READ / JSON ********************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/* Helper function to skip a space */
|
||||
static inline int
|
||||
m_serial_json_read_skip (FILE *f)
|
||||
@@ -367,7 +378,7 @@ m_serial_json_read_array_start(m_serial_local_t local, m_serial_read_t serial, s
|
||||
(void) n; // Unused. Parsing is checked through c (more robust)
|
||||
*num = 0; // don't know the size of the array.
|
||||
// Test how much the parsing succeed.
|
||||
if (final1 < 0) m_core_serial_fail();
|
||||
if (final1 < 0) return m_core_serial_fail();
|
||||
return (final2 < 0) ? M_SERIAL_OK_CONTINUE : M_SERIAL_OK_DONE;
|
||||
}
|
||||
|
||||
@@ -403,7 +414,7 @@ m_serial_json_read_map_start(m_serial_local_t local, m_serial_read_t serial, siz
|
||||
(void) n; // Unused. Parsing is checked through final (more robust)
|
||||
*num = 0; // don't know the size of the map.
|
||||
// Test how much the parsing succeed.
|
||||
if (final1 < 0) m_core_serial_fail();
|
||||
if (final1 < 0) return m_core_serial_fail();
|
||||
return (final2 < 0) ? M_SERIAL_OK_CONTINUE : M_SERIAL_OK_DONE;
|
||||
}
|
||||
|
||||
@@ -473,9 +484,9 @@ m_serial_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, cons
|
||||
}
|
||||
/* Read the field in the JSON */
|
||||
c = -1;
|
||||
char field[M_MAX_IDENTIFIER_LENGTH+1];
|
||||
int nn = m_core_fscanf(f, " \"%" M_APPLY(M_AS_STR, M_MAX_IDENTIFIER_LENGTH) "[^ \t\n\"]\":%n",
|
||||
m_core_arg_size(field, M_MAX_IDENTIFIER_LENGTH+1), &c);
|
||||
char field[M_USE_IDENTIFIER_ALLOC+1];
|
||||
int nn = m_core_fscanf(f, " \"%" M_AS_STR(M_USE_IDENTIFIER_ALLOC) "[^ \t\n\"]\":%n",
|
||||
m_core_arg_size(field, M_USE_IDENTIFIER_ALLOC+1), &c);
|
||||
(void) nn ; // Unused. Check is done through 'c' (more robust).
|
||||
if (c <= 0)
|
||||
return m_core_serial_fail();
|
||||
@@ -502,6 +513,7 @@ m_serial_json_read_variant_start(m_serial_local_t local, m_serial_read_t serial,
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
|
||||
int final1 = -1, final2 = -1;
|
||||
// TODO: Accept 'null' as empty variant?
|
||||
int nn = m_core_fscanf(f, " {%n }%n", &final1, &final2);
|
||||
(void) nn ; // Unused. Check is done through final (more robust).
|
||||
// Test how much the parsing succeed.
|
||||
@@ -509,9 +521,9 @@ m_serial_json_read_variant_start(m_serial_local_t local, m_serial_read_t serial,
|
||||
if (final2 > 0) return M_SERIAL_OK_DONE;
|
||||
|
||||
/* Read the field in the JSON */
|
||||
char field[M_MAX_IDENTIFIER_LENGTH+1];
|
||||
nn = m_core_fscanf(f, " \"%" M_APPLY(M_AS_STR, M_MAX_IDENTIFIER_LENGTH) "[^ \t\n\"]\":%n",
|
||||
m_core_arg_size(field, M_MAX_IDENTIFIER_LENGTH+1), &final2);
|
||||
char field[M_USE_IDENTIFIER_ALLOC+1];
|
||||
nn = m_core_fscanf(f, " \"%" M_AS_STR(M_USE_IDENTIFIER_ALLOC) "[^ \t\n\"]\":%n",
|
||||
m_core_arg_size(field, M_USE_IDENTIFIER_ALLOC+1), &final2);
|
||||
(void) nn ; // Unused. Check is done through final (more robust).
|
||||
if (final2 <= 0) return m_core_serial_fail();
|
||||
|
||||
@@ -573,7 +585,611 @@ static inline void m_serial_json_read_clear(m_serial_read_t serial)
|
||||
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) )
|
||||
(INIT_WITH(m_serial_json_read_init), CLEAR(m_serial_json_read_clear), \
|
||||
TYPE(m_serial_json_read_t) , PROPERTIES(( LET_AS_INIT_WITH(1) )) )
|
||||
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/************************** STRING / WRITE / JSON *******************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/* Write the boolean 'data' into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_boolean(m_serial_write_t serial, const bool data)
|
||||
{
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
int n = string_cat_printf(f, "%s", data ? "true" : "false");
|
||||
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
|
||||
{
|
||||
(void) size_of_type; // Ignored
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
int n = string_cat_printf(f, "%lld", data);
|
||||
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write the float 'data' of 'size_of_type' bytes into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
|
||||
{
|
||||
(void) size_of_type; // Ignored
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
int n = string_cat_printf(f, "%Lf", data);
|
||||
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write the null-terminated string 'data'into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_string(m_serial_write_t serial, const char data[], size_t length)
|
||||
{
|
||||
M_ASSERT_SLOW(length == strlen(data) );
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
M_ASSERT(f != NULL && data != NULL);
|
||||
/* HACK: Build dummy string to reuse string_get_str */
|
||||
string_t v2;
|
||||
uintptr_t ptr = (uintptr_t) data;
|
||||
v2->u.heap.size = length;
|
||||
v2->u.heap.alloc = length + 1;
|
||||
v2->ptr = (char*)ptr;
|
||||
string_get_str(f, v2, true);
|
||||
return M_SERIAL_OK_DONE;
|
||||
}
|
||||
|
||||
/* Start writing an array of 'number_of_elements' objects into the serial stream 'serial'.
|
||||
If 'number_of_elements' is 0, then either the array has no data,
|
||||
or the number of elements of the array is unkown.
|
||||
Initialize 'local' so that it can be used to serialize the array
|
||||
(local is an unique serialization object of the array).
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) number_of_elements; // Ignored
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
string_push_back(f, '[');
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
/* Write an array separator between elements of an array into the serial stream 'serial' if needed.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_array_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
string_push_back(f, ',');
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
/* End the writing of an array into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_array_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
string_push_back(f, ']');
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
/* Start writing a map of 'number_of_elements' pairs of objects into the serial stream 'serial'.
|
||||
If 'number_of_elements' is 0, then either the map has no data,
|
||||
or the number of elements is unkown.
|
||||
Initialize 'local' so that it can be used to serialize the map
|
||||
(local is an unique serialization object of the map).
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) number_of_elements; // Ignored
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
string_push_back(f, '{');
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
/* Write a value separator between element of the same pair of a map into the serial stream 'serial' if needed.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_map_value(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
string_push_back(f, ':');
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
/* Write a map separator between elements of a map into the serial stream 'serial' if needed.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_map_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
string_push_back(f, ',');
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
/* End the writing of a map into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
string_push_back(f, '}');
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
/* Start writing a tuple into the serial stream 'serial'.
|
||||
Initialize 'local' so that it can serial the tuple
|
||||
(local is an unique serialization object of the tuple).
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
string_push_back(f, '{');
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
/* Start writing the field named field_name[index] of a tuple into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) max; // Ignored
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
int n = string_cat_printf(f, "%c\"%s\":", index == 0 ? ' ' : ',', field_name[index]);
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* End the write of a tuple into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
string_push_back(f, '}');
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
/* Start writing a variant into the serial stream 'serial'.
|
||||
If index <= 0, the variant is empty.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise
|
||||
Otherwise, the field 'field_name[index]' will be filled.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) max; // argument not used
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
int n;
|
||||
if (index >= 0) {
|
||||
M_ASSERT (index < max);
|
||||
n = string_cat_printf(f, "{\"%s\":", field_name[index]);
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
} else {
|
||||
n = string_cat_printf(f, "{}");
|
||||
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
}
|
||||
|
||||
/* End Writing a variant into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
struct string_s *f = (struct string_s *)serial->data[0].p;
|
||||
string_push_back(f, '}');
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
/* The internal exported interface of m_serial_write_json. */
|
||||
static const m_serial_write_interface_t m_serial_str_json_write_interface = {
|
||||
m_serial_str_json_write_boolean,
|
||||
m_serial_str_json_write_integer,
|
||||
m_serial_str_json_write_float,
|
||||
m_serial_str_json_write_string,
|
||||
m_serial_str_json_write_array_start,
|
||||
m_serial_str_json_write_array_next,
|
||||
m_serial_str_json_write_array_end,
|
||||
m_serial_str_json_write_map_start,
|
||||
m_serial_str_json_write_map_value,
|
||||
m_serial_str_json_write_map_next,
|
||||
m_serial_str_json_write_map_end,
|
||||
m_serial_str_json_write_tuple_start,
|
||||
m_serial_str_json_write_tuple_id,
|
||||
m_serial_str_json_write_tuple_end,
|
||||
m_serial_str_json_write_variant_start,
|
||||
m_serial_str_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_str_json_write_init(m_serial_write_t serial, string_t s)
|
||||
{
|
||||
serial->m_interface = &m_serial_str_json_write_interface;
|
||||
serial->data[0].p = M_ASSIGN_CAST(struct string_s *, s);
|
||||
}
|
||||
|
||||
/* CLear the JSON serial object for writing*/
|
||||
static inline void m_serial_str_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_str_json_write_t;
|
||||
#define M_OPL_m_serial_str_json_write_t() \
|
||||
(INIT_WITH(m_serial_str_json_write_init), CLEAR(m_serial_str_json_write_clear), \
|
||||
TYPE(m_serial_str_json_write_t) , PROPERTIES(( LET_AS_INIT_WITH(1) )) )
|
||||
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/************************** STRING / READ / JSON *******************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/* Helper function to read a character and advance the stream */
|
||||
static inline char
|
||||
m_serial_str_json_getc(const char **p)
|
||||
{
|
||||
char c = **p;
|
||||
// Once it reaches the end of string character (== 0), stop advancing the stream.
|
||||
*p = *p + (c != 0);
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Helper function to skip space(s) */
|
||||
static inline void
|
||||
m_serial_str_json_skip (const char **p)
|
||||
{
|
||||
while (isspace (**p)) {
|
||||
(*p)++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper function to read a string with characters not present in reject */
|
||||
static inline void
|
||||
m_serial_str_json_gets(size_t alloc, char field[], const char reject[], const char **s)
|
||||
{
|
||||
M_ASSERT (alloc > 0);
|
||||
size_t length = strcspn(*s, reject);
|
||||
if (length >= alloc-1)
|
||||
length = alloc - 1;
|
||||
memcpy(field, *s, length);
|
||||
field[length] = 0;
|
||||
*s += length;
|
||||
}
|
||||
|
||||
/* Read from the stream 'serial' a boolean.
|
||||
Set '*b' with the boolean value if succeeds
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_read_boolean(m_serial_read_t serial, bool *b){
|
||||
const char **f = &serial->data[0].cstr;
|
||||
m_serial_str_json_skip(f);
|
||||
char c = m_serial_str_json_getc(f);
|
||||
if (c == 't') {
|
||||
*b = true;
|
||||
c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != 'r')) return m_core_serial_fail();
|
||||
c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != 'u')) return m_core_serial_fail();
|
||||
c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != 'e')) return m_core_serial_fail();
|
||||
return M_SERIAL_OK_DONE;
|
||||
} else if (M_LIKELY(c == 'f')) {
|
||||
*b = false;
|
||||
c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != 'a')) return m_core_serial_fail();
|
||||
c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != 'l')) return m_core_serial_fail();
|
||||
c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != 's')) return m_core_serial_fail();
|
||||
c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != 'e')) return m_core_serial_fail();
|
||||
return M_SERIAL_OK_DONE;
|
||||
} else {
|
||||
return m_core_serial_fail();
|
||||
}
|
||||
}
|
||||
|
||||
/* Read from the stream 'serial' an integer that can be represented with 'size_of_type' bytes.
|
||||
Set '*i' with the integer value if succeeds
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
|
||||
(void) size_of_type; // Ignored
|
||||
const char **f = &serial->data[0].cstr;
|
||||
char *e;
|
||||
*i = strtoll(*f, &e, 10);
|
||||
bool b = e != *f;
|
||||
serial->data[0].cstr = (const char*) e;
|
||||
return b ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Read from the stream 'serial' a float that can be represented with 'size_of_type' bytes.
|
||||
Set '*r' with the boolean value if succeeds
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
|
||||
(void) size_of_type; // Ignored
|
||||
const char **f = &serial->data[0].cstr;
|
||||
char *e;
|
||||
*r = strtold(*f, &e);
|
||||
bool b = e != *f;
|
||||
serial->data[0].cstr = (const char*) e;
|
||||
return b ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Read from the stream 'serial' a string.
|
||||
Set 's' with the string if succeeds
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
const char **f = &serial->data[0].cstr;
|
||||
m_serial_str_json_skip(f);
|
||||
const char *e;
|
||||
bool b = string_parse_str(s, *f, &e);
|
||||
serial->data[0].cstr = e;
|
||||
return b ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start reading from the stream 'serial' an array.
|
||||
Set '*num' with the number of elements, or 0 if it is not known.
|
||||
Initialize 'local' so that it can be used to serialize the array
|
||||
(local is an unique serialization object of the array).
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the array continue,
|
||||
M_SERIAL_OK_DONE if it succeeds and the array ends (the array is empty),
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
const char **f = &serial->data[0].cstr;
|
||||
m_serial_str_json_skip(f);
|
||||
char c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != '[')) {
|
||||
return m_core_serial_fail();
|
||||
}
|
||||
*num = 0; // Don't know the size of the array.
|
||||
m_serial_str_json_skip(f);
|
||||
if (M_UNLIKELY (**f == ']')) {
|
||||
c = m_serial_str_json_getc(f);
|
||||
return M_SERIAL_OK_DONE;
|
||||
} else {
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Continue reading from the stream 'serial' an array.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the array continue,
|
||||
M_SERIAL_OK_DONE if it succeeds and the array ends,
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_read_array_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
const char **f = &serial->data[0].cstr;
|
||||
m_serial_str_json_skip(f);
|
||||
char c = m_serial_str_json_getc(f);
|
||||
return c == ',' ? M_SERIAL_OK_CONTINUE : c == ']' ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start reading from the stream 'serial' a map.
|
||||
Set '*num' with the number of elements, or 0 if it is not known.
|
||||
Initialize 'local' so that it can be used to serialize the array
|
||||
(local is an unique serialization object of the array).
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the map continue,
|
||||
M_SERIAL_OK_DONE if it succeeds and the map ends (the map is empty),
|
||||
m_core_serial_fail() otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_read_map_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
const char **f = &serial->data[0].cstr;
|
||||
m_serial_str_json_skip(f);
|
||||
char c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != '{')) {
|
||||
return m_core_serial_fail();
|
||||
}
|
||||
*num = 0; // Don't know the size of the map
|
||||
m_serial_str_json_skip(f);
|
||||
if (M_UNLIKELY (**f == '}')) {
|
||||
c = m_serial_str_json_getc(f);
|
||||
return M_SERIAL_OK_DONE;
|
||||
} else {
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Continue reading from the stream 'serial' the value separator
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the map continue,
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_read_map_value(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
const char **f = &serial->data[0].cstr;
|
||||
m_serial_str_json_skip(f);
|
||||
char c = m_serial_str_json_getc(f);
|
||||
return c ==':' ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Continue reading from the stream 'serial' a map.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the map continue,
|
||||
M_SERIAL_OK_DONE if it succeeds and the map ends,
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_read_map_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
const char **f = &serial->data[0].cstr;
|
||||
m_serial_str_json_skip(f);
|
||||
char c = m_serial_str_json_getc(f);
|
||||
return c == ',' ? M_SERIAL_OK_CONTINUE : c == '}' ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start reading a tuple from the stream 'serial'.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the tuple continues,
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
const char **f = &serial->data[0].cstr;
|
||||
m_serial_str_json_skip(f);
|
||||
char c = m_serial_str_json_getc(f);
|
||||
return c == '{' ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Continue reading a tuple from the stream 'serial'.
|
||||
Set '*id' with the corresponding index of the table 'field_name[max]'
|
||||
associated to the parsed field in the stream.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the tuple continues,
|
||||
Return M_SERIAL_OK_DONE if it succeeds and the tuple ends,
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const char *const field_name [], const int max, int *id)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
const char **f = &serial->data[0].cstr;
|
||||
m_serial_str_json_skip(f);
|
||||
char c = m_serial_str_json_getc(f);
|
||||
if (c == 0) return m_core_serial_fail();
|
||||
if (c == '}') return M_SERIAL_OK_DONE;
|
||||
if (c == ',') {
|
||||
// If first call of read_tuple_id, it is a failure
|
||||
if (M_UNLIKELY (*id == -1)) return m_core_serial_fail();
|
||||
m_serial_str_json_skip(f);
|
||||
c = m_serial_str_json_getc(f);
|
||||
}
|
||||
|
||||
/* Read the field in the JSON */
|
||||
char field[M_USE_IDENTIFIER_ALLOC+1];
|
||||
if (M_UNLIKELY(c != '"')) return m_core_serial_fail();
|
||||
m_serial_str_json_gets(M_USE_IDENTIFIER_ALLOC+1, field, " \t\n\"", f);
|
||||
c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY (c != '"')) return m_core_serial_fail();
|
||||
c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY (c != ':')) return m_core_serial_fail();
|
||||
|
||||
/* Search for field in field_name */
|
||||
for(int n = 0; n < max; n++) {
|
||||
if (strcmp(field, field_name[n]) == 0) {
|
||||
*id = n;
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
}
|
||||
return m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start reading a variant from the stream 'serial'.
|
||||
Set '*id' with the corresponding index of the table 'field_name[max]'
|
||||
associated to the parsed field in the stream.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the variant continues,
|
||||
Return M_SERIAL_OK_DONE if it succeeds and the variant ends(variant is empty),
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_read_variant_start(m_serial_local_t local, m_serial_read_t serial, const char *const field_name[], const int max, int*id)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
const char **f = &serial->data[0].cstr;
|
||||
m_serial_str_json_skip(f);
|
||||
int c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY (c != '{'))
|
||||
// TODO: Accept 'null' as empty variant?
|
||||
return m_core_serial_fail();
|
||||
m_serial_str_json_skip(f);
|
||||
c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY (c == '}')) return M_SERIAL_OK_DONE; // Empty variant
|
||||
|
||||
/* Read the field in the JSON */
|
||||
char field[M_USE_IDENTIFIER_ALLOC+1];
|
||||
if (M_UNLIKELY(c != '"')) return m_core_serial_fail();
|
||||
m_serial_str_json_gets(M_USE_IDENTIFIER_ALLOC+1, field, " \t\n\"", f);
|
||||
c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY (c != '"')) return m_core_serial_fail();
|
||||
c = m_serial_str_json_getc(f);
|
||||
if (M_UNLIKELY (c != ':')) return m_core_serial_fail();
|
||||
|
||||
/* Linear Search for field in field_name */
|
||||
for(int n = 0; n < max; n++) {
|
||||
if (strcmp(field, field_name[n]) == 0) {
|
||||
*id = n;
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
}
|
||||
// Field not found
|
||||
return m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* End reading a variant from the stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds and the variant ends,
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_str_json_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
const char **f = &serial->data[0].cstr;
|
||||
m_serial_str_json_skip(f);
|
||||
int c = m_serial_str_json_getc(f);
|
||||
return (M_UNLIKELY (c != '}')) ? m_core_serial_fail() : M_SERIAL_OK_DONE;
|
||||
}
|
||||
|
||||
static const m_serial_read_interface_t m_serial_str_json_read_interface = {
|
||||
m_serial_str_json_read_boolean,
|
||||
m_serial_str_json_read_integer,
|
||||
m_serial_str_json_read_float,
|
||||
m_serial_str_json_read_string,
|
||||
m_serial_str_json_read_array_start,
|
||||
m_serial_str_json_read_array_next,
|
||||
m_serial_str_json_read_map_start,
|
||||
m_serial_str_json_read_map_value,
|
||||
m_serial_str_json_read_map_next,
|
||||
m_serial_str_json_read_tuple_start,
|
||||
m_serial_str_json_read_tuple_id,
|
||||
m_serial_str_json_read_variant_start,
|
||||
m_serial_str_json_read_variant_end
|
||||
};
|
||||
|
||||
/* Initialize the JSON serial object for reading any object from JSON format in the given const string */
|
||||
static inline void m_serial_str_json_read_init(m_serial_read_t serial, const char str[])
|
||||
{
|
||||
serial->m_interface = &m_serial_str_json_read_interface;
|
||||
serial->data[0].cstr = str;
|
||||
}
|
||||
|
||||
/* Clear the JSON serial object for reading from the FILE */
|
||||
static inline const char *m_serial_str_json_read_clear(m_serial_read_t serial)
|
||||
{
|
||||
// Nothing to clear. Return pointer to the last data parsed.
|
||||
return serial->data[0].cstr;
|
||||
}
|
||||
|
||||
/* Define a synonym of m_serial_read_t
|
||||
to the JSON serializer with its proper OPLIST */
|
||||
typedef m_serial_read_t m_serial_str_json_read_t;
|
||||
#define M_OPL_m_serial_str_json_read_t() \
|
||||
(INIT_WITH(m_serial_str_json_read_init), CLEAR(m_serial_str_json_read_clear), \
|
||||
TYPE(m_serial_str_json_read_t), PROPERTIES(( LET_AS_INIT_WITH(1) )) )
|
||||
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
+75
-80
@@ -34,7 +34,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define the oplist of a shared pointer.
|
||||
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define SHARED_PTR_OPLIST(...) \
|
||||
SHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_SHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
@@ -42,11 +42,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define shared pointer and its function.
|
||||
USAGE: SHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_ATOMIC_OPLIST, M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST, M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
SHARED_PTR_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define shared pointer and its function
|
||||
@@ -54,20 +50,16 @@ M_BEGIN_PROTECTED_CODE
|
||||
USAGE: SHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
|
||||
#define SHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_ATOMIC_OPLIST, name_t ), \
|
||||
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST, name_t ))) \
|
||||
M_SHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_SHAR3D_ATOMIC_OPLIST, name_t ), \
|
||||
(name, __VA_ARGS__ , M_SHAR3D_ATOMIC_OPLIST, name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define relaxed shared pointer and its function (thread unsafe).
|
||||
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_RELAXED_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_INTEGER_OPLIST, M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__, SHAREDI_INTEGER_OPLIST, M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
SHARED_PTR_RELAXED_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define relaxed shared pointer and its function (thread unsafe)
|
||||
@@ -75,9 +67,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_RELAXED_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_INTEGER_OPLIST, name_t ), \
|
||||
(name, __VA_ARGS__, SHAREDI_INTEGER_OPLIST, name_t ))) \
|
||||
M_SHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_SHAR3D_INTEGER_OPLIST, name_t ), \
|
||||
(name, __VA_ARGS__, M_SHAR3D_INTEGER_OPLIST, name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
@@ -85,11 +77,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
This is a bounded pool of resource shared by multiple owners.
|
||||
USAGE: SHARED_RESOURCE_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_RESOURCE_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_RESOURCE_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) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
SHARED_RESOURCE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define shared resource and its function
|
||||
@@ -98,7 +86,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
USAGE: SHARED_RESOURCE_DEF_AS(name, name_t, it_t, type, [, oplist]) */
|
||||
#define SHARED_RESOURCE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_SHAR3D_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -108,25 +96,26 @@ M_BEGIN_PROTECTED_CODE
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
// deferred evaluation
|
||||
#define SHAREDI_PTR_OPLIST_P1(arg) SHAREDI_PTR_OPLIST_P2 arg
|
||||
#define M_SHAR3D_PTR_OPLIST_P1(arg) M_SHAR3D_PTR_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given, shared_t oplist */
|
||||
#define SHAREDI_PTR_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_PTR_OPLIST_P3, SHAREDI_PTR_OPLIST_FAILURE)(name, oplist)
|
||||
#define M_SHAR3D_PTR_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_SHAR3D_PTR_OPLIST_P3, M_SHAR3D_PTR_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define SHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_SHAR3D_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) ( \
|
||||
#define M_SHAR3D_PTR_OPLIST_P3(name, oplist) ( \
|
||||
INIT(M_C(name, _init)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
SET(M_C(name, _set)) \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
CLEAN(M_C(name, _clean)), \
|
||||
RESET(M_C(name, _reset)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(name, _swap)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_C(name, _ct)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
@@ -134,44 +123,44 @@ M_BEGIN_PROTECTED_CODE
|
||||
)
|
||||
|
||||
// OPLIST to handle a counter of atomic type
|
||||
#define SHAREDI_ATOMIC_OPLIST (TYPE(atomic_int), \
|
||||
#define M_SHAR3D_ATOMIC_OPLIST (TYPE(atomic_int), \
|
||||
INIT_SET(atomic_init), \
|
||||
ADD(atomic_fetch_add), \
|
||||
SUB(atomic_fetch_sub), \
|
||||
IT_CREF(atomic_load))
|
||||
|
||||
// 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))
|
||||
#define M_SHAR3D_INTEGER_OPLIST (TYPE(int), \
|
||||
INIT_SET(m_shar3d_integer_init_set), \
|
||||
ADD(m_shar3d_integer_add), \
|
||||
SUB(m_shar3d_integer_sub), \
|
||||
IT_CREF(m_shar3d_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; }
|
||||
static inline void m_shar3d_integer_init_set(int *p, int val) { *p = val; }
|
||||
static inline int m_shar3d_integer_add(int *p, int val) { int r = *p; *p += val; return r; }
|
||||
static inline int m_shar3d_integer_sub(int *p, int val) { int r = *p; *p -= val; return r; }
|
||||
static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
|
||||
/* Contract of a shared pointer */
|
||||
#define SHAREDI_CONTRACT(shared, cpt_oplist) do { \
|
||||
#define M_SHAR3D_CONTRACT(shared, cpt_oplist) do { \
|
||||
M_ASSERT(shared != NULL); \
|
||||
M_ASSERT(*shared == NULL || M_CALL_IT_CREF(cpt_oplist, &(*shared)->cpt) >= 1); \
|
||||
} while (0)
|
||||
|
||||
// deferred evaluation
|
||||
#define SHAREDI_PTR_DEF_P1(arg) SHAREDI_PTR_DEF_P2 arg
|
||||
#define M_SHAR3D_PTR_DEF_P1(arg) M_SHAR3D_PTR_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define SHAREDI_PTR_DEF_P2(name, type, oplist, cpt_oplist, shared_t) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_PTR_DEF_P3, SHAREDI_PTR_DEF_FAILURE)(name, type, oplist, cpt_oplist, shared_t)
|
||||
#define M_SHAR3D_PTR_DEF_P2(name, type, oplist, cpt_oplist, shared_t) \
|
||||
M_IF_OPLIST(oplist)(M_SHAR3D_PTR_DEF_P3, M_SHAR3D_PTR_DEF_FAILURE)(name, type, oplist, cpt_oplist, shared_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SHAREDI_PTR_DEF_FAILURE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
#define M_SHAR3D_PTR_DEF_FAILURE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
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, shared_t) \
|
||||
#define M_SHAR3D_PTR_DEF_P3(name, type, oplist, cpt_oplist, shared_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s){ \
|
||||
type *data; /* Pointer to the data */ \
|
||||
@@ -216,7 +205,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
ptr->combineAlloc = false; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -236,13 +225,13 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
ptr->combineAlloc = true; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _NULL_p)(const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
return *shared == NULL; \
|
||||
} \
|
||||
\
|
||||
@@ -250,20 +239,20 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_C(name, _init_set)(shared_t dest, \
|
||||
const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT (dest != shared); \
|
||||
*dest = *shared; \
|
||||
if (*dest != NULL) { \
|
||||
int n = M_CALL_ADD(cpt_oplist, &((*dest)->cpt), 1); \
|
||||
(void) n; /* unused return value */ \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t dest) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
if (*dest != NULL) { \
|
||||
if (M_CALL_SUB(cpt_oplist, &((*dest)->cpt), 1) == 1) { \
|
||||
bool combineAlloc = (*dest)->combineAlloc; \
|
||||
@@ -278,22 +267,28 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
} \
|
||||
*dest = NULL; \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(shared_t dest) \
|
||||
M_C(name, _reset)(shared_t dest) \
|
||||
{ \
|
||||
/* NOTE: Clear will also set dest to NULL */ \
|
||||
M_C(name, _clear)(dest); \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(shared_t dest) \
|
||||
{ \
|
||||
M_C(name, _reset)(dest); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(shared_t dest, \
|
||||
const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_set)(dest, shared); \
|
||||
} \
|
||||
@@ -302,19 +297,19 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_C(name, _init_move)(shared_t dest, \
|
||||
shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT (dest != NULL && dest != shared); \
|
||||
*dest = *shared; \
|
||||
*shared = NULL; \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(shared_t dest, \
|
||||
shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT (dest != shared); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_move)(dest, shared); \
|
||||
@@ -324,27 +319,27 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_C(name, _swap)(shared_t p1, \
|
||||
shared_t p2) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(p1, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(p2, cpt_oplist); \
|
||||
/* NOTE: SWAP is not atomic */ \
|
||||
M_SWAP (struct M_C(name, _s)*, *p1, *p2); \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(p1, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(p2, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _equal_p)(const shared_t p1, \
|
||||
const shared_t p2) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(p1, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(p2, cpt_oplist); \
|
||||
return *p1 == *p2; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT(*shared != NULL); \
|
||||
type *data = (*shared)->data; \
|
||||
M_ASSERT (data != NULL); \
|
||||
@@ -354,7 +349,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
static inline type * \
|
||||
M_C(name, _ref)(shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT(*shared != NULL); \
|
||||
type *data = (*shared)->data; \
|
||||
M_ASSERT (data != NULL); \
|
||||
@@ -365,23 +360,23 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
|
||||
/********************************** SHARED RESOURCE ************************************/
|
||||
|
||||
#define SHAREDI_RESOURCE_CONTRACT(s) do { \
|
||||
#define M_SHAR3D_RESOURCE_CONTRACT(s) do { \
|
||||
M_ASSERT (s != NULL); \
|
||||
M_ASSERT (s->buffer != NULL); \
|
||||
} while (0)
|
||||
|
||||
// deferred
|
||||
#define SHAREDI_RESOURCE_DEF_P1(arg) SHAREDI_RESOURCE_DEF_P2 arg
|
||||
#define M_SHAR3D_RESOURCE_DEF_P1(arg) M_SHAR3D_RESOURCE_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define SHAREDI_RESOURCE_DEF_P2(name, type, oplist, shared_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_RESOURCE_DEF_P3, SHAREDI_RESOURCE_DEF_FAILURE)(name, type, oplist, shared_t, it_t)
|
||||
#define M_SHAR3D_RESOURCE_DEF_P2(name, type, oplist, shared_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(M_SHAR3D_RESOURCE_DEF_P3, M_SHAR3D_RESOURCE_DEF_FAILURE)(name, type, oplist, shared_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SHAREDI_RESOURCE_DEF_FAILURE(name, type, oplist, shared_t, it_t) \
|
||||
#define M_SHAR3D_RESOURCE_DEF_FAILURE(name, type, oplist, shared_t, it_t) \
|
||||
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, shared_t, it_t) \
|
||||
#define M_SHAR3D_RESOURCE_DEF_P3(name, type, oplist, shared_t, it_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _atype_s) { \
|
||||
@@ -418,13 +413,13 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
atomic_init (&s->buffer[i].cpt, 0U); \
|
||||
} \
|
||||
genint_init(s->core, (unsigned int) n); \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(s); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(s); \
|
||||
size_t n = genint_size(s->core); \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_CLEAR(oplist, s->buffer[i].x); \
|
||||
@@ -437,7 +432,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, shared_t s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(s); \
|
||||
M_ASSERT (it != NULL); \
|
||||
unsigned int idx = genint_pop(s->core); \
|
||||
it->idx = idx; \
|
||||
@@ -459,7 +454,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_C(name, _ref)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
SHAREDI_RESOURCE_CONTRACT(it->ref); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(it->ref); \
|
||||
return &it->ref->buffer[it->idx].x; \
|
||||
} \
|
||||
\
|
||||
@@ -467,14 +462,14 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_C(name, _cref)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
SHAREDI_RESOURCE_CONTRACT(it->ref); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(it->ref); \
|
||||
return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _end)(it_t it, shared_t s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(s); \
|
||||
M_ASSERT (it != NULL); \
|
||||
M_ASSERT (it->ref == s); \
|
||||
unsigned int idx = it->idx; \
|
||||
@@ -491,7 +486,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_C(name, _it_set)(it_t itd, it_t its) \
|
||||
{ \
|
||||
M_ASSERT (itd != NULL && its != NULL); \
|
||||
SHAREDI_RESOURCE_CONTRACT(its->ref); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(its->ref); \
|
||||
itd->ref = its->ref; \
|
||||
unsigned int idx = its->idx; \
|
||||
itd->idx = idx; \
|
||||
|
||||
+169
-180
@@ -22,8 +22,8 @@
|
||||
* (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_SNAPSHOT
|
||||
#define MSTARLIB_SNAPSHOT
|
||||
#ifndef MSTARLIB_SNAPSHOT_H
|
||||
#define MSTARLIB_SNAPSHOT_H
|
||||
|
||||
#include "m-atomic.h"
|
||||
#include "m-core.h"
|
||||
@@ -34,11 +34,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define a Single Producer Single Consummer snapshot and its functions
|
||||
USAGE: SNAPSHOT_SPSC_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_SPSC_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
SNAPSHOT_SPSC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Single Producer Single Consummer snapshot and its functions
|
||||
@@ -46,7 +42,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
USAGE: SNAPSHOT_SPSC_DEF_AS(name, name_t, type[, oplist]) */
|
||||
#define SNAPSHOT_SPSC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_SNAPSH0T_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__ , name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -55,11 +51,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define a Single Producer Multiple Consummer snapshot and its functions
|
||||
USAGE: SNAPSHOT_SPMC_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_SPMC_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_SPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
SNAPSHOT_SPMC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Single Producer Multiple Consummer snapshot and its functions
|
||||
@@ -67,7 +59,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
USAGE: SNAPSHOT_SPMC_DEF_AS(name, type[, oplist]) */
|
||||
#define SNAPSHOT_SPMC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_SPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_SNAPSH0T_SPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__ , name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -76,11 +68,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
|
||||
USAGE: SNAPSHOT_MPMC_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_MPMC_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
SNAPSHOT_MPMC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
|
||||
@@ -88,7 +76,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
USAGE: SNAPSHOT_MPMC_DEF_AS(name, name_t, type[, oplist]) */
|
||||
#define SNAPSHOT_MPMC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_SNAPSH0T_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__ , name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -97,7 +85,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define the oplist of a snapshot (SPSC, SPMC or MPMC).
|
||||
USAGE: SNAPSHOT_OPLIST(name[, oplist]) */
|
||||
#define SNAPSHOT_OPLIST(...) \
|
||||
SNAPSHOTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_SNAPSH0T_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
@@ -105,22 +93,23 @@ M_BEGIN_PROTECTED_CODE
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
// deferred evaluation of the input
|
||||
#define SNAPSHOTI_OPLIST_P1(arg) SNAPSHOTI_OPLIST_P2 arg
|
||||
#define M_SNAPSH0T_OPLIST_P1(arg) M_SNAPSH0T_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)
|
||||
#define M_SNAPSH0T_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_SNAPSH0T_OPLIST_P3, M_SNAPSH0T_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define SNAPSHOTI_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_SNAPSH0T_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_P3(name, oplist) \
|
||||
#define M_SNAPSH0T_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,SET(M_C(name, _set)) \
|
||||
,CLEAR(M_C(name, _clear)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_C(name, _ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,OPLIST(oplist) \
|
||||
@@ -138,47 +127,47 @@ M_BEGIN_PROTECTED_CODE
|
||||
* - b: Boolean indicating that the read buffer shall be updated
|
||||
* all fields packed in an unsigned char type.
|
||||
*/
|
||||
#define SNAPSHOTI_SPSC_FLAG(r, w, f, b) \
|
||||
#define M_SNAPSH0T_SPSC_FLAG(r, w, f, b) \
|
||||
((unsigned char)( ( (r) << 4) | ((w) << 2) | ((f)) | ((b) << 6)))
|
||||
#define SNAPSHOTI_SPSC_R(flags) \
|
||||
#define M_SNAPSH0T_SPSC_R(flags) \
|
||||
(((unsigned int) (flags) >> 4) & 0x03u)
|
||||
#define SNAPSHOTI_SPSC_W(flags) \
|
||||
#define M_SNAPSH0T_SPSC_W(flags) \
|
||||
(((unsigned int) (flags) >> 2) & 0x03u)
|
||||
#define SNAPSHOTI_SPSC_F(flags) \
|
||||
#define M_SNAPSH0T_SPSC_F(flags) \
|
||||
(((unsigned int) (flags) >> 0) & 0x03u)
|
||||
#define SNAPSHOTI_SPSC_B(flags) \
|
||||
#define M_SNAPSH0T_SPSC_B(flags) \
|
||||
(((unsigned int) (flags) >> 6) & 0x01u)
|
||||
|
||||
/* NOTE: Due to atomic_load only accepting non-const pointer,
|
||||
we can't have any const in the interface. */
|
||||
#define SNAPSHOTI_SPSC_FLAGS_CONTRACT(flags) \
|
||||
M_ASSERT(SNAPSHOTI_SPSC_R(flags) != SNAPSHOTI_SPSC_W(flags) \
|
||||
&& SNAPSHOTI_SPSC_R(flags) != SNAPSHOTI_SPSC_F(flags) \
|
||||
&& SNAPSHOTI_SPSC_W(flags) != SNAPSHOTI_SPSC_F(flags))
|
||||
#define M_SNAPSH0T_SPSC_FLAGS_CONTRACT(flags) \
|
||||
M_ASSERT(M_SNAPSH0T_SPSC_R(flags) != M_SNAPSH0T_SPSC_W(flags) \
|
||||
&& M_SNAPSH0T_SPSC_R(flags) != M_SNAPSH0T_SPSC_F(flags) \
|
||||
&& M_SNAPSH0T_SPSC_W(flags) != M_SNAPSH0T_SPSC_F(flags))
|
||||
|
||||
#define SNAPSHOTI_SPSC_CONTRACT(snap) do { \
|
||||
#define M_SNAPSH0T_SPSC_CONTRACT(snap) do { \
|
||||
M_ASSERT((snap) != NULL); \
|
||||
unsigned char f = atomic_load (&(snap)->flags); \
|
||||
SNAPSHOTI_SPSC_FLAGS_CONTRACT(f); \
|
||||
M_SNAPSH0T_SPSC_FLAGS_CONTRACT(f); \
|
||||
} while (0)
|
||||
|
||||
// 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 M_SNAPSH0T_SPSC_MAX_BUFFER 3
|
||||
|
||||
// Defered evaluation of the arguments.
|
||||
#define SNAPSHOTI_SPSC_DEF_P1(arg) SNAPSHOTI_SPSC_DEF_P2 arg
|
||||
#define M_SNAPSH0T_SPSC_DEF_P1(arg) M_SNAPSH0T_SPSC_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define SNAPSHOTI_SPSC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_SPSC_DEF_P3, SNAPSHOTI_SPSC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
#define M_SNAPSH0T_SPSC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(M_SNAPSH0T_SPSC_DEF_P3, M_SNAPSH0T_SPSC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SNAPSHOTI_SPSC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
#define M_SNAPSH0T_SPSC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_SPSC_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Expand the type and the functions of a SPSC snapshot */
|
||||
#define SNAPSHOTI_SPSC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
#define M_SNAPSH0T_SPSC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _aligned_type_s) { \
|
||||
@@ -187,7 +176,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
} M_C(name, _aligned_type_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _aligned_type_ct) data[SNAPSHOTI_SPSC_MAX_BUFFER]; \
|
||||
M_C(name, _aligned_type_ct) data[M_SNAPSH0T_SPSC_MAX_BUFFER]; \
|
||||
atomic_uchar flags; \
|
||||
} snapshot_t[1]; \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
@@ -203,18 +192,18 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_C(name, _init)(snapshot_t snap) \
|
||||
{ \
|
||||
M_ASSERT(snap != NULL); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_INIT(oplist, snap->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, SNAPSHOTI_SPSC_FLAG(0, 1, 2, 0)); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
atomic_init (&snap->flags, M_SNAPSH0T_SPSC_FLAG(0, 1, 2, 0)); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_CLEAR(oplist, snap->data[i].x); \
|
||||
} \
|
||||
} \
|
||||
@@ -223,40 +212,40 @@ M_BEGIN_PROTECTED_CODE
|
||||
static inline void \
|
||||
M_C(name, _init_set)(snapshot_t snap, snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(org); \
|
||||
M_ASSERT(snap != NULL && snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_INIT_SET(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, atomic_load(&org->flags)); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
/* const is missing for org due to use of atomic_load of org */ \
|
||||
static inline void \
|
||||
M_C(name, _set)(snapshot_t snap, snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(org); \
|
||||
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_SET(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, atomic_load(&org->flags)); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT_MOVE, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _init_move)(snapshot_t snap, snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(org); \
|
||||
M_ASSERT(snap != NULL && snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_INIT_MOVE(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_store (&snap->flags, atomic_load(&org->flags)); \
|
||||
atomic_store (&org->flags, SNAPSHOTI_SPSC_FLAG(0,0,0,0) ); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
atomic_store (&org->flags, M_SNAPSH0T_SPSC_FLAG(0,0,0,0) ); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
,) /* IF_METHOD (INIT_MOVE) */ \
|
||||
\
|
||||
@@ -265,133 +254,133 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_C(name, _move)(snapshot_t snap, \
|
||||
snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(org); \
|
||||
M_ASSERT(snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_MOVE(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_store (&snap->flags, atomic_load(&org->flags)); \
|
||||
atomic_store (&org->flags, SNAPSHOTI_SPSC_FLAG(0,0,0,0) ); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
atomic_store (&org->flags, M_SNAPSH0T_SPSC_FLAG(0,0,0,0) ); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
,) /* IF_METHOD (MOVE) */ \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _write)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
||||
/* Atomic CAS operation */ \
|
||||
do { \
|
||||
/* Swap F and W buffer, setting exchange flag */ \
|
||||
nextFlags = SNAPSHOTI_SPSC_FLAG(SNAPSHOTI_SPSC_R(origFlags), \
|
||||
SNAPSHOTI_SPSC_F(origFlags), \
|
||||
SNAPSHOTI_SPSC_W(origFlags), 1); \
|
||||
nextFlags = M_SNAPSH0T_SPSC_FLAG(M_SNAPSH0T_SPSC_R(origFlags), \
|
||||
M_SNAPSH0T_SPSC_F(origFlags), \
|
||||
M_SNAPSH0T_SPSC_W(origFlags), 1); \
|
||||
/* exponential backoff is not needed as there can't be more \
|
||||
than 2 threads which try to update the data. */ \
|
||||
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
||||
nextFlags)); \
|
||||
/* Return new write buffer for new updating */ \
|
||||
return &snap->data[SNAPSHOTI_SPSC_W(nextFlags)].x; \
|
||||
return &snap->data[M_SNAPSH0T_SPSC_W(nextFlags)].x; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _read)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
||||
/* Atomic CAS operation */ \
|
||||
do { \
|
||||
/* If no exchange registered, do nothing and keep the same */ \
|
||||
if (!SNAPSHOTI_SPSC_B(origFlags)) { \
|
||||
if (!M_SNAPSH0T_SPSC_B(origFlags)) { \
|
||||
nextFlags = origFlags; \
|
||||
break; \
|
||||
} \
|
||||
/* Swap R and F buffer, clearing exchange flag */ \
|
||||
nextFlags = SNAPSHOTI_SPSC_FLAG(SNAPSHOTI_SPSC_F(origFlags), \
|
||||
SNAPSHOTI_SPSC_W(origFlags), \
|
||||
SNAPSHOTI_SPSC_R(origFlags), 0); \
|
||||
nextFlags = M_SNAPSH0T_SPSC_FLAG(M_SNAPSH0T_SPSC_F(origFlags), \
|
||||
M_SNAPSH0T_SPSC_W(origFlags), \
|
||||
M_SNAPSH0T_SPSC_R(origFlags), 0); \
|
||||
/* exponential backoff is not needed as there can't be more \
|
||||
than 2 threads which try to update the data. */ \
|
||||
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
||||
nextFlags)); \
|
||||
/* Return current read buffer */ \
|
||||
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SPSC_R(nextFlags)].x); \
|
||||
return M_CONST_CAST(type, &snap->data[M_SNAPSH0T_SPSC_R(nextFlags)].x); \
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline bool \
|
||||
M_C(name, _updated_p)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load (&snap->flags); \
|
||||
return SNAPSHOTI_SPSC_B(flags); \
|
||||
return M_SNAPSH0T_SPSC_B(flags); \
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline type * \
|
||||
M_C(name, _get_write_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load(&snap->flags); \
|
||||
return &snap->data[SNAPSHOTI_SPSC_W(flags)].x; \
|
||||
return &snap->data[M_SNAPSH0T_SPSC_W(flags)].x; \
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline type const * \
|
||||
M_C(name, _get_read_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load(&snap->flags); \
|
||||
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SPSC_R(flags)].x); \
|
||||
return M_CONST_CAST(type, &snap->data[M_SNAPSH0T_SPSC_R(flags)].x); \
|
||||
} \
|
||||
|
||||
|
||||
|
||||
/******************************** INTERNAL SPMC **********************************/
|
||||
|
||||
#define SNAPSHOTI_SPMC_INT_FLAG(w, n) ( ((w) << 1) | (n) )
|
||||
#define SNAPSHOTI_SPMC_INT_FLAG_W(f) ((f) >> 1)
|
||||
#define SNAPSHOTI_SPMC_INT_FLAG_N(f) ((f) & 1)
|
||||
#define M_SNAPSH0T_SPMC_INT_FLAG(w, n) ( ((w) << 1) | (n) )
|
||||
#define M_SNAPSH0T_SPMC_INT_FLAG_W(f) ((f) >> 1)
|
||||
#define M_SNAPSH0T_SPMC_INT_FLAG_N(f) ((f) & 1)
|
||||
|
||||
// 2 more buffer than the number of readers are needed
|
||||
#define SNAPSHOTI_SPMC_EXTRA_BUFFER 2
|
||||
#define M_SNAPSH0T_SPMC_EXTRA_BUFFER 2
|
||||
|
||||
#define SNAPSHOTI_SPMC_MAX_READER (GENINT_MAX_ALLOC-SNAPSHOTI_SPMC_EXTRA_BUFFER)
|
||||
#define M_SNAPSH0T_SPMC_MAX_READER (GENINT_MAX_ALLOC-M_SNAPSH0T_SPMC_EXTRA_BUFFER)
|
||||
|
||||
/* Internal structure to handle SPMC snapshot but return an unique index in the buffer array.
|
||||
- lastNext: last published written index + next flag (format SNAPSHOTI_SPMC_INT_FLAG)
|
||||
- lastNext: last published written index + next flag (format M_SNAPSH0T_SPMC_INT_FLAG)
|
||||
- currentWrite: the index being currently written.
|
||||
- n_reader : number of readers
|
||||
- cptTab: ref counter array to keep track of how many readers use the corresponding buffer.
|
||||
- freeList: a pool of free integers.
|
||||
*/
|
||||
typedef struct snapshot_mrsw_int_s {
|
||||
typedef struct m_snapshot_mrsw_s {
|
||||
atomic_uint lastNext;
|
||||
unsigned int currentWrite;
|
||||
size_t n_reader;
|
||||
atomic_uint *cptTab;
|
||||
genint_t freeList;
|
||||
} snapshot_mrsw_int_ct[1];
|
||||
} m_snapshot_mrsw_ct[1];
|
||||
|
||||
// can't check currentWrite due to potential data race on it
|
||||
#define SNAPSHOTI_SPMC_INT_CONTRACT(s) do { \
|
||||
#define M_SNAPSH0T_SPMC_INT_CONTRACT(s) do { \
|
||||
M_ASSERT (s != NULL); \
|
||||
M_ASSERT (s->n_reader > 0 && s->n_reader <= SNAPSHOTI_SPMC_MAX_READER); \
|
||||
M_ASSERT ((size_t)SNAPSHOTI_SPMC_INT_FLAG_W(atomic_load(&s->lastNext)) \
|
||||
<= s->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
M_ASSERT (s->n_reader > 0 && s->n_reader <= M_SNAPSH0T_SPMC_MAX_READER); \
|
||||
M_ASSERT ((size_t)M_SNAPSH0T_SPMC_INT_FLAG_W(atomic_load(&s->lastNext)) \
|
||||
<= s->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
|
||||
M_ASSERT (s->cptTab != NULL); \
|
||||
} while (0)
|
||||
|
||||
/* Initialize snapshot_mrsw_int_ct for n readers (constructor) */
|
||||
/* Initialize m_snapshot_mrsw_ct for n readers (constructor) */
|
||||
static inline void
|
||||
snapshot_mrsw_int_init(snapshot_mrsw_int_ct s, size_t n)
|
||||
m_snapsh0t_mrsw_init(m_snapshot_mrsw_ct s, size_t n)
|
||||
{
|
||||
M_ASSERT (s != NULL);
|
||||
M_ASSERT (n >= 1 && n <= SNAPSHOTI_SPMC_MAX_READER);
|
||||
M_ASSERT (n >= 1 && n <= M_SNAPSH0T_SPMC_MAX_READER);
|
||||
s->n_reader = n;
|
||||
n += SNAPSHOTI_SPMC_EXTRA_BUFFER;
|
||||
n += M_SNAPSH0T_SPMC_EXTRA_BUFFER;
|
||||
|
||||
// Initialize the counters to zero (no reader use it)
|
||||
atomic_uint *ptr = M_MEMORY_REALLOC (atomic_uint, NULL, n);
|
||||
@@ -408,20 +397,20 @@ snapshot_mrsw_int_init(snapshot_mrsw_int_ct s, size_t n)
|
||||
unsigned int w = genint_pop(s->freeList);
|
||||
M_ASSERT (w != GENINT_ERROR);
|
||||
atomic_store(&s->cptTab[w], 1U);
|
||||
atomic_init(&s->lastNext, SNAPSHOTI_SPMC_INT_FLAG(w, true));
|
||||
atomic_init(&s->lastNext, M_SNAPSH0T_SPMC_INT_FLAG(w, true));
|
||||
|
||||
// Get working buffer
|
||||
s->currentWrite = genint_pop(s->freeList);
|
||||
M_ASSERT (s->currentWrite != GENINT_ERROR);
|
||||
atomic_store(&s->cptTab[s->currentWrite], 1U);
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
|
||||
/* Clear snapshot_mrsw_int_ct (destructor) */
|
||||
/* Clear m_snapshot_mrsw_ct (destructor) */
|
||||
static inline void
|
||||
snapshot_mrsw_int_clear(snapshot_mrsw_int_ct s)
|
||||
m_snapsh0t_mrsw_clear(m_snapshot_mrsw_ct s)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
M_MEMORY_FREE (s->cptTab);
|
||||
genint_clear(s->freeList);
|
||||
s->cptTab = NULL;
|
||||
@@ -430,43 +419,43 @@ snapshot_mrsw_int_clear(snapshot_mrsw_int_ct s)
|
||||
|
||||
/* Return the current index that is written in the buffer */
|
||||
static inline unsigned int
|
||||
snapshot_mrsw_int_get_write_idx(snapshot_mrsw_int_ct s)
|
||||
m_snapsh0t_mrsw_get_write_idx(m_snapshot_mrsw_ct s)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return s->currentWrite;
|
||||
}
|
||||
|
||||
/* Return the number of readers */
|
||||
static inline unsigned int
|
||||
snapshot_mrsw_int_size(snapshot_mrsw_int_ct s)
|
||||
m_snapsh0t_mrsw_size(m_snapshot_mrsw_ct s)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return (unsigned int) s->n_reader;
|
||||
}
|
||||
|
||||
/* Give the current index that is written to the readers,
|
||||
and return new available index for writter */
|
||||
and return new available index for the writer thread */
|
||||
static inline unsigned int
|
||||
snapshot_mrsw_int_write_idx(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
m_snapsh0t_mrsw_write_idx(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
|
||||
// Provide the finalized written buffer to the readers.
|
||||
unsigned int newNext, previous = atomic_load(&s->lastNext);
|
||||
do {
|
||||
newNext = SNAPSHOTI_SPMC_INT_FLAG(idx, true);
|
||||
newNext = M_SNAPSH0T_SPMC_INT_FLAG(idx, true);
|
||||
} while (!atomic_compare_exchange_weak(&s->lastNext, &previous, newNext));
|
||||
|
||||
if (SNAPSHOTI_SPMC_INT_FLAG_N(previous)) {
|
||||
if (M_SNAPSH0T_SPMC_INT_FLAG_N(previous)) {
|
||||
// Reuse previous buffer as it was not used by any reader
|
||||
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
|
||||
idx = M_SNAPSH0T_SPMC_INT_FLAG_W(previous);
|
||||
// Some other read threads may already have try to reserve this index
|
||||
// So atomic_load(&s->cptTab[idx]) can be greater than 1.
|
||||
// However they will fail to ack it in lastNext,
|
||||
// so they will remove their reservation later
|
||||
} else {
|
||||
// Remove the writer thread counter from the count of the previous buffer
|
||||
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
|
||||
idx = M_SNAPSH0T_SPMC_INT_FLAG_W(previous);
|
||||
unsigned int c = atomic_fetch_sub(&s->cptTab[idx], 1U);
|
||||
M_ASSERT (c != 0 && c <= s->n_reader + 1);
|
||||
// Get a new buffer.
|
||||
@@ -479,72 +468,72 @@ snapshot_mrsw_int_write_idx(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
// No other thread keep track of this buffer.
|
||||
// Reuse it.
|
||||
}
|
||||
M_ASSERT (idx < s->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER);
|
||||
M_ASSERT (idx < s->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER);
|
||||
M_ASSERT (atomic_load(&s->cptTab[idx]) == 0);
|
||||
atomic_store(&s->cptTab[idx], 1U);
|
||||
}
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* Perform a swap of the current write buffer and return a new one */
|
||||
static inline unsigned int
|
||||
snapshot_mrsw_int_write(snapshot_mrsw_int_ct s)
|
||||
m_snapsh0t_mrsw_write(m_snapshot_mrsw_ct s)
|
||||
{
|
||||
s->currentWrite = snapshot_mrsw_int_write_idx(s, s->currentWrite);
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
s->currentWrite = m_snapsh0t_mrsw_write_idx(s, s->currentWrite);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return s->currentWrite;
|
||||
}
|
||||
|
||||
/* Start writing to the write buffer and return its index */
|
||||
static inline unsigned int
|
||||
snapshot_mrsw_int_write_start(snapshot_mrsw_int_ct s)
|
||||
m_snapsh0t_mrsw_write_start(m_snapshot_mrsw_ct s)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
// Get a new buffer.
|
||||
unsigned int idx = genint_pop(s->freeList);
|
||||
M_ASSERT (idx != GENINT_ERROR);
|
||||
M_ASSERT (idx < s->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER);
|
||||
M_ASSERT (idx < s->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER);
|
||||
M_ASSERT (atomic_load(&s->cptTab[idx]) == 0);
|
||||
atomic_store(&s->cptTab[idx], 1U);
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* End writing to the given write buffer */
|
||||
static inline void
|
||||
snapshot_mrsw_int_write_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
m_snapsh0t_mrsw_write_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
|
||||
// Provide this write bufer to the readers
|
||||
unsigned int newNext, previous = atomic_load(&s->lastNext);
|
||||
do {
|
||||
newNext = SNAPSHOTI_SPMC_INT_FLAG(idx, true);
|
||||
newNext = M_SNAPSH0T_SPMC_INT_FLAG(idx, true);
|
||||
} while (!atomic_compare_exchange_weak(&s->lastNext, &previous, newNext));
|
||||
|
||||
// Free the previous write buffer
|
||||
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
|
||||
idx = M_SNAPSH0T_SPMC_INT_FLAG_W(previous);
|
||||
unsigned int c = atomic_fetch_sub(&s->cptTab[idx], 1U);
|
||||
M_ASSERT (c != 0 && c <= s->n_reader + 1);
|
||||
if (c == 1) {
|
||||
genint_push(s->freeList, idx);
|
||||
}
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
|
||||
/* Start reading the latest written buffer and return the index to it */
|
||||
static inline unsigned int
|
||||
snapshot_mrsw_int_read_start(snapshot_mrsw_int_ct s)
|
||||
m_snapsh0t_mrsw_read_start(m_snapshot_mrsw_ct s)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
unsigned int idx, previous;
|
||||
reload:
|
||||
// Load the last published index + Next flag
|
||||
previous = atomic_load(&s->lastNext);
|
||||
while (true) {
|
||||
// Get the last published index
|
||||
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
|
||||
idx = M_SNAPSH0T_SPMC_INT_FLAG_W(previous);
|
||||
// Load the number of threads using this index
|
||||
unsigned int c = atomic_load(&s->cptTab[idx]);
|
||||
M_ASSERT (c <= s->n_reader + 1);
|
||||
@@ -553,16 +542,16 @@ snapshot_mrsw_int_read_start(snapshot_mrsw_int_ct s)
|
||||
|| !atomic_compare_exchange_strong(&s->cptTab[idx], &c, c+1)))
|
||||
goto reload;
|
||||
// Try to ack it
|
||||
unsigned int newNext = SNAPSHOTI_SPMC_INT_FLAG(idx, false);
|
||||
unsigned int newNext = M_SNAPSH0T_SPMC_INT_FLAG(idx, false);
|
||||
reforce:
|
||||
if (M_LIKELY (atomic_compare_exchange_strong(&s->lastNext, &previous, newNext)))
|
||||
break;
|
||||
// We have been preempted by another thread
|
||||
if (idx == SNAPSHOTI_SPMC_INT_FLAG_W(previous)) {
|
||||
if (idx == M_SNAPSH0T_SPMC_INT_FLAG_W(previous)) {
|
||||
// This is still ok if the index has not changed
|
||||
// We can get previous to true again if the writer has recycled the index,
|
||||
// while we reserved it, and the reader get prempted until its CAS.
|
||||
if (M_UNLIKELY (SNAPSHOTI_SPMC_INT_FLAG_N(previous) == true)) goto reforce;
|
||||
if (M_UNLIKELY (M_SNAPSH0T_SPMC_INT_FLAG_N(previous) == true)) goto reforce;
|
||||
break;
|
||||
}
|
||||
// Free the reserved index as we failed it to ack it
|
||||
@@ -572,16 +561,16 @@ snapshot_mrsw_int_read_start(snapshot_mrsw_int_ct s)
|
||||
genint_push(s->freeList, idx);
|
||||
}
|
||||
}
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* End the reading the given buffer */
|
||||
static inline void
|
||||
snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_ASSERT (idx < s->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
M_ASSERT (idx < s->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER);
|
||||
// Decrement reference counter of the buffer
|
||||
unsigned int c = atomic_fetch_sub(&s->cptTab[idx], 1U);
|
||||
M_ASSERT (c != 0 && c <= s->n_reader + 1);
|
||||
@@ -590,30 +579,30 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
// Push back index in free list
|
||||
genint_push(s->freeList, idx);
|
||||
}
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
|
||||
/* Contract of a SPMC snapshot.
|
||||
Nothing notable as it can be accessed concurrently */
|
||||
#define SNAPSHOTI_SPMC_CONTRACT(snap) do { \
|
||||
#define M_SNAPSH0T_SPMC_CONTRACT(snap) do { \
|
||||
M_ASSERT (snap != NULL); \
|
||||
M_ASSERT (snap->data != NULL); \
|
||||
} while (0)
|
||||
|
||||
|
||||
// Defered evaluation
|
||||
#define SNAPSHOTI_SPMC_DEF_P1(arg) SNAPSHOTI_SPMC_DEF_P2 arg
|
||||
#define M_SNAPSH0T_SPMC_DEF_P1(arg) M_SNAPSH0T_SPMC_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define SNAPSHOTI_SPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_SPMC_DEF_P3, SNAPSHOTI_SPMC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
#define M_SNAPSH0T_SPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(M_SNAPSH0T_SPMC_DEF_P3, M_SNAPSH0T_SPMC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SNAPSHOTI_SPMC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
#define M_SNAPSH0T_SPMC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_SPMC_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Expand the type and the functions of a SPMC snapshot */
|
||||
#define SNAPSHOTI_SPMC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
#define M_SNAPSH0T_SPMC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _aligned_type_s) { \
|
||||
@@ -623,7 +612,7 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _aligned_type_ct) *data; \
|
||||
snapshot_mrsw_int_ct core; \
|
||||
m_snapshot_mrsw_ct core; \
|
||||
} snapshot_t[1]; \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
@@ -636,68 +625,68 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
M_C(name, _init)(snapshot_t snap, size_t nReader) \
|
||||
{ \
|
||||
M_ASSERT (snap != NULL); \
|
||||
M_ASSERT (nReader > 0 && nReader <= SNAPSHOTI_SPMC_MAX_READER); \
|
||||
M_ASSERT (nReader > 0 && nReader <= M_SNAPSH0T_SPMC_MAX_READER); \
|
||||
snap->data = M_CALL_REALLOC(oplist, M_C(name, _aligned_type_ct), \
|
||||
NULL, nReader+SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
NULL, nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
|
||||
if (M_UNLIKELY (snap->data == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _aligned_type_ct)) * \
|
||||
(nReader+SNAPSHOTI_SPMC_EXTRA_BUFFER)); \
|
||||
(nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER)); \
|
||||
return; \
|
||||
} \
|
||||
for(size_t i = 0; i < nReader + SNAPSHOTI_SPMC_EXTRA_BUFFER; i++) { \
|
||||
for(size_t i = 0; i < nReader + M_SNAPSH0T_SPMC_EXTRA_BUFFER; i++) { \
|
||||
M_CALL_INIT(oplist, snap->data[i].x); \
|
||||
} \
|
||||
snapshot_mrsw_int_init(snap->core, nReader); \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
m_snapsh0t_mrsw_init(snap->core, nReader); \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
size_t nReader = snapshot_mrsw_int_size(snap->core); \
|
||||
for(size_t i = 0; i < nReader + SNAPSHOTI_SPMC_EXTRA_BUFFER; i++) { \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
size_t nReader = m_snapsh0t_mrsw_size(snap->core); \
|
||||
for(size_t i = 0; i < nReader + M_SNAPSH0T_SPMC_EXTRA_BUFFER; i++) { \
|
||||
M_CALL_CLEAR(oplist, snap->data[i].x); \
|
||||
} \
|
||||
M_CALL_FREE(oplist, snap->data); \
|
||||
snapshot_mrsw_int_clear(snap->core); \
|
||||
m_snapsh0t_mrsw_clear(snap->core); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _write)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_write(snap->core); \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = m_snapsh0t_mrsw_write(snap->core); \
|
||||
return &snap->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _read_start)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_read_start(snap->core); \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = m_snapsh0t_mrsw_read_start(snap->core); \
|
||||
return M_CONST_CAST(type, &snap->data[idx].x); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _read_end)(snapshot_t snap, type const *old) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
M_ASSERT (old != NULL); \
|
||||
const M_C(name, _aligned_type_ct) *oldx; \
|
||||
oldx = M_CTYPE_FROM_FIELD(M_C(name, _aligned_type_ct), old, type, x); \
|
||||
M_ASSERT (oldx >= snap->data); \
|
||||
M_ASSERT (oldx < snap->data + snap->core->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
M_ASSERT(snap->core->n_reader +SNAPSHOTI_SPMC_EXTRA_BUFFER < UINT_MAX); \
|
||||
M_ASSERT (oldx < snap->data + snap->core->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
|
||||
M_ASSERT(snap->core->n_reader +M_SNAPSH0T_SPMC_EXTRA_BUFFER < UINT_MAX); \
|
||||
const unsigned int idx = (unsigned int) (oldx - snap->data); \
|
||||
snapshot_mrsw_int_read_end(snap->core, idx); \
|
||||
m_snapsh0t_mrsw_read_end(snap->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _get_write_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_get_write_idx(snap->core); \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = m_snapsh0t_mrsw_get_write_idx(snap->core); \
|
||||
return &snap->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
@@ -711,20 +700,20 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
// MPMC is built upon SPMC
|
||||
|
||||
// Defered evaluation
|
||||
#define SNAPSHOTI_MPMC_DEF_P1(arg) SNAPSHOTI_MPMC_DEF_P2 arg
|
||||
#define M_SNAPSH0T_MPMC_DEF_P1(arg) M_SNAPSH0T_MPMC_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define SNAPSHOTI_MPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_MPMC_DEF_P3, SNAPSHOTI_MPMC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
#define M_SNAPSH0T_MPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(M_SNAPSH0T_MPMC_DEF_P3, M_SNAPSH0T_MPMC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SNAPSHOTI_MPMC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
#define M_SNAPSH0T_MPMC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_MPMC_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Expand the type and the functions of a MPMC snapshot */
|
||||
#define SNAPSHOTI_MPMC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
#define M_SNAPSH0T_MPMC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
SNAPSHOTI_SPMC_DEF_P1((M_C(name, _mrsw), type, oplist, M_C(name, _mrsw_pct))) \
|
||||
M_SNAPSH0T_SPMC_DEF_P1((M_C(name, _mrsw), type, oplist, M_C(name, _mrsw_pct))) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _mrsw_pct) core; \
|
||||
@@ -742,7 +731,7 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
M_C(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \
|
||||
unsigned int idx = snap->core->core->currentWrite; \
|
||||
snap->core->core->currentWrite = GENINT_ERROR; \
|
||||
snapshot_mrsw_int_write_end(snap->core->core, idx); \
|
||||
m_snapsh0t_mrsw_write_end(snap->core->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -754,22 +743,22 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
static inline type * \
|
||||
M_C(name, _write_start)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap->core); \
|
||||
const unsigned int idx = snapshot_mrsw_int_write_start(snap->core->core); \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap->core); \
|
||||
const unsigned int idx = m_snapsh0t_mrsw_write_start(snap->core->core); \
|
||||
return &snap->core->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _write_end)(snapshot_t snap, type *old) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap->core); \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap->core); \
|
||||
const M_C(name, _mrsw_aligned_type_ct) *oldx; \
|
||||
oldx = M_CTYPE_FROM_FIELD(M_C(name, _mrsw_aligned_type_ct), old, type, x); \
|
||||
M_ASSERT (oldx >= snap->core->data); \
|
||||
M_ASSERT (oldx < snap->core->data + snap->core->core->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
M_ASSERT(snap->core->core->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER < UINT_MAX); \
|
||||
M_ASSERT (oldx < snap->core->data + snap->core->core->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
|
||||
M_ASSERT(snap->core->core->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER < UINT_MAX); \
|
||||
const unsigned int idx = (unsigned int) (oldx - snap->core->data); \
|
||||
snapshot_mrsw_int_write_end(snap->core->core, idx); \
|
||||
m_snapsh0t_mrsw_write_end(snap->core->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
@@ -785,7 +774,7 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
} \
|
||||
\
|
||||
|
||||
//TODO: _set_, _init_set
|
||||
//FIXME: Evaluate the needs for the methods _set_, _init_set.
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
+356
-299
File diff suppressed because it is too large.
Load diff
@@ -33,9 +33,7 @@
|
||||
USAGE:
|
||||
TUPLE_DEF2(name, [(field1, type1[, oplist1]), (field2, type2[, oplist2]), ...] ) */
|
||||
#define TUPLE_DEF2(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
TUPLEI_DEF2_P1( (name, M_C(name, _t) TUPLEI_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
M_END_PROTECTED_CODE
|
||||
TUPLE_DEF2_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define the tuple type and functions
|
||||
@@ -44,7 +42,7 @@
|
||||
TUPLE_DEF2_AS(name, name_t, [(field1, type1[, oplist1]), (field2, type2[, oplist2]), ...] ) */
|
||||
#define TUPLE_DEF2_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
TUPLEI_DEF2_P1( (name, name_t TUPLEI_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
M_TUPL3_DEF2_P1( (name, name_t M_TUPL3_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
@@ -52,8 +50,8 @@
|
||||
USAGE: TUPLE_OPLIST(name[, oplist of the first type, ...]) */
|
||||
#define TUPLE_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(TUPLEI_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST )), \
|
||||
TUPLEI_OPLIST_P1((__VA_ARGS__ )))
|
||||
(M_TUPL3_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST )), \
|
||||
M_TUPL3_OPLIST_P1((__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Return an array suitable for the WIP _cmp_order function.
|
||||
@@ -63,14 +61,14 @@
|
||||
*/
|
||||
#ifndef __cplusplus
|
||||
#define TUPLE_ORDER(name, ...) \
|
||||
( (const int[]) {M_MAP2_C(TUPLEI_ORDER_CONVERT, name, __VA_ARGS__), 0})
|
||||
( (const int[]) {M_MAP2_C(M_TUPL3_ORDER_CONVERT, name, __VA_ARGS__), 0})
|
||||
#else
|
||||
#include <initializer_list>
|
||||
namespace m_lib {
|
||||
template <unsigned int N>
|
||||
struct m_int_array {
|
||||
struct m_tupl3_integer_va {
|
||||
int data[N];
|
||||
/*constexpr*/ inline m_int_array(std::initializer_list<int> init){
|
||||
/*constexpr*/ inline m_tupl3_integer_va(std::initializer_list<int> init){
|
||||
int j = 0;
|
||||
for(auto i:init) {
|
||||
data[j++] = i;
|
||||
@@ -79,425 +77,440 @@ namespace m_lib {
|
||||
};
|
||||
}
|
||||
#define TUPLE_ORDER(name, ...) \
|
||||
(m_lib::m_int_array<M_NARGS(__VA_ARGS__,0)>({M_MAP2_C(TUPLEI_ORDER_CONVERT, name, __VA_ARGS__), 0}).data)
|
||||
(m_lib::m_tupl3_integer_va<M_NARGS(__VA_ARGS__,0)>({M_MAP2_C(M_TUPL3_ORDER_CONVERT, name, __VA_ARGS__), 0}).data)
|
||||
#endif
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Contract of a tuple. Nothing notable */
|
||||
#define TUPLEI_CONTRACT(tup) do { \
|
||||
#define M_TUPL3_CONTRACT(tup) do { \
|
||||
M_ASSERT(tup != NULL); \
|
||||
} while (0)
|
||||
|
||||
/* Inject the oplist within the list of arguments */
|
||||
#define TUPLEI_INJECT_GLOBAL(...) \
|
||||
M_MAP(TUPLEI_INJECT_OPLIST_A, __VA_ARGS__)
|
||||
#define M_TUPL3_INJECT_GLOBAL(...) \
|
||||
M_MAP(M_TUPL3_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
|
||||
#define M_TUPL3_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
M_TUPL3_INJECT_OPLIST_B duo_or_trio
|
||||
|
||||
#define TUPLEI_INJECT_OPLIST_B( f, ... ) \
|
||||
#define M_TUPL3_INJECT_OPLIST_B( f, ... ) \
|
||||
M_DEFERRED_COMMA \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
|
||||
|
||||
// Deferred evaluation
|
||||
#define TUPLEI_DEF2_P1(...) TUPLEI_DEF2_P2 __VA_ARGS__
|
||||
#define M_TUPL3_DEF2_P1(...) M_TUPL3_DEF2_P2 __VA_ARGS__
|
||||
|
||||
// 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__))
|
||||
#define M_TUPL3_IF_ALL_OPLIST(...) \
|
||||
M_IF(M_REDUCE(M_TUPL3_IS_OPLIST_P, M_AND, __VA_ARGS__))
|
||||
|
||||
// Test if the third argument of (name, type, oplist) is an oplist
|
||||
#define TUPLEI_IS_OPLIST_P(a) \
|
||||
#define M_TUPL3_IS_OPLIST_P(a) \
|
||||
M_OPLIST_P(M_RET_ARG3 a)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define TUPLEI_DEF2_P2(name, name_t, ...) \
|
||||
TUPLEI_IF_ALL_OPLIST(__VA_ARGS__)(TUPLEI_DEF2_P3, TUPLEI_DEF2_FAILURE)(name, name_t, __VA_ARGS__)
|
||||
#define M_TUPL3_DEF2_P2(name, name_t, ...) \
|
||||
M_TUPL3_IF_ALL_OPLIST(__VA_ARGS__)(M_TUPL3_DEF2_P3, M_TUPL3_DEF2_FAILURE)(name, name_t, __VA_ARGS__)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define TUPLEI_DEF2_FAILURE(name, name_t, ...) \
|
||||
#define M_TUPL3_DEF2_FAILURE(name, name_t, ...) \
|
||||
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, name_t, ...) \
|
||||
TUPLEI_DEFINE_TYPE(name, name_t, __VA_ARGS__) \
|
||||
TUPLEI_DEFINE_ENUM(name, __VA_ARGS__) \
|
||||
TUPLEI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
TUPLEI_IF_ALL(INIT, __VA_ARGS__)(TUPLEI_DEFINE_INIT(name, __VA_ARGS__),) \
|
||||
TUPLEI_DEFINE_INIT_SET(name, __VA_ARGS__) \
|
||||
TUPLEI_DEFINE_INIT_SET2(name, __VA_ARGS__) \
|
||||
TUPLEI_DEFINE_SET(name, __VA_ARGS__) \
|
||||
TUPLEI_DEFINE_SET2(name, __VA_ARGS__) \
|
||||
TUPLEI_DEFINE_CLEAR(name, __VA_ARGS__) \
|
||||
TUPLEI_DEFINE_GETTER_FIELD(name, __VA_ARGS__) \
|
||||
TUPLEI_DEFINE_SETTER_FIELD(name, __VA_ARGS__) \
|
||||
TUPLEI_IF_ALL(CMP, __VA_ARGS__)(TUPLEI_DEFINE_CMP(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(CMP, __VA_ARGS__)(TUPLEI_DEFINE_CMP_ORDER(name, __VA_ARGS__),) \
|
||||
TUPLEI_DEFINE_CMP_FIELD(name, __VA_ARGS__) \
|
||||
TUPLEI_IF_ALL(HASH, __VA_ARGS__)(TUPLEI_DEFINE_HASH(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(EQUAL, __VA_ARGS__)(TUPLEI_DEFINE_EQUAL(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(GET_STR, __VA_ARGS__)(TUPLEI_DEFINE_GET_STR(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(OUT_STR, __VA_ARGS__)(TUPLEI_DEFINE_OUT_STR(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(IN_STR, __VA_ARGS__)(TUPLEI_DEFINE_IN_STR(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(PARSE_STR, __VA_ARGS__)(TUPLEI_DEFINE_PARSE_STR(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(OUT_SERIAL, __VA_ARGS__)(TUPLEI_DEFINE_OUT_SERIAL(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(IN_SERIAL, __VA_ARGS__)(TUPLEI_DEFINE_IN_SERIAL(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(INIT_MOVE, __VA_ARGS__)(TUPLEI_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(MOVE, __VA_ARGS__)(TUPLEI_DEFINE_MOVE(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(SWAP, __VA_ARGS__)(TUPLEI_DEFINE_SWAP(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(CLEAN, __VA_ARGS__)(TUPLEI_DEFINE_CLEAN(name, __VA_ARGS__),)
|
||||
#define M_TUPL3_DEF2_P3(name, name_t, ...) \
|
||||
M_TUPL3_DEFINE_TYPE(name, name_t, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_ENUM(name, __VA_ARGS__) \
|
||||
M_TUPL3_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
M_TUPL3_IF_ALL(INIT, __VA_ARGS__)(M_TUPL3_DEFINE_INIT(name, __VA_ARGS__),) \
|
||||
M_TUPL3_DEFINE_INIT_SET(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_INIT_SET2(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_SET(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_SET2(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_CLEAR(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_GETTER_FIELD(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_SETTER_FIELD(name, __VA_ARGS__) \
|
||||
M_TUPL3_IF_ONE(CMP, __VA_ARGS__)(M_TUPL3_DEFINE_CMP(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(CMP, __VA_ARGS__)(M_TUPL3_DEFINE_CMP_ORDER(name, __VA_ARGS__),) \
|
||||
M_TUPL3_DEFINE_CMP_FIELD(name, __VA_ARGS__) \
|
||||
M_TUPL3_IF_ONE(HASH, __VA_ARGS__)(M_TUPL3_DEFINE_HASH(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ONE(EQUAL, __VA_ARGS__)(M_TUPL3_DEFINE_EQUAL(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(GET_STR, __VA_ARGS__)(M_TUPL3_DEFINE_GET_STR(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(OUT_STR, __VA_ARGS__)(M_TUPL3_DEFINE_OUT_STR(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(IN_STR, __VA_ARGS__)(M_TUPL3_DEFINE_IN_STR(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(PARSE_STR, __VA_ARGS__)(M_TUPL3_DEFINE_PARSE_STR(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(OUT_SERIAL, __VA_ARGS__)(M_TUPL3_DEFINE_OUT_SERIAL(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(IN_SERIAL, __VA_ARGS__)(M_TUPL3_DEFINE_IN_SERIAL(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(INIT_MOVE, __VA_ARGS__)(M_TUPL3_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(MOVE, __VA_ARGS__)(M_TUPL3_DEFINE_MOVE(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(SWAP, __VA_ARGS__)(M_TUPL3_DEFINE_SWAP(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(RESET, __VA_ARGS__)(M_TUPL3_DEFINE_RESET(name, __VA_ARGS__),)
|
||||
|
||||
/* Provide order for _cmp_order */
|
||||
#define TUPLEI_ORDER_CONVERT(name, x) M_C(name, M_C(TUPLEI_ORDER_CONVERT_, x))
|
||||
#define TUPLEI_ORDER_CONVERT_ASC(x) M_C3(_,x,_value)
|
||||
#define TUPLEI_ORDER_CONVERT_DSC(x) M_C3(_,x,_value)*-1
|
||||
#define M_TUPL3_ORDER_CONVERT(name, x) M_C(name, M_C(M_TUPL3_ORDER_CONVERT_, x))
|
||||
#define M_TUPL3_ORDER_CONVERT_ASC(x) M_C3(_,x,_value)
|
||||
#define M_TUPL3_ORDER_CONVERT_DSC(x) M_C3(_,x,_value)*-1
|
||||
|
||||
/* Get the field name, the type, the oplist or the methods
|
||||
based on the tuple (field, type, oplist) */
|
||||
#define TUPLEI_GET_FIELD(f,t,o) f
|
||||
#define TUPLEI_GET_TYPE(f,t,o) t
|
||||
#define TUPLEI_GET_OPLIST(f,t,o) o
|
||||
#define TUPLEI_GET_INIT(f,t,o) M_GET_INIT o
|
||||
#define TUPLEI_GET_INIT_SET(f,t,o) M_GET_INIT_SET o
|
||||
#define TUPLEI_GET_INIT_MOVE(f,t,o) M_GET_INIT_MOVE o
|
||||
#define TUPLEI_GET_MOVE(f,t,o) M_GET_MOVE o
|
||||
#define TUPLEI_GET_SET(f,t,o) M_GET_SET o
|
||||
#define TUPLEI_GET_CLEAR(f,t,o) M_GET_CLEAR o
|
||||
#define TUPLEI_GET_CMP(f,t,o) M_GET_CMP o
|
||||
#define TUPLEI_GET_HASH(f,t,o) M_GET_HASH o
|
||||
#define TUPLEI_GET_EQUAL(f,t,o) M_GET_EQUAL o
|
||||
#define TUPLEI_GET_STR(f,t,o) M_GET_GET_STR o
|
||||
#define TUPLEI_GET_OUT_STR(f,t,o) M_GET_OUT_STR o
|
||||
#define TUPLEI_GET_IN_STR(f,t,o) M_GET_IN_STR o
|
||||
#define TUPLEI_GET_OUT_SERIAL(f,t,o) M_GET_OUT_SERIAL o
|
||||
#define TUPLEI_GET_IN_SERIAL(f,t,o) M_GET_IN_SERIAL o
|
||||
#define TUPLEI_GET_PARSE_STR(f,t,o) M_GET_PARSE_STR o
|
||||
#define TUPLEI_GET_SWAP(f,t,o) M_GET_SWAP o
|
||||
#define TUPLEI_GET_CLEAN(f,t,o) M_GET_CLEAN o
|
||||
#define M_TUPL3_GET_FIELD(f,t,o) f
|
||||
#define M_TUPL3_GET_TYPE(f,t,o) t
|
||||
#define M_TUPL3_GET_OPLIST(f,t,o) o
|
||||
#define M_TUPL3_GET_INIT(f,t,o) M_GET_INIT o
|
||||
#define M_TUPL3_GET_INIT_SET(f,t,o) M_GET_INIT_SET o
|
||||
#define M_TUPL3_GET_INIT_MOVE(f,t,o) M_GET_INIT_MOVE o
|
||||
#define M_TUPL3_GET_MOVE(f,t,o) M_GET_MOVE o
|
||||
#define M_TUPL3_GET_SET(f,t,o) M_GET_SET o
|
||||
#define M_TUPL3_GET_CLEAR(f,t,o) M_GET_CLEAR o
|
||||
#define M_TUPL3_GET_CMP(f,t,o) M_GET_CMP o
|
||||
#define M_TUPL3_GET_HASH(f,t,o) M_GET_HASH o
|
||||
#define M_TUPL3_GET_EQUAL(f,t,o) M_GET_EQUAL o
|
||||
#define M_TUPL3_GET_STR(f,t,o) M_GET_GET_STR o
|
||||
#define M_TUPL3_GET_OUT_STR(f,t,o) M_GET_OUT_STR o
|
||||
#define M_TUPL3_GET_IN_STR(f,t,o) M_GET_IN_STR o
|
||||
#define M_TUPL3_GET_OUT_SERIAL(f,t,o) M_GET_OUT_SERIAL o
|
||||
#define M_TUPL3_GET_IN_SERIAL(f,t,o) M_GET_IN_SERIAL o
|
||||
#define M_TUPL3_GET_PARSE_STR(f,t,o) M_GET_PARSE_STR o
|
||||
#define M_TUPL3_GET_SWAP(f,t,o) M_GET_SWAP o
|
||||
#define M_TUPL3_GET_RESET(f,t,o) M_GET_RESET o
|
||||
|
||||
/* Call the method associated to the given operator for the given parameter
|
||||
of the tuple t=(name, type, oplist) */
|
||||
#define TUPLEI_CALL_INIT(t, ...) M_APPLY_API(TUPLEI_GET_INIT t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_INIT_SET(t, ...) M_APPLY_API(TUPLEI_GET_INIT_SET t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_INIT_MOVE(t, ...) M_APPLY_API(TUPLEI_GET_INIT_MOVE t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_MOVE(t, ...) M_APPLY_API(TUPLEI_GET_MOVE t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_SET(t, ...) M_APPLY_API(TUPLEI_GET_SET t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_CLEAR(t, ...) M_APPLY_API(TUPLEI_GET_CLEAR t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_CMP(t, ...) M_APPLY_API(TUPLEI_GET_CMP t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_HASH(t, ...) M_APPLY_API(TUPLEI_GET_HASH t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_EQUAL(t, ...) M_APPLY_API(TUPLEI_GET_EQUAL t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_GET_STR(t, ...) M_APPLY_API(TUPLEI_GET_STR t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_OUT_STR(t, ...) M_APPLY_API(TUPLEI_GET_OUT_STR t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_IN_STR(t, ...) M_APPLY_API(TUPLEI_GET_IN_STR t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_PARSE_STR(t, ...) M_APPLY_API(TUPLEI_GET_PARSE_STR t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_OUT_SERIAL(t, ...) M_APPLY_API(TUPLEI_GET_OUT_SERIAL t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_IN_SERIAL(t, ...) M_APPLY_API(TUPLEI_GET_IN_SERIAL t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_SWAP(t, ...) M_APPLY_API(TUPLEI_GET_SWAP t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_CLEAN(t, ...) M_APPLY_API(TUPLEI_GET_CLEAN t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_INIT(t, ...) M_APPLY_API(M_TUPL3_GET_INIT t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_INIT_SET(t, ...) M_APPLY_API(M_TUPL3_GET_INIT_SET t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_INIT_MOVE(t, ...) M_APPLY_API(M_TUPL3_GET_INIT_MOVE t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_MOVE(t, ...) M_APPLY_API(M_TUPL3_GET_MOVE t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_SET(t, ...) M_APPLY_API(M_TUPL3_GET_SET t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_CLEAR(t, ...) M_APPLY_API(M_TUPL3_GET_CLEAR t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_CMP(t, ...) M_APPLY_API(M_TUPL3_GET_CMP t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_HASH(t, ...) M_APPLY_API(M_TUPL3_GET_HASH t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_EQUAL(t, ...) M_APPLY_API(M_TUPL3_GET_EQUAL t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_GET_STR(t, ...) M_APPLY_API(M_TUPL3_GET_STR t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_OUT_STR(t, ...) M_APPLY_API(M_TUPL3_GET_OUT_STR t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_IN_STR(t, ...) M_APPLY_API(M_TUPL3_GET_IN_STR t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_PARSE_STR(t, ...) M_APPLY_API(M_TUPL3_GET_PARSE_STR t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_OUT_SERIAL(t, ...) M_APPLY_API(M_TUPL3_GET_OUT_SERIAL t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_IN_SERIAL(t, ...) M_APPLY_API(M_TUPL3_GET_IN_SERIAL t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_SWAP(t, ...) M_APPLY_API(M_TUPL3_GET_SWAP t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_RESET(t, ...) M_APPLY_API(M_TUPL3_GET_RESET t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define the type of a tuple */
|
||||
#define TUPLEI_DEFINE_TYPE(name, name_t, ...) \
|
||||
#define M_TUPL3_DEFINE_TYPE(name, name_t, ...) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_MAP(TUPLEI_DEFINE_RECUR_TYPE_ELE , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_RECUR_TYPE_ELE , __VA_ARGS__) \
|
||||
} name_t[1]; \
|
||||
\
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
/* Define internal type for oplist */ \
|
||||
typedef name_t M_C(name, _ct);
|
||||
typedef name_t M_C(name, _ct); \
|
||||
/* Save constant as the number of arguments (internal) */ \
|
||||
typedef enum { \
|
||||
M_C3(m_tupl3_, name, _num_args) = M_NARGS(__VA_ARGS__) \
|
||||
} M_C3(m_tupl3_, name, _num_args_ct);
|
||||
|
||||
#define TUPLEI_DEFINE_RECUR_TYPE_ELE(a) \
|
||||
TUPLEI_GET_TYPE a TUPLEI_GET_FIELD a ;
|
||||
#define M_TUPL3_DEFINE_RECUR_TYPE_ELE(a) \
|
||||
M_TUPL3_GET_TYPE a M_TUPL3_GET_FIELD a ;
|
||||
|
||||
/* Define the basic enumerate, identifying a parameter */
|
||||
#define TUPLEI_DEFINE_ENUM(name, ...) \
|
||||
#define M_TUPL3_DEFINE_ENUM(name, ...) \
|
||||
typedef enum { \
|
||||
M_C(name, _first_one_val), \
|
||||
M_MAP2_C(TUPLEI_DEFINE_ENUM_ELE , name, __VA_ARGS__) \
|
||||
M_MAP2_C(M_TUPL3_DEFINE_ENUM_ELE , name, __VA_ARGS__) \
|
||||
} M_C(name,_field_e);
|
||||
|
||||
#define TUPLEI_DEFINE_ENUM_ELE(name, a) \
|
||||
M_C4(name, _, TUPLEI_GET_FIELD a, _value)
|
||||
#define M_TUPL3_DEFINE_ENUM_ELE(name, a) \
|
||||
M_C4(name, _, M_TUPL3_GET_FIELD a, _value)
|
||||
|
||||
/* Control that all given oplists of all parameters are really oplists */
|
||||
#define TUPLEI_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(TUPLEI_CONTROL_OPLIST, name, __VA_ARGS__)
|
||||
#define M_TUPL3_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(M_TUPL3_CONTROL_OPLIST, name, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, TUPLEI_GET_FIELD a, \
|
||||
TUPLEI_GET_TYPE a, TUPLEI_GET_OPLIST a)
|
||||
#define M_TUPL3_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, M_TUPL3_GET_FIELD a, \
|
||||
M_TUPL3_GET_TYPE a, M_TUPL3_GET_OPLIST a)
|
||||
|
||||
/* Define the INIT method calling the INIT method for all params */
|
||||
#define TUPLEI_DEFINE_INIT(name, ...) \
|
||||
#define M_TUPL3_DEFINE_INIT(name, ...) \
|
||||
static inline void M_C(name, _init)(M_C(name,_ct) my) { \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_INIT_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_INIT_FUNC(a) \
|
||||
TUPLEI_CALL_INIT(a, my -> TUPLEI_GET_FIELD a );
|
||||
#define M_TUPL3_DEFINE_INIT_FUNC(a) \
|
||||
M_TUPL3_CALL_INIT(a, my -> M_TUPL3_GET_FIELD a );
|
||||
|
||||
/* Define the INIT_SET method calling the INIT_SET method for all params */
|
||||
#define TUPLEI_DEFINE_INIT_SET(name, ...) \
|
||||
#define M_TUPL3_DEFINE_INIT_SET(name, ...) \
|
||||
static inline void M_C(name, _init_set)(M_C(name,_ct) my , M_C(name,_ct) const org) { \
|
||||
TUPLEI_CONTRACT(org); \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_SET_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(org); \
|
||||
M_MAP(M_TUPL3_DEFINE_INIT_SET_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLEI_DEFINE_INIT_SET_FUNC(a) \
|
||||
TUPLEI_CALL_INIT_SET(a, my -> TUPLEI_GET_FIELD a , org -> TUPLEI_GET_FIELD a );
|
||||
#define M_TUPL3_DEFINE_INIT_SET_FUNC(a) \
|
||||
M_TUPL3_CALL_INIT_SET(a, my -> M_TUPL3_GET_FIELD a , org -> M_TUPL3_GET_FIELD a );
|
||||
|
||||
/* Define the INIT_WITH method calling the INIT_SET method for all params. */
|
||||
#define TUPLEI_DEFINE_INIT_SET2(name, ...) \
|
||||
#define M_TUPL3_DEFINE_INIT_SET2(name, ...) \
|
||||
static inline void M_C(name, _init_emplace)(M_C(name,_ct) my \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_SET2_PROTO, __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_INIT_SET2_PROTO, __VA_ARGS__) \
|
||||
) { \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_SET2_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_INIT_SET2_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_INIT_SET2_PROTO(a) \
|
||||
, TUPLEI_GET_TYPE a const TUPLEI_GET_FIELD a
|
||||
#define M_TUPL3_DEFINE_INIT_SET2_PROTO(a) \
|
||||
, M_TUPL3_GET_TYPE a const M_TUPL3_GET_FIELD a
|
||||
|
||||
#define TUPLEI_DEFINE_INIT_SET2_FUNC(a) \
|
||||
TUPLEI_CALL_INIT_SET(a, my -> TUPLEI_GET_FIELD a , TUPLEI_GET_FIELD a );
|
||||
#define M_TUPL3_DEFINE_INIT_SET2_FUNC(a) \
|
||||
M_TUPL3_CALL_INIT_SET(a, my -> M_TUPL3_GET_FIELD a , M_TUPL3_GET_FIELD a );
|
||||
|
||||
|
||||
/* Define the SET method calling the SET method for all params. */
|
||||
#define TUPLEI_DEFINE_SET(name, ...) \
|
||||
#define M_TUPL3_DEFINE_SET(name, ...) \
|
||||
static inline void M_C(name, _set)(M_C(name,_ct) my , \
|
||||
M_C(name,_ct) const org) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
TUPLEI_CONTRACT(org); \
|
||||
M_MAP(TUPLEI_DEFINE_SET_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(my); \
|
||||
M_TUPL3_CONTRACT(org); \
|
||||
M_MAP(M_TUPL3_DEFINE_SET_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_SET_FUNC(a) \
|
||||
TUPLEI_CALL_SET(a, my -> TUPLEI_GET_FIELD a , org -> TUPLEI_GET_FIELD a );
|
||||
#define M_TUPL3_DEFINE_SET_FUNC(a) \
|
||||
M_TUPL3_CALL_SET(a, my -> M_TUPL3_GET_FIELD a , org -> M_TUPL3_GET_FIELD a );
|
||||
|
||||
|
||||
/* Define the SET_WITH method calling the SET method for all params. */
|
||||
#define TUPLEI_DEFINE_SET2(name, ...) \
|
||||
#define M_TUPL3_DEFINE_SET2(name, ...) \
|
||||
static inline void M_C(name, _emplace)(M_C(name,_ct) my \
|
||||
M_MAP(TUPLEI_DEFINE_SET2_PROTO, __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_SET2_PROTO, __VA_ARGS__) \
|
||||
) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
M_MAP(TUPLEI_DEFINE_SET2_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(my); \
|
||||
M_MAP(M_TUPL3_DEFINE_SET2_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLEI_DEFINE_SET2_PROTO(a) \
|
||||
, TUPLEI_GET_TYPE a const TUPLEI_GET_FIELD a
|
||||
#define M_TUPL3_DEFINE_SET2_PROTO(a) \
|
||||
, M_TUPL3_GET_TYPE a const M_TUPL3_GET_FIELD a
|
||||
|
||||
#define TUPLEI_DEFINE_SET2_FUNC(a) \
|
||||
TUPLEI_CALL_SET(a, my -> TUPLEI_GET_FIELD a , TUPLEI_GET_FIELD a );
|
||||
#define M_TUPL3_DEFINE_SET2_FUNC(a) \
|
||||
M_TUPL3_CALL_SET(a, my -> M_TUPL3_GET_FIELD a , M_TUPL3_GET_FIELD a );
|
||||
|
||||
|
||||
/* Define the CLEAR method calling the CLEAR method for all params. */
|
||||
#define TUPLEI_DEFINE_CLEAR(name, ...) \
|
||||
#define M_TUPL3_DEFINE_CLEAR(name, ...) \
|
||||
static inline void M_C(name, _clear)(M_C(name,_ct) my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
M_MAP(TUPLEI_DEFINE_CLEAR_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(my); \
|
||||
M_MAP(M_TUPL3_DEFINE_CLEAR_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_CLEAR_FUNC(a) \
|
||||
TUPLEI_CALL_CLEAR(a, my -> TUPLEI_GET_FIELD a );
|
||||
#define M_TUPL3_DEFINE_CLEAR_FUNC(a) \
|
||||
M_TUPL3_CALL_CLEAR(a, my -> M_TUPL3_GET_FIELD a );
|
||||
|
||||
|
||||
/* Define the GET_AT_field & CGET_AT methods for all params. */
|
||||
#define TUPLEI_DEFINE_GETTER_FIELD(name, ...) \
|
||||
M_MAP2(TUPLEI_DEFINE_GETTER_FIELD_PROTO, name, __VA_ARGS__)
|
||||
#define M_TUPL3_DEFINE_GETTER_FIELD(name, ...) \
|
||||
M_MAP3(M_TUPL3_DEFINE_GETTER_FIELD_PROTO, name, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_DEFINE_GETTER_FIELD_PROTO(name, a) \
|
||||
static inline TUPLEI_GET_TYPE a * M_C3(name, _get_at_, TUPLEI_GET_FIELD a) \
|
||||
#define M_TUPL3_DEFINE_GETTER_FIELD_PROTO(name, num, a) \
|
||||
static inline M_TUPL3_GET_TYPE a * M_C3(name, _get_at_, M_TUPL3_GET_FIELD a) \
|
||||
(M_C(name,_ct) my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
return &(my->TUPLEI_GET_FIELD a); \
|
||||
M_TUPL3_CONTRACT(my); \
|
||||
return &(my->M_TUPL3_GET_FIELD a); \
|
||||
} \
|
||||
static inline TUPLEI_GET_TYPE a const * M_C3(name, _cget_at_, TUPLEI_GET_FIELD a) \
|
||||
static inline M_TUPL3_GET_TYPE a const * M_C3(name, _cget_at_, M_TUPL3_GET_FIELD a) \
|
||||
(M_C(name,_ct) const my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
return &(my->TUPLEI_GET_FIELD a); \
|
||||
}
|
||||
M_TUPL3_CONTRACT(my); \
|
||||
return &(my->M_TUPL3_GET_FIELD a); \
|
||||
} \
|
||||
/* Same but uses numerical index for accessing the field (internal) */ \
|
||||
static inline M_TUPL3_GET_TYPE a * M_C4(m_tupl3_, name, _get_at_, num) \
|
||||
(M_C(name,_ct) my) { \
|
||||
return &(my->M_TUPL3_GET_FIELD a); \
|
||||
} \
|
||||
|
||||
|
||||
/* Define the SET_field methods for all params. */
|
||||
#define TUPLEI_DEFINE_SETTER_FIELD(name, ...) \
|
||||
M_MAP2(TUPLEI_DEFINE_SETTER_FIELD_PROTO, name, __VA_ARGS__)
|
||||
#define M_TUPL3_DEFINE_SETTER_FIELD(name, ...) \
|
||||
M_MAP2(M_TUPL3_DEFINE_SETTER_FIELD_PROTO, name, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_DEFINE_SETTER_FIELD_PROTO(name, a) \
|
||||
static inline void M_C3(name, _set_, TUPLEI_GET_FIELD a) \
|
||||
(M_C(name,_ct) my, TUPLEI_GET_TYPE a const TUPLEI_GET_FIELD a) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
TUPLEI_CALL_SET(a, my ->TUPLEI_GET_FIELD a, TUPLEI_GET_FIELD a); \
|
||||
#define M_TUPL3_DEFINE_SETTER_FIELD_PROTO(name, a) \
|
||||
static inline void M_C3(name, _set_, M_TUPL3_GET_FIELD a) \
|
||||
(M_C(name,_ct) my, M_TUPL3_GET_TYPE a const M_TUPL3_GET_FIELD a) { \
|
||||
M_TUPL3_CONTRACT(my); \
|
||||
M_TUPL3_CALL_SET(a, my ->M_TUPL3_GET_FIELD a, M_TUPL3_GET_FIELD a); \
|
||||
}
|
||||
|
||||
|
||||
/* Define the CMP method by calling CMP methods for all params. */
|
||||
#define TUPLEI_DEFINE_CMP(name, ...) \
|
||||
#define M_TUPL3_DEFINE_CMP(name, ...) \
|
||||
static inline int M_C(name, _cmp)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2) { \
|
||||
int i; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
M_MAP(TUPLEI_DEFINE_CMP_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(e1); \
|
||||
M_TUPL3_CONTRACT(e2); \
|
||||
M_MAP(M_TUPL3_DEFINE_CMP_FUNC_P0, __VA_ARGS__) \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_CMP_FUNC(a) \
|
||||
i = TUPLEI_CALL_CMP(a, e1 -> TUPLEI_GET_FIELD a , e2 -> TUPLEI_GET_FIELD a ); \
|
||||
#define M_TUPL3_DEFINE_CMP_FUNC_P0(a) \
|
||||
M_IF(M_TUPL3_TEST_METHOD_P(CMP, a))(M_TUPL3_DEFINE_CMP_FUNC_P1, M_EAT)(a)
|
||||
#define M_TUPL3_DEFINE_CMP_FUNC_P1(a) \
|
||||
i = M_TUPL3_CALL_CMP(a, e1 -> M_TUPL3_GET_FIELD a , e2 -> M_TUPL3_GET_FIELD a ); \
|
||||
if (i != 0) return i;
|
||||
|
||||
|
||||
/* Define the CMP_ORDER method by calling CMP methods for all params
|
||||
In the right order
|
||||
FIXME: _cmp_order is not supported by algorithm yet.
|
||||
FIXME: All oplists shall define the CMP operator or at least one?
|
||||
*/
|
||||
#define TUPLEI_DEFINE_CMP_ORDER(name, ...) \
|
||||
#define M_TUPL3_DEFINE_CMP_ORDER(name, ...) \
|
||||
static inline int M_C(name, _cmp_order)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2, \
|
||||
const int order[]) { \
|
||||
int i, r; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
M_TUPL3_CONTRACT(e1); \
|
||||
M_TUPL3_CONTRACT(e2); \
|
||||
while (true) { \
|
||||
i=*order++; \
|
||||
switch (i) { \
|
||||
case 0: return 0; \
|
||||
M_MAP2(TUPLEI_DEFINE_CMP_ORDER_FUNC , name, __VA_ARGS__) \
|
||||
M_MAP2(M_TUPL3_DEFINE_CMP_ORDER_FUNC , name, __VA_ARGS__) \
|
||||
default: M_ASSERT(0); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_CMP_ORDER_FUNC(name, a) \
|
||||
case M_C4(name, _, TUPLEI_GET_FIELD a, _value): \
|
||||
case -M_C4(name, _, TUPLEI_GET_FIELD a, _value): \
|
||||
r = TUPLEI_CALL_CMP(a, e1 -> TUPLEI_GET_FIELD a , e2 -> TUPLEI_GET_FIELD a ); \
|
||||
#define M_TUPL3_DEFINE_CMP_ORDER_FUNC(name, a) \
|
||||
case M_C4(name, _, M_TUPL3_GET_FIELD a, _value): \
|
||||
case -M_C4(name, _, M_TUPL3_GET_FIELD a, _value): \
|
||||
r = M_TUPL3_CALL_CMP(a, e1 -> M_TUPL3_GET_FIELD a , e2 -> M_TUPL3_GET_FIELD a ); \
|
||||
if (r != 0) return i < 0 ? -r : r; \
|
||||
break;
|
||||
|
||||
|
||||
/* Define a CMP_field method for all given params that export a CMP method */
|
||||
#define TUPLEI_DEFINE_CMP_FIELD(name, ...) \
|
||||
M_MAP2(TUPLEI_MAP_CMP_FIELD, name, __VA_ARGS__)
|
||||
#define M_TUPL3_DEFINE_CMP_FIELD(name, ...) \
|
||||
M_MAP2(M_TUPL3_MAP_CMP_FIELD, name, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_MAP_CMP_FIELD(name, a) \
|
||||
M_IF_METHOD(CMP, TUPLEI_GET_OPLIST a)( \
|
||||
TUPLEI_DEFINE_CMP_FIELD_FUNC(name, TUPLEI_GET_FIELD a, TUPLEI_GET_CMP a), \
|
||||
#define M_TUPL3_MAP_CMP_FIELD(name, a) \
|
||||
M_IF_METHOD(CMP, M_TUPL3_GET_OPLIST a)( \
|
||||
M_TUPL3_DEFINE_CMP_FIELD_FUNC(name, M_TUPL3_GET_FIELD a, M_TUPL3_GET_CMP a), \
|
||||
)
|
||||
|
||||
#define TUPLEI_DEFINE_CMP_FIELD_FUNC(name, field, func_cmp) \
|
||||
#define M_TUPL3_DEFINE_CMP_FIELD_FUNC(name, field, func_cmp) \
|
||||
static inline int M_C3(name, _cmp_, field)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2) { \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
M_TUPL3_CONTRACT(e1); \
|
||||
M_TUPL3_CONTRACT(e2); \
|
||||
return func_cmp ( e1 -> field , e2 -> field ); \
|
||||
}
|
||||
|
||||
|
||||
/* Define a EQUAL method by calling the EQUAL methods for all params */
|
||||
#define TUPLEI_DEFINE_EQUAL(name, ...) \
|
||||
#define M_TUPL3_DEFINE_EQUAL(name, ...) \
|
||||
static inline bool M_C(name, _equal_p)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2) { \
|
||||
bool b; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
M_MAP(TUPLEI_DEFINE_EQUAL_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(e1); \
|
||||
M_TUPL3_CONTRACT(e2); \
|
||||
M_MAP(M_TUPL3_DEFINE_EQUAL_FUNC_P0, __VA_ARGS__) \
|
||||
return true; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_EQUAL_FUNC(a) \
|
||||
b = TUPLEI_CALL_EQUAL(a, e1 -> TUPLEI_GET_FIELD a , e2 -> TUPLEI_GET_FIELD a ); \
|
||||
#define M_TUPL3_DEFINE_EQUAL_FUNC_P0(a) \
|
||||
M_IF(M_TUPL3_TEST_METHOD_P(EQUAL, a))(M_TUPL3_DEFINE_EQUAL_FUNC_P1, M_EAT)(a)
|
||||
#define M_TUPL3_DEFINE_EQUAL_FUNC_P1(a) \
|
||||
b = M_TUPL3_CALL_EQUAL(a, e1 -> M_TUPL3_GET_FIELD a , e2 -> M_TUPL3_GET_FIELD a ); \
|
||||
if (!b) return false;
|
||||
|
||||
|
||||
/* Define a HASH method by calling the HASH methods for all params */
|
||||
#define TUPLEI_DEFINE_HASH(name, ...) \
|
||||
#define M_TUPL3_DEFINE_HASH(name, ...) \
|
||||
static inline size_t M_C(name, _hash)(M_C(name,_ct) const e1) { \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
M_TUPL3_CONTRACT(e1); \
|
||||
M_HASH_DECL(hash); \
|
||||
M_MAP(TUPLEI_DEFINE_HASH_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_HASH_FUNC_P0, __VA_ARGS__) \
|
||||
return M_HASH_FINAL (hash); \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_HASH_FUNC(a) \
|
||||
M_HASH_UP(hash, TUPLEI_CALL_HASH(a, e1 -> TUPLEI_GET_FIELD a) );
|
||||
#define M_TUPL3_DEFINE_HASH_FUNC_P0(a) \
|
||||
M_IF(M_TUPL3_TEST_METHOD_P(HASH, a))(M_TUPL3_DEFINE_HASH_FUNC_P1, M_EAT)(a)
|
||||
#define M_TUPL3_DEFINE_HASH_FUNC_P1(a) \
|
||||
M_HASH_UP(hash, M_TUPL3_CALL_HASH(a, e1 -> M_TUPL3_GET_FIELD a) );
|
||||
|
||||
|
||||
/* Define a GET_STR method by calling the GET_STR methods for all params */
|
||||
#define TUPLEI_DEFINE_GET_STR(name, ...) \
|
||||
#define M_TUPL3_DEFINE_GET_STR(name, ...) \
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
M_C(name,_ct) const el, \
|
||||
bool append) { \
|
||||
bool comma = false; \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_ASSERT (str != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "("); \
|
||||
M_MAP(TUPLEI_DEFINE_GET_STR_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_GET_STR_FUNC , __VA_ARGS__) \
|
||||
string_push_back (str, ')'); \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_GET_STR_FUNC(a) \
|
||||
#define M_TUPL3_DEFINE_GET_STR_FUNC(a) \
|
||||
if (comma) string_push_back (str, ','); \
|
||||
comma = true; \
|
||||
TUPLEI_CALL_GET_STR(a, str, el -> TUPLEI_GET_FIELD a, true); \
|
||||
M_TUPL3_CALL_GET_STR(a, str, el -> M_TUPL3_GET_FIELD a, true); \
|
||||
|
||||
|
||||
/* Define a OUT_STR method by calling the OUT_STR methods for all params */
|
||||
#define TUPLEI_DEFINE_OUT_STR(name, ...) \
|
||||
#define M_TUPL3_DEFINE_OUT_STR(name, ...) \
|
||||
static inline void M_C(name, _out_str)(FILE *f, \
|
||||
M_C(name,_ct) const el) { \
|
||||
bool comma = false; \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_ASSERT (f != NULL); \
|
||||
fputc('(', f); \
|
||||
M_MAP(TUPLEI_DEFINE_OUT_STR_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_OUT_STR_FUNC , __VA_ARGS__) \
|
||||
fputc (')', f); \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_OUT_STR_FUNC(a) \
|
||||
#define M_TUPL3_DEFINE_OUT_STR_FUNC(a) \
|
||||
if (comma) fputc (',', f); \
|
||||
comma = true; \
|
||||
TUPLEI_CALL_OUT_STR(a, f, el -> TUPLEI_GET_FIELD a); \
|
||||
M_TUPL3_CALL_OUT_STR(a, f, el -> M_TUPL3_GET_FIELD a); \
|
||||
|
||||
|
||||
/* Define a IN_STR method by calling the IN_STR methods for all params */
|
||||
#define TUPLEI_DEFINE_IN_STR(name, ...) \
|
||||
#define M_TUPL3_DEFINE_IN_STR(name, ...) \
|
||||
static inline bool M_C(name, _in_str)(M_C(name,_ct) el, FILE *f) { \
|
||||
bool comma = false; \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_ASSERT (f != NULL); \
|
||||
int c = fgetc(f); \
|
||||
if (c != '(') return false; \
|
||||
M_MAP(TUPLEI_DEFINE_IN_STR_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_IN_STR_FUNC , __VA_ARGS__) \
|
||||
c = fgetc(f); \
|
||||
return (c == ')'); \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_IN_STR_FUNC(a) \
|
||||
#define M_TUPL3_DEFINE_IN_STR_FUNC(a) \
|
||||
if (comma) { \
|
||||
c = fgetc (f); \
|
||||
if (c != ',' || c == EOF) return false; \
|
||||
} \
|
||||
comma = true; \
|
||||
if (TUPLEI_CALL_IN_STR(a, el -> TUPLEI_GET_FIELD a, f) == false) \
|
||||
if (M_TUPL3_CALL_IN_STR(a, el -> M_TUPL3_GET_FIELD a, f) == false) \
|
||||
return false ; \
|
||||
|
||||
|
||||
/* Define a PARSE_STR method by calling the PARSE_STR methods for all params */
|
||||
#define TUPLEI_DEFINE_PARSE_STR(name, ...) \
|
||||
#define M_TUPL3_DEFINE_PARSE_STR(name, ...) \
|
||||
static inline bool M_C(name, _parse_str)(M_C(name,_ct) el, \
|
||||
const char str[], \
|
||||
const char **endptr) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_ASSERT (str != NULL); \
|
||||
bool success = false; \
|
||||
bool comma = false; \
|
||||
int c = *str++; \
|
||||
if (c != '(') goto exit; \
|
||||
M_MAP(TUPLEI_DEFINE_PARSE_STR_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_PARSE_STR_FUNC , __VA_ARGS__) \
|
||||
c = *str++; \
|
||||
success = (c == ')'); \
|
||||
exit: \
|
||||
@@ -505,58 +518,58 @@ namespace m_lib {
|
||||
return success; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_PARSE_STR_FUNC(a) \
|
||||
#define M_TUPL3_DEFINE_PARSE_STR_FUNC(a) \
|
||||
if (comma) { \
|
||||
c = *str++; \
|
||||
if (c != ',' || c == 0) goto exit; \
|
||||
} \
|
||||
comma = true; \
|
||||
if (TUPLEI_CALL_PARSE_STR(a, el -> TUPLEI_GET_FIELD a, str, &str) == false) \
|
||||
if (M_TUPL3_CALL_PARSE_STR(a, el -> M_TUPL3_GET_FIELD a, str, &str) == false) \
|
||||
goto exit ; \
|
||||
|
||||
|
||||
/* Return the parameter name as a C string */
|
||||
#define TUPLEI_STRINGIFY_NAME(a) \
|
||||
M_APPLY(M_AS_STR, TUPLEI_GET_FIELD a)
|
||||
#define M_TUPL3_STRINGIFY_NAME(a) \
|
||||
M_AS_STR(M_TUPL3_GET_FIELD a)
|
||||
|
||||
|
||||
/* Define a OUT_SERIAL method by calling the OUT_SERIAL methods for all params */
|
||||
#define TUPLEI_DEFINE_OUT_SERIAL(name, ...) \
|
||||
#define M_TUPL3_DEFINE_OUT_SERIAL(name, ...) \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, \
|
||||
M_C(name,_ct) const el) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
const int field_max = M_NARGS(__VA_ARGS__); \
|
||||
/* Define a constant static table of all fields names */ \
|
||||
static const char *const field_name[] = \
|
||||
{ M_REDUCE(TUPLEI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
{ M_REDUCE(M_TUPL3_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); \
|
||||
M_MAP(TUPLEI_DEFINE_OUT_SERIAL_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_OUT_SERIAL_FUNC , __VA_ARGS__) \
|
||||
M_ASSERT( index == field_max); \
|
||||
ret |= f->m_interface->write_tuple_end(local, f); \
|
||||
return ret & M_SERIAL_FAIL; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_OUT_SERIAL_FUNC(a) \
|
||||
#define M_TUPL3_DEFINE_OUT_SERIAL_FUNC(a) \
|
||||
f->m_interface->write_tuple_id(local, f, field_name, field_max, index); \
|
||||
TUPLEI_CALL_OUT_SERIAL(a, f, el -> TUPLEI_GET_FIELD a); \
|
||||
M_TUPL3_CALL_OUT_SERIAL(a, f, el -> M_TUPL3_GET_FIELD a); \
|
||||
index++; \
|
||||
|
||||
|
||||
/* Define a IN_SERIAL method by calling the IN_SERIAL methods for all params */
|
||||
#define TUPLEI_DEFINE_IN_SERIAL(name, ...) \
|
||||
#define M_TUPL3_DEFINE_IN_SERIAL(name, ...) \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(M_C(name,_ct) el, m_serial_read_t f) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_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(TUPLEI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
{ M_REDUCE(M_TUPL3_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); \
|
||||
@@ -565,7 +578,7 @@ namespace m_lib {
|
||||
if (ret == M_SERIAL_OK_CONTINUE) { \
|
||||
M_ASSERT (index >= 0 && index < field_max); \
|
||||
switch (1+index) { \
|
||||
M_MAP2(TUPLEI_DEFINE_IN_SERIAL_FUNC , name, __VA_ARGS__) \
|
||||
M_MAP2(M_TUPL3_DEFINE_IN_SERIAL_FUNC , name, __VA_ARGS__) \
|
||||
default: M_ASSERT(0); \
|
||||
} \
|
||||
ret = (ret == M_SERIAL_OK_DONE) ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL; \
|
||||
@@ -574,88 +587,143 @@ namespace m_lib {
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_IN_SERIAL_FUNC(name, a) \
|
||||
case M_C4(name, _, TUPLEI_GET_FIELD a, _value): \
|
||||
ret = TUPLEI_CALL_IN_SERIAL(a, el -> TUPLEI_GET_FIELD a, f); \
|
||||
#define M_TUPL3_DEFINE_IN_SERIAL_FUNC(name, a) \
|
||||
case M_C4(name, _, M_TUPL3_GET_FIELD a, _value): \
|
||||
ret = M_TUPL3_CALL_IN_SERIAL(a, el -> M_TUPL3_GET_FIELD a, f); \
|
||||
break; \
|
||||
|
||||
|
||||
/* Define a INIT_MOVE method by calling the INIT_MOVE methods for all params */
|
||||
#define TUPLEI_DEFINE_INIT_MOVE(name, ...) \
|
||||
#define M_TUPL3_DEFINE_INIT_MOVE(name, ...) \
|
||||
static inline void M_C(name, _init_move)(M_C(name,_ct) el, M_C(name,_ct) org) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_MOVE_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_MAP(M_TUPL3_DEFINE_INIT_MOVE_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_INIT_MOVE_FUNC(a) \
|
||||
TUPLEI_CALL_INIT_MOVE(a, el -> TUPLEI_GET_FIELD a, org -> TUPLEI_GET_FIELD a);
|
||||
#define M_TUPL3_DEFINE_INIT_MOVE_FUNC(a) \
|
||||
M_TUPL3_CALL_INIT_MOVE(a, el -> M_TUPL3_GET_FIELD a, org -> M_TUPL3_GET_FIELD a);
|
||||
|
||||
|
||||
/* Define a MOVE method by calling the MOVE methods for all params */
|
||||
#define TUPLEI_DEFINE_MOVE(name, ...) \
|
||||
#define M_TUPL3_DEFINE_MOVE(name, ...) \
|
||||
static inline void M_C(name, _move)(M_C(name,_ct) el, M_C(name,_ct) org) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_MAP(TUPLEI_DEFINE_MOVE_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_MAP(M_TUPL3_DEFINE_MOVE_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_MOVE_FUNC(a) \
|
||||
TUPLEI_CALL_MOVE(a, el -> TUPLEI_GET_FIELD a, org -> TUPLEI_GET_FIELD a);
|
||||
#define M_TUPL3_DEFINE_MOVE_FUNC(a) \
|
||||
M_TUPL3_CALL_MOVE(a, el -> M_TUPL3_GET_FIELD a, org -> M_TUPL3_GET_FIELD a);
|
||||
|
||||
|
||||
/* Define a SWAP method by calling the SWAP methods for all params */
|
||||
#define TUPLEI_DEFINE_SWAP(name, ...) \
|
||||
#define M_TUPL3_DEFINE_SWAP(name, ...) \
|
||||
static inline void M_C(name, _swap)(M_C(name,_ct) el1, M_C(name,_ct) el2) { \
|
||||
TUPLEI_CONTRACT(el1); \
|
||||
TUPLEI_CONTRACT(el2); \
|
||||
M_MAP(TUPLEI_DEFINE_SWAP_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(el1); \
|
||||
M_TUPL3_CONTRACT(el2); \
|
||||
M_MAP(M_TUPL3_DEFINE_SWAP_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_SWAP_FUNC(a) \
|
||||
TUPLEI_CALL_SWAP(a, el1 -> TUPLEI_GET_FIELD a, el2 -> TUPLEI_GET_FIELD a);
|
||||
#define M_TUPL3_DEFINE_SWAP_FUNC(a) \
|
||||
M_TUPL3_CALL_SWAP(a, el1 -> M_TUPL3_GET_FIELD a, el2 -> M_TUPL3_GET_FIELD a);
|
||||
|
||||
|
||||
/* Define a CLEAN method by calling the CLEAN methods for all params */
|
||||
#define TUPLEI_DEFINE_CLEAN(name, ...) \
|
||||
static inline void M_C(name, _clean)(M_C(name,_ct) el1) { \
|
||||
TUPLEI_CONTRACT(el1); \
|
||||
M_MAP(TUPLEI_DEFINE_CLEAN_FUNC , __VA_ARGS__) \
|
||||
/* Define a RESET method by calling the RESET methods for all params */
|
||||
#define M_TUPL3_DEFINE_RESET(name, ...) \
|
||||
static inline void M_C(name, _reset)(M_C(name,_ct) el1) { \
|
||||
M_TUPL3_CONTRACT(el1); \
|
||||
M_MAP(M_TUPL3_DEFINE_RESET_FUNC , __VA_ARGS__) \
|
||||
} \
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(M_C(name,_ct) el1) { \
|
||||
M_C(name, _reset)(el1); \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_CLEAN_FUNC(a) \
|
||||
TUPLEI_CALL_CLEAN(a, el1 -> TUPLEI_GET_FIELD a);
|
||||
#define M_TUPL3_DEFINE_RESET_FUNC(a) \
|
||||
M_TUPL3_CALL_RESET(a, el1 -> M_TUPL3_GET_FIELD a);
|
||||
|
||||
|
||||
/* INIT_WITH macro enabling recursive INIT_WITH initialization
|
||||
tuple = { int, string_t, array<string_t> }
|
||||
USAGE:
|
||||
M_LET( (x, 2, ("John"), ( ("Bear"), ("Rabbit") )), tuple_t)
|
||||
|
||||
"If you think it's simple, you're deluding yourself."
|
||||
|
||||
Several pass are done:
|
||||
1) If the number of arguments doesn't match the number of oplists of the
|
||||
tuple oplist, it is assumed something is wrong. It uses the _init_emplace
|
||||
function to provide proper warning in such case.
|
||||
2) Otherwise, it checks that the number of arguments matches the number
|
||||
of arguments of the tuple definition.
|
||||
3) Mix all arguments with their associated oplists to have pair (arg, oplist),
|
||||
4) Map the following macro for each computed pair :
|
||||
4.a) If INIT_WITH macro is not defined for this pair, it uses INIT_SET
|
||||
4.b) If the argument is encapsulated with parenthesis, it uses INIT_WITH
|
||||
4.c) If the oplist property LET_AS_INIT_WITH is defined, it uses INIT_WITH
|
||||
4.d) Otherwise it uses INIT_SET.
|
||||
*/
|
||||
#define M_TUPL3_INIT_WITH(oplist, dest, ...) \
|
||||
M_TUPL3_INIT_WITH_P1(M_GET_NAME oplist, M_GET_OPLIST oplist, dest, __VA_ARGS__)
|
||||
#define M_TUPL3_INIT_WITH_P1(name, oplist_arglist, dest, ...) \
|
||||
M_IF(M_NOTEQUAL( M_NARGS oplist_arglist, M_NARGS (__VA_ARGS__))) \
|
||||
(M_TUPL3_INIT_WITH_P1_FUNC, M_TUPL3_INIT_WITH_P1_MACRO)(name, oplist_arglist, dest, __VA_ARGS__)
|
||||
#define M_TUPL3_INIT_WITH_P1_FUNC(name, oplist_arglist, dest, ...) \
|
||||
M_C(name, _init_emplace)(dest, __VA_ARGS__)
|
||||
#define M_TUPL3_INIT_WITH_P1_MACRO(name, oplist_arglist, dest, ...) \
|
||||
( M_STATIC_ASSERT( M_NARGS oplist_arglist == M_C3(m_tupl3_, name, _num_args), M_LIB_DIMENSION_ERROR, "The number of oplists given to TUPLE_OPLIST don't match the number of oplists used to create the tuple." ), \
|
||||
M_STATIC_ASSERT( M_NARGS(__VA_ARGS__) == M_C3(m_tupl3_, name, _num_args), M_LIB_DIMENSION_ERROR, "Missing / Too many arguments for tuple"), \
|
||||
M_MAP3(M_TUPL3_INIT_WITH_P2, (name, dest), M_OPFLAT M_MERGE_ARGLIST( oplist_arglist, (__VA_ARGS__) ) ) \
|
||||
(void) 0)
|
||||
#define M_TUPL3_INIT_WITH_P2(name_dest, num, pair) \
|
||||
M_TUPL3_INIT_WITH_P3( M_PAIR_1 name_dest, M_PAIR_2 name_dest, num, M_PAIR_1 pair, M_PAIR_2 pair )
|
||||
#define M_TUPL3_INIT_WITH_P3(name, dest, num, oplist, param) \
|
||||
M_IF(M_TEST_METHOD_P(INIT_WITH, oplist))(M_TUPL3_INIT_WITH_P4, M_TUPL3_INIT_WITH_SET)(name, dest, num, oplist, param)
|
||||
#define M_TUPL3_INIT_WITH_SET(name, dest, num, oplist, param) \
|
||||
M_CALL_INIT_SET (oplist, *M_C4(m_tupl3_, name, _get_at_, num)(dest), param) ,
|
||||
#define M_TUPL3_INIT_WITH_P4(name, dest, num, oplist, param) \
|
||||
M_IF(M_PARENTHESIS_P( param))(M_TUPL3_INIT_WITH_P5, M_TUPL3_INIT_WITH_P6)(name, dest, num, oplist, param)
|
||||
#define M_TUPL3_INIT_WITH_P5(name, dest, num, oplist, param) \
|
||||
M_CALL_INIT_WITH(oplist, *M_C4(m_tupl3_, name, _get_at_, num)(dest), M_REMOVE_PARENTHESIS (param) ) ,
|
||||
#define M_TUPL3_INIT_WITH_P6(name, dest, num, oplist, param) \
|
||||
M_IF(M_GET_PROPERTY(oplist, LET_AS_INIT_WITH))(M_TUPL3_INIT_WITH_P5, M_TUPL3_INIT_WITH_SET)(name, dest, num, oplist, param)
|
||||
|
||||
/* Macros for testing for the presence of a method in the parameter (name, type, oplist) */
|
||||
#define TUPLEI_TEST_METHOD_P(method, trio) \
|
||||
M_APPLY(TUPLEI_TEST_METHOD2_P, method, M_OPFLAT trio)
|
||||
#define M_TUPL3_TEST_METHOD_P(method, trio) \
|
||||
M_APPLY(M_TUPL3_TEST_METHOD2_P, method, M_OPFLAT trio)
|
||||
|
||||
#define TUPLEI_TEST_METHOD2_P(method, f, t, op) \
|
||||
#define M_TUPL3_TEST_METHOD2_P(method, f, t, op) \
|
||||
M_TEST_METHOD_P(method, op)
|
||||
|
||||
|
||||
/* Macros for testing for the presence of a method in all the params */
|
||||
#define TUPLEI_IF_ALL(method, ...) \
|
||||
M_IF(M_REDUCE2(TUPLEI_TEST_METHOD_P, M_AND, method, __VA_ARGS__))
|
||||
#define M_TUPL3_IF_ALL(method, ...) \
|
||||
M_IF(M_REDUCE2(M_TUPL3_TEST_METHOD_P, M_AND, method, __VA_ARGS__))
|
||||
|
||||
/* Macros for testing for the presence of a method in at least one params */
|
||||
#define M_TUPL3_IF_ONE(method, ...) \
|
||||
M_IF(M_REDUCE2(M_TUPL3_TEST_METHOD_P, M_OR, method, __VA_ARGS__))
|
||||
|
||||
// deferred evaluation
|
||||
#define TUPLEI_OPLIST_P1(arg) TUPLEI_OPLIST_P2 arg
|
||||
#define M_TUPL3_OPLIST_P1(arg) M_TUPL3_OPLIST_P2 arg
|
||||
|
||||
/* 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__)
|
||||
#define M_TUPL3_OPLIST_P2(name, ...) \
|
||||
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(M_TUPL3_OPLIST_P3, M_TUPL3_OPLIST_FAILURE)(name, __VA_ARGS__)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define TUPLEI_OPLIST_FAILURE(name, ...) \
|
||||
((M_LIB_ERROR(ONE_ARGUMENT_OF_TUPLEI_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)))
|
||||
#define M_TUPL3_OPLIST_FAILURE(name, ...) \
|
||||
((M_LIB_ERROR(ONE_ARGUMENT_OF_M_TUPL3_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)))
|
||||
|
||||
/* Define the TUPLE oplist */
|
||||
#define TUPLEI_OPLIST_P3(name, ...) \
|
||||
#define M_TUPL3_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_emplace)), \
|
||||
INIT_WITH(API_1(M_TUPL3_INIT_WITH)), \
|
||||
SET(M_C(name,_set)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
OPLIST( (__VA_ARGS__) ), \
|
||||
M_IF_METHOD_ALL(CMP, __VA_ARGS__)(CMP(M_C(name, _cmp)),), \
|
||||
M_IF_METHOD_ALL(HASH, __VA_ARGS__)(HASH(M_C(name, _hash)),), \
|
||||
M_IF_METHOD_ALL(EQUAL, __VA_ARGS__)(EQUAL(M_C(name, _equal_p)),), \
|
||||
@@ -668,7 +736,7 @@ namespace m_lib {
|
||||
M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(INIT_MOVE(M_C(name, _init_move)),), \
|
||||
M_IF_METHOD_ALL(MOVE, __VA_ARGS__)(MOVE(M_C(name, _move)),), \
|
||||
M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(SWAP(M_C(name, _swap)),), \
|
||||
M_IF_METHOD_ALL(CLEAN, __VA_ARGS__)(CLEAN(M_C(name, _clean)),), \
|
||||
M_IF_METHOD_ALL(RESET, __VA_ARGS__)(RESET(M_C(name, _reset)),), \
|
||||
M_IF_METHOD(NEW, M_RET_ARG1(__VA_ARGS__,))(NEW(M_DELAY2(M_GET_NEW) M_RET_ARG1(__VA_ARGS__,)),), \
|
||||
M_IF_METHOD(REALLOC, M_RET_ARG1(__VA_ARGS__,))(REALLOC(M_DELAY2(M_GET_REALLOC) M_RET_ARG1(__VA_ARGS__,)),), \
|
||||
M_IF_METHOD(DEL, M_RET_ARG1(__VA_ARGS__,))(DEL(M_DELAY2(M_GET_DEL) M_RET_ARG1(__VA_ARGS__,)),), \
|
||||
|
||||
+292
-289
@@ -34,9 +34,7 @@
|
||||
USAGE:
|
||||
VARIANT_DEF2(name, [(field1, type1, oplist1), (field2, type2, oplist2), ...] ) */
|
||||
#define VARIANT_DEF2(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
VARIANTI_DEF2_P1( (name, M_C(name, _t) VARIANTI_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
M_END_PROTECTED_CODE
|
||||
VARIANT_DEF2_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define the variant type and functions
|
||||
@@ -45,7 +43,7 @@
|
||||
VARIANT_DEF2_AS(name, name_t, [(field1, type1, oplist1), (field2, type2, oplist2), ...] ) */
|
||||
#define VARIANT_DEF2_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
VARIANTI_DEF2_P1( (name, name_t VARIANTI_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
M_VAR1ANT_DEF2_P1( (name, name_t M_VAR1ANT_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
@@ -53,138 +51,138 @@
|
||||
USAGE: VARIANT_OPLIST(name[, oplist of the first type, ...]) */
|
||||
#define VARIANT_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(VARIANTI_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST)), \
|
||||
VARIANTI_OPLIST_P1((__VA_ARGS__ )))
|
||||
(M_VAR1ANT_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST)), \
|
||||
M_VAR1ANT_OPLIST_P1((__VA_ARGS__ )))
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Contract of a variant. */
|
||||
#define VARIANTI_CONTRACT(name, my) do { \
|
||||
#define M_VAR1ANT_CONTRACT(name, my) do { \
|
||||
M_ASSERT(my != NULL); \
|
||||
M_ASSERT(my->type >= M_C(name, _EMPTY)); \
|
||||
M_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(VARIANTI_INJECT_OPLIST_A, __VA_ARGS__)
|
||||
#define M_VAR1ANT_INJECT_GLOBAL(...) \
|
||||
M_MAP(M_VAR1ANT_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
|
||||
#define M_VAR1ANT_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
M_VAR1ANT_INJECT_OPLIST_B duo_or_trio
|
||||
|
||||
#define VARIANTI_INJECT_OPLIST_B( f, ... ) \
|
||||
#define M_VAR1ANT_INJECT_OPLIST_B( f, ... ) \
|
||||
M_DEFERRED_COMMA \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
|
||||
|
||||
// Deferred evaluation
|
||||
#define VARIANTI_DEF2_P1(...) VARIANTI_DEF2_P2 __VA_ARGS__
|
||||
#define M_VAR1ANT_DEF2_P1(...) M_VAR1ANT_DEF2_P2 __VA_ARGS__
|
||||
|
||||
// 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__))
|
||||
#define M_VAR1ANT_IF_ALL_OPLIST(...) \
|
||||
M_IF(M_REDUCE(M_VAR1ANT_IS_OPLIST_P, M_AND, __VA_ARGS__))
|
||||
|
||||
// Test if the third argument is an oplist
|
||||
#define VARIANTI_IS_OPLIST_P(a) \
|
||||
#define M_VAR1ANT_IS_OPLIST_P(a) \
|
||||
M_OPLIST_P(M_RET_ARG3 a)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define VARIANTI_DEF2_P2(name, name_t, ...) \
|
||||
VARIANTI_IF_ALL_OPLIST(__VA_ARGS__)(VARIANTI_DEF2_P3, VARIANTI_DEF2_FAILURE)(name, name_t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_DEF2_P2(name, name_t, ...) \
|
||||
M_VAR1ANT_IF_ALL_OPLIST(__VA_ARGS__)(M_VAR1ANT_DEF2_P3, M_VAR1ANT_DEF2_FAILURE)(name, name_t, __VA_ARGS__)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define VARIANTI_DEF2_FAILURE(name, name_t, ...) \
|
||||
#define M_VAR1ANT_DEF2_FAILURE(name, name_t, ...) \
|
||||
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, name_t, ...) \
|
||||
VARIANTI_DEFINE_TYPE(name, name_t, __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__) \
|
||||
VARIANTI_DEFINE_SET(name, __VA_ARGS__) \
|
||||
VARIANTI_DEFINE_TEST_P(name, __VA_ARGS__) \
|
||||
VARIANTI_IF_ALL(INIT, __VA_ARGS__) \
|
||||
(VARIANTI_DEFINE_INIT_FIELD(name, __VA_ARGS__),) \
|
||||
VARIANTI_DEFINE_INIT_SETTER_FIELD(name, __VA_ARGS__) \
|
||||
VARIANTI_DEFINE_SETTER_FIELD(name, __VA_ARGS__) \
|
||||
VARIANTI_DEFINE_GETTER_FIELD(name, __VA_ARGS__) \
|
||||
VARIANTI_DEFINE_CLEAN_FUNC(name, __VA_ARGS__) \
|
||||
VARIANTI_IF_ALL(HASH, __VA_ARGS__) \
|
||||
(VARIANTI_DEFINE_HASH(name, __VA_ARGS__),) \
|
||||
VARIANTI_IF_ALL(EQUAL, __VA_ARGS__) \
|
||||
(VARIANTI_DEFINE_EQUAL(name, __VA_ARGS__),) \
|
||||
VARIANTI_IF_ALL(GET_STR, __VA_ARGS__) \
|
||||
(VARIANTI_DEFINE_GET_STR(name, __VA_ARGS__),) \
|
||||
VARIANTI_IF_ALL2(PARSE_STR, INIT, __VA_ARGS__) \
|
||||
(VARIANTI_DEFINE_PARSE_STR(name, __VA_ARGS__),) \
|
||||
VARIANTI_IF_ALL(OUT_STR, __VA_ARGS__) \
|
||||
(VARIANTI_DEFINE_OUT_STR(name, __VA_ARGS__),) \
|
||||
VARIANTI_IF_ALL2(IN_STR, INIT, __VA_ARGS__) \
|
||||
(VARIANTI_DEFINE_IN_STR(name, __VA_ARGS__),) \
|
||||
VARIANTI_IF_ALL(OUT_SERIAL, __VA_ARGS__) \
|
||||
(VARIANTI_DEFINE_OUT_SERIAL(name, __VA_ARGS__),) \
|
||||
VARIANTI_IF_ALL2(IN_SERIAL, INIT, __VA_ARGS__) \
|
||||
(VARIANTI_DEFINE_IN_SERIAL(name, __VA_ARGS__),) \
|
||||
VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \
|
||||
(VARIANTI_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \
|
||||
VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \
|
||||
(VARIANTI_DEFINE_MOVE(name, __VA_ARGS__),) \
|
||||
VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \
|
||||
(VARIANTI_DEFINE_MOVER(name, __VA_ARGS__),) \
|
||||
VARIANTI_IF_ALL(SWAP, __VA_ARGS__) \
|
||||
(VARIANTI_DEFINE_SWAP(name, __VA_ARGS__),)
|
||||
#define M_VAR1ANT_DEF2_P3(name, name_t, ...) \
|
||||
M_VAR1ANT_DEFINE_TYPE(name, name_t, __VA_ARGS__) \
|
||||
M_VAR1ANT_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_DEFINE_INIT(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_DEFINE_CLEAR(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_DEFINE_INIT_SET(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_DEFINE_SET(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_DEFINE_TEST_P(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL(INIT, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_INIT_FIELD(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_DEFINE_INIT_SETTER_FIELD(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_DEFINE_SETTER_FIELD(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_DEFINE_GETTER_FIELD(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_DEFINE_RESET_FUNC(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL(HASH, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_HASH(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(EQUAL, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_EQUAL(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(GET_STR, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_GET_STR(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL2(PARSE_STR, INIT, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_PARSE_STR(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(OUT_STR, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_OUT_STR(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL2(IN_STR, INIT, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_IN_STR(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(OUT_SERIAL, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_OUT_SERIAL(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL2(IN_SERIAL, INIT, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_IN_SERIAL(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(INIT_MOVE, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(INIT_MOVE, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_MOVE(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(INIT_MOVE, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_MOVER(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(SWAP, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_SWAP(name, __VA_ARGS__),)
|
||||
|
||||
|
||||
/* Get the field name, the type, the oplist or the methods
|
||||
based on the variant (field, type, oplist) */
|
||||
#define VARIANTI_GET_FIELD(f,t,o) f
|
||||
#define VARIANTI_GET_TYPE(f,t,o) t
|
||||
#define VARIANTI_GET_OPLIST(f,t,o) o
|
||||
#define VARIANTI_GET_INIT(f,t,o) M_GET_INIT o
|
||||
#define VARIANTI_GET_INIT_SET(f,t,o) M_GET_INIT_SET o
|
||||
#define VARIANTI_GET_INIT_MOVE(f,t,o) M_GET_INIT_MOVE o
|
||||
#define VARIANTI_GET_MOVE(f,t,o) M_GET_MOVE o
|
||||
#define VARIANTI_GET_SET(f,t,o) M_GET_SET o
|
||||
#define VARIANTI_GET_CLEAR(f,t,o) M_GET_CLEAR o
|
||||
#define VARIANTI_GET_CMP(f,t,o) M_GET_CMP o
|
||||
#define VARIANTI_GET_HASH(f,t,o) M_GET_HASH o
|
||||
#define VARIANTI_GET_EQUAL(f,t,o) M_GET_EQUAL o
|
||||
#define VARIANTI_GET_STR(f,t,o) M_GET_GET_STR o
|
||||
#define VARIANTI_GET_PARSE_STR(f,t,o) M_GET_PARSE_STR o
|
||||
#define VARIANTI_GET_OUT_STR(f,t,o) M_GET_OUT_STR o
|
||||
#define VARIANTI_GET_IN_STR(f,t,o) M_GET_IN_STR o
|
||||
#define VARIANTI_GET_OUT_SERIAL(f,t,o) M_GET_OUT_SERIAL o
|
||||
#define VARIANTI_GET_IN_SERIAL(f,t,o) M_GET_IN_SERIAL o
|
||||
#define VARIANTI_GET_SWAP(f,t,o) M_GET_SWAP o
|
||||
#define M_VAR1ANT_GET_FIELD(f,t,o) f
|
||||
#define M_VAR1ANT_GET_TYPE(f,t,o) t
|
||||
#define M_VAR1ANT_GET_OPLIST(f,t,o) o
|
||||
#define M_VAR1ANT_GET_INIT(f,t,o) M_GET_INIT o
|
||||
#define M_VAR1ANT_GET_INIT_SET(f,t,o) M_GET_INIT_SET o
|
||||
#define M_VAR1ANT_GET_INIT_MOVE(f,t,o) M_GET_INIT_MOVE o
|
||||
#define M_VAR1ANT_GET_MOVE(f,t,o) M_GET_MOVE o
|
||||
#define M_VAR1ANT_GET_SET(f,t,o) M_GET_SET o
|
||||
#define M_VAR1ANT_GET_CLEAR(f,t,o) M_GET_CLEAR o
|
||||
#define M_VAR1ANT_GET_CMP(f,t,o) M_GET_CMP o
|
||||
#define M_VAR1ANT_GET_HASH(f,t,o) M_GET_HASH o
|
||||
#define M_VAR1ANT_GET_EQUAL(f,t,o) M_GET_EQUAL o
|
||||
#define M_VAR1ANT_GET_STR(f,t,o) M_GET_GET_STR o
|
||||
#define M_VAR1ANT_GET_PARSE_STR(f,t,o) M_GET_PARSE_STR o
|
||||
#define M_VAR1ANT_GET_OUT_STR(f,t,o) M_GET_OUT_STR o
|
||||
#define M_VAR1ANT_GET_IN_STR(f,t,o) M_GET_IN_STR o
|
||||
#define M_VAR1ANT_GET_OUT_SERIAL(f,t,o) M_GET_OUT_SERIAL o
|
||||
#define M_VAR1ANT_GET_IN_SERIAL(f,t,o) M_GET_IN_SERIAL o
|
||||
#define M_VAR1ANT_GET_SWAP(f,t,o) M_GET_SWAP o
|
||||
|
||||
/* Call the methods through API */
|
||||
#define VARIANTI_CALL_INIT(t, ...) M_APPLY_API(VARIANTI_GET_INIT t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_INIT_SET(t, ...) M_APPLY_API(VARIANTI_GET_INIT_SET t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_INIT_MOVE(t, ...) M_APPLY_API(VARIANTI_GET_INIT_MOVE t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_MOVE(t, ...) M_APPLY_API(VARIANTI_GET_MOVE t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_SET(t, ...) M_APPLY_API(VARIANTI_GET_SET t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_CLEAR(t, ...) M_APPLY_API(VARIANTI_GET_CLEAR t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_CMP(t, ...) M_APPLY_API(VARIANTI_GET_CMP t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_HASH(t, ...) M_APPLY_API(VARIANTI_GET_HASH t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_EQUAL(t, ...) M_APPLY_API(VARIANTI_GET_EQUAL t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_GET_STR(t, ...) M_APPLY_API(VARIANTI_GET_STR t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_PARSE_STR(t, ...) M_APPLY_API(VARIANTI_GET_PARSE_STR t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_OUT_STR(t, ...) M_APPLY_API(VARIANTI_GET_OUT_STR t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_IN_STR(t, ...) M_APPLY_API(VARIANTI_GET_IN_STR t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_OUT_SERIAL(t, ...) M_APPLY_API(VARIANTI_GET_OUT_SERIAL t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_IN_SERIAL(t, ...) M_APPLY_API(VARIANTI_GET_IN_SERIAL t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define VARIANTI_CALL_SWAP(t, ...) M_APPLY_API(VARIANTI_GET_SWAP t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_INIT(t, ...) M_APPLY_API(M_VAR1ANT_GET_INIT t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_INIT_SET(t, ...) M_APPLY_API(M_VAR1ANT_GET_INIT_SET t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_INIT_MOVE(t, ...) M_APPLY_API(M_VAR1ANT_GET_INIT_MOVE t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_MOVE(t, ...) M_APPLY_API(M_VAR1ANT_GET_MOVE t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_SET(t, ...) M_APPLY_API(M_VAR1ANT_GET_SET t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_CLEAR(t, ...) M_APPLY_API(M_VAR1ANT_GET_CLEAR t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_CMP(t, ...) M_APPLY_API(M_VAR1ANT_GET_CMP t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_HASH(t, ...) M_APPLY_API(M_VAR1ANT_GET_HASH t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_EQUAL(t, ...) M_APPLY_API(M_VAR1ANT_GET_EQUAL t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_GET_STR(t, ...) M_APPLY_API(M_VAR1ANT_GET_STR t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_PARSE_STR(t, ...) M_APPLY_API(M_VAR1ANT_GET_PARSE_STR t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_OUT_STR(t, ...) M_APPLY_API(M_VAR1ANT_GET_OUT_STR t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_IN_STR(t, ...) M_APPLY_API(M_VAR1ANT_GET_IN_STR t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_OUT_SERIAL(t, ...) M_APPLY_API(M_VAR1ANT_GET_OUT_SERIAL t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_IN_SERIAL(t, ...) M_APPLY_API(M_VAR1ANT_GET_IN_SERIAL t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CALL_SWAP(t, ...) M_APPLY_API(M_VAR1ANT_GET_SWAP t, M_VAR1ANT_GET_OPLIST t, __VA_ARGS__)
|
||||
|
||||
/* Define the type */
|
||||
#define VARIANTI_DEFINE_TYPE(name, name_t, ...) \
|
||||
#define M_VAR1ANT_DEFINE_TYPE(name, name_t, ...) \
|
||||
/* Define enum of all types of the variant */ \
|
||||
enum M_C(name, _enum) { M_C(name, _EMPTY) \
|
||||
M_MAP2(VARIANTI_DEFINE_UNION_ELE, name, __VA_ARGS__) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_UNION_ELE, name, __VA_ARGS__) \
|
||||
}; \
|
||||
/* Define enum equal to the number of types of the variant */ \
|
||||
enum M_C(name, _enum_max) { \
|
||||
@@ -194,7 +192,7 @@
|
||||
typedef struct M_C(name, _s) { \
|
||||
enum M_C(name, _enum) type; \
|
||||
union { \
|
||||
M_MAP(VARIANTI_DEFINE_TYPE_ELE , __VA_ARGS__) \
|
||||
M_MAP(M_VAR1ANT_DEFINE_TYPE_ELE , __VA_ARGS__) \
|
||||
} value; \
|
||||
} name_t[1]; \
|
||||
\
|
||||
@@ -203,55 +201,55 @@
|
||||
/* Define internal type for oplist */ \
|
||||
typedef name_t M_C(name, _ct);
|
||||
|
||||
#define VARIANTI_DEFINE_UNION_ELE(name, a) \
|
||||
, M_C4(name, _, VARIANTI_GET_FIELD a, _value)
|
||||
#define M_VAR1ANT_DEFINE_UNION_ELE(name, a) \
|
||||
, M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value)
|
||||
|
||||
#define VARIANTI_DEFINE_TYPE_ELE(a) \
|
||||
VARIANTI_GET_TYPE a VARIANTI_GET_FIELD a ;
|
||||
#define M_VAR1ANT_DEFINE_TYPE_ELE(a) \
|
||||
M_VAR1ANT_GET_TYPE a M_VAR1ANT_GET_FIELD a ;
|
||||
|
||||
|
||||
/* Control that all given oplists of all parameters are really oplists */
|
||||
#define VARIANTI_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(VARIANTI_CONTROL_OPLIST, name, __VA_ARGS__)
|
||||
#define M_VAR1ANT_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(M_VAR1ANT_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 M_VAR1ANT_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, M_VAR1ANT_GET_FIELD a, \
|
||||
M_VAR1ANT_GET_TYPE a, M_VAR1ANT_GET_OPLIST a)
|
||||
|
||||
|
||||
/* Define the INIT function. Init the variant to empty */
|
||||
#define VARIANTI_DEFINE_INIT(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_INIT(name, ...) \
|
||||
static inline void M_C(name, _init)(M_C(name,_ct) my) { \
|
||||
my->type = M_C(name, _EMPTY); \
|
||||
}
|
||||
|
||||
|
||||
/* Define the INIT_SET function. */
|
||||
#define VARIANTI_DEFINE_INIT_SET(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_INIT_SET(name, ...) \
|
||||
static inline void M_C(name, _init_set)(M_C(name,_ct) my , \
|
||||
M_C(name,_ct) const org) { \
|
||||
VARIANTI_CONTRACT(name, org); \
|
||||
M_VAR1ANT_CONTRACT(name, org); \
|
||||
my->type = org->type; \
|
||||
switch (org->type) { \
|
||||
case M_C(name, _EMPTY): break; \
|
||||
M_MAP2(VARIANTI_DEFINE_INIT_SET_FUNC, name, __VA_ARGS__) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_INIT_SET_FUNC, name, __VA_ARGS__) \
|
||||
default: M_ASSERT(false); break; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define VARIANTI_DEFINE_INIT_SET_FUNC(name, a) \
|
||||
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
|
||||
VARIANTI_CALL_INIT_SET(a, my -> value. VARIANTI_GET_FIELD a , \
|
||||
org -> value.VARIANTI_GET_FIELD a ); \
|
||||
#define M_VAR1ANT_DEFINE_INIT_SET_FUNC(name, a) \
|
||||
case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \
|
||||
M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a , \
|
||||
org -> value.M_VAR1ANT_GET_FIELD a ); \
|
||||
break;
|
||||
|
||||
|
||||
/* Define the SET function. */
|
||||
#define VARIANTI_DEFINE_SET(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_SET(name, ...) \
|
||||
static inline void M_C(name, _set)(M_C(name,_ct) my , \
|
||||
M_C(name,_ct) const org) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
VARIANTI_CONTRACT(name, org); \
|
||||
M_VAR1ANT_CONTRACT(name, my); \
|
||||
M_VAR1ANT_CONTRACT(name, org); \
|
||||
if (my->type != org->type) { \
|
||||
/* Different types: clear previous one and create new */ \
|
||||
M_C(name, _clear)(my); \
|
||||
@@ -260,193 +258,193 @@
|
||||
/* Same type: optimize the set */ \
|
||||
switch (org->type) { \
|
||||
case M_C(name, _EMPTY): break; \
|
||||
M_MAP2(VARIANTI_DEFINE_SET_FUNC, name, __VA_ARGS__) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_SET_FUNC, name, __VA_ARGS__) \
|
||||
default: M_ASSERT(false); break; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define VARIANTI_DEFINE_SET_FUNC(name, a) \
|
||||
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
|
||||
VARIANTI_CALL_SET(a, my -> value. VARIANTI_GET_FIELD a , \
|
||||
org -> value.VARIANTI_GET_FIELD a ); \
|
||||
#define M_VAR1ANT_DEFINE_SET_FUNC(name, a) \
|
||||
case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \
|
||||
M_VAR1ANT_CALL_SET(a, my -> value. M_VAR1ANT_GET_FIELD a , \
|
||||
org -> value.M_VAR1ANT_GET_FIELD a ); \
|
||||
break;
|
||||
|
||||
|
||||
/* Define the CLEAR function. */
|
||||
#define VARIANTI_DEFINE_CLEAR(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_CLEAR(name, ...) \
|
||||
static inline void M_C(name, _clear)(M_C(name,_ct) my) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
M_VAR1ANT_CONTRACT(name, my); \
|
||||
switch (my->type) { \
|
||||
case M_C(name, _EMPTY): break; \
|
||||
M_MAP2(VARIANTI_DEFINE_CLEAR_FUNC, name, __VA_ARGS__) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_CLEAR_FUNC, name, __VA_ARGS__) \
|
||||
default: M_ASSERT(false); break; \
|
||||
} \
|
||||
my->type = M_C(name, _EMPTY); \
|
||||
}
|
||||
|
||||
#define VARIANTI_DEFINE_CLEAR_FUNC(name, a) \
|
||||
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
|
||||
VARIANTI_CALL_CLEAR(a, my -> value. VARIANTI_GET_FIELD a); \
|
||||
#define M_VAR1ANT_DEFINE_CLEAR_FUNC(name, a) \
|
||||
case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \
|
||||
M_VAR1ANT_CALL_CLEAR(a, my -> value. M_VAR1ANT_GET_FIELD a); \
|
||||
break;
|
||||
|
||||
|
||||
/* Define the TEST_P function. */
|
||||
#define VARIANTI_DEFINE_TEST_P(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_TEST_P(name, ...) \
|
||||
static inline bool M_C(name, _empty_p)(M_C(name,_ct) const my) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
M_VAR1ANT_CONTRACT(name, my); \
|
||||
return my->type == M_C(name, _EMPTY); \
|
||||
} \
|
||||
static inline enum M_C(name, _enum) \
|
||||
M_C(name, _type)(M_C(name,_ct) my) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
M_VAR1ANT_CONTRACT(name, my); \
|
||||
return my->type; \
|
||||
} \
|
||||
M_MAP2(VARIANTI_DEFINE_TEST_FUNC, name, __VA_ARGS__)
|
||||
M_MAP2(M_VAR1ANT_DEFINE_TEST_FUNC, name, __VA_ARGS__)
|
||||
|
||||
#define VARIANTI_DEFINE_TEST_FUNC(name, a) \
|
||||
#define M_VAR1ANT_DEFINE_TEST_FUNC(name, a) \
|
||||
static inline bool \
|
||||
M_C4(name, _, VARIANTI_GET_FIELD a, _p)(M_C(name,_ct) const my) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
return my->type == M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
|
||||
M_C4(name, _, M_VAR1ANT_GET_FIELD a, _p)(M_C(name,_ct) const my) { \
|
||||
M_VAR1ANT_CONTRACT(name, my); \
|
||||
return my->type == M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \
|
||||
}
|
||||
|
||||
|
||||
/* Define the INIT function. */
|
||||
#define VARIANTI_DEFINE_INIT_FIELD(name, ...) \
|
||||
M_MAP2(VARIANTI_DEFINE_INIT_FIELD_FUNC, name, __VA_ARGS__)
|
||||
#define M_VAR1ANT_DEFINE_INIT_FIELD(name, ...) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_INIT_FIELD_FUNC, name, __VA_ARGS__)
|
||||
|
||||
#define VARIANTI_DEFINE_INIT_FIELD_FUNC(name, a) \
|
||||
#define M_VAR1ANT_DEFINE_INIT_FIELD_FUNC(name, a) \
|
||||
static inline void \
|
||||
M_C3(name, _init_, VARIANTI_GET_FIELD a)(M_C(name,_ct) my) { \
|
||||
M_C3(name, _init_, M_VAR1ANT_GET_FIELD a)(M_C(name,_ct) my) { \
|
||||
/* Reinit variable with the given value */ \
|
||||
my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
|
||||
VARIANTI_CALL_INIT(a, my -> value. VARIANTI_GET_FIELD a); \
|
||||
my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \
|
||||
M_VAR1ANT_CALL_INIT(a, my -> value. M_VAR1ANT_GET_FIELD a); \
|
||||
}
|
||||
|
||||
|
||||
/* Define the INIT_SET of a given type function. */
|
||||
#define VARIANTI_DEFINE_INIT_SETTER_FIELD(name, ...) \
|
||||
M_MAP2(VARIANTI_DEFINE_INIT_SETTER_FIELD_FUNC, name, __VA_ARGS__)
|
||||
#define M_VAR1ANT_DEFINE_INIT_SETTER_FIELD(name, ...) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_INIT_SETTER_FIELD_FUNC, name, __VA_ARGS__)
|
||||
|
||||
#define VARIANTI_DEFINE_INIT_SETTER_FIELD_FUNC(name, a) \
|
||||
#define M_VAR1ANT_DEFINE_INIT_SETTER_FIELD_FUNC(name, a) \
|
||||
static inline void \
|
||||
M_C3(name, _init_set_, VARIANTI_GET_FIELD a)(M_C(name,_ct) my, \
|
||||
VARIANTI_GET_TYPE a const VARIANTI_GET_FIELD a ) { \
|
||||
my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
|
||||
VARIANTI_CALL_INIT_SET(a, my -> value. VARIANTI_GET_FIELD a, \
|
||||
VARIANTI_GET_FIELD a); \
|
||||
M_C3(name, _init_set_, M_VAR1ANT_GET_FIELD a)(M_C(name,_ct) my, \
|
||||
M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a ) { \
|
||||
my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \
|
||||
M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \
|
||||
M_VAR1ANT_GET_FIELD a); \
|
||||
}
|
||||
|
||||
|
||||
/* Define the SET of a given type function. */
|
||||
#define VARIANTI_DEFINE_SETTER_FIELD(name, ...) \
|
||||
M_MAP2(VARIANTI_DEFINE_SETTER_FIELD_FUNC, name, __VA_ARGS__)
|
||||
#define M_VAR1ANT_DEFINE_SETTER_FIELD(name, ...) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_SETTER_FIELD_FUNC, name, __VA_ARGS__)
|
||||
|
||||
#define VARIANTI_DEFINE_SETTER_FIELD_FUNC(name, a) \
|
||||
#define M_VAR1ANT_DEFINE_SETTER_FIELD_FUNC(name, a) \
|
||||
static inline void \
|
||||
M_C3(name, _set_, VARIANTI_GET_FIELD a)(M_C(name,_ct) 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); \
|
||||
M_C3(name, _set_, M_VAR1ANT_GET_FIELD a)(M_C(name,_ct) my, \
|
||||
M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a ) { \
|
||||
M_VAR1ANT_CONTRACT(name, my); \
|
||||
if (my->type == M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value) ) { \
|
||||
M_VAR1ANT_CALL_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \
|
||||
M_VAR1ANT_GET_FIELD a); \
|
||||
} else { \
|
||||
M_C(name, _clear)(my); \
|
||||
/* Reinit variable with the given value */ \
|
||||
my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
|
||||
VARIANTI_CALL_INIT_SET(a, my -> value. VARIANTI_GET_FIELD a, \
|
||||
VARIANTI_GET_FIELD a); \
|
||||
my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \
|
||||
M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \
|
||||
M_VAR1ANT_GET_FIELD a); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/* Define the GET_field of a given type function. */
|
||||
#define VARIANTI_DEFINE_GETTER_FIELD(name, ...) \
|
||||
M_MAP2(VARIANTI_DEFINE_GETTER_FIELD_FUNC, name, __VA_ARGS__)
|
||||
#define M_VAR1ANT_DEFINE_GETTER_FIELD(name, ...) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_GETTER_FIELD_FUNC, name, __VA_ARGS__)
|
||||
|
||||
#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,_ct) my) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
if (my->type != M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \
|
||||
#define M_VAR1ANT_DEFINE_GETTER_FIELD_FUNC(name, a) \
|
||||
static inline M_VAR1ANT_GET_TYPE a * \
|
||||
M_C3(name, _get_, M_VAR1ANT_GET_FIELD a)(M_C(name,_ct) my) { \
|
||||
M_VAR1ANT_CONTRACT(name, my); \
|
||||
if (my->type != M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value) ) { \
|
||||
return NULL; \
|
||||
} \
|
||||
return &my -> value . VARIANTI_GET_FIELD a; \
|
||||
return &my -> value . M_VAR1ANT_GET_FIELD a; \
|
||||
} \
|
||||
\
|
||||
static inline VARIANTI_GET_TYPE a const * \
|
||||
M_C3(name, _cget_, VARIANTI_GET_FIELD a)(M_C(name,_ct) const my) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
if (my->type != M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \
|
||||
static inline M_VAR1ANT_GET_TYPE a const * \
|
||||
M_C3(name, _cget_, M_VAR1ANT_GET_FIELD a)(M_C(name,_ct) const my) { \
|
||||
M_VAR1ANT_CONTRACT(name, my); \
|
||||
if (my->type != M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value) ) { \
|
||||
return NULL; \
|
||||
} \
|
||||
return &my -> value . VARIANTI_GET_FIELD a; \
|
||||
return &my -> value . M_VAR1ANT_GET_FIELD a; \
|
||||
}
|
||||
|
||||
|
||||
/* Define the EQUAL_P function. */
|
||||
#define VARIANTI_DEFINE_EQUAL(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_EQUAL(name, ...) \
|
||||
static inline bool M_C(name, _equal_p)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2) { \
|
||||
bool b; \
|
||||
VARIANTI_CONTRACT(name, e1); \
|
||||
VARIANTI_CONTRACT(name, e2); \
|
||||
M_VAR1ANT_CONTRACT(name, e1); \
|
||||
M_VAR1ANT_CONTRACT(name, e2); \
|
||||
if (e1->type != e2->type) return false; \
|
||||
switch (e1->type) { \
|
||||
case M_C(name, _EMPTY): break; \
|
||||
M_MAP2(VARIANTI_DEFINE_EQUAL_FUNC , name, __VA_ARGS__) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_EQUAL_FUNC , name, __VA_ARGS__) \
|
||||
default: M_ASSERT(false); break; \
|
||||
} \
|
||||
return true; \
|
||||
}
|
||||
|
||||
#define VARIANTI_DEFINE_EQUAL_FUNC(name, a) \
|
||||
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
|
||||
b = VARIANTI_CALL_EQUAL(a, e1 -> value . VARIANTI_GET_FIELD a , \
|
||||
e2 -> value . VARIANTI_GET_FIELD a ); \
|
||||
#define M_VAR1ANT_DEFINE_EQUAL_FUNC(name, a) \
|
||||
case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \
|
||||
b = M_VAR1ANT_CALL_EQUAL(a, e1 -> value . M_VAR1ANT_GET_FIELD a , \
|
||||
e2 -> value . M_VAR1ANT_GET_FIELD a ); \
|
||||
return b; \
|
||||
break;
|
||||
|
||||
|
||||
/* Define the HASH function. */
|
||||
#define VARIANTI_DEFINE_HASH(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_HASH(name, ...) \
|
||||
static inline size_t M_C(name, _hash)(M_C(name,_ct) const e1) { \
|
||||
VARIANTI_CONTRACT(name, e1); \
|
||||
M_VAR1ANT_CONTRACT(name, e1); \
|
||||
M_HASH_DECL(hash); \
|
||||
M_HASH_UP (hash, (unsigned int) (e1 -> type)); \
|
||||
switch (e1->type) { \
|
||||
case M_C(name, _EMPTY): break; \
|
||||
M_MAP2(VARIANTI_DEFINE_HASH_FUNC , name, __VA_ARGS__) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_HASH_FUNC , name, __VA_ARGS__) \
|
||||
default: M_ASSERT(false); break; \
|
||||
} \
|
||||
return M_HASH_FINAL (hash); \
|
||||
}
|
||||
|
||||
#define VARIANTI_DEFINE_HASH_FUNC(name, a) \
|
||||
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
|
||||
M_HASH_UP(hash, VARIANTI_CALL_HASH(a, e1 -> value . VARIANTI_GET_FIELD a) ); \
|
||||
#define M_VAR1ANT_DEFINE_HASH_FUNC(name, a) \
|
||||
case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \
|
||||
M_HASH_UP(hash, M_VAR1ANT_CALL_HASH(a, e1 -> value . M_VAR1ANT_GET_FIELD a) ); \
|
||||
break;
|
||||
|
||||
|
||||
/* Define the INIT_MOVE function. */
|
||||
#define VARIANTI_DEFINE_INIT_MOVE(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_INIT_MOVE(name, ...) \
|
||||
static inline void \
|
||||
M_C(name, _init_move)(M_C(name,_ct) el, M_C(name,_ct) org) { \
|
||||
VARIANTI_CONTRACT(name, org); \
|
||||
M_VAR1ANT_CONTRACT(name, org); \
|
||||
el -> type = org -> type; \
|
||||
switch (el->type) { \
|
||||
case M_C(name, _EMPTY): break; \
|
||||
M_MAP2(VARIANTI_DEFINE_INIT_MOVE_FUNC , name, __VA_ARGS__) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_INIT_MOVE_FUNC , name, __VA_ARGS__) \
|
||||
default: M_ASSERT(false); break; \
|
||||
} \
|
||||
org -> type = M_C(name, _EMPTY); \
|
||||
}
|
||||
|
||||
#define VARIANTI_DEFINE_INIT_MOVE_FUNC(name, a) \
|
||||
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
|
||||
VARIANTI_CALL_INIT_MOVE(a, el -> value . VARIANTI_GET_FIELD a, \
|
||||
org -> value . VARIANTI_GET_FIELD a); \
|
||||
#define M_VAR1ANT_DEFINE_INIT_MOVE_FUNC(name, a) \
|
||||
case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \
|
||||
M_VAR1ANT_CALL_INIT_MOVE(a, el -> value . M_VAR1ANT_GET_FIELD a, \
|
||||
org -> value . M_VAR1ANT_GET_FIELD a); \
|
||||
break;
|
||||
|
||||
|
||||
@@ -454,48 +452,48 @@
|
||||
This is not optimized version.
|
||||
It can be optimized if both types are the same.
|
||||
*/
|
||||
#define VARIANTI_DEFINE_MOVE(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_MOVE(name, ...) \
|
||||
static inline void \
|
||||
M_C(name, _move)(M_C(name,_ct) el, M_C(name,_ct) org) { \
|
||||
VARIANTI_CONTRACT(name, el); \
|
||||
VARIANTI_CONTRACT(name, org); \
|
||||
M_VAR1ANT_CONTRACT(name, el); \
|
||||
M_VAR1ANT_CONTRACT(name, org); \
|
||||
M_C(name, _clear)(el); \
|
||||
M_C(name, _init_move)(el , org); \
|
||||
}
|
||||
|
||||
|
||||
/* Define the MOVE function of a given type */
|
||||
#define VARIANTI_DEFINE_MOVER(name, ...) \
|
||||
M_MAP2(VARIANTI_DEFINE_MOVER_FUNC, name, __VA_ARGS__)
|
||||
#define M_VAR1ANT_DEFINE_MOVER(name, ...) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_MOVER_FUNC, name, __VA_ARGS__)
|
||||
|
||||
#define VARIANTI_DEFINE_MOVER_FUNC(name, a) \
|
||||
#define M_VAR1ANT_DEFINE_MOVER_FUNC(name, a) \
|
||||
static inline void \
|
||||
M_C3(name, _move_, VARIANTI_GET_FIELD a)(M_C(name,_ct) my, \
|
||||
VARIANTI_GET_TYPE a VARIANTI_GET_FIELD a ) { \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
M_C3(name, _move_, M_VAR1ANT_GET_FIELD a)(M_C(name,_ct) my, \
|
||||
M_VAR1ANT_GET_TYPE a M_VAR1ANT_GET_FIELD a ) { \
|
||||
M_VAR1ANT_CONTRACT(name, my); \
|
||||
M_C(name, _clear)(my); \
|
||||
/* Reinit variable with the given value */ \
|
||||
my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
|
||||
VARIANTI_CALL_INIT_MOVE(a, my -> value. VARIANTI_GET_FIELD a, \
|
||||
VARIANTI_GET_FIELD a); \
|
||||
my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \
|
||||
M_VAR1ANT_CALL_INIT_MOVE(a, my -> value. M_VAR1ANT_GET_FIELD a, \
|
||||
M_VAR1ANT_GET_FIELD a); \
|
||||
}
|
||||
|
||||
|
||||
/* Define the SWAP function */
|
||||
#define VARIANTI_DEFINE_SWAP(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_SWAP(name, ...) \
|
||||
static inline void \
|
||||
M_C(name, _swap)(M_C(name,_ct) el1, M_C(name,_ct) el2) { \
|
||||
VARIANTI_CONTRACT(name, el1); \
|
||||
VARIANTI_CONTRACT(name, el2); \
|
||||
M_VAR1ANT_CONTRACT(name, el1); \
|
||||
M_VAR1ANT_CONTRACT(name, el2); \
|
||||
if (el1->type == el2->type) { \
|
||||
switch (el1->type) { \
|
||||
case M_C(name, _EMPTY): break; \
|
||||
M_MAP2(VARIANTI_DEFINE_INIT_SWAP_FUNC , name, __VA_ARGS__) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_INIT_SWAP_FUNC , name, __VA_ARGS__) \
|
||||
default: M_ASSERT(false); break; \
|
||||
} \
|
||||
} else { \
|
||||
M_C(name,_ct) tmp; \
|
||||
VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL(INIT_MOVE, __VA_ARGS__) \
|
||||
( /* NOTE: Slow implementation */ \
|
||||
M_C(name, _init_move)(tmp, el1); \
|
||||
M_C(name, _init_move)(el1, el2); \
|
||||
@@ -510,49 +508,49 @@
|
||||
} \
|
||||
}
|
||||
|
||||
#define VARIANTI_DEFINE_INIT_SWAP_FUNC(name, a) \
|
||||
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
|
||||
VARIANTI_CALL_SWAP(a, el1 -> value . VARIANTI_GET_FIELD a, \
|
||||
el2 -> value . VARIANTI_GET_FIELD a); \
|
||||
#define M_VAR1ANT_DEFINE_INIT_SWAP_FUNC(name, a) \
|
||||
case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \
|
||||
M_VAR1ANT_CALL_SWAP(a, el1 -> value . M_VAR1ANT_GET_FIELD a, \
|
||||
el2 -> value . M_VAR1ANT_GET_FIELD a); \
|
||||
break;
|
||||
|
||||
|
||||
/* Define the GET_STR function */
|
||||
#define VARIANTI_DEFINE_GET_STR(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_GET_STR(name, ...) \
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
M_C(name,_ct) const el, \
|
||||
bool append) { \
|
||||
VARIANTI_CONTRACT(name, el); \
|
||||
M_VAR1ANT_CONTRACT(name, el); \
|
||||
M_ASSERT (str != NULL); \
|
||||
void (*func)(string_t, const char *); \
|
||||
func = append ? string_cat_str : string_set_str; \
|
||||
switch (el->type) { \
|
||||
case M_C(name, _EMPTY): func(str, "@EMPTY@"); break; \
|
||||
M_MAP2(VARIANTI_DEFINE_GET_STR_FUNC , name, __VA_ARGS__) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_GET_STR_FUNC , name, __VA_ARGS__) \
|
||||
default: M_ASSERT(false); break; \
|
||||
} \
|
||||
string_push_back (str, '@'); \
|
||||
}
|
||||
|
||||
#define VARIANTI_DEFINE_GET_STR_FUNC(name, a) \
|
||||
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
|
||||
func(str, "@" M_APPLY (M_AS_STR, VARIANTI_GET_FIELD a) "@"); \
|
||||
VARIANTI_CALL_GET_STR(a, str, el -> value . VARIANTI_GET_FIELD a, true); \
|
||||
#define M_VAR1ANT_DEFINE_GET_STR_FUNC(name, a) \
|
||||
case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \
|
||||
func(str, "@" M_AS_STR(M_VAR1ANT_GET_FIELD a) "@"); \
|
||||
M_VAR1ANT_CALL_GET_STR(a, str, el -> value . M_VAR1ANT_GET_FIELD a, true); \
|
||||
break;
|
||||
|
||||
|
||||
/* Define the PARSE_STR function */
|
||||
#define VARIANTI_DEFINE_PARSE_STR(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_PARSE_STR(name, ...) \
|
||||
static inline bool M_C(name, _parse_str)(M_C(name,_ct) el, \
|
||||
const char str[], \
|
||||
const char **endp) { \
|
||||
VARIANTI_CONTRACT(name, el); \
|
||||
M_VAR1ANT_CONTRACT(name, el); \
|
||||
M_ASSERT (str != NULL); \
|
||||
bool success = false; \
|
||||
char variantTypeBuf[M_MAX_IDENTIFIER_LENGTH+1]; \
|
||||
char variantTypeBuf[M_USE_IDENTIFIER_ALLOC+1]; \
|
||||
int c = *str++; \
|
||||
unsigned int i = 0; \
|
||||
M_C(name, _clean)(el); \
|
||||
M_C(name, _reset)(el); \
|
||||
if (c != '@') goto exit; \
|
||||
/* First read the name of the type */ \
|
||||
c = *str++; \
|
||||
@@ -567,7 +565,7 @@
|
||||
if (strcmp(variantTypeBuf, "EMPTY") == 0) { \
|
||||
el->type = M_C(name, _EMPTY); \
|
||||
} \
|
||||
M_MAP2(VARIANTI_DEFINE_PARSE_STR_FUNC , name, __VA_ARGS__) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_PARSE_STR_FUNC , name, __VA_ARGS__) \
|
||||
else goto exit; \
|
||||
success = (*str++ == '@'); \
|
||||
exit: \
|
||||
@@ -575,44 +573,44 @@
|
||||
return success; \
|
||||
}
|
||||
|
||||
#define VARIANTI_DEFINE_PARSE_STR_FUNC(name, a) \
|
||||
else if (strcmp (variantTypeBuf, M_APPLY (M_AS_STR, VARIANTI_GET_FIELD a)) == 0) { \
|
||||
el->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
|
||||
VARIANTI_CALL_INIT(a, el ->value . VARIANTI_GET_FIELD a ); \
|
||||
bool b = VARIANTI_CALL_PARSE_STR(a, el -> value . VARIANTI_GET_FIELD a, str, &str); \
|
||||
#define M_VAR1ANT_DEFINE_PARSE_STR_FUNC(name, a) \
|
||||
else if (strcmp (variantTypeBuf, M_AS_STR(M_VAR1ANT_GET_FIELD a)) == 0) { \
|
||||
el->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \
|
||||
M_VAR1ANT_CALL_INIT(a, el ->value . M_VAR1ANT_GET_FIELD a ); \
|
||||
bool b = M_VAR1ANT_CALL_PARSE_STR(a, el -> value . M_VAR1ANT_GET_FIELD a, str, &str); \
|
||||
if (!b) goto exit; \
|
||||
}
|
||||
|
||||
|
||||
/* Define the OUT_STR function */
|
||||
#define VARIANTI_DEFINE_OUT_STR(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_OUT_STR(name, ...) \
|
||||
static inline void M_C(name, _out_str)(FILE *f, \
|
||||
M_C(name,_ct) const el) { \
|
||||
VARIANTI_CONTRACT(name, el); \
|
||||
M_VAR1ANT_CONTRACT(name, el); \
|
||||
M_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__) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_OUT_STR_FUNC , name, __VA_ARGS__) \
|
||||
default: M_ASSERT(false); break; \
|
||||
} \
|
||||
fputc ('@', f); \
|
||||
}
|
||||
|
||||
#define VARIANTI_DEFINE_OUT_STR_FUNC(name, a) \
|
||||
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
|
||||
fprintf(f, "@" M_APPLY(M_AS_STR, VARIANTI_GET_FIELD a) "@"); \
|
||||
VARIANTI_CALL_OUT_STR(a, f, el -> value . VARIANTI_GET_FIELD a); \
|
||||
#define M_VAR1ANT_DEFINE_OUT_STR_FUNC(name, a) \
|
||||
case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \
|
||||
fprintf(f, "@" M_AS_STR(M_VAR1ANT_GET_FIELD a) "@"); \
|
||||
M_VAR1ANT_CALL_OUT_STR(a, f, el -> value . M_VAR1ANT_GET_FIELD a); \
|
||||
break;
|
||||
|
||||
|
||||
/* Define the IN_STR function */
|
||||
#define VARIANTI_DEFINE_IN_STR(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_IN_STR(name, ...) \
|
||||
static inline bool M_C(name, _in_str)(M_C(name,_ct) el, \
|
||||
FILE *f) { \
|
||||
VARIANTI_CONTRACT(name, el); \
|
||||
M_VAR1ANT_CONTRACT(name, el); \
|
||||
M_ASSERT (f != NULL); \
|
||||
char variantTypeBuf[M_MAX_IDENTIFIER_LENGTH+1]; \
|
||||
M_C(name, _clean)(el); \
|
||||
char variantTypeBuf[M_USE_IDENTIFIER_ALLOC+1]; \
|
||||
M_C(name, _reset)(el); \
|
||||
if (fgetc(f) != '@') return false; \
|
||||
/* First read the name of the type */ \
|
||||
bool b = true; \
|
||||
@@ -629,33 +627,33 @@
|
||||
if (strcmp(variantTypeBuf, "EMPTY") == 0) { \
|
||||
el->type = M_C(name, _EMPTY); \
|
||||
} \
|
||||
M_MAP2(VARIANTI_DEFINE_IN_STR_FUNC , name, __VA_ARGS__) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_IN_STR_FUNC , name, __VA_ARGS__) \
|
||||
else { b = false; } \
|
||||
return b && (fgetc(f) == '@'); \
|
||||
}
|
||||
|
||||
#define VARIANTI_DEFINE_IN_STR_FUNC(name, a) \
|
||||
else if (strcmp (variantTypeBuf, M_APPLY (M_AS_STR, VARIANTI_GET_FIELD a)) == 0) { \
|
||||
el->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
|
||||
VARIANTI_CALL_INIT(a, el ->value . VARIANTI_GET_FIELD a ); \
|
||||
b = VARIANTI_CALL_IN_STR(a, el -> value . VARIANTI_GET_FIELD a, f); \
|
||||
#define M_VAR1ANT_DEFINE_IN_STR_FUNC(name, a) \
|
||||
else if (strcmp (variantTypeBuf, M_AS_STR(M_VAR1ANT_GET_FIELD a)) == 0) { \
|
||||
el->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \
|
||||
M_VAR1ANT_CALL_INIT(a, el ->value . M_VAR1ANT_GET_FIELD a ); \
|
||||
b = M_VAR1ANT_CALL_IN_STR(a, el -> value . M_VAR1ANT_GET_FIELD a, f); \
|
||||
}
|
||||
|
||||
|
||||
/* Return the STRING version of a parameter name */
|
||||
#define VARIANTI_STRINGIFY_NAME(a) \
|
||||
M_APPLY(M_AS_STR, VARIANTI_GET_FIELD a)
|
||||
#define M_VAR1ANT_STRINGIFY_NAME(a) \
|
||||
M_AS_STR(M_VAR1ANT_GET_FIELD a)
|
||||
|
||||
|
||||
/* Define the OUT_SERIAL function */
|
||||
#define VARIANTI_DEFINE_OUT_SERIAL(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_OUT_SERIAL(name, ...) \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, \
|
||||
M_C(name,_ct) const el) { \
|
||||
VARIANTI_CONTRACT(name, el); \
|
||||
M_VAR1ANT_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__) }; \
|
||||
{ M_REDUCE(M_VAR1ANT_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
@@ -663,41 +661,41 @@
|
||||
case M_C(name, _EMPTY): \
|
||||
return f->m_interface->write_variant_start(local, f, field_name, field_max, -1); \
|
||||
break; \
|
||||
M_MAP2(VARIANTI_DEFINE_OUT_SERIAL_FUNC , name, __VA_ARGS__) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_OUT_SERIAL_FUNC , name, __VA_ARGS__) \
|
||||
default: M_ASSERT(false); break; \
|
||||
} \
|
||||
ret |= f->m_interface->write_variant_end(local, f); \
|
||||
return ret & M_SERIAL_FAIL; \
|
||||
}
|
||||
|
||||
#define VARIANTI_DEFINE_OUT_SERIAL_FUNC(name, a) \
|
||||
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
|
||||
#define M_VAR1ANT_DEFINE_OUT_SERIAL_FUNC(name, a) \
|
||||
case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \
|
||||
ret = f->m_interface->write_variant_start(local, f, field_name, field_max, \
|
||||
M_C4(name, _, VARIANTI_GET_FIELD a, _value) -1); \
|
||||
VARIANTI_CALL_OUT_SERIAL(a, f, el -> value . VARIANTI_GET_FIELD a); \
|
||||
M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value) -1); \
|
||||
M_VAR1ANT_CALL_OUT_SERIAL(a, f, el -> value . M_VAR1ANT_GET_FIELD a); \
|
||||
break;
|
||||
|
||||
|
||||
/* Define the IN_SERIAL function */
|
||||
#define VARIANTI_DEFINE_IN_SERIAL(name, ...) \
|
||||
#define M_VAR1ANT_DEFINE_IN_SERIAL(name, ...) \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(M_C(name,_ct) el, \
|
||||
m_serial_read_t f) { \
|
||||
VARIANTI_CONTRACT(name, el); \
|
||||
M_VAR1ANT_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__) }; \
|
||||
{ M_REDUCE(M_VAR1ANT_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
int id = -1; \
|
||||
M_C(name, _clean)(el); \
|
||||
M_C(name, _reset)(el); \
|
||||
ret = f->m_interface->read_variant_start(local, f, field_name, field_max, &id); \
|
||||
if (ret != M_SERIAL_OK_CONTINUE) return ret; \
|
||||
M_ASSERT (id >= 0 && id < field_max); \
|
||||
el->type = (enum M_C(name, _enum))(id+1); \
|
||||
switch (id+1) { \
|
||||
M_MAP2(VARIANTI_DEFINE_IN_SERIAL_FUNC , name, __VA_ARGS__) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_IN_SERIAL_FUNC , name, __VA_ARGS__) \
|
||||
default: M_ASSERT(false); break; \
|
||||
} \
|
||||
if (ret == M_SERIAL_OK_DONE) \
|
||||
@@ -705,41 +703,46 @@
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define VARIANTI_DEFINE_IN_SERIAL_FUNC(name, a) \
|
||||
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
|
||||
VARIANTI_CALL_INIT(a, el ->value . VARIANTI_GET_FIELD a ); \
|
||||
ret = VARIANTI_CALL_IN_SERIAL(a, el -> value . VARIANTI_GET_FIELD a, f); \
|
||||
#define M_VAR1ANT_DEFINE_IN_SERIAL_FUNC(name, a) \
|
||||
case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \
|
||||
M_VAR1ANT_CALL_INIT(a, el ->value . M_VAR1ANT_GET_FIELD a ); \
|
||||
ret = M_VAR1ANT_CALL_IN_SERIAL(a, el -> value . M_VAR1ANT_GET_FIELD a, f); \
|
||||
break; \
|
||||
|
||||
|
||||
/* Define the CLEAN function */
|
||||
#define VARIANTI_DEFINE_CLEAN_FUNC(name, ...) \
|
||||
static inline void M_C(name, _clean)(M_C(name,_ct) my) \
|
||||
/* Define the RESET function */
|
||||
#define M_VAR1ANT_DEFINE_RESET_FUNC(name, ...) \
|
||||
static inline void M_C(name, _reset)(M_C(name,_ct) my) \
|
||||
{ \
|
||||
VARIANTI_CONTRACT(name, my); \
|
||||
M_VAR1ANT_CONTRACT(name, my); \
|
||||
M_C(name, _clear)(my); \
|
||||
M_C(name, _init)(my); \
|
||||
} \
|
||||
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(M_C(name,_ct) my) \
|
||||
{ \
|
||||
M_C(name, _reset)(my); \
|
||||
}
|
||||
|
||||
/* deferred evaluation of the oplist */
|
||||
#define VARIANTI_OPLIST_P1(arg) VARIANTI_OPLIST_P2 arg
|
||||
#define M_VAR1ANT_OPLIST_P1(arg) M_VAR1ANT_OPLIST_P2 arg
|
||||
|
||||
/* 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__)
|
||||
#define M_VAR1ANT_OPLIST_P2(name, ...) \
|
||||
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(M_VAR1ANT_OPLIST_P3, M_VAR1ANT_OPLIST_FAILURE)(name, __VA_ARGS__)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define VARIANTI_OPLIST_FAILURE(name, ...) \
|
||||
#define M_VAR1ANT_OPLIST_FAILURE(name, ...) \
|
||||
((M_LIB_ERROR(ONE_ARGUMENT_OF_VARIANT_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)))
|
||||
|
||||
/* Define the oplist */
|
||||
#define VARIANTI_OPLIST_P3(name, ...) \
|
||||
#define M_VAR1ANT_OPLIST_P3(name, ...) \
|
||||
(INIT(M_C(name,_init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
SET(M_C(name,_set)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
CLEAN(M_C(name, _clean)), \
|
||||
RESET(M_C(name, _reset)), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
EMPTY_P(M_C(name,_empty_p)), \
|
||||
M_IF_METHOD_ALL(HASH, __VA_ARGS__)(HASH(M_C(name, _hash)),), \
|
||||
@@ -759,18 +762,18 @@
|
||||
)
|
||||
|
||||
/* Macros for testing for method presence */
|
||||
#define VARIANTI_TEST_METHOD_P2(method, f, t, op) \
|
||||
#define M_VAR1ANT_TEST_METHOD_P2(method, f, t, op) \
|
||||
M_TEST_METHOD_P(method, op)
|
||||
#define VARIANTI_TEST_METHOD_P(method, trio) \
|
||||
M_APPLY(VARIANTI_TEST_METHOD_P2, method, M_OPFLAT trio)
|
||||
#define VARIANTI_IF_ALL(method, ...) \
|
||||
M_IF(M_REDUCE2(VARIANTI_TEST_METHOD_P, M_AND, method, __VA_ARGS__))
|
||||
#define M_VAR1ANT_TEST_METHOD_P(method, trio) \
|
||||
M_APPLY(M_VAR1ANT_TEST_METHOD_P2, method, M_OPFLAT trio)
|
||||
#define M_VAR1ANT_IF_ALL(method, ...) \
|
||||
M_IF(M_REDUCE2(M_VAR1ANT_TEST_METHOD_P, M_AND, method, __VA_ARGS__))
|
||||
|
||||
#define VARIANTI_TEST_METHOD2_P2(method1, method2, f, t, op) \
|
||||
#define M_VAR1ANT_TEST_METHOD2_P2(method1, method2, f, t, op) \
|
||||
M_AND(M_TEST_METHOD_P(method1, op), M_TEST_METHOD_P(method2, op))
|
||||
#define VARIANTI_TEST_METHOD2_P(method, trio) \
|
||||
M_APPLY(VARIANTI_TEST_METHOD2_P2, M_PAIR_1 method, M_PAIR_2 method, M_OPFLAT trio)
|
||||
#define VARIANTI_IF_ALL2(method1, method2, ...) \
|
||||
M_IF(M_REDUCE2(VARIANTI_TEST_METHOD2_P, M_AND, (method1, method2), __VA_ARGS__))
|
||||
#define M_VAR1ANT_TEST_METHOD2_P(method, trio) \
|
||||
M_APPLY(M_VAR1ANT_TEST_METHOD2_P2, M_PAIR_1 method, M_PAIR_2 method, M_OPFLAT trio)
|
||||
#define M_VAR1ANT_IF_ALL2(method1, method2, ...) \
|
||||
M_IF(M_REDUCE2(M_VAR1ANT_TEST_METHOD2_P, M_AND, (method1, method2), __VA_ARGS__))
|
||||
|
||||
#endif
|
||||
+77
-77
@@ -113,25 +113,25 @@ typedef struct work_order_s {
|
||||
* * MACRO to complete the not-used fields
|
||||
*/
|
||||
#if M_USE_WORKER_CLANG_BLOCK || M_USE_WORKER_CPP_FUNCTION
|
||||
# define WORKERI_EMPTY_ORDER { NULL, NULL, NULL, NULL }
|
||||
# define WORKERI_EXTRA_ORDER , NULL
|
||||
# define M_WORK3R_EMPTY_ORDER { NULL, NULL, NULL, NULL }
|
||||
# define M_WORK3R_EXTRA_ORDER , NULL
|
||||
#else
|
||||
# define WORKERI_EMPTY_ORDER { NULL, NULL, NULL }
|
||||
# define WORKERI_EXTRA_ORDER
|
||||
# define M_WORK3R_EMPTY_ORDER { NULL, NULL, NULL }
|
||||
# define M_WORK3R_EXTRA_ORDER
|
||||
#endif
|
||||
|
||||
/* As in C++, it uses std::function, M_POD_OPLIST
|
||||
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 WORKERI_CPP_INIT(x) (new (&(x)) worker_order_ct())
|
||||
# define WORKERI_CPP_INIT_SET(x, y) (new (&(x)) worker_order_ct(y))
|
||||
# define WORKERI_CPP_SET(x, y) ((x) = (y))
|
||||
# define WORKERI_CPP_CLEAR(x) ((&(x))->~worker_order_ct())
|
||||
# define WORKERI_CPP_INIT_MOVE(x,y) (new (&(x)) worker_order_ct(y), ((&(y))->~worker_order_ct()))
|
||||
# define M_WORK3R_CPP_INIT(x) (new (&(x)) worker_order_ct())
|
||||
# define M_WORK3R_CPP_INIT_SET(x, y) (new (&(x)) worker_order_ct(y))
|
||||
# define M_WORK3R_CPP_SET(x, y) ((x) = (y))
|
||||
# define M_WORK3R_CPP_CLEAR(x) ((&(x))->~worker_order_ct())
|
||||
# define M_WORK3R_CPP_INIT_MOVE(x,y) (new (&(x)) worker_order_ct(y), ((&(y))->~worker_order_ct()))
|
||||
# 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) )
|
||||
(INIT(M_WORK3R_CPP_INIT), INIT_SET(M_WORK3R_CPP_INIT_SET), \
|
||||
SET(M_WORK3R_CPP_SET), CLEAR(M_WORK3R_CPP_CLEAR), INIT_MOVE(M_WORK3R_CPP_INIT_MOVE) )
|
||||
#else
|
||||
# define WORKER_OPLIST M_POD_OPLIST
|
||||
#endif
|
||||
@@ -200,9 +200,9 @@ workeri_get_cpu_count(void)
|
||||
|
||||
// (INTERNAL) Debug support for workers
|
||||
#if 1
|
||||
#define WORKERI_DEBUG(...) (void) 0
|
||||
#define M_WORK3R_DEBUG(...) (void) 0
|
||||
#else
|
||||
#define WORKERI_DEBUG(...) printf(__VA_ARGS__)
|
||||
#define M_WORK3R_DEBUG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* Execute the registered work order **synchronously** */
|
||||
@@ -210,15 +210,15 @@ static inline void
|
||||
workeri_exec(worker_order_ct *w)
|
||||
{
|
||||
M_ASSERT (w!= NULL && w->block != NULL);
|
||||
WORKERI_DEBUG ("Starting thread with data %p\n", w->data);
|
||||
M_WORK3R_DEBUG ("Starting thread with data %p\n", w->data);
|
||||
#if M_USE_WORKER_CLANG_BLOCK
|
||||
WORKERI_DEBUG ("Running %s f=%p b=%p\n", (w->func == NULL) ? "Blocks" : "Function", w->func, w->blockFunc);
|
||||
M_WORK3R_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
|
||||
WORKERI_DEBUG ("Running %s f=%p b=%p\n", (w->function == NULL) ? "Lambda" : "Function", w->func, w->blockFunc);
|
||||
M_WORK3R_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
|
||||
@@ -242,7 +242,7 @@ workeri_thread(void *arg)
|
||||
g->resetFunc_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));
|
||||
M_WORK3R_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
|
||||
@@ -278,7 +278,7 @@ worker_init(worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc
|
||||
// Auto compute number of workers if the argument is 0
|
||||
if (numWorker <= 0)
|
||||
numWorker = (1 + (numWorker == -1))*workeri_get_cpu_count()-1;
|
||||
WORKERI_DEBUG ("Starting queue with: %d\n", numWorker + extraQueue);
|
||||
M_WORK3R_DEBUG ("Starting queue with: %d\n", numWorker + extraQueue);
|
||||
// Initialization
|
||||
// numWorker can still be 0 if it is a single core cpu (no worker available)
|
||||
M_ASSERT(numWorker >= 0);
|
||||
@@ -316,7 +316,7 @@ worker_clear(worker_t g)
|
||||
M_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_ct w = WORKERI_EMPTY_ORDER;
|
||||
worker_order_ct w = M_WORK3R_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.
|
||||
@@ -351,14 +351,14 @@ worker_start(worker_sync_t block, worker_t g)
|
||||
static inline void
|
||||
worker_spawn(worker_sync_t block, void (*func)(void *data), void *data)
|
||||
{
|
||||
const worker_order_ct w = { block, data, func WORKERI_EXTRA_ORDER };
|
||||
const worker_order_ct w = { block, data, func M_WORK3R_EXTRA_ORDER };
|
||||
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
|
||||
&& worker_queue_push (block->worker->queue_g, w) == true) {
|
||||
WORKERI_DEBUG ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
M_WORK3R_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;
|
||||
}
|
||||
WORKERI_DEBUG ("Running data ourself: %p\n", data);
|
||||
M_WORK3R_DEBUG ("Running data ourself: %p\n", data);
|
||||
/* No worker available. Call the function ourself */
|
||||
(*func) (data);
|
||||
}
|
||||
@@ -372,11 +372,11 @@ worker_spawn_block(worker_sync_t block, void (^func)(void *data), void *data)
|
||||
const worker_order_ct 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) {
|
||||
WORKERI_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
M_WORK3R_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;
|
||||
}
|
||||
WORKERI_DEBUG ("Running data ourself as block: %p\n", data);
|
||||
M_WORK3R_DEBUG ("Running data ourself as block: %p\n", data);
|
||||
/* No worker available. Call the function ourself */
|
||||
func (data);
|
||||
}
|
||||
@@ -391,11 +391,11 @@ worker_spawn_function(worker_sync_t block, std::function<void(void *data)> func,
|
||||
const worker_order_ct 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) {
|
||||
WORKERI_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
M_WORK3R_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;
|
||||
}
|
||||
WORKERI_DEBUG ("Running data ourself as block: %p\n", data);
|
||||
M_WORK3R_DEBUG ("Running data ourself as block: %p\n", data);
|
||||
/* No worker available. Call the function ourself */
|
||||
func (data);
|
||||
}
|
||||
@@ -415,7 +415,7 @@ worker_sync_p(worker_sync_t block)
|
||||
static inline void
|
||||
worker_sync(worker_sync_t block)
|
||||
{
|
||||
WORKERI_DEBUG ("Waiting for thread terminasion.\n");
|
||||
M_WORK3R_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
|
||||
@@ -455,77 +455,77 @@ worker_count(worker_t g)
|
||||
*/
|
||||
#if M_USE_WORKER_CLANG_BLOCK
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
WORKER_DEF_DATA(_input, _output) \
|
||||
WORKER_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
worker_spawn_block ((_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
|
||||
M_WORK3R_DEF_DATA(_input, _output) \
|
||||
M_WORK3R_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
worker_spawn_block ((_block), M_WORK3R_SPAWN_SUBFUNC_NAME, &M_WORK3R_SPAWN_DATA_NAME)
|
||||
#elif M_USE_WORKER_CPP_FUNCTION
|
||||
// TODO: Explicit pass all arguments by reference.
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
worker_spawn_function ((_block), [&](void *param) {(void)param ; _core } , NULL)
|
||||
#else
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
WORKER_DEF_DATA(_input, _output) \
|
||||
WORKER_DEF_SUBFUNC(_input, _output, _core) \
|
||||
worker_spawn ((_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
|
||||
M_WORK3R_DEF_DATA(_input, _output) \
|
||||
M_WORK3R_DEF_SUBFUNC(_input, _output, _core) \
|
||||
worker_spawn ((_block), M_WORK3R_SPAWN_SUBFUNC_NAME, &M_WORK3R_SPAWN_DATA_NAME)
|
||||
#endif
|
||||
|
||||
#define WORKER_SPAWN_STRUCT_NAME M_C(worker_data_s_, __LINE__)
|
||||
#define WORKER_SPAWN_DATA_NAME M_C(worker_data_, __LINE__)
|
||||
#define WORKER_SPAWN_SUBFUNC_NAME M_C(worker_subfunc_, __LINE__)
|
||||
#define WORKER_DEF_DATA(_input, _output) \
|
||||
struct WORKER_SPAWN_STRUCT_NAME { \
|
||||
WORKER_DEF_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_DEF_DATA_OUTPUT _output) \
|
||||
} WORKER_SPAWN_DATA_NAME = { \
|
||||
WORKER_INIT_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output (, WORKER_INIT_DATA_OUTPUT _output) \
|
||||
#define M_WORK3R_SPAWN_STRUCT_NAME M_C(worker_data_s_, __LINE__)
|
||||
#define M_WORK3R_SPAWN_DATA_NAME M_C(worker_data_, __LINE__)
|
||||
#define M_WORK3R_SPAWN_SUBFUNC_NAME M_C(worker_subfunc_, __LINE__)
|
||||
#define M_WORK3R_DEF_DATA(_input, _output) \
|
||||
struct M_WORK3R_SPAWN_STRUCT_NAME { \
|
||||
M_WORK3R_DEF_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output ( , M_WORK3R_DEF_DATA_OUTPUT _output) \
|
||||
} M_WORK3R_SPAWN_DATA_NAME = { \
|
||||
M_WORK3R_INIT_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output (, M_WORK3R_INIT_DATA_OUTPUT _output) \
|
||||
};
|
||||
#define WORKER_DEF_SINGLE_INPUT(var) __typeof__(var) var;
|
||||
#define WORKER_DEF_DATA_INPUT(...) \
|
||||
M_MAP(WORKER_DEF_SINGLE_INPUT, __VA_ARGS__)
|
||||
#define WORKER_DEF_SINGLE_OUTPUT(var) \
|
||||
#define M_WORK3R_DEF_SINGLE_INPUT(var) __typeof__(var) var;
|
||||
#define M_WORK3R_DEF_DATA_INPUT(...) \
|
||||
M_MAP(M_WORK3R_DEF_SINGLE_INPUT, __VA_ARGS__)
|
||||
#define M_WORK3R_DEF_SINGLE_OUTPUT(var) \
|
||||
__typeof__(var) *M_C(var, _ptr);
|
||||
#define WORKER_DEF_DATA_OUTPUT(...) \
|
||||
M_MAP(WORKER_DEF_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
#define WORKER_INIT_SINGLE_INPUT(var) \
|
||||
#define M_WORK3R_DEF_DATA_OUTPUT(...) \
|
||||
M_MAP(M_WORK3R_DEF_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
#define M_WORK3R_INIT_SINGLE_INPUT(var) \
|
||||
.var = var,
|
||||
#define WORKER_INIT_DATA_INPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_INPUT, __VA_ARGS__)
|
||||
#define WORKER_INIT_SINGLE_OUTPUT(var) \
|
||||
#define M_WORK3R_INIT_DATA_INPUT(...) \
|
||||
M_MAP(M_WORK3R_INIT_SINGLE_INPUT, __VA_ARGS__)
|
||||
#define M_WORK3R_INIT_SINGLE_OUTPUT(var) \
|
||||
.M_C(var, _ptr) = &var,
|
||||
#define WORKER_INIT_DATA_OUTPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
#define WORKER_DEF_SUBFUNC(_input, _output, _core) \
|
||||
__extension__ auto void WORKER_SPAWN_SUBFUNC_NAME(void *) ; \
|
||||
__extension__ void WORKER_SPAWN_SUBFUNC_NAME(void *_data) \
|
||||
#define M_WORK3R_INIT_DATA_OUTPUT(...) \
|
||||
M_MAP(M_WORK3R_INIT_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
#define M_WORK3R_DEF_SUBFUNC(_input, _output, _core) \
|
||||
__extension__ auto void M_WORK3R_SPAWN_SUBFUNC_NAME(void *) ; \
|
||||
__extension__ void M_WORK3R_SPAWN_SUBFUNC_NAME(void *_data) \
|
||||
{ \
|
||||
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
WORKER_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
|
||||
struct M_WORK3R_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
M_WORK3R_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , M_WORK3R_INIT_LOCAL_OUTPUT _output) \
|
||||
do { _core } while (0); \
|
||||
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
M_IF_EMPTY _output ( , M_WORK3R_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
};
|
||||
#define WORKER_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
void (^WORKER_SPAWN_SUBFUNC_NAME) (void *) = ^ void (void * _data) \
|
||||
#define M_WORK3R_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
void (^M_WORK3R_SPAWN_SUBFUNC_NAME) (void *) = ^ void (void * _data) \
|
||||
{ \
|
||||
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
WORKER_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
|
||||
struct M_WORK3R_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
M_WORK3R_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , M_WORK3R_INIT_LOCAL_OUTPUT _output) \
|
||||
do { _core } while (0); \
|
||||
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
M_IF_EMPTY _output ( , M_WORK3R_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
};
|
||||
#define WORKER_INIT_SINGLE_LOCAL_INPUT(var) \
|
||||
#define M_WORK3R_INIT_SINGLE_LOCAL_INPUT(var) \
|
||||
__typeof__(var) var = _s_data->var;
|
||||
#define WORKER_INIT_LOCAL_INPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_LOCAL_INPUT, __VA_ARGS__)
|
||||
#define WORKER_INIT_SINGLE_LOCAL_OUTPUT(var) \
|
||||
#define M_WORK3R_INIT_LOCAL_INPUT(...) \
|
||||
M_MAP(M_WORK3R_INIT_SINGLE_LOCAL_INPUT, __VA_ARGS__)
|
||||
#define M_WORK3R_INIT_SINGLE_LOCAL_OUTPUT(var) \
|
||||
__typeof__(var) var;
|
||||
#define WORKER_INIT_LOCAL_OUTPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_LOCAL_OUTPUT, __VA_ARGS__)
|
||||
#define WORKER_PROPAGATE_SINGLE_OUTPUT(var) \
|
||||
#define M_WORK3R_INIT_LOCAL_OUTPUT(...) \
|
||||
M_MAP(M_WORK3R_INIT_SINGLE_LOCAL_OUTPUT, __VA_ARGS__)
|
||||
#define M_WORK3R_PROPAGATE_SINGLE_OUTPUT(var) \
|
||||
*(_s_data->M_C(var, _ptr)) = var;
|
||||
#define WORKER_PROPAGATE_LOCAL_OUTPUT(...) \
|
||||
M_MAP(WORKER_PROPAGATE_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
#define M_WORK3R_PROPAGATE_LOCAL_OUTPUT(...) \
|
||||
M_MAP(M_WORK3R_PROPAGATE_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
+38
-4
@@ -21,6 +21,7 @@
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
CC=cc -std=c99
|
||||
CXX=c++ -std=c++11
|
||||
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 -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wunused-function -ftrapv -Wsign-conversion -Wdate-time -Wconversion -Wformat=2 -Winit-self -Wjump-misses-init -Wstack-protector -Wtrampolines -Wwrite-strings -Wformat-security -Wno-float-conversion -O
|
||||
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 -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wunused-function -ftrapv -Wsign-conversion -O
|
||||
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 -Wunused-function -ftrapv -Wsign-conversion
|
||||
@@ -44,14 +45,20 @@ all:
|
||||
.POSIX:
|
||||
.PHONY: scan-build sanitize check clean *.log coverage synthesis
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .exe .log .depend .gcov
|
||||
.SUFFIXES: .c .exe .log .depend .gcov .analyzer .cpp
|
||||
.SECONDARY:
|
||||
|
||||
.c.exe:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(LDFLAGS) $< -o $@
|
||||
|
||||
.cpp.exe:
|
||||
$(CXX) $(WCFLAGS_CPP) -Wno-sign-conversion -Wno-inline $(XCFLAGS) $(CPPFLAGS) -g $(LDFLAGS) $< -o $@
|
||||
|
||||
.c.depend:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -MM -MT `echo $< |$(SED) 's/\.c/\.exe/g'` $< > $@
|
||||
$(CC) $(CPPFLAGS) -MM -MT `echo $< |$(SED) 's/\.c/\.exe/g'` $< > $@
|
||||
|
||||
.cpp.depend:
|
||||
$(CXX) $(CPPFLAGS) -MM -MT `echo $< |$(SED) 's/\.cpp/\.exe/g'` $< > $@
|
||||
|
||||
.exe.log:
|
||||
$(LOG_COMPILER) ./$<
|
||||
@@ -74,6 +81,7 @@ depend:
|
||||
$(RM) depend
|
||||
echo "" > depend
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.depend/g'`
|
||||
$(CXX) --version 2> /dev/null && $(MAKE) `ls check-*.cpp|$(SED) 's/\.cpp/\.depend/g'` || echo "Skip C++ tests"
|
||||
cat *.depend > depend
|
||||
$(RM) *.depend
|
||||
|
||||
@@ -82,6 +90,7 @@ depend:
|
||||
# Clean
|
||||
#####################################################################################################
|
||||
|
||||
# This target generates all executable to be tested by CodeQL
|
||||
exe: depend
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.exe/g'` CC="$(CC)" CFLAGS="$(CFLAGS)"
|
||||
@echo All executable generated
|
||||
@@ -90,9 +99,13 @@ check: depend
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'` `ls fail-*.c|$(SED) 's/\.c/\.log/g'` CC="$(CC)" CFLAGS="$(CFLAGS)"
|
||||
@echo All tests passed
|
||||
|
||||
check-stl: depend
|
||||
$(MAKE) `ls check-*.cpp|$(SED) 's/\.cpp/\.log/g'` CXX="$(CXX)" XCFLAGS="-O2 -fsanitize=address,undefined,leak"
|
||||
@echo All comparison against C++ STL passed
|
||||
|
||||
clean:
|
||||
$(RM) *.exe *.s *~ *.o *.log a*.dat
|
||||
$(RM) *.gcda *.gcno *.gcov all.info test.tar *.synt clang_output_* *.c.c *.end.c *.first.c *.middle.c
|
||||
$(RM) *.gcda *.gcno *.gcov all.info test.tar *.synt clang_output_* *.c.c *.end.c *.first.c *.middle.c *.analyzer
|
||||
$(RMDIR) coverage coverage-dir mlib-report
|
||||
|
||||
distclean: clean
|
||||
@@ -144,7 +157,11 @@ gene-queue:
|
||||
gene-string:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -march=native -DNDEBUG -S tgen-mstring.c && less tgen-mstring.s
|
||||
|
||||
gene-serial:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -march=native -DNDEBUG -S -std=c11 tgen-mserial.c && less tgen-mserial.s
|
||||
|
||||
|
||||
#####################################################################################################
|
||||
# Coverage
|
||||
#####################################################################################################
|
||||
|
||||
@@ -195,17 +212,34 @@ synthesis:
|
||||
# Code analyzer tools
|
||||
#####################################################################################################
|
||||
|
||||
# Static analysis of the code using clang scan-build
|
||||
scan-build: clean
|
||||
$(RM) -rf ./mlib-report
|
||||
scan-build -o ./mlib-report $(MAKE) exe XCFLAGS="-std=c99"
|
||||
|
||||
# Relaunch the test suite with the sanitizer.
|
||||
sanitize:
|
||||
$(MAKE) clean check XCFLAGS="-fsanitize=address,undefined,leak"
|
||||
$(MAKE) clean check XCFLAGS="-fsanitize=thread -pie -fPIE"
|
||||
|
||||
|
||||
# Static analysis of the code using GCC "-fanalyzer" option
|
||||
# Need GCC >= 10
|
||||
# Preprocess the file before given it to the analyser (just like coverage) to have better report.
|
||||
.c.analyzer:
|
||||
awk '/START_COVERAGE/ { printit=1} (printit == 0) { print }' $< > $<.first.c
|
||||
awk ' printit { print } /END_COVERAGE/ { printit=1}' $< > $<.end.c
|
||||
$(CC) $(CPPFLAGS) -E -DNDEBUG -DWITHIN_COVERAGE $< |grep -v '^#' |awk ' /END_COVERAGE/ { printit=0} printit { print } /START_COVERAGE/ { printit=1 }' |perl -p -e "s/;(?![\"'])/;\n/g ; s/}(?![\"'])/}\n/g ; s/{(?![\"'])/{\n/g" > $<.middle.c
|
||||
cat $<.first.c $<.middle.c $<.end.c > $<.c
|
||||
$(CC) $(CPPFLAGS) $(LDFLAGS) -fanalyzer -Wall -W -O2 -g $<.c -o $<.exe 2> `basename $< .c`.analyzer
|
||||
$(RM) $<.first.c $<.end.c $<.middle.c $<.c $<.exe
|
||||
|
||||
analyze:
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.analyzer/g'`
|
||||
|
||||
|
||||
#####################################################################################################
|
||||
# Test All
|
||||
# Test with the maximum representative number of compiler and flags.
|
||||
#####################################################################################################
|
||||
|
||||
checkall:
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 <vector>
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF(array_int, int)
|
||||
|
||||
// Transform an integer 'i' into a M*LIB base item 'a'
|
||||
#define TYPE_SET_INT(a, i) (a) = (i)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL ARRAY_OPLIST(array_int, M_OPL_int())
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// Transform an integer 'i' into a C++ base item 'a'
|
||||
#define CLASS_SET_INT(a, i) (a) = (i)
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::vector<int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
// Compate the M*LIB base object to the C++ base object
|
||||
#define CMP_BASE(a, b) assert( (a) == (b) )
|
||||
|
||||
void cmp_cont(array_int_t a, std::vector<int> b)
|
||||
{
|
||||
size_t s = array_int_size(a);
|
||||
assert (s == b.size());
|
||||
for(size_t i = 0; i < s; i++) {
|
||||
int *b0 = array_int_get(a, i);
|
||||
int &b1 = b.at(i);
|
||||
CMP_BASE(*b0, b1);
|
||||
}
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 1000000
|
||||
#define HAVE_RESERVE
|
||||
#define HAVE_RESIZE
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 <deque>
|
||||
#include "m-deque.h"
|
||||
|
||||
DEQUE_DEF(deque_float, float)
|
||||
|
||||
// Transform an integer 'i' into a M*LIB base item 'a'
|
||||
#define TYPE_SET_INT(a, i) (a) = (i)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL DEQUE_OPLIST(deque_float, M_OPL_float())
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS float
|
||||
|
||||
// Transform an integer 'i' into a C++ base item 'a'
|
||||
#define CLASS_SET_INT(a, i) (a) = (i)
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::deque<float>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
// Compate the M*LIB base object to the C++ base object
|
||||
#define CMP_BASE(a, b) assert( (a) == (b) )
|
||||
|
||||
void cmp_cont(deque_float_t a, std::deque<float> b)
|
||||
{
|
||||
deque_float_it_t ita;
|
||||
deque_float_it(ita, a);
|
||||
auto itb = b.begin();
|
||||
while (itb != b.end()) {
|
||||
assert(!deque_float_end_p(ita));
|
||||
const float *b0 = deque_float_cref(ita);
|
||||
float &b1 = *itb;
|
||||
CMP_BASE(*b0, b1);
|
||||
itb++;
|
||||
deque_float_next(ita);
|
||||
}
|
||||
assert(deque_float_end_p(ita));
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 1000000
|
||||
#define HAVE_PUSH_FRONT
|
||||
#define HAVE_POP_FRONT
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 <list>
|
||||
#include "m-list.h"
|
||||
|
||||
LIST_DUAL_PUSH_DEF(list_int, int)
|
||||
|
||||
// Transform an integer 'i' into a M*LIB base item 'a'
|
||||
#define TYPE_SET_INT(a, i) (a) = (i)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL LIST_OPLIST(list_int, M_OPL_int())
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// Transform an integer 'i' into a C++ base item 'a'
|
||||
#define CLASS_SET_INT(a, i) (a) = (i)
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::list<int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
// Compate the M*LIB base object to the C++ base object
|
||||
#define CMP_BASE(a, b) assert( (a) == (b) )
|
||||
|
||||
void cmp_cont(const list_int_t a, const std::list<int> &b)
|
||||
{
|
||||
list_int_it_t ita;
|
||||
list_int_it(ita, a);
|
||||
auto itb = b.rbegin();
|
||||
while (itb != b.rend()) {
|
||||
assert(!list_int_end_p(ita));
|
||||
const int *b0 = list_int_cref(ita);
|
||||
const int &b1 = *itb;
|
||||
//printf("%d VS %d\n", *b0, b1);
|
||||
CMP_BASE(*b0, b1);
|
||||
itb++;
|
||||
list_int_next(ita);
|
||||
}
|
||||
assert(list_int_end_p(ita));
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 100000
|
||||
|
||||
#define HAVE_PUSH_FRONT
|
||||
#define HAVE_REVERSE_IT
|
||||
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,509 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
|
||||
/* This test will perform random generic operations on the
|
||||
M*LIB container and compares it to the same operation on the
|
||||
C++ equivalent container.
|
||||
If there are some differences, it reports an error.
|
||||
It is therefore quite generic and based on the properties of the container
|
||||
*/
|
||||
|
||||
/* Get the types from the container oplist if needed */
|
||||
#ifndef CONT_TYPE
|
||||
# define CONT_TYPE_(CONT_OPL) M_GET_TYPE CONT_OPL
|
||||
# define CONT_TYPE CONT_TYPE_(CONT_OPL)
|
||||
#endif
|
||||
#ifndef BASE_TYPE
|
||||
# define BASE_TYPE_(CONT_OPL) M_GET_SUBTYPE CONT_OPL
|
||||
# define BASE_TYPE BASE_TYPE_(CONT_OPL)
|
||||
#endif
|
||||
|
||||
#define CONT_NAME_(CONT_OPL) M_GET_NAME CONT_OPL
|
||||
#define CONT_NAME CONT_NAME_(CONT_OPL)
|
||||
|
||||
#define MAX_TEST 28
|
||||
|
||||
#ifdef HAVE_REVERSE_IT
|
||||
// Scan the C++ sequence in reverse
|
||||
# define begin rbegin
|
||||
# define end rend
|
||||
# define IT(x) std::prev(x.base(), 1)
|
||||
#else
|
||||
# define IT(x) x
|
||||
#endif
|
||||
|
||||
volatile int test_case;
|
||||
|
||||
void test(int select_test, int index,
|
||||
BASE_TYPE &b0, BASE_CLASS &b1, CONT_TYPE &c0, CONT_CLASS &c1)
|
||||
{
|
||||
bool p0 = false, p1 = false;
|
||||
size_t s0 = 0, s1 = 0;
|
||||
CONT_TYPE tmp;
|
||||
#if M_TEST_METHOD_P(IT_TYPE, CONT_OPL)
|
||||
M_ID(M_GET_IT_TYPE CONT_OPL) it0;
|
||||
auto it1 = c1.begin();
|
||||
#endif
|
||||
|
||||
// Save in a volatile variable the last test for debug purpose
|
||||
test_case = select_test % MAX_TEST;
|
||||
#ifdef DEBUG
|
||||
printf("Case=%d\n", test_case);
|
||||
#endif
|
||||
switch (test_case) {
|
||||
#if M_TEST_METHOD_P(PUSH, CONT_OPL)
|
||||
case 0:
|
||||
TYPE_SET_INT(b0, index);
|
||||
CLASS_SET_INT(b1, index);
|
||||
M_CALL_PUSH(CONT_OPL, c0, b0);
|
||||
c1.push_back(b1);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
index = index % 1000;
|
||||
for(int i = 0; i < index; i++) {
|
||||
TYPE_SET_INT(b0, i);
|
||||
CLASS_SET_INT(b1, i);
|
||||
M_CALL_PUSH(CONT_OPL, c0, b0);
|
||||
c1.push_back(b1);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(POP, CONT_OPL)
|
||||
case 2:
|
||||
if (!c1.empty()) {
|
||||
M_CALL_POP(CONT_OPL, &b0, c0);
|
||||
b1 = c1.back();
|
||||
c1.pop_back();
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(EMPTY_P, CONT_OPL)
|
||||
case 3:
|
||||
p0 = M_CALL_EMPTY_P(CONT_OPL, c0);
|
||||
p1 = c1.empty();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(SIZE, CONT_OPL)
|
||||
case 4:
|
||||
s0 = M_CALL_SIZE(CONT_OPL, c0);
|
||||
s1 = c1.size();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(RESET, CONT_OPL)
|
||||
case 5:
|
||||
M_CALL_RESET(CONT_OPL, c0);
|
||||
c1.clear();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(GET_KEY, CONT_OPL)
|
||||
case 6:
|
||||
if (!c1.empty()) {
|
||||
// To rework for dict
|
||||
index = index % c1.size();
|
||||
#ifndef HAVE_GET_KEY_THROUGH_FIND
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_GET_KEY(CONT_OPL, c0, index));
|
||||
b1 = c1[index];
|
||||
#else
|
||||
BASE_TYPE *p = M_CALL_GET_KEY(CONT_OPL, c0, index);
|
||||
if (p!= NULL) {
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *p);
|
||||
auto i = c1.find(index);
|
||||
assert(i != c1.end());
|
||||
b1 = *i;
|
||||
} else {
|
||||
auto i = c1.find(index);
|
||||
assert(i == c1.end());
|
||||
TYPE_SET_INT(b0, 0);
|
||||
CLASS_SET_INT(b1, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(SET_KEY, CONT_OPL)
|
||||
case 7:
|
||||
if (!c1.empty()) {
|
||||
TYPE_SET_INT(b0, index);
|
||||
CLASS_SET_INT(b1, index);
|
||||
index = index % c1.size();
|
||||
M_CALL_SET_KEY(CONT_OPL, c0, index, b0);
|
||||
c1[index] = b1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(ERASE_KEY, CONT_OPL)
|
||||
case 8:
|
||||
if (!c1.empty()) {
|
||||
index = index % c1.size();
|
||||
p0 = M_CALL_ERASE_KEY(CONT_OPL, c0, index);
|
||||
#ifndef HAVE_GET_KEY_THROUGH_FIND
|
||||
c1.erase(c1.begin() + index);
|
||||
p1 = true;
|
||||
#else
|
||||
auto i = c1.find(index);
|
||||
if (i != c1.end()) {
|
||||
c1.erase(i);
|
||||
p1 = true;
|
||||
} else {
|
||||
p1 = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(SET, CONT_OPL) && M_TEST_METHOD_P(INIT_SET, CONT_OPL)
|
||||
case 9:
|
||||
M_CALL_INIT_SET(CONT_OPL, tmp, c0);
|
||||
#if M_TEST_METHOD_P(EQUAL_P, CONT_OPL)
|
||||
assert( M_CALL_EQUAL_P(CONT_OPL, tmp, c0) );
|
||||
#endif
|
||||
M_CALL_SET(CONT_OPL, c0, tmp);
|
||||
M_CALL_CLEAR(CONT_OPL, tmp);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(INIT_MOVE, CONT_OPL)
|
||||
case 10:
|
||||
M_CALL_INIT_MOVE(CONT_OPL, tmp, c0);
|
||||
M_CALL_INIT_MOVE(CONT_OPL, c0, tmp);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(MOVE, CONT_OPL) && M_TEST_METHOD_P(INIT_MOVE, CONT_OPL)
|
||||
case 11:
|
||||
M_CALL_INIT_SET(CONT_OPL, tmp, c0);
|
||||
M_CALL_MOVE(CONT_OPL, tmp, c0);
|
||||
M_CALL_INIT_MOVE(CONT_OPL, c0, tmp);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(SWAP, CONT_OPL) && M_TEST_METHOD_P(GET_SIZE, CONT_OPL)
|
||||
case 12:
|
||||
s0 = M_CALL_GET_SIZE(CONT_OPL, c0);
|
||||
M_CALL_INIT(CONT_OPL, tmp);
|
||||
M_CALL_SWAP(CONT_OPL, tmp, c0);
|
||||
s1 = M_CALL_GET_SIZE(CONT_OPL, tmp);
|
||||
M_CALL_SWAP(CONT_OPL, tmp, c0);
|
||||
M_CALL_CLEAR(CONT_OPL, tmp);
|
||||
break;
|
||||
case 13:
|
||||
M_CALL_INIT_SET(CONT_OPL, tmp, c0);
|
||||
M_CALL_SWAP(CONT_OPL, tmp, c0);
|
||||
M_CALL_CLEAR(CONT_OPL, tmp);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(SAFE_GET_KEY, CONT_OPL)
|
||||
case 14:
|
||||
// To rework for dict
|
||||
index = (1 + (c1.size() < 1000000)) * (index % ( c1.size() + 1) );
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_SAFE_GET_KEY(CONT_OPL, c0, index));
|
||||
#ifndef HAVE_GET_KEY_THROUGH_FIND
|
||||
if ((size_t) index >= c1.size() ) {
|
||||
c1.resize(index+1);
|
||||
}
|
||||
b1 = c1[index];
|
||||
#else
|
||||
{
|
||||
auto i = c1.find(index);
|
||||
if (i == c1.end()) {
|
||||
c1.insert(index);
|
||||
i = c1.find(index);
|
||||
}
|
||||
b1 = *i;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(IT_CREF, CONT_OPL)
|
||||
case 15:
|
||||
M_CALL_IT_FIRST(CONT_OPL, it0, c0);
|
||||
it1 = c1.begin();
|
||||
while (!M_CALL_IT_END_P(CONT_OPL, it0)) {
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_IT_CREF(CONT_OPL, it0));
|
||||
#ifndef DONT_HAVE_SEQUENCE_IT
|
||||
assert(it1 != c1.end());
|
||||
b1 = *it1;
|
||||
it1++;
|
||||
#else
|
||||
it1 = c1.find(b0);
|
||||
assert(it1 != c1.end());
|
||||
b1 = *it1;
|
||||
#endif
|
||||
CMP_BASE(b0, b1);
|
||||
M_CALL_IT_NEXT(CONT_OPL, it0);
|
||||
}
|
||||
#ifndef DONT_HAVE_SEQUENCE_IT
|
||||
assert(it1 == c1.end());
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(IT_REF, CONT_OPL)
|
||||
case 16:
|
||||
M_CALL_IT_FIRST(CONT_OPL, it0, c0);
|
||||
it1 = c1.begin();
|
||||
while (it1 != c1.end()) {
|
||||
assert( !M_CALL_IT_END_P(CONT_OPL, it0));
|
||||
TYPE_SET_INT(b0, index);
|
||||
CLASS_SET_INT(b1, index);
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, *M_CALL_IT_REF(CONT_OPL, it0), b0);
|
||||
*it1 = b1;
|
||||
M_CALL_IT_NEXT(CONT_OPL, it0);
|
||||
it1++;
|
||||
index = 1457857U * index + 458741U;
|
||||
}
|
||||
assert(M_CALL_IT_END_P(CONT_OPL, it0));
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(IT_LAST, CONT_OPL)
|
||||
case 17:
|
||||
{
|
||||
M_CALL_IT_LAST(CONT_OPL, it0, c0);
|
||||
auto it1b = c1.rbegin();
|
||||
while (it1b != c1.rend()) {
|
||||
assert( !M_CALL_IT_END_P(CONT_OPL, it0));
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_IT_CREF(CONT_OPL, it0));
|
||||
b1 = *it1b;
|
||||
CMP_BASE(b0, b1);
|
||||
M_CALL_IT_PREVIOUS(CONT_OPL, it0);
|
||||
it1b++;
|
||||
}
|
||||
assert(M_CALL_IT_END_P(CONT_OPL, it0));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(IT_INSERT, CONT_OPL)
|
||||
case 18:
|
||||
M_CALL_IT_FIRST(CONT_OPL, it0, c0);
|
||||
it1 = c1.begin();
|
||||
TYPE_SET_INT(b0, index);
|
||||
CLASS_SET_INT(b1, index);
|
||||
#ifdef HAVE_INSERT_AFTER
|
||||
while (it1 != c1.end() ) {
|
||||
if (rand() > index)
|
||||
break;
|
||||
M_CALL_IT_NEXT(CONT_OPL, it0);
|
||||
it1++;
|
||||
}
|
||||
if (it1 != c1.end() ) {
|
||||
M_CALL_IT_INSERT(CONT_OPL, c0, it0, b0);
|
||||
c1.insert_after(it1, b1);
|
||||
}
|
||||
#else
|
||||
if (!c1.empty() ){
|
||||
index = index % c1.size();
|
||||
if (index == 0) {
|
||||
M_CALL_IT_END(CONT_OPL, it0, c0);
|
||||
} else {
|
||||
for(int i = 0; i < index; i++) {
|
||||
assert( it1 != c1.end());
|
||||
assert( !M_CALL_IT_END_P(CONT_OPL, it0));
|
||||
M_CALL_IT_NEXT(CONT_OPL, it0);
|
||||
it1++;
|
||||
}
|
||||
it1++;
|
||||
}
|
||||
}
|
||||
M_CALL_IT_INSERT(CONT_OPL, c0, it0, b0);
|
||||
#ifdef HAVE_REVERSE_IT
|
||||
// in cases of reverse iterator, fix iterator.
|
||||
it1 = std::prev(it1, 1);
|
||||
#endif
|
||||
c1.insert(IT(it1), b1);
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(IT_REMOVE, CONT_OPL)
|
||||
case 19:
|
||||
M_CALL_IT_FIRST(CONT_OPL, it0, c0);
|
||||
it1 = c1.begin();
|
||||
#ifdef HAVE_ERASE_AFTER
|
||||
while (it1 != c1.end() ) {
|
||||
M_CALL_IT_NEXT(CONT_OPL, it0);
|
||||
if (rand() > index)
|
||||
break;
|
||||
it1++;
|
||||
}
|
||||
if (it1 != c1.end() && !M_CALL_IT_END_P(CONT_OPL, it0) ) {
|
||||
M_CALL_IT_REMOVE(CONT_OPL, c0, it0);
|
||||
c1.erase_after(it1);
|
||||
}
|
||||
#else
|
||||
if (!c1.empty() ){
|
||||
index = index % c1.size();
|
||||
for(int i = 0; i < index; i++) {
|
||||
assert( it1 != c1.end());
|
||||
assert( !M_CALL_IT_END_P(CONT_OPL, it0));
|
||||
M_CALL_IT_NEXT(CONT_OPL, it0);
|
||||
it1++;
|
||||
}
|
||||
M_CALL_IT_REMOVE(CONT_OPL, c0, it0);
|
||||
c1.erase(IT(it1));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(REVERSE, CONT_OPL)
|
||||
case 20:
|
||||
M_CALL_REVERSE(CONT_OPL, c0);
|
||||
c1.reverse();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(SPLICE_BACK, CONT_OPL)
|
||||
case 21:
|
||||
M_CALL_REVERSE(CONT_OPL, c0);
|
||||
c1.reverse();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PUSH_FRONT
|
||||
case 22:
|
||||
TYPE_SET_INT(b0, index);
|
||||
CLASS_SET_INT(b1, index);
|
||||
M_C(CONT_NAME, _push_front)(c0, b0);
|
||||
c1.push_front(b1);
|
||||
break;
|
||||
|
||||
case 23:
|
||||
index = index % 1000;
|
||||
for(int i = 0; i < index; i++) {
|
||||
TYPE_SET_INT(b0, i);
|
||||
CLASS_SET_INT(b1, i);
|
||||
M_C(CONT_NAME, _push_front)(c0, b0);
|
||||
c1.push_front(b1);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POP_FRONT
|
||||
case 24:
|
||||
if (!c1.empty()) {
|
||||
M_C(CONT_NAME, _pop_front)(&b0, c0);
|
||||
b1 = c1.front();
|
||||
c1.pop_front();
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RESIZE
|
||||
case 25:
|
||||
index = (1 + (c1.size() < 1000000)) * (index % ( c1.size() + 1) );
|
||||
M_C(CONT_NAME, _resize)(c0, index);
|
||||
c1.resize(index);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RESERVE
|
||||
case 26:
|
||||
index = c1.size() + ( index % (c1.size() + 1) );
|
||||
M_C(CONT_NAME, _reserve)(c0, index);
|
||||
c1.reserve(index);
|
||||
break;
|
||||
|
||||
case 27:
|
||||
M_C(CONT_NAME, _reserve)(c0, 0);
|
||||
c1.shrink_to_fit();
|
||||
break;
|
||||
#endif
|
||||
|
||||
// SPLICE_BACK
|
||||
// SPLICE_AT
|
||||
// Needs SPLICE ?
|
||||
|
||||
default:
|
||||
// Nothing to do
|
||||
break;
|
||||
}
|
||||
CMP_BASE(b0, b1);
|
||||
CMP_CONT(c0, c1);
|
||||
assert(p0 == p1);
|
||||
assert(s0 == s1);
|
||||
}
|
||||
|
||||
static void init_rand(void)
|
||||
{
|
||||
const char *seed = getenv("CHECK_RANDOMIZE");
|
||||
if (seed == NULL) {
|
||||
// No check randomize requested.
|
||||
// Initialize with a common value
|
||||
srand(0x45856525U);
|
||||
} else {
|
||||
unsigned int seed_value = strtoul (seed, NULL, 10);
|
||||
if (seed_value > 1) {
|
||||
// Seed has been set by the user. Use it.
|
||||
printf("Using seed = %u\n", seed_value);
|
||||
} else {
|
||||
time_t tv;
|
||||
time (&tv);
|
||||
seed_value = tv;
|
||||
printf("Generating seed = %u\n", seed_value);
|
||||
}
|
||||
srand(seed_value);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int loop = argc >= 2 ? atoi(argv[1]) : DEFAULT_NUMBER;
|
||||
|
||||
BASE_TYPE b0;
|
||||
BASE_CLASS b1;
|
||||
CONT_TYPE c0;
|
||||
CONT_CLASS c1;
|
||||
|
||||
init_rand();
|
||||
M_CALL_INIT(CONT_OPL, c0);
|
||||
M_CALL_INIT(M_GET_OPLIST CONT_OPL, b0);
|
||||
TYPE_SET_INT(b0, 0);
|
||||
CLASS_SET_INT(b1, 0);
|
||||
|
||||
for(int i = 0; i < loop; i++) {
|
||||
int t = rand();
|
||||
int s = rand();
|
||||
test(t, s, b0, b1, c0, c1);
|
||||
}
|
||||
|
||||
M_CALL_CLEAR(M_GET_OPLIST CONT_OPL, b0);
|
||||
M_CALL_CLEAR(CONT_OPL, c0);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 <forward_list>
|
||||
#include "m-list.h"
|
||||
|
||||
LIST_DEF(list_int, int)
|
||||
|
||||
// Transform an integer 'i' into a M*LIB base item 'a'
|
||||
#define TYPE_SET_INT(a, i) (a) = (i)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL LIST_OPLIST(list_int, M_OPL_int())
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// Transform an integer 'i' into a C++ base item 'a'
|
||||
#define CLASS_SET_INT(a, i) (a) = (i)
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::forward_list<int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
// Compate the M*LIB base object to the C++ base object
|
||||
#define CMP_BASE(a, b) assert( (a) == (b) )
|
||||
|
||||
void cmp_cont(list_int_t a, std::forward_list<int> b)
|
||||
{
|
||||
list_int_it_t ita;
|
||||
list_int_it(ita, a);
|
||||
auto itb = b.begin();
|
||||
while (itb != b.end()) {
|
||||
assert(!list_int_end_p(ita));
|
||||
const int *b0 = list_int_cref(ita);
|
||||
int &b1 = *itb;
|
||||
CMP_BASE(*b0, b1);
|
||||
itb++;
|
||||
list_int_next(ita);
|
||||
}
|
||||
assert(list_int_end_p(ita));
|
||||
}
|
||||
|
||||
#define HAVE_INSERT_AFTER
|
||||
#define HAVE_ERASE_AFTER
|
||||
#define DEFAULT_NUMBER 100000
|
||||
|
||||
// C++ forward_list pushs in front instead of in back
|
||||
#define push_back push_front
|
||||
#define pop_back pop_front
|
||||
#define back front
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 <set>
|
||||
#include "m-rbtree.h"
|
||||
|
||||
RBTREE_DEF(tree_int, int)
|
||||
|
||||
// Transform an integer 'i' into a M*LIB base item 'a'
|
||||
#define TYPE_SET_INT(a, i) (a) = (i)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL RBTREE_OPLIST(tree_int, M_OPL_int())
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// Transform an integer 'i' into a C++ base item 'a'
|
||||
#define CLASS_SET_INT(a, i) (a) = (i)
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::set<int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
// Compate the M*LIB base object to the C++ base object
|
||||
#define CMP_BASE(a, b) assert( (a) == (b) )
|
||||
|
||||
void cmp_cont(const tree_int_t a, const std::set<int> &b)
|
||||
{
|
||||
tree_int_it_t ita;
|
||||
tree_int_it(ita, a);
|
||||
auto itb = b.begin();
|
||||
while (itb != b.end()) {
|
||||
assert(!tree_int_end_p(ita));
|
||||
const int *b0 = tree_int_cref(ita);
|
||||
const int &b1 = *itb;
|
||||
//printf("%d VS %d\n", *b0, b1);
|
||||
CMP_BASE(*b0, b1);
|
||||
itb++;
|
||||
tree_int_next(ita);
|
||||
}
|
||||
assert(tree_int_end_p(ita));
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 1000000
|
||||
|
||||
#define push_back insert
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 <unordered_set>
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_SET_DEF(dict_int, int)
|
||||
|
||||
// Transform an integer 'i' into a M*LIB base item 'a'
|
||||
#define TYPE_SET_INT(a, i) (a) = (i)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL DICT_SET_OPLIST(dict_int, M_OPL_int())
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// Transform an integer 'i' into a C++ base item 'a'
|
||||
#define CLASS_SET_INT(a, i) (a) = (i)
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::unordered_set<int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
// Compate the M*LIB base object to the C++ base object
|
||||
#define CMP_BASE(a, b) assert( (a) == (b) )
|
||||
|
||||
void cmp_cont(const dict_int_t a, const std::unordered_set<int> &b)
|
||||
{
|
||||
size_t n = 0;
|
||||
auto itb = b.begin();
|
||||
while (itb != b.end()) {
|
||||
const int &b1 = *itb;
|
||||
const int *b0 = dict_int_get(a, b1);
|
||||
assert(b0 != nullptr);
|
||||
CMP_BASE(*b0, b1);
|
||||
itb++;
|
||||
n++;
|
||||
}
|
||||
assert(dict_int_size(a) == n);
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 1000000
|
||||
|
||||
#define HAVE_GET_KEY_THROUGH_FIND
|
||||
#define DONT_HAVE_SEQUENCE_IT
|
||||
|
||||
#define push_back insert
|
||||
#include "check-generic.hpp"
|
||||
+46
-18
@@ -44,35 +44,63 @@
|
||||
/* For coverage build, do not expand the
|
||||
typical macros assert, NULL, etc. */
|
||||
#undef assert
|
||||
#undef M_ASSERT
|
||||
#undef M_ASSERT_SLOW
|
||||
#undef M_ASSERT_INIT
|
||||
#undef M_ASSERT_INDEX
|
||||
#undef M_STATIC_FAILURE
|
||||
#undef M_STATIC_ASSERT
|
||||
#undef M_ASSUME
|
||||
#undef NULL
|
||||
#undef M_LIKELY
|
||||
#undef M_UNLIKELY
|
||||
#undef M_MEMORY_FULL
|
||||
#undef M_SWAP
|
||||
#undef STRINGI_CONTRACT
|
||||
#undef ARRAYI_CONTRACT
|
||||
#undef LIST_CONTRACT
|
||||
#undef DICTI_CONTRACT
|
||||
#undef DICTI_OA_CONTRACT
|
||||
#undef SHAREDI_CONTRACT
|
||||
#undef SHAREDI_RESSOURCE_CONTRACT
|
||||
#undef BUFFERI_CONTRACT
|
||||
#undef BUFFERI_PROTECTED_CONTRACT
|
||||
#undef ILISTI_CONTRACT
|
||||
#undef DEQUEI_CONTRACT
|
||||
#undef QUEUEI_MPMC_CONTRACT
|
||||
#undef RBTREEI_CONTRACT_NODE
|
||||
#undef RBTREEI_CONTRACT
|
||||
#undef BPTREEI_NODE_CONTRACT
|
||||
#undef BPTREEI_CONTRACT
|
||||
#undef LISTI_CONTRACT
|
||||
#undef LISTI_DUAL_PUSH_CONTRACT
|
||||
#undef M_ARRA4_CONTRACT
|
||||
#undef M_B1TSET_CONTRACT
|
||||
#undef M_BPTR33_NODE_CONTRACT
|
||||
#undef M_BPTR33_NODE_CONTRACT
|
||||
#undef M_BPTR33_CONTRACT
|
||||
#undef M_BUFF3R_CONTRACT
|
||||
#undef M_BUFF3R_PROTECTED_CONTRACT
|
||||
#undef M_QU3UE_MPMC_CONTRACT
|
||||
#undef M_QU3UE_MPMC_CONTRACT
|
||||
#undef M_QU3UE_SPSC_CONTRACT
|
||||
#undef M_QU3UE_SPSC_CONTRACT
|
||||
#undef M_C0NCURRENT_CONTRACT
|
||||
#undef M_D3QU3_CONTRACT
|
||||
#undef M_D1CT_CONTRACT
|
||||
#undef M_D1CT_OA_CONTRACT
|
||||
#undef M_GEN1NT_CONTRACT
|
||||
#undef M_IL1ST_CONTRACT
|
||||
#undef M_IL1ST_NODE_CONTRACT
|
||||
#undef M_L1ST_CONTRACT
|
||||
#undef M_L1ST_DUAL_PUSH_CONTRACT
|
||||
#undef M_M3MPOOL_CONTRACT
|
||||
#undef M_RBTR33_CONTRACT
|
||||
#undef M_RBTR33_CONTRACT_NODE
|
||||
#undef M_SHAR3D_CONTRACT
|
||||
#undef M_SHAR3D_RESOURCE_CONTRACT
|
||||
#undef M_SNAPSH0T_SPSC_FLAGS_CONTRACT
|
||||
#undef M_SNAPSH0T_SPSC_CONTRACT
|
||||
#undef M_SNAPSH0T_SPMC_INT_CONTRACT
|
||||
#undef M_SNAPSH0T_SPMC_CONTRACT
|
||||
#undef M_STR1NG_CONTRACT
|
||||
#undef M_BOUNDED_STR1NG_CONTRACT
|
||||
#undef M_TUPL3_CONTRACT
|
||||
#undef M_VAR1ANT_CONTRACT
|
||||
#undef NDEBUG
|
||||
#undef atomic_init
|
||||
#undef atomic_load
|
||||
#undef atomic_store
|
||||
#undef atomic_compare_exchange_weak
|
||||
#undef atomic_compare_exchange_strong
|
||||
#undef atomic_fetch_add
|
||||
#undef atomic_fetch_sub
|
||||
#undef M_CONST_CAST
|
||||
#undef M_ASSIGN_CAST
|
||||
#undef M_CHECK_DEFAULT_TYPE
|
||||
#undef M_CHECK_SAME
|
||||
#else
|
||||
/* For normal builds, empty macros which does nothing */
|
||||
#define START_COVERAGE
|
||||
|
||||
+53
-15
@@ -26,6 +26,7 @@
|
||||
#include "m-string.h"
|
||||
#include "m-deque.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-algo.h"
|
||||
|
||||
#include "test-obj.h"
|
||||
@@ -51,6 +52,11 @@ DICT_DEF2(dict_int, string_t, int)
|
||||
ARRAY_DEF(array_uint, unsigned int)
|
||||
#define M_OPL_array_uint_t() ARRAY_OPLIST(array_uint)
|
||||
|
||||
TUPLE_DEF2(person, (age, int), (name, string_t) )
|
||||
#define M_OPL_person_t() TUPLE_OPLIST(person, M_DEFAULT_OPLIST, STRING_OPLIST)
|
||||
ARRAY_DEF(array_person, person_t)
|
||||
#define M_OPL_array_person_t() ARRAY_OPLIST(array_person, M_OPL_person_t() )
|
||||
|
||||
#include "coverage.h"
|
||||
START_COVERAGE
|
||||
ALGO_DEF(algo_array, array_int_t)
|
||||
@@ -196,7 +202,8 @@ static void test_list(void)
|
||||
|
||||
list_int_clear(l);
|
||||
|
||||
ALGO_INIT_VA(l, LIST_OPLIST(list_int), 1, 2, 3, 4, 5);
|
||||
list_int_init(l);
|
||||
for(int i = 1; i <= 5; i++) list_int_push_back(l, i);
|
||||
assert (list_int_size(l) == 5);
|
||||
|
||||
algo_list_remove_val(l, 3);
|
||||
@@ -238,7 +245,7 @@ static void test_list(void)
|
||||
assert(list_int_equal_p (l1, l3));
|
||||
}
|
||||
|
||||
M_LET( (l1, 4, 28, 29, 31, 34), (l2, 1, 3, 31, 32, 33), (l3, 31), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
|
||||
M_LET( (l1, 4, 28, 29, 31, 34), (l2, 1, 3, 31, 32, 33), (l3, (31)), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
|
||||
algo_list_sort_intersect(l1, l2);
|
||||
assert(list_int_equal_p (l1, l3));
|
||||
}
|
||||
@@ -321,7 +328,7 @@ static void test_array(void)
|
||||
assert(*array_int_get(l, 100) == 17);
|
||||
assert(*array_int_get(tmp, 100) == 17 * 17);
|
||||
|
||||
array_int_clean(tmp);
|
||||
array_int_reset(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);
|
||||
@@ -330,7 +337,7 @@ static void test_array(void)
|
||||
assert(*array_int_get(tmp, (size_t) i) == i + 1);
|
||||
}
|
||||
|
||||
array_int_clean(tmp);
|
||||
array_int_reset(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);
|
||||
@@ -388,7 +395,7 @@ static void test_array(void)
|
||||
assert (array_int_end_p (it2));
|
||||
}
|
||||
|
||||
array_int_clean(l);
|
||||
array_int_reset(l);
|
||||
assert (algo_array_min(l) == NULL);
|
||||
assert (algo_array_max(l) == NULL);
|
||||
algo_array_minmax(&min, &max, l);
|
||||
@@ -409,7 +416,8 @@ static void test_array(void)
|
||||
|
||||
array_int_clear(l);
|
||||
|
||||
ALGO_INIT_VA(l, ARRAY_OPLIST(array_int), 1, 2, 3, 4, 5);
|
||||
array_int_init(l);
|
||||
for(int i = 1; i <= 5; i++) array_int_push_back(l, i);
|
||||
assert (array_int_size(l) == 5);
|
||||
assert (algo_array_sort_p(l) == true);
|
||||
assert (algo_array_sort_dsc_p(l) == false);
|
||||
@@ -419,7 +427,7 @@ static void test_array(void)
|
||||
|
||||
array_int_clear(l);
|
||||
|
||||
ALGO_LET_INIT_VA(arr, array_int_t, 1, 5, 34) {
|
||||
M_LET( (arr, 1, 5, 34), array_int_t) {
|
||||
assert (array_int_size(arr) == 3);
|
||||
assert (algo_array_sort_p(arr) == true);
|
||||
assert (algo_array_sort_dsc_p(arr) == false);
|
||||
@@ -491,6 +499,14 @@ static void test_string(void)
|
||||
string_clear(s);
|
||||
|
||||
list_string_clear(l);
|
||||
|
||||
M_LET( (a, (13, ("Jean") ),(14, ("Michael"))), array_person_t ) {
|
||||
assert( array_person_size(a) == 2);
|
||||
assert( (*array_person_get(a, 0))->age == 13 );
|
||||
assert( string_equal_str_p( (*array_person_get(a, 0))->name, "Jean") );
|
||||
assert( (*array_person_get(a, 1))->age == 14 );
|
||||
assert( string_equal_str_p( (*array_person_get(a, 1))->name, "Michael") );
|
||||
}
|
||||
}
|
||||
|
||||
static void test_extract(void)
|
||||
@@ -542,14 +558,14 @@ static void test_extract(void)
|
||||
ALGO_REDUCE(dst, a, ARRAY_OPLIST(array_int), or);
|
||||
assert (dst == 127);
|
||||
|
||||
unsigned long long dst_l;
|
||||
unsigned long long dst_l = 0;
|
||||
// To avoid warnings about sign conversion between int and unsigned long long
|
||||
#define my_set(a, b) do { (a) = (unsigned int) (b); } while (0)
|
||||
#define my_sum(a, b) do { (a) += (unsigned int) (b); } while (0)
|
||||
ALGO_REDUCE( (dst_l, M_OPEXTEND(M_STANDARD_OPLIST, SET(my_set), TYPE(unsigned long long))), a, array_int_t, my_sum);
|
||||
assert (dst_l == 100*99/2-10*11/2);
|
||||
|
||||
array_int_clean(a);
|
||||
array_int_reset(a);
|
||||
for(int i = 1; i < 10; i++)
|
||||
array_int_push_back(a, i);
|
||||
ALGO_REDUCE(dst, a, ARRAY_OPLIST(array_int), product);
|
||||
@@ -579,22 +595,44 @@ LIST_DEF(lint, int)
|
||||
|
||||
static void test_insert(void)
|
||||
{
|
||||
ALGO_LET_INIT_VA(a, lint_t, 1, 2, 3, 4)
|
||||
ALGO_LET_INIT_VA(b, aint_t, -1, -2, -3) {
|
||||
M_LET( (a, 1, 2, 3, 4), aint_t)
|
||||
M_LET( (b, -1, -2, -3), aint_t) {
|
||||
aint_it_t i;
|
||||
aint_it(i, a);
|
||||
// Insert it after first element of the array.
|
||||
ALGO_INSERT_AT(a, aint_t, i, b, aint_t);
|
||||
M_LET( (c, 1, -1, -2, -3, 2, 3, 4), aint_t) {
|
||||
assert (aint_equal_p (c, a));
|
||||
}
|
||||
}
|
||||
|
||||
M_LET( (a, 1, 2, 3, 4), lint_t)
|
||||
M_LET( (b, -1, -2, -3), aint_t) {
|
||||
lint_it_t i;
|
||||
lint_it(i, a);
|
||||
// Insert it after first element
|
||||
// Insert it after first element (aka back)
|
||||
ALGO_INSERT_AT(a, lint_t, i, b, aint_t);
|
||||
// TBC: order ok for the list (the reverse is confusing...)?
|
||||
ALGO_LET_INIT_VA(c, lint_t, 1, 2, 3, -3, -2, -1, 4) {
|
||||
M_LET( (c, 1, -1, -2, -3, 2, 3, 4), lint_t) {
|
||||
assert (lint_equal_p (c, a));
|
||||
}
|
||||
}
|
||||
|
||||
M_LET( (a, 1, 2, 3, 4), lint_t)
|
||||
M_LET( (b, -1, -2, -3), lint_t) {
|
||||
lint_it_t i;
|
||||
lint_it(i, a);
|
||||
// Insert it after first element (aka back)
|
||||
ALGO_INSERT_AT(a, lint_t, i, b, lint_t);
|
||||
M_LET( (c, 1, -1, -2, -3, 2, 3, 4), lint_t) {
|
||||
assert (lint_equal_p (c, a));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void test_string_utf8(void)
|
||||
{
|
||||
M_LET( (s, "H€llo René Chaînôr¬"), string_t)
|
||||
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_uint_t) {
|
||||
// Convert the string into an array of unicode.
|
||||
ALGO_EXTRACT(a, array_uint_t, s, string_t);
|
||||
|
||||
+34
-5
@@ -41,6 +41,8 @@ ARRAY_DEF(array_ulong, uint64_t)
|
||||
ARRAY_DEF_AS(array_double, ArrayDouble, ArrayDoubleIt, double)
|
||||
#define M_OPL_ArrayDouble() ARRAY_OPLIST(array_double, M_DEFAULT_OPLIST)
|
||||
|
||||
ArrayDouble g_array = ARRAY_INIT_VALUE();
|
||||
|
||||
static void test_uint(void)
|
||||
{
|
||||
array_uint_t v;
|
||||
@@ -160,12 +162,12 @@ static void test_uint(void)
|
||||
array_uint_set (v2, v);
|
||||
assert(array_uint_size(v2) == 1005);
|
||||
|
||||
array_uint_clean(v);
|
||||
array_uint_reset(v);
|
||||
assert (array_uint_capacity(v) > 0);
|
||||
array_uint_reserve(v, 0);
|
||||
assert (array_uint_capacity(v) == 0);
|
||||
|
||||
array_uint_clean(v2);
|
||||
array_uint_reset(v2);
|
||||
array_uint_splice(v, v2);
|
||||
assert (array_uint_size(v) == 0);
|
||||
assert (array_uint_size(v2) == 0);
|
||||
@@ -242,7 +244,7 @@ static void test_mpz(void)
|
||||
assert (array_mpz_equal_p (array1, array2));
|
||||
fclose(f);
|
||||
|
||||
array_mpz_clean(array1);
|
||||
array_mpz_reset(array1);
|
||||
|
||||
M_LET(str, STRING_OPLIST) {
|
||||
array_mpz_get_str(str, array1, false);
|
||||
@@ -307,7 +309,7 @@ static void test_d(void)
|
||||
for(int i = 9; i < 19; i++)
|
||||
assert (*array_uint_get (a1, (size_t) i) == 18U -(unsigned int) i);
|
||||
|
||||
*array_uint_get_at(a1, 100) = 100;
|
||||
*array_uint_safe_get(a1, 100) = 100;
|
||||
assert (*array_uint_back(a1) == 100);
|
||||
assert (array_uint_size(a1) == 101);
|
||||
array_uint_pop_back (NULL, a1);
|
||||
@@ -337,6 +339,13 @@ static void test_d(void)
|
||||
array_uint_insert(a1, it2, 17);
|
||||
assert (array_uint_size(a1) == 300);
|
||||
assert (*array_uint_ref(it2) == 17);
|
||||
|
||||
array_uint_it_end(it2, a1);
|
||||
array_uint_insert(a1, it2, 17789);
|
||||
assert (array_uint_size(a1) == 301);
|
||||
assert (*array_uint_ref(it2) == 17789);
|
||||
array_uint_it(it, a1);
|
||||
assert (array_uint_it_equal_p (it, it2));
|
||||
|
||||
array_uint_init_set (a2, a1);
|
||||
assert (array_uint_equal_p (a2, a1));
|
||||
@@ -344,7 +353,7 @@ static void test_d(void)
|
||||
size_t h = array_uint_hash(a2);
|
||||
assert (h != 0);
|
||||
|
||||
array_uint_clean(a1);
|
||||
array_uint_reset(a1);
|
||||
array_uint_it(it, a1);
|
||||
assert (array_uint_end_p (it));
|
||||
assert (array_uint_last_p (it));
|
||||
@@ -361,7 +370,27 @@ static void test_double(void)
|
||||
assert (*i == ref);
|
||||
ref += 1.0;
|
||||
}
|
||||
// Test of buffer overflow (with address sanitizer)
|
||||
// _init_set provides an allocated buffer of the exact needed size
|
||||
ArrayDouble tab1;
|
||||
array_double_init_set(tab1, tab);
|
||||
array_double_pop_at(NULL, tab1, 0);
|
||||
array_double_clear(tab1);
|
||||
array_double_init_set(tab1, tab);
|
||||
array_double_insert_v(tab1, 0, 2);
|
||||
array_double_clear(tab1);
|
||||
array_double_init_set(tab1, tab);
|
||||
array_double_remove_v(tab1, 0, 1);
|
||||
array_double_clear(tab1);
|
||||
array_double_init_set(tab1, tab);
|
||||
array_double_push_at(tab1, 0, 2.);
|
||||
array_double_clear(tab1);
|
||||
}
|
||||
|
||||
assert( array_double_empty_p(g_array));
|
||||
array_double_push_back(g_array, 34.);
|
||||
assert( array_double_size(g_array) == 1);
|
||||
array_double_clear(g_array);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
|
||||
+31
-5
@@ -46,7 +46,7 @@ static void test1(void)
|
||||
bitset_t set2;
|
||||
bitset_init_set(set2, set);
|
||||
|
||||
bitset_clean(set);
|
||||
bitset_reset(set);
|
||||
assert(bitset_size(set) == 0);
|
||||
assert(bitset_empty_p(set) == true);
|
||||
|
||||
@@ -69,6 +69,20 @@ static void test1(void)
|
||||
for(int i = 50; i < 100; i ++) {
|
||||
assert (bitset_get(set2, (size_t) i) == false);
|
||||
}
|
||||
bitset_resize(set2, 128);
|
||||
for(int i = 0; i < 50; i ++) {
|
||||
assert (bitset_get(set2, (size_t) i) == M_ASSIGN_CAST(bool, i%2));
|
||||
}
|
||||
for(int i = 50; i < 128; i ++) {
|
||||
assert (bitset_get(set2, (size_t) i) == false);
|
||||
}
|
||||
bitset_resize(set2, 64);
|
||||
for(int i = 0; i < 50; i ++) {
|
||||
assert (bitset_get(set2, (size_t) i) == M_ASSIGN_CAST(bool, i%2));
|
||||
}
|
||||
for(int i = 50; i < 64; i ++) {
|
||||
assert (bitset_get(set2, (size_t) i) == false);
|
||||
}
|
||||
bitset_resize(set2, 50);
|
||||
|
||||
// Push from 0
|
||||
@@ -104,7 +118,7 @@ static void test1(void)
|
||||
bitset_pop_at(&b, set, 9);
|
||||
assert (b == true);
|
||||
assert (bitset_size(set) == 197);
|
||||
bitset_pop_at(&b, set, 9);
|
||||
bitset_pop_at(&b, set, 71);
|
||||
assert (b == false);
|
||||
assert (bitset_size(set) == 196);
|
||||
|
||||
@@ -121,7 +135,7 @@ static void test1(void)
|
||||
assert (*sp == 0);
|
||||
bitset_clear(set3);
|
||||
|
||||
bitset_clean(set);
|
||||
bitset_reset(set);
|
||||
for(int i = 0; i < 200; i++)
|
||||
bitset_push_back(set, ((size_t) i*17547854547UL)&1) ;
|
||||
bitset_it_t it;
|
||||
@@ -150,7 +164,7 @@ static void test1(void)
|
||||
|
||||
bitset_reserve(set, 0);
|
||||
assert(bitset_capacity (set) > 0);
|
||||
bitset_clean(set);
|
||||
bitset_reset(set);
|
||||
bitset_reserve(set, 0);
|
||||
assert(bitset_capacity (set) == 0);
|
||||
|
||||
@@ -203,7 +217,7 @@ static void test1(void)
|
||||
|
||||
assert (bitset_hash(set) != 0);
|
||||
|
||||
bitset_clean(set);
|
||||
bitset_reset(set);
|
||||
bitset_it(it, set);
|
||||
assert(bitset_end_p(it));
|
||||
assert(bitset_last_p(it));
|
||||
@@ -321,6 +335,7 @@ static void test_let(void)
|
||||
static void test_clz(void)
|
||||
{
|
||||
M_LET(s1, bitset_t) {
|
||||
assert (bitset_clz(s1) == 0);
|
||||
bitset_push_back(s1, false);
|
||||
assert (bitset_clz(s1) == 1);
|
||||
bitset_push_back(s1, false);
|
||||
@@ -351,6 +366,17 @@ static void test_clz(void)
|
||||
bitset_set_at(s1, 0, false);
|
||||
assert (bitset_clz(s1) == 64+620+1);
|
||||
}
|
||||
|
||||
M_LET(s1, bitset_t) {
|
||||
bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]");
|
||||
assert(bitset_popcount(s1) == 0);
|
||||
bitset_set_str(s1, "[10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]");
|
||||
assert(bitset_popcount(s1) == 1);
|
||||
bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]");
|
||||
assert(bitset_popcount(s1) == 1);
|
||||
bitset_set_str(s1, "[10000011100000110010101010110000011111111111111110000001110001110001110001110000]");
|
||||
assert(bitset_popcount(s1) == 40);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
|
||||
+19
-4
@@ -154,6 +154,13 @@ static void test1(void)
|
||||
}
|
||||
assert (btree_size(b) == 0);
|
||||
assert (btree_empty_p(b));
|
||||
|
||||
int *p = btree_safe_get(b, 1000);
|
||||
assert(p != NULL && *p == 0);
|
||||
*p = 23;
|
||||
p = btree_safe_get(b, 1000);
|
||||
assert(p != NULL && *p == 23);
|
||||
|
||||
btree_clear(b);
|
||||
}
|
||||
|
||||
@@ -180,7 +187,7 @@ static void test2(void)
|
||||
assert (k == -2);
|
||||
r = btree_pop_at(NULL, b, 0);
|
||||
assert (r == false);
|
||||
btree_clean(b);
|
||||
btree_reset(b);
|
||||
assert (btree_size(b) == 0);
|
||||
assert (btree_empty_p(b));
|
||||
btree_clear(b);
|
||||
@@ -348,8 +355,17 @@ static void test4(void)
|
||||
static void test5(void)
|
||||
{
|
||||
btree_t b;
|
||||
btree_it_t it, it2;
|
||||
btree_init(b);
|
||||
|
||||
assert (btree_cmin(b) == NULL);
|
||||
assert (btree_cmax(b) == NULL);
|
||||
|
||||
btree_it(it, b);
|
||||
assert(btree_end_p(it));
|
||||
btree_it_end(it, b);
|
||||
assert(btree_end_p(it));
|
||||
|
||||
for(int i = 0; i < 1000; i+=3)
|
||||
btree_set_at(b, i, 1000*i);
|
||||
for(int i = 1; i < 1000; i+=3)
|
||||
@@ -361,9 +377,8 @@ static void test5(void)
|
||||
assert (*btree_cmin(b) == 0*1000);
|
||||
assert (*btree_cmax(b) == 999*1000);
|
||||
|
||||
btree_it_t it, it2;
|
||||
int i = 0;
|
||||
for(btree_it(it, b), btree_it_set(it2, it); !btree_end_p(it); btree_next(it)) {
|
||||
for(btree_it(it, b) ; !btree_end_p(it); btree_it_set(it2, it) , btree_next(it)) {
|
||||
const btree_itref_t *item = btree_cref(it);
|
||||
assert (*item->key_ptr == i);
|
||||
assert (*item->value_ptr == 1000*i);
|
||||
@@ -562,7 +577,7 @@ test_multiset(void)
|
||||
for(multiset_it_from(it, b, k);
|
||||
multiset_it_while_p(it, k);
|
||||
multiset_next(it)) {
|
||||
const multiset_itref_t *ref = multiset_cref(it);
|
||||
const int *ref = multiset_cref(it);
|
||||
assert(*ref == k);
|
||||
j++;
|
||||
}
|
||||
|
||||
+39
-10
@@ -59,21 +59,31 @@ buffer_uint_t g_buffB;
|
||||
// Number of thread created by the test (twice this amount).
|
||||
#define MAX_TEST_THREAD 100
|
||||
#define MAX_TEST_THREAD2 (MAX_TEST_THREAD*2/3)
|
||||
#define MAX_COUNT 1024
|
||||
|
||||
/* Global counter.
|
||||
Each thread has its own row of the matrix (exclusive use). */
|
||||
unsigned int g_count[MAX_TEST_THREAD][MAX_COUNT];
|
||||
|
||||
static void conso(void *arg)
|
||||
{
|
||||
unsigned int j;
|
||||
assert (arg == NULL);
|
||||
for(int i = 0; i < 1000;i++) {
|
||||
uintptr_t thread_id = (uintptr_t) arg;
|
||||
assert(thread_id < MAX_TEST_THREAD);
|
||||
for(int i = 0; i < MAX_COUNT;i++) {
|
||||
buffer_uint_pop(&j, g_buff);
|
||||
assert (j < 1000);
|
||||
assert (j < MAX_COUNT);
|
||||
// Each thread fill in its own row of the matrix, ensuring separate access.
|
||||
// We don't want atomic access which may perturbate the test
|
||||
// by adding memory barries that will hide some issues in the code.
|
||||
g_count[thread_id][j] ++;
|
||||
}
|
||||
}
|
||||
|
||||
static void prod(void *arg)
|
||||
{
|
||||
assert (arg == NULL);
|
||||
for(unsigned int i = 0; i < 1000;i++)
|
||||
for(unsigned int i = 0; i < MAX_COUNT;i++)
|
||||
buffer_uint_push(g_buff, i);
|
||||
}
|
||||
|
||||
@@ -84,20 +94,38 @@ static void test_global(void)
|
||||
|
||||
buffer_uint_init(g_buff, 10);
|
||||
assert (buffer_uint_capacity(g_buff) == 10);
|
||||
|
||||
assert (buffer_uint_empty_p(g_buff));
|
||||
assert (!buffer_uint_full_p(g_buff));
|
||||
assert (buffer_uint_size(g_buff) == 0);
|
||||
|
||||
// Run multiple producer & consummer threads in parallel
|
||||
for(int i = 0; i < MAX_TEST_THREAD; i++) {
|
||||
m_thread_create (idx_p[i], conso, NULL);
|
||||
m_thread_create (idx_p[i], conso, (void*)(uintptr_t) i);
|
||||
m_thread_create (idx_c[i], prod, NULL);
|
||||
}
|
||||
for(int i = 0; i < MAX_TEST_THREAD;i++) {
|
||||
m_thread_join(idx_p[i]);
|
||||
m_thread_join(idx_c[i]);
|
||||
}
|
||||
|
||||
// Check if the data were correctly transmitted
|
||||
// from the producer threads to the consummer threads
|
||||
// First, consolidate the data
|
||||
for(int i = 1 ; i < MAX_TEST_THREAD; i++) {
|
||||
for(int j = 0 ; j < MAX_COUNT; j++) {
|
||||
g_count[0][j] += g_count[i][j];
|
||||
}
|
||||
}
|
||||
// Then check then
|
||||
for(int j = 0 ; j < MAX_COUNT; j++) {
|
||||
assert(g_count[0][j] == MAX_TEST_THREAD);
|
||||
}
|
||||
|
||||
assert (buffer_uint_empty_p(g_buff));
|
||||
assert (!buffer_uint_full_p(g_buff));
|
||||
assert (buffer_uint_size(g_buff) == 0);
|
||||
|
||||
buffer_uint_clean(g_buff);
|
||||
buffer_uint_reset(g_buff);
|
||||
assert (buffer_uint_empty_p(g_buff));
|
||||
assert (!buffer_uint_full_p(g_buff));
|
||||
assert (buffer_uint_size(g_buff) == 0);
|
||||
@@ -117,7 +145,7 @@ static void test_global(void)
|
||||
assert (buffer_uint_size(g_buff) == 10);
|
||||
assert (buffer_uint_push_blocking(g_buff, 15, false) == false);
|
||||
|
||||
buffer_uint_clean(g_buff);
|
||||
buffer_uint_reset(g_buff);
|
||||
assert (buffer_uint_empty_p(g_buff));
|
||||
assert (!buffer_uint_full_p(g_buff));
|
||||
assert (buffer_uint_size(g_buff) == 0);
|
||||
@@ -232,7 +260,7 @@ static void test_no_thread(void)
|
||||
|
||||
b = buffer_llong_push(buff, c);
|
||||
assert (b == true);
|
||||
buffer_llong_clean(buff);
|
||||
buffer_llong_reset(buff);
|
||||
assert (buffer_llong_empty_p(buff) == true);
|
||||
|
||||
buffer_llong_clear(buff);
|
||||
@@ -507,7 +535,8 @@ static void test_spsc(void)
|
||||
b = squeue_uint_pop(&j, q);
|
||||
} while (b);
|
||||
assert(squeue_uint_empty_p(q));
|
||||
b = squeue_uint_push_move(q, 65536);
|
||||
unsigned l = 65536;
|
||||
b = squeue_uint_push_move(q, &l);
|
||||
assert(b);
|
||||
b = squeue_uint_pop(&j, q);
|
||||
assert(b);
|
||||
|
||||
@@ -217,10 +217,12 @@ static void test_double(void)
|
||||
{
|
||||
ConcurrentDouble d;
|
||||
ConcurrentDouble_init(d);
|
||||
ConcurrentDouble_reset(d);
|
||||
ConcurrentDouble_clear(d);
|
||||
|
||||
ConcurrentRpDouble r;
|
||||
ConcurrentRpDouble_init(r);
|
||||
ConcurrentRpDouble_reset(r);
|
||||
ConcurrentRpDouble_clear(r);
|
||||
}
|
||||
|
||||
|
||||
+149
-9
@@ -112,6 +112,50 @@ static void test_incdec(void)
|
||||
|
||||
assert( M_ADD(2,5) == M_SUB(10,3));
|
||||
assert( M_ADD(5,15) == M_SUB(25,5));
|
||||
|
||||
assert(M_EQUAL(2, 2));
|
||||
assert(!M_EQUAL(1, 2));
|
||||
assert(M_EQUAL(52, 52));
|
||||
|
||||
assert(!M_NOTEQUAL(2, 2));
|
||||
assert(M_NOTEQUAL(1, 2));
|
||||
assert(!M_NOTEQUAL(52, 52));
|
||||
|
||||
assert(!M_LESS_THAN_P(4, 2));
|
||||
assert(!M_LESS_THAN_P(4, 3));
|
||||
assert(!M_LESS_THAN_P(4, 4));
|
||||
assert(M_LESS_THAN_P(4, 5));
|
||||
assert(M_LESS_THAN_P(4, 6));
|
||||
assert(M_LESS_THAN_P(4, 7));
|
||||
|
||||
assert(M_GREATER_OR_EQUAL_P(4, 2));
|
||||
assert(M_GREATER_OR_EQUAL_P(4, 3));
|
||||
assert(M_GREATER_OR_EQUAL_P(4, 4));
|
||||
assert(!M_GREATER_OR_EQUAL_P(4, 5));
|
||||
assert(!M_GREATER_OR_EQUAL_P(4, 6));
|
||||
assert(!M_GREATER_OR_EQUAL_P(4, 7));
|
||||
|
||||
assert(M_GREATER_THAN_P(4, 2));
|
||||
assert(M_GREATER_THAN_P(4, 3));
|
||||
assert(!M_GREATER_THAN_P(4, 4));
|
||||
assert(!M_GREATER_THAN_P(4, 5));
|
||||
assert(!M_GREATER_THAN_P(4, 6));
|
||||
assert(!M_GREATER_THAN_P(4, 7));
|
||||
|
||||
assert(!M_LESS_OR_EQUAL_P(4, 2));
|
||||
assert(!M_LESS_OR_EQUAL_P(4, 3));
|
||||
assert(M_LESS_OR_EQUAL_P(4, 4));
|
||||
assert(M_LESS_OR_EQUAL_P(4, 5));
|
||||
assert(M_LESS_OR_EQUAL_P(4, 6));
|
||||
assert(M_LESS_OR_EQUAL_P(4, 7));
|
||||
|
||||
assert(!M_KEYWORD_P(M_UNDERFLOW, M_SUB(1, 1)));
|
||||
assert(M_KEYWORD_P(M_UNDERFLOW, M_SUB(1, 2)));
|
||||
assert(M_KEYWORD_P(M_UNDERFLOW, M_SUB(1, 6)));
|
||||
assert(M_KEYWORD_P(M_UNDERFLOW, M_SUB(1, 5)));
|
||||
assert(!M_KEYWORD_P(M_OVERFLOW, M_ADD(M_MAX_NB_ARGUMENT, 1)));
|
||||
assert(M_KEYWORD_P(M_OVERFLOW, M_ADD(M_MAX_NB_ARGUMENT, 2)));
|
||||
assert(M_KEYWORD_P(M_OVERFLOW, M_ADD(M_MAX_NB_ARGUMENT, 3)));
|
||||
}
|
||||
|
||||
static void test_return(void)
|
||||
@@ -127,10 +171,10 @@ static void test_return(void)
|
||||
|
||||
static void test_invert(void)
|
||||
{
|
||||
assert (M_RET_ARG1 M_INVERT(0,1));
|
||||
assert (M_RET_ARG1 M_INVERT(0,0,1));
|
||||
assert (M_RET_ARG1 M_INVERT(0,0,0,1));
|
||||
assert (M_RET_ARG1 M_INVERT(0,0,0,0,1));
|
||||
assert (M_RET_ARG1 (M_REVERSE(0,1)));
|
||||
assert (M_RET_ARG1 (M_REVERSE(0,0,1)));
|
||||
assert (M_RET_ARG1 (M_REVERSE(0,0,0,1)));
|
||||
assert (M_RET_ARG1 (M_REVERSE(0,0,0,0,1)));
|
||||
}
|
||||
|
||||
static void test_min(void)
|
||||
@@ -204,13 +248,13 @@ static void test_let(void)
|
||||
M_LET((zz,z), M_CLASSIC_OPLIST(testobj)) {
|
||||
assert( testobj_cmp_ui(zz, 12) == 0);
|
||||
}
|
||||
M_LET((zz,42), M_OPEXTEND(M_CLASSIC_OPLIST(testobj), INIT_WITH(testobj_init_set_ui))) {
|
||||
M_LET((zz,(42)), M_OPEXTEND(M_CLASSIC_OPLIST(testobj), INIT_WITH(testobj_init_set_ui))) {
|
||||
assert( testobj_cmp_ui(zz, 42) == 0);
|
||||
}
|
||||
M_LET((zz,z), z2, M_CLASSIC_OPLIST(testobj)) {
|
||||
assert( testobj_cmp_ui(zz, 12) == 0);
|
||||
}
|
||||
M_LET(z3, (zz,42), M_OPEXTEND(M_CLASSIC_OPLIST(testobj), INIT_WITH(testobj_init_set_ui))) {
|
||||
M_LET(z3, (zz,(42)), M_OPEXTEND(M_CLASSIC_OPLIST(testobj), INIT_WITH(testobj_init_set_ui))) {
|
||||
assert( testobj_cmp_ui(zz, 42) == 0);
|
||||
}
|
||||
b = true;
|
||||
@@ -219,6 +263,33 @@ static void test_let(void)
|
||||
}
|
||||
assert(b);
|
||||
|
||||
// Test of recursive INIT_WITH within M_LET
|
||||
#define OPL1 (TYPE(int), INIT_WITH(OPL1_F))
|
||||
#define OPL1_F(d, x) ((d) = (x))
|
||||
#define OPL2 (TYPE(int), INIT_WITH(API_1(OPL2_F)), OPLIST(OPL1) )
|
||||
#define OPL2_F(opl, d, x) M_APPLY_API(M_GET_INIT_WITH M_GET_OPLIST opl, M_GET_OPLIST opl, d, x)
|
||||
#define OPL3 (TYPE(int), INIT_WITH(API_1(OPL3_F)), OPLIST(OPL2) )
|
||||
#define OPL3_F(opl, d, x) M_APPLY_API(M_GET_INIT_WITH M_GET_OPLIST opl, M_GET_OPLIST opl, d, x)
|
||||
#define OPL4 (TYPE(int), INIT_WITH(API_1(OPL4_F)), OPLIST(OPL3) )
|
||||
#define OPL4_F(opl, d, x) M_APPLY_API(M_GET_INIT_WITH M_GET_OPLIST opl, M_GET_OPLIST opl, d, x)
|
||||
#define OPL5 (TYPE(int), INIT_WITH(API_1(OPL5_F)), OPLIST(OPL4) )
|
||||
#define OPL5_F(opl, d, x) M_APPLY_API(M_GET_INIT_WITH M_GET_OPLIST opl, M_GET_OPLIST opl, d, x)
|
||||
#define OPL6 (TYPE(int), INIT_WITH(API_1(OPL6_F)), OPLIST(OPL5) )
|
||||
#define OPL6_F(opl, d, x) M_APPLY_API(M_GET_INIT_WITH M_GET_OPLIST opl, M_GET_OPLIST opl, d, x)
|
||||
|
||||
M_LET( (x, 4585) , OPL1)
|
||||
assert (x == 4585);
|
||||
M_LET( (x, 4586) , OPL2)
|
||||
assert (x == 4586);
|
||||
M_LET( (x, 4587) , OPL3)
|
||||
assert (x == 4587);
|
||||
M_LET( (x, 4588) , OPL4)
|
||||
assert (x == 4588);
|
||||
M_LET( (x, 4589) , OPL5)
|
||||
assert (x == 4589);
|
||||
M_LET( (x, 4590) , OPL6)
|
||||
assert (x == 4590);
|
||||
|
||||
int c = 0;
|
||||
M_LET_IF( assert(c++ == 0), (assert(c++ == 1), true), assert(c++ == 3)) {
|
||||
assert(c++ == 2);
|
||||
@@ -305,6 +376,40 @@ static void test_list(void)
|
||||
assert(M_KEEP_ARGS(1, 1, 0, 0, 0, 0));
|
||||
assert(M_SKIP_ARGS(4, 0, 0, 0, 0, 1));
|
||||
assert(M_MID_ARGS(2, 1, 0, 0, 1, 0));
|
||||
|
||||
const int tab[] = { M_REPLICATE_C(5, 1) };
|
||||
assert(sizeof tab == 5 * sizeof (int) );
|
||||
for(int i = 0; i < 5; i++) assert(tab[i] == 1);
|
||||
const char str[] = M_REPLICATE(10, "N");
|
||||
assert(strcmp(str, "NNNNNNNNNN") == 0);
|
||||
|
||||
assert(M_EQUAL(M_REMOVE_PARENTHESIS( 17 ), 17));
|
||||
assert(M_EQUAL(M_REMOVE_PARENTHESIS( (17) ), 17));
|
||||
|
||||
assert( M_FILTER(M_EQUAL, 17, 1, 42, 17, 89) );
|
||||
assert( M_FILTER_C(M_EQUAL, 17, 1, 42, 17, 89) );
|
||||
const int tab2[] = { M_FILTER_C(M_NOTEQUAL, 8, 1, 3, 4, 8, 9, 8, 10) };
|
||||
assert(sizeof tab2 == 5 * sizeof (int) );
|
||||
const int tabref[] = { 1, 3, 4, 9, 10 };
|
||||
assert (sizeof tab2 == sizeof tabref);
|
||||
for(int i = 0; i < 5 ; i++) assert(tab2[i] == tabref[i]);
|
||||
|
||||
#define TEST_MUL(a) M_PAIR_1 a * M_PAIR_2 a
|
||||
#define TEST_ADD(a,b) a + b
|
||||
int red = M_REDUCE(TEST_MUL, TEST_ADD, M_OPFLAT M_MERGE_ARGLIST( (1, 2, 3), (4, 5, 6) ) );
|
||||
assert(red == 1 * 4 + 2 * 5 + 3 * 6);
|
||||
red = M_REDUCE(TEST_MUL, TEST_ADD, M_OPFLAT M_MERGE_ARGLIST( (1), (4) ) );
|
||||
assert(red == 1 * 4);
|
||||
red = M_REDUCE(TEST_MUL, TEST_ADD, M_OPFLAT M_MERGE_ARGLIST( (3, 5), (7, 11) ) );
|
||||
assert(red == 3 * 7 + 5 * 11);
|
||||
|
||||
red = M_REDUCE(M_ID, TEST_ADD, M_OPFLAT M_CAT_ARGLIST( , (3)));
|
||||
assert(red == 3);
|
||||
red = M_REDUCE(M_ID, TEST_ADD, M_OPFLAT M_CAT_ARGLIST((5, 4), ));
|
||||
assert(red == 5 + 4);
|
||||
red = M_REDUCE(M_ID, TEST_ADD, M_OPFLAT M_CAT_ARGLIST((5, 4), ( 9, 25, 111) ));
|
||||
assert(red == 5 + 4 + 9 + 25 + 111);
|
||||
|
||||
}
|
||||
|
||||
static void test_oplist(void)
|
||||
@@ -402,6 +507,18 @@ static void test_reduce(void)
|
||||
assert ( M_REDUCE(M_ID, add, M_SEQ(1, 5))
|
||||
+ M_REDUCE(M_ID, add, M_SEQ(6, 10))
|
||||
== M_REDUCE(M_ID, add, M_SEQ(1, 10)));
|
||||
|
||||
#define add3(a,b,c) (a + b + c)
|
||||
#define mul(a,b) (a) * (b)
|
||||
int d = 42;
|
||||
assert ( M_REDUCE3(add3, mul, d, 20, 4, 5) ==
|
||||
(d + 1 + 20) * (
|
||||
(d + 2 + 4) * (
|
||||
(d + 3 + 5)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
static void test_as_type(void)
|
||||
@@ -611,14 +728,36 @@ static void test_str_hash(void)
|
||||
|
||||
static void test_M_CSTR(void)
|
||||
{
|
||||
assert ( strcmp(M_CSTR("Len=%d", 17), "Len=17") == 0);
|
||||
assert ( strcmp(M_CSTR("Hello %s %c", "World", '!'), "Hello World !") == 0);
|
||||
int r;
|
||||
r = strcmp(M_CSTR("Len=%d", 17), "Len=17");
|
||||
assert (r == 0);
|
||||
r = strcmp(M_CSTR("Hello %s %c", "World", '!'), "Hello World !");
|
||||
assert (r == 0);
|
||||
|
||||
// Reduce allocation to test truncation
|
||||
#undef M_USE_CSTR_ALLOC
|
||||
#define M_USE_CSTR_ALLOC 8
|
||||
assert ( strcmp(M_CSTR("Hello %s %c", "World", '!'), "Hello W") == 0);
|
||||
// Disable GNUC warning as we want to test this behavior.
|
||||
// this warning is not supported by CLANG
|
||||
#if defined (__GNUC__) && __GNUC__ >= 7 && !defined(__clang__)
|
||||
_Pragma("GCC diagnostic push")
|
||||
_Pragma("GCC diagnostic ignored \"-Wformat-truncation\"")
|
||||
#endif
|
||||
r = strcmp(M_CSTR("Hello %s %c", "World", '!'), "Hello W");
|
||||
#if defined(__GNUC__) && __GNUC__ >= 7 && !defined(__clang__)
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#endif
|
||||
assert (r == 0);
|
||||
}
|
||||
|
||||
static void test_properties(void)
|
||||
{
|
||||
#define OP_PROP() ( INIT(init), PROPERTIES((INIT(1), IT_TYPE(2), INIT_WITH(priority))) )
|
||||
assert( M_GET_PROPERTY (OP_PROP(), INIT ) == 1);
|
||||
assert( M_GET_PROPERTY (OP_PROP(), CLEAR ) == 0);
|
||||
assert( M_GET_PROPERTY (OP_PROP(), IT_TYPE ) == 2);
|
||||
assert( M_KEYWORD_P( M_GET_PROPERTY (OP_PROP(), INIT_WITH ), priority));
|
||||
}
|
||||
int main(void)
|
||||
{
|
||||
test_cat();
|
||||
@@ -643,5 +782,6 @@ int main(void)
|
||||
test_builtin();
|
||||
test_str_hash();
|
||||
test_M_CSTR();
|
||||
test_properties();
|
||||
exit(0);
|
||||
}
|
||||
+141
-9
@@ -23,9 +23,10 @@
|
||||
#include <stdio.h>
|
||||
#include "test-obj.h"
|
||||
|
||||
#include "m-string.h"
|
||||
#include "m-deque.h"
|
||||
|
||||
#include "m-string.h"
|
||||
#include "m-array.h"
|
||||
#include "coverage.h"
|
||||
|
||||
START_COVERAGE
|
||||
@@ -47,12 +48,14 @@ DEQUE_DEF(deque_retcode, ReturnCode_t, M_ENUM_OPLIST(ReturnCode_t, SUCCESS))
|
||||
DEQUE_DEF_AS(DequeDouble, DequeDouble, DequeDoubleIt, double)
|
||||
#define M_OPL_DequeDouble() DEQUE_OPLIST(DequeDouble, M_DEFAULT_OPLIST)
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
|
||||
static void test_ti1(int n)
|
||||
{
|
||||
deque_t d;
|
||||
|
||||
deque_init(d);
|
||||
assert(deque_capacity(d) == DEQUEUI_DEFAULT_SIZE);
|
||||
assert(deque_capacity(d) == M_USE_DEQUE_DEFAULT_SIZE);
|
||||
|
||||
for(int i =0; i < n ;i++) {
|
||||
deque_push_back(d, i);
|
||||
@@ -113,9 +116,11 @@ static void test1(void)
|
||||
for(int i = 0; i < 99*2; i++)
|
||||
assert (*deque_get(d, (size_t) i) == (i < 99) ? i - 99 : i - 98);
|
||||
for(int i = 0; i < 98; i++) {
|
||||
deque_pop_back(NULL, d);
|
||||
deque_pop_back(&j, d);
|
||||
assert (j == i - 99);
|
||||
assert (*deque_back(d) == i - 98);
|
||||
deque_pop_front(NULL, d);
|
||||
deque_pop_front(&j, d);
|
||||
assert (j == 99 - i);
|
||||
assert (*deque_front(d) == 98 - i);
|
||||
}
|
||||
deque_pop_back(&j, d);
|
||||
@@ -130,6 +135,10 @@ static void test1(void)
|
||||
assert (*deque_get(d, 0) == 1918);
|
||||
assert (*deque_get(d, 1) == 1914);
|
||||
|
||||
deque_pop_back(NULL, d);
|
||||
deque_pop_front(NULL, d);
|
||||
assert (deque_empty_p(d));
|
||||
|
||||
deque_clear(d);
|
||||
}
|
||||
|
||||
@@ -184,6 +193,30 @@ static void test_it(void)
|
||||
assert (deque_last_p(it));
|
||||
assert (deque_end_p(it) || *deque_cref (it) == (int)(1996+i));
|
||||
}
|
||||
deque_reset(d);
|
||||
for(int i = 0; i < 4000; i++) {
|
||||
deque_push_back(d, i);
|
||||
deque_it(it, d);
|
||||
int z = 0;
|
||||
while (!deque_end_p(it)) {
|
||||
assert ( *deque_cref(it) == z);
|
||||
z ++;
|
||||
deque_next(it);
|
||||
}
|
||||
assert(z == i+1);
|
||||
}
|
||||
deque_reset(d);
|
||||
for(int i = 0; i < 4000; i++) {
|
||||
deque_push_front(d, i);
|
||||
deque_it_last(it, d);
|
||||
int z = 0;
|
||||
while (!deque_end_p(it)) {
|
||||
assert ( *deque_cref(it) == z);
|
||||
z ++;
|
||||
deque_previous(it);
|
||||
}
|
||||
assert(z == i+1);
|
||||
}
|
||||
}
|
||||
M_LET(d, OPL) {
|
||||
deque_it_t it;
|
||||
@@ -213,7 +246,7 @@ static void test_set(void)
|
||||
assert (deque_end_p (it2));
|
||||
assert (deque_equal_p(d, e));
|
||||
assert (deque_hash(d) != 0);
|
||||
deque_clean (e);
|
||||
deque_reset (e);
|
||||
assert (deque_size (d) == 1997);
|
||||
assert (deque_size (e) == 0);
|
||||
deque_swap(d, e);
|
||||
@@ -246,19 +279,34 @@ static void test_set(void)
|
||||
// deque will continously allocate a new space whereas at most only
|
||||
// one item is in the container!
|
||||
// This is still quite slow.
|
||||
static void test_advance(void)
|
||||
static void test_forward(void)
|
||||
{
|
||||
deque_t d;
|
||||
int j;
|
||||
deque_init(d);
|
||||
for(int i = 0; i < 100000000; i ++) {
|
||||
for(int i = 0; i < 10000000; i ++) {
|
||||
deque_push_back(d, i);
|
||||
assert(*deque_back(d) == i);
|
||||
deque_pop_front(&j, d);
|
||||
assert (i == j);
|
||||
}
|
||||
deque_clear(d);
|
||||
}
|
||||
|
||||
static void test_backward(void)
|
||||
{
|
||||
deque_t d;
|
||||
int j;
|
||||
deque_init(d);
|
||||
for(int i = 0; i < 10000000; i ++) {
|
||||
deque_push_front(d, i);
|
||||
assert(*deque_front(d) == i);
|
||||
deque_pop_back(&j, d);
|
||||
assert (i == j);
|
||||
}
|
||||
deque_clear(d);
|
||||
}
|
||||
|
||||
static void test_z(void)
|
||||
{
|
||||
M_LET(d, DEQUE_OPLIST(deque_mpz, TESTOBJ_OPLIST))
|
||||
@@ -315,7 +363,7 @@ static void test_io(void)
|
||||
assert (deque_mpz_equal_p (d1, d2));
|
||||
fclose(f);
|
||||
|
||||
deque_mpz_clean(d1);
|
||||
deque_mpz_reset(d1);
|
||||
|
||||
deque_mpz_get_str(str, d1, false);
|
||||
assert (string_cmp_str (str, "[]") == 0);
|
||||
@@ -397,6 +445,88 @@ static void test_double(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_remove(void)
|
||||
{
|
||||
deque_t d;
|
||||
deque_it_t it, it2;
|
||||
array_t a;
|
||||
array_it_t ita;
|
||||
deque_init(d);
|
||||
array_init(a);
|
||||
|
||||
deque_push_back(d, 34);
|
||||
deque_it(it, d);
|
||||
deque_remove(d, it);
|
||||
assert(deque_empty_p(d));
|
||||
|
||||
deque_push_back(d, 34);
|
||||
deque_push_back(d, 43);
|
||||
deque_it(it, d);
|
||||
deque_remove(d, it);
|
||||
assert(deque_size(d) == 1);
|
||||
assert(*deque_front(d) == 43);
|
||||
assert(*deque_back(d) == 43);
|
||||
|
||||
for(int n = 2; n < 1000; n++) {
|
||||
deque_reset(d);
|
||||
array_reset(a);
|
||||
for(int i = 0 ; i < n ; i++) {
|
||||
deque_push_back(d, i);
|
||||
array_push_back(a, i);
|
||||
}
|
||||
deque_it(it, d);
|
||||
array_it(ita, a);
|
||||
for(int i = 0 ; i < n ; i++) {
|
||||
for(unsigned j = 0; j <= ((unsigned)n&3) ; j++) {
|
||||
deque_next(it);
|
||||
array_next(ita);
|
||||
}
|
||||
if (deque_end_p(it)) break;
|
||||
assert(*deque_cref(it) == *array_cref(ita));
|
||||
deque_remove(d, it);
|
||||
array_remove(a, ita);
|
||||
if (!deque_end_p(it))
|
||||
assert(*deque_cref(it) == *array_cref(ita));
|
||||
unsigned j = 0;
|
||||
for(deque_it(it2, d); !deque_end_p(it2); deque_next(it2)) {
|
||||
assert(*deque_cref(it2) == *array_get(a, j));
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int n = 2; n < 1000; n++) {
|
||||
deque_reset(d);
|
||||
array_reset(a);
|
||||
for(int i = 0 ; i < n ; i++) {
|
||||
deque_push_front(d, n-1-i);
|
||||
array_push_back(a, i);
|
||||
}
|
||||
deque_it(it, d);
|
||||
array_it(ita, a);
|
||||
for(int i = 0 ; i < n ; i++) {
|
||||
for(unsigned j = 0; j < ((unsigned)n&3) ; j++) {
|
||||
deque_next(it);
|
||||
array_next(ita);
|
||||
}
|
||||
if (deque_end_p(it)) break;
|
||||
assert(*deque_cref(it) == *array_cref(ita));
|
||||
deque_remove(d, it);
|
||||
array_remove(a, ita);
|
||||
if (!deque_end_p(it))
|
||||
assert(*deque_cref(it) == *array_cref(ita));
|
||||
unsigned j = 0;
|
||||
for(deque_it(it2, d); !deque_end_p(it2); deque_next(it2)) {
|
||||
assert(*deque_cref(it2) == *array_get(a, j));
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deque_clear(d);
|
||||
array_clear(a);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test1();
|
||||
@@ -409,7 +539,9 @@ int main(void)
|
||||
test_io();
|
||||
test_io_enum();
|
||||
test_z();
|
||||
test_advance();
|
||||
test_forward();
|
||||
test_backward();
|
||||
test_double();
|
||||
test_remove();
|
||||
exit(0);
|
||||
}
|
||||
+25
-11
@@ -30,11 +30,11 @@
|
||||
|
||||
static inline bool oor_equal_p(int k, unsigned char n) { return k == (int)-n-1; }
|
||||
static inline void oor_set(int *k, unsigned char n) { *k = (int)-n-1; }
|
||||
static inline void update_value (int *p, const int val) { *p += val; }
|
||||
static inline void update_value (int *p, const int p1, const int p2) { *p = p1 + p2; }
|
||||
#include "coverage.h"
|
||||
START_COVERAGE
|
||||
DICT_DEF2(dict_str, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
|
||||
DICT_OA_DEF2(dict_oa_int, int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)), int, M_OPEXTEND(M_DEFAULT_OPLIST, UPDATE(update_value M_IPTR)))
|
||||
DICT_OA_DEF2(dict_oa_int, int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)), int, M_OPEXTEND(M_DEFAULT_OPLIST, ADD(update_value M_IPTR)))
|
||||
END_COVERAGE
|
||||
|
||||
DICT_STOREHASH_DEF2(dict_str2, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
|
||||
@@ -154,7 +154,7 @@ static void test_set(void)
|
||||
string_t *p = dict_setstr_get(set, str);
|
||||
assert (p != NULL);
|
||||
assert(string_equal_p (*p, str));
|
||||
p = dict_setstr_get_at(set, str);
|
||||
p = dict_setstr_safe_get(set, str);
|
||||
assert (p != NULL);
|
||||
assert(string_equal_p (*p, str));
|
||||
}
|
||||
@@ -179,7 +179,7 @@ static void test_init(void)
|
||||
string_t *p = dict_str_get (d1, str1);
|
||||
assert (p != NULL);
|
||||
assert (string_equal_p(*p, str2));
|
||||
p = dict_str_get_at (d1, str1);
|
||||
p = dict_str_safe_get (d1, str1);
|
||||
assert (p != NULL);
|
||||
assert (string_equal_p(*p, str2));
|
||||
}
|
||||
@@ -223,13 +223,13 @@ static void test_init(void)
|
||||
assert (dict_str_size (d1) == 100);
|
||||
dict_str_move (d2, d3);
|
||||
assert (dict_str_size (d2) == 100);
|
||||
dict_str_clean (d2);
|
||||
dict_str_reset (d2);
|
||||
assert (dict_str_size (d2) == 0);
|
||||
|
||||
assert (dict_str_size (d1) == 100);
|
||||
for(int i = 100; i < 200; i++) {
|
||||
string_printf(str1, "%d", 2*i);
|
||||
string_printf(*dict_str_get_at (d1, str1), "%d", 2*i+1);
|
||||
string_printf(*dict_str_safe_get (d1, str1), "%d", 2*i+1);
|
||||
}
|
||||
assert (dict_str_size (d1) == 200);
|
||||
for(int i = 100; i < 200; i++) {
|
||||
@@ -238,7 +238,7 @@ static void test_init(void)
|
||||
string_t *p = dict_str_get (d1, str1);
|
||||
assert (p != NULL);
|
||||
assert (string_equal_p(*p, str2));
|
||||
p = dict_str_get_at (d1, str1);
|
||||
p = dict_str_safe_get (d1, str1);
|
||||
assert (p != NULL);
|
||||
assert (string_equal_p(*p, str2));
|
||||
}
|
||||
@@ -356,7 +356,7 @@ static void test_oa(void)
|
||||
assert(dict_oa_int_size(d) == 50);
|
||||
|
||||
for(int i = 1 ; i < 150; i+= 3)
|
||||
*dict_oa_int_get_at(d, i) = i*i;
|
||||
*dict_oa_int_safe_get(d, i) = i*i;
|
||||
assert(dict_oa_int_size(d) == 100);
|
||||
for(int i = 0 ; i < 150; i++) {
|
||||
int *p = dict_oa_int_get(d, i);
|
||||
@@ -425,16 +425,30 @@ static void test_init_oa(void)
|
||||
assert (dict_oa_int_size (d1) == 100);
|
||||
dict_oa_int_move (d2, d3);
|
||||
assert (dict_oa_int_size (d2) == 100);
|
||||
dict_oa_int_clean (d2);
|
||||
dict_oa_int_reset (d2);
|
||||
assert (dict_oa_int_size (d2) == 0);
|
||||
|
||||
//assert (dict_oa_int_hash (d2) != 0);
|
||||
}
|
||||
M_LET( (d1, (1, 2), (2, 3), (4, 5)), (d2, (1, 3), (4, 7), (10, 14)), (r1, (1, 5), (2, 3), (4, 12), (10, 14) ), DICT_OPLIST(dict_oa_int, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)) {
|
||||
dict_oa_int_splice(d1, d2);
|
||||
assert(dict_oa_int_equal_p(d1, r1));
|
||||
assert(dict_oa_int_empty_p(d2));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_it_oa(void)
|
||||
{
|
||||
M_LET(d1, DICT_OPLIST(dict_oa_int, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)){
|
||||
|
||||
dict_oa_int_it_t it0;
|
||||
dict_oa_int_it(it0, d1);
|
||||
assert( dict_oa_int_end_p(it0) );
|
||||
dict_oa_int_it_last(it0, d1);
|
||||
assert( dict_oa_int_end_p(it0) );
|
||||
dict_oa_int_it_end(it0, d1);
|
||||
assert( dict_oa_int_end_p(it0) );
|
||||
|
||||
for(int i = 0; i < 100; i++) {
|
||||
dict_oa_int_set_at (d1, 2*i, 2*i+1);
|
||||
}
|
||||
@@ -492,7 +506,7 @@ test_oa_str1(void)
|
||||
dict_oa_str_set_at(dict, BOUNDED_STRING_CTE(symbol, "y"), 2);
|
||||
dict_oa_str_set_at(dict, BOUNDED_STRING_CTE(symbol, "z"), 3);
|
||||
|
||||
p = dict_oa_str_get_at(dict, BOUNDED_STRING_CTE(symbol, "x"));
|
||||
p = dict_oa_str_safe_get(dict, BOUNDED_STRING_CTE(symbol, "x"));
|
||||
assert(p != NULL);
|
||||
assert(*p == 1);
|
||||
|
||||
@@ -512,7 +526,7 @@ test_oa_str2(void)
|
||||
dict_oa_bstr_set_at(dict, STRING_CTE("y"), 2);
|
||||
dict_oa_bstr_set_at(dict, STRING_CTE("z"), 3);
|
||||
|
||||
p = dict_oa_bstr_get_at(dict, STRING_CTE("x"));
|
||||
p = dict_oa_bstr_safe_get(dict, STRING_CTE("x"));
|
||||
assert(p != NULL);
|
||||
assert(*p == 1);
|
||||
|
||||
|
||||
@@ -135,6 +135,9 @@ static void test(void)
|
||||
assert (ilist_tname_size (list) == 2);
|
||||
assert (ilist_tname_cref(it1) == &x3);
|
||||
assert (ilist_tname_previous_obj(list, &x3) == &x1);
|
||||
|
||||
ilist_tname_reset(list);
|
||||
assert (ilist_tname_empty_p(list));
|
||||
|
||||
ilist_tname_clear(list);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ static void test_single(void)
|
||||
|
||||
p1 = ishared1_init(NULL);
|
||||
ishared1_set(&p1, p2);
|
||||
ishared1_clean(&p2);
|
||||
ishared1_reset(&p2);
|
||||
assert(p2 == NULL);
|
||||
ishared_test(p1);
|
||||
ishared1_clear(p1);
|
||||
@@ -106,7 +106,7 @@ static void test_static(void)
|
||||
ishared2_clear(p2);
|
||||
}
|
||||
|
||||
#define MAX_THREAD 256
|
||||
#define MAX_THREAD 128
|
||||
#define MAX_VAR 5
|
||||
|
||||
#define VAL(x) { ISHARED_PTR_STATIC_INIT(ishared1, struct ishared_s), ISHARED_PTR_STATIC_INIT(ishared2, struct ishared_s), { 0 } }
|
||||
|
||||
+61
-7
@@ -39,6 +39,8 @@ LIST_DUAL_PUSH_DEF(list2_mpz, testobj_t, TESTOBJ_OPLIST)
|
||||
LIST_DEF(list_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear)))
|
||||
LIST_DUAL_PUSH_DEF(list2_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear)))
|
||||
|
||||
LIST_DEF(list_string, string_t)
|
||||
#define M_OPL_list_string_t() LIST_OPLIST(list_string, STRING_OPLIST)
|
||||
|
||||
LIST_DEF_AS(list_double, ListDouble, ListDoubleIt, double)
|
||||
#define M_OPL_ListDouble() LIST_OPLIST(list_double, M_DEFAULT_OPLIST)
|
||||
@@ -46,6 +48,9 @@ LIST_DEF_AS(list_double, ListDouble, ListDoubleIt, double)
|
||||
LIST_DUAL_PUSH_DEF_AS(list_doubleDP, ListDoubleDP, ListDoubleDPIt, double)
|
||||
#define M_OPL_ListDoubleDP() LIST_OPLIST(list_doubleDP, M_DEFAULT_OPLIST)
|
||||
|
||||
ListDouble g_array1 = LIST_INIT_VALUE();
|
||||
ListDoubleDP g_array2 = LIST_DUAL_PUSH_INIT_VALUE();
|
||||
|
||||
static void test_uint(void)
|
||||
{
|
||||
list_uint_t v;
|
||||
@@ -119,7 +124,7 @@ static void test_uint(void)
|
||||
list_uint_it(u2, v2); //v2 is the first el
|
||||
assert (*list_uint_cref(u2) == 997);
|
||||
|
||||
list_uint_clean(v);
|
||||
list_uint_reset(v);
|
||||
assert (list_uint_empty_p(v) == true);
|
||||
assert (list_uint_empty_p(v2) == false);
|
||||
assert (list_uint_size(v2) == 998);
|
||||
@@ -177,7 +182,7 @@ static void test_uint(void)
|
||||
assert(list_uint_equal_p(v,v2));
|
||||
assert(list_uint_equal_p(v,v));
|
||||
|
||||
list_uint_clean(v);
|
||||
list_uint_reset(v);
|
||||
list_uint_push_back (v2, 14562398);
|
||||
list_uint_it(u, v2);
|
||||
s2 = list_uint_size(v2);
|
||||
@@ -202,8 +207,8 @@ static void test_uint(void)
|
||||
assert (x == 1478963);
|
||||
assert (s == *list_uint_back(v));
|
||||
|
||||
list_uint_clean(v);
|
||||
list_uint_clean(v2);
|
||||
list_uint_reset(v);
|
||||
list_uint_reset(v2);
|
||||
for(unsigned int i = 0; i < 10; i++)
|
||||
list_uint_push_back (v, i);
|
||||
list_uint_it (u, v);
|
||||
@@ -271,7 +276,21 @@ static void test_mpz(void)
|
||||
assert (list_mpz_equal_p (v, list2));
|
||||
list_mpz_clear(list2);
|
||||
|
||||
list_mpz_clean(v);
|
||||
// Print using M_FPRINT
|
||||
f = m_core_fopen ("a-mlist.dat", "wt");
|
||||
if (!f) abort();
|
||||
M_FPRINT(f, (v, LIST_OPLIST(list_mpz, TESTOBJ_OPLIST)) );
|
||||
fclose (f);
|
||||
|
||||
list_mpz_init(list2);
|
||||
f = m_core_fopen ("a-mlist.dat", "rt");
|
||||
b = list_mpz_in_str (list2, f);
|
||||
assert (b == true);
|
||||
fclose(f);
|
||||
assert (list_mpz_equal_p (v, list2));
|
||||
list_mpz_clear(list2);
|
||||
|
||||
list_mpz_reset(v);
|
||||
list_mpz_init(list2);
|
||||
M_LET(str, STRING_OPLIST) {
|
||||
list_mpz_get_str(str, v, false);
|
||||
@@ -579,8 +598,8 @@ static void test_dual_it1(void)
|
||||
list2_double_next(it2);
|
||||
assert(*list2_double_cref(it2) == 1.0);
|
||||
|
||||
list2_double_clean(list);
|
||||
list2_double_clean(list2);
|
||||
list2_double_reset(list);
|
||||
list2_double_reset(list2);
|
||||
for(double i = 0; i < 10; i++)
|
||||
list2_double_push_back (list, i);
|
||||
list2_double_it (it, list);
|
||||
@@ -658,6 +677,40 @@ static void test_double(void)
|
||||
ref += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
assert( list_double_empty_p (g_array1) );
|
||||
assert( list_doubleDP_empty_p (g_array2) );
|
||||
|
||||
list_double_push_back(g_array1, 23.0);
|
||||
list_doubleDP_push_front(g_array2, 23.0);
|
||||
|
||||
list_double_clear(g_array1);
|
||||
list_doubleDP_clear(g_array2);
|
||||
}
|
||||
|
||||
static void test_let_string(void)
|
||||
{
|
||||
M_LET( (y, ("!") ), string_t) // string_t y = string_t{"!"}
|
||||
M_LET( (z, y), string_t) // string_t z = y
|
||||
M_LET( (x, ("Hello"), ("%d World", 2), y ), list_string_t) // astr_t x = { string_t{"Hello"}, string_t{"World"}, z }
|
||||
M_LET( (xx, x), list_string_t) // astr_t xx = x
|
||||
M_LET( (zz, (("Hellno")) ), list_string_t) // astr_t zz = { string_t{"Hellno"} }
|
||||
M_LET( (zx, (y) ), list_string_t) // astr_t zx = { z }
|
||||
M_LET( (tab_name, STRING_CTE("My"), STRING_CTE("CD"), STRING_CTE("IS"), STRING_CTE("OUT")), list_string_t)
|
||||
{
|
||||
assert(string_equal_str_p( y, "!"));
|
||||
assert(string_equal_str_p( z, "!"));
|
||||
list_string_get_str(y, x, false);
|
||||
assert(string_equal_str_p(y, "[\"Hello\",\"2 World\",\"!\"]"));
|
||||
list_string_get_str(y, xx, false);
|
||||
assert(string_equal_str_p(y, "[\"Hello\",\"2 World\",\"!\"]"));
|
||||
list_string_get_str(y, zz, false);
|
||||
assert(string_equal_str_p(y, "[\"Hellno\"]"));
|
||||
list_string_get_str(y, zx, false);
|
||||
assert(string_equal_str_p(y, "[\"!\"]"));
|
||||
list_string_get_str(y, tab_name, false);
|
||||
assert(string_equal_str_p(y, "[\"My\",\"CD\",\"IS\",\"OUT\"]"));
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
@@ -668,6 +721,7 @@ int main(void)
|
||||
test_dual_it1();
|
||||
test_out_default_oplist();
|
||||
test_double();
|
||||
test_let_string();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -275,7 +275,7 @@ static void test_it(void)
|
||||
int_pqueue_swap(p, q);
|
||||
assert(int_pqueue_size(p) == 20);
|
||||
assert(int_pqueue_size(q) == 21);
|
||||
int_pqueue_clean(q);
|
||||
int_pqueue_reset(q);
|
||||
assert(!int_pqueue_equal_p(p, q));
|
||||
assert(int_pqueue_empty_p(q));
|
||||
assert(!int_pqueue_empty_p(p));
|
||||
|
||||
+228
-5
@@ -71,39 +71,148 @@ static void test_uint(void)
|
||||
rbtree_uint_init_set(tree2, tree);
|
||||
assert (rbtree_uint_empty_p(tree2));
|
||||
|
||||
int k = 0;
|
||||
assert(rbtree_uint_size(tree) == 0);
|
||||
for M_EACH(item, tree, UINT_OPLIST) {
|
||||
assert(item != NULL);
|
||||
assert (false);
|
||||
k ++;
|
||||
}
|
||||
assert(k == 0);
|
||||
|
||||
rbtree_uint_push(tree, 10);
|
||||
|
||||
k = 0;
|
||||
assert(rbtree_uint_size(tree) == 1);
|
||||
for M_EACH(item, tree, UINT_OPLIST) {
|
||||
assert (*item == 10);
|
||||
k ++;
|
||||
}
|
||||
assert(k == 1);
|
||||
|
||||
rbtree_uint_push(tree, 5);
|
||||
|
||||
k = 0;
|
||||
assert(rbtree_uint_size(tree) == 2);
|
||||
const unsigned int tab2[] = {5, 10};
|
||||
for M_EACH(item, tree, UINT_OPLIST) {
|
||||
assert (*item == tab2[k] );
|
||||
k ++;
|
||||
}
|
||||
assert(k == 2);
|
||||
|
||||
rbtree_uint_push(tree, 17);
|
||||
|
||||
k = 0;
|
||||
assert(rbtree_uint_size(tree) == 3);
|
||||
const unsigned int tab3[] = {5, 10, 17};
|
||||
for M_EACH(item, tree, UINT_OPLIST) {
|
||||
assert (*item == tab3[k] );
|
||||
k ++;
|
||||
}
|
||||
assert(k == 3);
|
||||
|
||||
rbtree_uint_push(tree, 3);
|
||||
|
||||
k = 0;
|
||||
assert(rbtree_uint_size(tree) == 4);
|
||||
const unsigned int tab4[] = {3, 5, 10, 17};
|
||||
for M_EACH(item, tree, UINT_OPLIST) {
|
||||
assert (*item == tab4[k] );
|
||||
k ++;
|
||||
}
|
||||
assert(k == 4);
|
||||
|
||||
rbtree_uint_push(tree, 11);
|
||||
|
||||
assert(rbtree_uint_size(tree) == 5);
|
||||
assert(rbtree_uint_empty_p(tree) == false);
|
||||
const unsigned int tab[] = {3, 5, 10, 11, 17};
|
||||
int k = 0;
|
||||
const unsigned int tab5[] = {3, 5, 10, 11, 17};
|
||||
k = 0;
|
||||
for M_EACH(item, tree, UINT_OPLIST) {
|
||||
assert (tab[k] == *item);
|
||||
assert (tab5[k] == *item);
|
||||
k ++;
|
||||
}
|
||||
assert (k == 5);
|
||||
|
||||
rbtree_uint_it_t it, it2;
|
||||
rbtree_uint_it(it2, tree);
|
||||
for (rbtree_uint_it_last(it, tree) ; !rbtree_uint_end_p(it) ; rbtree_uint_previous(it)) {
|
||||
k--;
|
||||
rbtree_uint_it_set(it2, it);
|
||||
assert(rbtree_uint_it_equal_p(it2, it));
|
||||
assert (tab[k] == *rbtree_uint_cref(it2) );
|
||||
assert (tab5[k] == *rbtree_uint_cref(it2) );
|
||||
}
|
||||
rbtree_uint_it_end(it, tree);
|
||||
assert (rbtree_uint_end_p(it));
|
||||
assert(!rbtree_uint_it_equal_p(it2, it));
|
||||
rbtree_uint_it_end(it2, tree);
|
||||
assert(rbtree_uint_it_equal_p(it2, it));
|
||||
assert( k == 0);
|
||||
assert (rbtree_uint_hash(tree) != 0);
|
||||
|
||||
rbtree_uint_init(tree3);
|
||||
rbtree_uint_push(tree3, 5);
|
||||
assert(rbtree_uint_size(tree3) == 1);
|
||||
assert(*rbtree_uint_cmin(tree3) == 5);
|
||||
assert(*rbtree_uint_cmax(tree3) == 5);
|
||||
rbtree_uint_move(tree3, tree);
|
||||
rbtree_uint_clear(tree3);
|
||||
|
||||
rbtree_uint_init(tree3);
|
||||
rbtree_uint_push(tree3, 5);
|
||||
rbtree_uint_push(tree3, 3);
|
||||
rbtree_uint_push(tree3, 7);
|
||||
rbtree_uint_push(tree3, 2);
|
||||
assert(rbtree_uint_size(tree3) == 4);
|
||||
rbtree_uint_it(it, tree3);
|
||||
rbtree_uint_remove(tree3, it);
|
||||
assert(rbtree_uint_size(tree3) == 3);
|
||||
assert(*rbtree_uint_cref(it) == 3);
|
||||
rbtree_uint_remove(tree3, it);
|
||||
assert(rbtree_uint_size(tree3) == 2);
|
||||
assert(*rbtree_uint_cref(it) == 5);
|
||||
rbtree_uint_remove(tree3, it);
|
||||
assert(rbtree_uint_size(tree3) == 1);
|
||||
assert(*rbtree_uint_cref(it) == 7);
|
||||
rbtree_uint_remove(tree3, it);
|
||||
assert(rbtree_uint_size(tree3) == 0);
|
||||
|
||||
rbtree_uint_push(tree3, 1);
|
||||
rbtree_uint_push(tree3, 0);
|
||||
rbtree_uint_push(tree3, 5);
|
||||
rbtree_uint_push(tree3, 3);
|
||||
rbtree_uint_push(tree3, 7);
|
||||
rbtree_uint_push(tree3, 2);
|
||||
rbtree_uint_push(tree3, 8);
|
||||
rbtree_uint_push(tree3, 9);
|
||||
rbtree_uint_push(tree3, 10);
|
||||
rbtree_uint_it(it, tree3);
|
||||
assert(*rbtree_uint_cref(it) == 0);
|
||||
rbtree_uint_next(it);
|
||||
assert(*rbtree_uint_cref(it) == 1);
|
||||
rbtree_uint_next(it);
|
||||
assert(*rbtree_uint_cref(it) == 2);
|
||||
rbtree_uint_next(it);
|
||||
assert(*rbtree_uint_cref(it) == 3);
|
||||
rbtree_uint_previous(it);
|
||||
assert(*rbtree_uint_cref(it) == 2);
|
||||
rbtree_uint_next(it);
|
||||
assert(*rbtree_uint_cref(it) == 3);
|
||||
rbtree_uint_remove(tree3, it);
|
||||
assert(*rbtree_uint_cref(it) == 5);
|
||||
rbtree_uint_previous(it);
|
||||
assert(*rbtree_uint_cref(it) == 2);
|
||||
rbtree_uint_remove(tree3, it);
|
||||
assert(*rbtree_uint_cref(it) == 5);
|
||||
rbtree_uint_remove(tree3, it);
|
||||
assert(*rbtree_uint_cref(it) == 7);
|
||||
rbtree_uint_next(it);
|
||||
rbtree_uint_remove(tree3, it);
|
||||
assert(*rbtree_uint_cref(it) == 9);
|
||||
|
||||
rbtree_uint_clear(tree3);
|
||||
|
||||
rbtree_uint_init_move(tree, tree2);
|
||||
rbtree_uint_init_move(tree2, tree);
|
||||
assert (rbtree_uint_empty_p(tree2));
|
||||
@@ -157,7 +266,7 @@ static void test_uint(void)
|
||||
|
||||
rbtree_uint_init (tree);
|
||||
assert(rbtree_uint_empty_p(tree));
|
||||
rbtree_uint_clean(tree2);
|
||||
rbtree_uint_reset(tree2);
|
||||
rbtree_uint_push(tree2, 17421);
|
||||
assert(rbtree_uint_size(tree2) == 1);
|
||||
rbtree_uint_swap(tree, tree2);
|
||||
@@ -274,6 +383,119 @@ static void test_double(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_from(void)
|
||||
{
|
||||
rbtree_uint_t tree;
|
||||
rbtree_uint_it_t it;
|
||||
|
||||
rbtree_uint_init(tree);
|
||||
|
||||
// No element.
|
||||
rbtree_uint_it_from(it, tree, 3);
|
||||
assert(rbtree_uint_end_p(it));
|
||||
assert(rbtree_uint_it_until_p(it, 3));
|
||||
assert(!rbtree_uint_it_while_p(it, 3));
|
||||
|
||||
// One element
|
||||
rbtree_uint_push(tree, 3);
|
||||
rbtree_uint_it_from(it, tree, 3);
|
||||
assert(!rbtree_uint_end_p(it));
|
||||
assert(rbtree_uint_it_until_p(it, 3));
|
||||
assert(rbtree_uint_it_while_p(it, 3));
|
||||
assert(!rbtree_uint_it_until_p(it, 4));
|
||||
assert(rbtree_uint_it_while_p(it, 4));
|
||||
assert(rbtree_uint_it_until_p(it, 2));
|
||||
assert(!rbtree_uint_it_while_p(it, 2));
|
||||
|
||||
rbtree_uint_it_from(it, tree, 2);
|
||||
assert(!rbtree_uint_end_p(it));
|
||||
assert(rbtree_uint_it_until_p(it, 3));
|
||||
assert(rbtree_uint_it_while_p(it, 3));
|
||||
assert(!rbtree_uint_it_until_p(it, 4));
|
||||
assert(rbtree_uint_it_while_p(it, 4));
|
||||
assert(rbtree_uint_it_until_p(it, 2));
|
||||
assert(!rbtree_uint_it_while_p(it, 2));
|
||||
|
||||
rbtree_uint_it_from(it, tree, 4);
|
||||
assert(rbtree_uint_end_p(it));
|
||||
assert(rbtree_uint_it_until_p(it, 3));
|
||||
assert(!rbtree_uint_it_while_p(it, 3));
|
||||
|
||||
// More elements
|
||||
rbtree_uint_push(tree, 10);
|
||||
rbtree_uint_push(tree, 5);
|
||||
rbtree_uint_push(tree, 1);
|
||||
rbtree_uint_push(tree, 7);
|
||||
|
||||
int k = 0;
|
||||
const unsigned int tab0[] = { 3, 5, 7};
|
||||
for( rbtree_uint_it_from(it, tree, 3); !rbtree_uint_it_until_p(it, 8); rbtree_uint_next(it)) {
|
||||
assert (k < 3);
|
||||
assert(tab0[k] == *rbtree_uint_cref(it));
|
||||
k++;
|
||||
}
|
||||
assert(k == 3);
|
||||
k = 0;
|
||||
for( rbtree_uint_it_from(it, tree, 3); !rbtree_uint_it_until_p(it, 7); rbtree_uint_next(it)) {
|
||||
assert (k < 3);
|
||||
assert(tab0[k] == *rbtree_uint_cref(it));
|
||||
k++;
|
||||
}
|
||||
assert(k == 2);
|
||||
|
||||
k = 0;
|
||||
for( rbtree_uint_it_from(it, tree, 3); rbtree_uint_it_while_p(it, 8); rbtree_uint_next(it)) {
|
||||
assert (k < 3);
|
||||
assert(tab0[k] == *rbtree_uint_cref(it));
|
||||
k++;
|
||||
}
|
||||
assert(k == 3);
|
||||
|
||||
k = 0;
|
||||
for( rbtree_uint_it_from(it, tree, 3); rbtree_uint_it_while_p(it, 7); rbtree_uint_next(it)) {
|
||||
assert (k < 3);
|
||||
assert(tab0[k] == *rbtree_uint_cref(it));
|
||||
k++;
|
||||
}
|
||||
assert(k == 3);
|
||||
|
||||
k = 0;
|
||||
for( rbtree_uint_it_from(it, tree, 3); rbtree_uint_it_while_p(it, 6); rbtree_uint_next(it)) {
|
||||
assert (k < 3);
|
||||
assert(tab0[k] == *rbtree_uint_cref(it));
|
||||
k++;
|
||||
}
|
||||
assert(k == 2);
|
||||
|
||||
k = 0;
|
||||
const unsigned int tab1[] = { 1, 3, 5};
|
||||
for( rbtree_uint_it_from(it, tree, 0); rbtree_uint_it_while_p(it, 6); rbtree_uint_next(it)) {
|
||||
assert (k < 3);
|
||||
assert(tab1[k] == *rbtree_uint_cref(it));
|
||||
k++;
|
||||
}
|
||||
assert(k == 3);
|
||||
|
||||
k = 0;
|
||||
const unsigned int tab2[] = { 5, 7};
|
||||
for( rbtree_uint_it_from(it, tree, 4); rbtree_uint_it_while_p(it, 7); rbtree_uint_next(it)) {
|
||||
assert (k < 2);
|
||||
assert(tab2[k] == *rbtree_uint_cref(it));
|
||||
k++;
|
||||
}
|
||||
assert(k == 2);
|
||||
|
||||
// From higher than all elements in the tree ==> no iterator.
|
||||
k = 0;
|
||||
for( rbtree_uint_it_from(it, tree, 11); rbtree_uint_it_while_p(it, 17); rbtree_uint_next(it)) {
|
||||
assert (k < 2);
|
||||
k++;
|
||||
}
|
||||
assert(k == 0);
|
||||
|
||||
rbtree_uint_clear(tree);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_uint();
|
||||
@@ -281,5 +503,6 @@ int main(void)
|
||||
test_float();
|
||||
test_io();
|
||||
test_double();
|
||||
test_from();
|
||||
exit(0);
|
||||
}
|
||||
@@ -173,10 +173,100 @@ static void test_out_fill(void)
|
||||
my2_clear(el2);
|
||||
}
|
||||
|
||||
static void test_out_str_empty(void)
|
||||
{
|
||||
m_serial_read_t in;
|
||||
m_serial_write_t out;
|
||||
m_serial_return_code_t ret;
|
||||
my2_t el1, el2;
|
||||
my2_init(el1);
|
||||
my2_init(el2);
|
||||
|
||||
string_t f;
|
||||
string_init(f);
|
||||
m_serial_str_json_write_init(out, f);
|
||||
ret = my2_out_serial(out, el1);
|
||||
assert (ret == M_SERIAL_OK_DONE);
|
||||
m_serial_str_json_write_clear(out);
|
||||
|
||||
static const char expected[] = "{ \"activated\":false,\"data\":{ \"vala\":0,\"valb\":0.000000,\"valc\":false,\"vald\":\"\",\"vale\":[],\"valf\":{},\"valg\":[],\"valh\":{},\"vali\":0}";
|
||||
assert (string_equal_str_p(f, expected) == 0);
|
||||
|
||||
m_serial_str_json_read_init(in, string_get_cstr(f) );
|
||||
ret = my2_in_serial(el2, in);
|
||||
assert (ret == M_SERIAL_OK_DONE);
|
||||
const char *end = m_serial_str_json_read_clear(in);
|
||||
assert (*end == 0);
|
||||
|
||||
assert (my2_equal_p (el1, el2));
|
||||
|
||||
my2_clear(el1);
|
||||
my2_clear(el2);
|
||||
string_clear(f);
|
||||
}
|
||||
|
||||
static void test_out_str_fill(void)
|
||||
{
|
||||
m_serial_read_t in;
|
||||
m_serial_write_t out;
|
||||
m_serial_return_code_t ret;
|
||||
my2_t el1, el2;
|
||||
my2_init(el1);
|
||||
my2_init(el2);
|
||||
|
||||
string_t f;
|
||||
string_init(f);
|
||||
string_init_set_str(f,
|
||||
"{\n"
|
||||
" \"activated\":false,\n"
|
||||
"\"data\": {\n"
|
||||
" \"valb\": -2.300000 , \n"
|
||||
"\"vale\": [1,2,3],\n"
|
||||
"\"valg\": [1,2,3,4,5,6],\n"
|
||||
"\"valh\": { \"jane\": 3, \"steeve\": -4 },\n"
|
||||
"\"valf\": { \"is_bool\": true },\n"
|
||||
" \"vala\":1742,\n"
|
||||
" \"vald\": \"This is a test\",\n"
|
||||
"\"vali\": 3,"
|
||||
" \"valc\": true } }\n");
|
||||
|
||||
m_serial_str_json_read_init(in, string_get_cstr(f) );
|
||||
ret = my2_in_serial(el2, in);
|
||||
assert (ret == M_SERIAL_OK_DONE);
|
||||
const char *end = m_serial_str_json_read_clear(in);
|
||||
assert (*end == '\n');
|
||||
string_reset(f);
|
||||
|
||||
m_serial_str_json_write_init(out, f);
|
||||
ret = my2_out_serial(out, el2);
|
||||
assert (ret == M_SERIAL_OK_DONE);
|
||||
m_serial_str_json_write_clear(out);
|
||||
|
||||
// In function of the precise hashing (different between 64 bits & 32 bits), both strings are possible:
|
||||
static const char expected[] = "{ \"activated\":false,\"data\":{ \"vala\":1742,\"valb\":-2.300000,\"valc\":true,\"vald\":\"This is a test\",\"vale\":[1,2,3],\"valf\":{\"is_bool\":true},\"valg\":[1,2,3,4,5,6],\"valh\":{\"steeve\":-4,\"jane\":3},\"vali\":3}}";
|
||||
static const char expected2[] = "{ \"activated\":false,\"data\":{ \"vala\":1742,\"valb\":-2.300000,\"valc\":true,\"vald\":\"This is a test\",\"vale\":[1,2,3],\"valf\":{\"is_bool\":true},\"valg\":[1,2,3,4,5,6],\"valh\":{\"jane\":3,\"steeve\":-4},\"vali\":3}}";
|
||||
assert(string_equal_str_p(f, expected) || string_equal_str_p(f, expected2) );
|
||||
|
||||
m_serial_str_json_read_init(in, string_get_cstr(f) );
|
||||
ret = my2_in_serial(el1, in);
|
||||
assert (ret == M_SERIAL_OK_DONE);
|
||||
end = m_serial_str_json_read_clear(in);
|
||||
assert (*end == 0);
|
||||
|
||||
assert (my2_equal_p (el1, el2));
|
||||
|
||||
my2_clear(el1);
|
||||
my2_clear(el2);
|
||||
string_clear(f);
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_out_empty();
|
||||
test_out_fill();
|
||||
test_out_str_empty();
|
||||
test_out_str_fill();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -59,14 +59,14 @@ static void test1(void)
|
||||
shared_int_init_set(p2, p1);
|
||||
assert(f(p2) == 12);
|
||||
|
||||
shared_int_clean(p1);
|
||||
shared_int_reset(p1);
|
||||
assert(shared_int_NULL_p(p1));
|
||||
assert(!shared_int_NULL_p(p2));
|
||||
assert(f(p2) == 12);
|
||||
|
||||
shared_int_set(p1, p2);
|
||||
|
||||
shared_int_clean(p2);
|
||||
shared_int_reset(p2);
|
||||
assert(!shared_int_NULL_p(p1));
|
||||
assert(shared_int_NULL_p(p2));
|
||||
assert(f(p1) == 12);
|
||||
@@ -75,8 +75,8 @@ static void test1(void)
|
||||
assert(!shared_int_NULL_p(p2));
|
||||
assert(f(p2) == 12);
|
||||
|
||||
shared_int_clean(p2);
|
||||
shared_int_clean(p1);
|
||||
shared_int_reset(p2);
|
||||
shared_int_reset(p1);
|
||||
|
||||
assert(shared_int_NULL_p(p1));
|
||||
assert(shared_int_NULL_p(p2));
|
||||
|
||||
+45
-43
@@ -154,65 +154,67 @@ static void test_global(void)
|
||||
|
||||
static void test_mrsw_int1(void)
|
||||
{
|
||||
snapshot_mrsw_int_ct idx;
|
||||
snapshot_mrsw_int_init(idx, 1);
|
||||
// Test of internal interface.
|
||||
m_snapshot_mrsw_ct idx;
|
||||
m_snapsh0t_mrsw_init(idx, 1);
|
||||
|
||||
assert (snapshot_mrsw_int_get_write_idx(idx) == 1);
|
||||
assert (m_snapsh0t_mrsw_get_write_idx(idx) == 1);
|
||||
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 1);
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 1);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 0);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 1);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 0);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 1);
|
||||
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 0);
|
||||
snapshot_mrsw_int_read_end(idx, 0);
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 0);
|
||||
snapshot_mrsw_int_read_end(idx, 0);
|
||||
assert (m_snapsh0t_mrsw_read_start(idx) == 0);
|
||||
m_snapsh0t_mrsw_read_end(idx, 0);
|
||||
assert (m_snapsh0t_mrsw_read_start(idx) == 0);
|
||||
m_snapsh0t_mrsw_read_end(idx, 0);
|
||||
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 0);
|
||||
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 1);
|
||||
assert (snapshot_mrsw_int_write(idx) == 2);
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 2);
|
||||
snapshot_mrsw_int_read_end(idx, 1);
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 1);
|
||||
assert (m_snapsh0t_mrsw_read_start(idx) == 1);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 2);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 0);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 2);
|
||||
m_snapsh0t_mrsw_read_end(idx, 1);
|
||||
assert (m_snapsh0t_mrsw_read_start(idx) == 0);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 1);
|
||||
|
||||
snapshot_mrsw_int_clear(idx);
|
||||
m_snapsh0t_mrsw_clear(idx);
|
||||
}
|
||||
|
||||
static void test_mrsw_int2(void)
|
||||
{
|
||||
snapshot_mrsw_int_ct idx;
|
||||
snapshot_mrsw_int_init(idx, 2);
|
||||
// Test of internal interface
|
||||
m_snapshot_mrsw_ct idx;
|
||||
m_snapsh0t_mrsw_init(idx, 2);
|
||||
|
||||
assert (snapshot_mrsw_int_get_write_idx(idx) == 1);
|
||||
assert (m_snapsh0t_mrsw_get_write_idx(idx) == 1);
|
||||
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 1);
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 1);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 0);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 1);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 0);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 1);
|
||||
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 0);
|
||||
snapshot_mrsw_int_read_end(idx, 0);
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 0);
|
||||
snapshot_mrsw_int_read_end(idx, 0);
|
||||
assert (m_snapsh0t_mrsw_read_start(idx) == 0);
|
||||
m_snapsh0t_mrsw_read_end(idx, 0);
|
||||
assert (m_snapsh0t_mrsw_read_start(idx) == 0);
|
||||
m_snapsh0t_mrsw_read_end(idx, 0);
|
||||
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 0);
|
||||
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 1);
|
||||
assert (snapshot_mrsw_int_write(idx) == 2);
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 2);
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 3);
|
||||
snapshot_mrsw_int_read_end(idx, 1);
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 2);
|
||||
assert (snapshot_mrsw_int_write(idx) == 1);
|
||||
snapshot_mrsw_int_read_end(idx, 0);
|
||||
assert (m_snapsh0t_mrsw_read_start(idx) == 1);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 2);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 0);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 2);
|
||||
assert (m_snapsh0t_mrsw_read_start(idx) == 0);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 3);
|
||||
m_snapsh0t_mrsw_read_end(idx, 1);
|
||||
assert (m_snapsh0t_mrsw_read_start(idx) == 2);
|
||||
assert (m_snapsh0t_mrsw_write(idx) == 1);
|
||||
m_snapsh0t_mrsw_read_end(idx, 0);
|
||||
|
||||
snapshot_mrsw_int_clear(idx);
|
||||
m_snapsh0t_mrsw_clear(idx);
|
||||
}
|
||||
|
||||
snapshot_mrsw_data_t global_mrsw;
|
||||
|
||||
+35
-18
@@ -39,7 +39,7 @@ static void test_utf8_basic(void)
|
||||
if (i < 0xD800U || i > 0xDFFFU) {
|
||||
string_it_t it;
|
||||
char buf[5] = {0};
|
||||
stringi_utf8_encode (buf, i);
|
||||
m_str1ng_utf8_encode (buf, i);
|
||||
/* Low level access for internal testing */
|
||||
it->ptr = buf;
|
||||
bool b = string_end_p(it);
|
||||
@@ -47,10 +47,10 @@ static void test_utf8_basic(void)
|
||||
assert (it->u == i);
|
||||
assert (string_get_cref(it) == i);
|
||||
assert (*it->next_ptr == 0);
|
||||
assert (stringi_utf8_length(buf) == 1);
|
||||
assert (stringi_utf8_valid_str_p(buf) == true);
|
||||
assert (m_str1ng_utf8_length(buf) == 1);
|
||||
assert (m_str1ng_utf8_valid_str_p(buf) == true);
|
||||
/* Higher level access */
|
||||
string_clean(s);
|
||||
string_reset(s);
|
||||
string_push_u(s, i);
|
||||
assert(string_utf8_p(s) == true);
|
||||
assert(string_length_u(s) == 1);
|
||||
@@ -59,13 +59,13 @@ static void test_utf8_basic(void)
|
||||
|
||||
/* Reject out of range value */
|
||||
for (string_unicode_t i = 0x110000; i < 0x1fffff; i++) {
|
||||
string_clean(s);
|
||||
string_reset(s);
|
||||
string_push_u(s, i);
|
||||
assert(string_utf8_p(s) == false);
|
||||
}
|
||||
/* Test rejection of surrogate halves */
|
||||
for (string_unicode_t i = 0xd800; i <= 0xdfff; i++) {
|
||||
string_clean(s);
|
||||
string_reset(s);
|
||||
string_push_u(s, i);
|
||||
assert(string_utf8_p(s) == false);
|
||||
}
|
||||
@@ -108,7 +108,7 @@ static void test_utf8_it(void)
|
||||
assert(tab2[i] == *string_cref(it2));
|
||||
}
|
||||
assert (i == 19);
|
||||
string_clean(s);
|
||||
string_reset(s);
|
||||
for(i = 0 ; i < 19; i++)
|
||||
string_push_u(s, tab2[i]);
|
||||
assert (string_equal_str_p(s, "H€llo René Chaînôr¬"));
|
||||
@@ -133,18 +133,21 @@ static void test0(void)
|
||||
string_set_str (s1, "Hello, world!");
|
||||
assert (string_size(s1) == 13);
|
||||
assert (string_get_char(s1, 1) == 'e');
|
||||
string_set_char(s1, 1, 'E');
|
||||
assert (string_get_char(s1, 1) == 'E');
|
||||
string_set_char(s1, 1, 'e');
|
||||
|
||||
string_clean(s1);
|
||||
string_reset(s1);
|
||||
assert (string_size(s1) == 0);
|
||||
assert (string_empty_p(s1) == true);
|
||||
assert (strcmp(string_get_cstr(s1), "") == 0);
|
||||
|
||||
string_set_strn(s1, "Hello, world!", 14);
|
||||
assert (strcmp(string_get_cstr(s1), "Hello, world!") == 0);
|
||||
string_clean(s1);
|
||||
string_reset(s1);
|
||||
string_set_strn(s1, "Hello, world!", 5);
|
||||
assert (strcmp(string_get_cstr(s1), "Hello") == 0);
|
||||
string_clean(s1);
|
||||
string_reset(s1);
|
||||
|
||||
string_set_str (s1, "Hello");
|
||||
string_set_str (s2, "Hello, world!");
|
||||
@@ -155,7 +158,7 @@ static void test0(void)
|
||||
assert (string_size(s1) == 22);
|
||||
assert (strcmp(string_get_cstr(s1), "Hello beautiful world!") == 0);
|
||||
|
||||
string_clean(s1);
|
||||
string_reset(s1);
|
||||
string_set_n (s2, s1, 0, 5);
|
||||
assert(string_empty_p(s2));
|
||||
|
||||
@@ -451,6 +454,21 @@ static void test0(void)
|
||||
assert(!b);
|
||||
fclose(f);
|
||||
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
|
||||
string_set_str(s1, "This is a string");
|
||||
|
||||
f = m_core_fopen ("a-mstring.dat", "wt");
|
||||
assert (f != NULL);
|
||||
M_FPRINT(f, "The string is '", s1, "' and the number is ", 42, ".\n");
|
||||
fclose (f);
|
||||
f = m_core_fopen("a-mstring.dat", "rt");
|
||||
assert (f != NULL);
|
||||
b = string_fgets(s2, f, STRING_READ_PURE_LINE);
|
||||
assert(b);
|
||||
assert( string_equal_str_p (s2, "The string is 'This is a string' and the number is 42.") );
|
||||
fclose(f);
|
||||
#endif
|
||||
|
||||
string_set_str(s1, "AZERTY");
|
||||
string_set_str(s2, "QWERTY");
|
||||
string_swap (s1, s2);
|
||||
@@ -606,7 +624,7 @@ static void test0(void)
|
||||
h = string_search_pbrk(s1, "oO");
|
||||
assert(h==4);
|
||||
|
||||
string_clean(s1);
|
||||
string_reset(s1);
|
||||
string_reserve(s1, 0);
|
||||
string_cat_printf(s1, "%d little %s.", 42, "suns");
|
||||
string_set_str(s2, "42 little suns.");
|
||||
@@ -636,7 +654,7 @@ static void test_bounded1(void)
|
||||
assert (string16_cmp_str(s, "Hello") == 0);
|
||||
assert (string16_get_char(s, 1) == 'e');
|
||||
assert (strcmp(string16_get_cstr(s), "Hello") == 0);
|
||||
string16_clean(s);
|
||||
string16_reset(s);
|
||||
assert (string16_empty_p(s));
|
||||
assert (string16_size(s) == 0);
|
||||
string16_set_str(s, "Hello, world! How do you do?");
|
||||
@@ -665,7 +683,7 @@ static void test_bounded1(void)
|
||||
|
||||
string16_set_strn(s, "Hello, world! How do you do?", 15);
|
||||
string16_init_set(d, s);
|
||||
string16_clean(s);
|
||||
string16_reset(s);
|
||||
assert (string16_equal_str_p(d, "Hello, world! H"));
|
||||
|
||||
string16_clear(d);
|
||||
@@ -713,7 +731,7 @@ static void test_bounded_M_LET(void)
|
||||
assert (string16_empty_p(x));
|
||||
}
|
||||
|
||||
M_LET( (x,"tree"), BOUNDED_STRING_OPLIST(string16)) {
|
||||
M_LET( (x, ("tree")), BOUNDED_STRING_OPLIST(string16)) {
|
||||
assert (string16_equal_str_p(x, "tree"));
|
||||
}
|
||||
|
||||
@@ -738,7 +756,7 @@ static void test_M_LET(void)
|
||||
string_set(s2, s1);
|
||||
assert(string_equal_p(s1, s2));
|
||||
}
|
||||
M_LET((s1,"OK"),string_t) {
|
||||
M_LET((s1,("OK")),string_t) {
|
||||
assert(string_equal_str_p(s1, "OK"));
|
||||
}
|
||||
M_LET((s1,"OK S=%d", 16),string_t) {
|
||||
@@ -749,10 +767,9 @@ static void test_M_LET(void)
|
||||
assert(string_empty_p(s2));
|
||||
assert(string_equal_str_p(s3, "42-17"));
|
||||
}
|
||||
M_LET( (s1, "Hello"), string_t) {
|
||||
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"));
|
||||
|
||||
+58
-4
@@ -84,6 +84,8 @@ TUPLE_DEF2(rtuple4, (value, rtuple3_t) )
|
||||
TUPLE_DEF2_AS(vector, Vector, (x, double), (y, double), (z, double) )
|
||||
#define M_OPL_Vector() TUPLE_OPLIST(vector, M_DEFAULT_OPLIST )
|
||||
|
||||
TUPLE_DEF2(rtuple5, (x, int, M_OPL_int()), (priority, int, M_OPEXTEND( M_OPL_int(), CMP(0), HASH(0), EQUAL(0) ) ) )
|
||||
|
||||
static void check_swap(void)
|
||||
{
|
||||
pair_str_t p1, p2;
|
||||
@@ -102,22 +104,64 @@ static void check_swap(void)
|
||||
pair_str_clear(p2);
|
||||
}
|
||||
|
||||
static void check_clean(void)
|
||||
static void check_reset(void)
|
||||
{
|
||||
single_str_t p1;
|
||||
single_str_init (p1);
|
||||
|
||||
string_set_str(p1->vala, "Hello");
|
||||
single_str_clean(p1);
|
||||
single_str_reset(p1);
|
||||
assert(string_equal_str_p (p1->vala, ""));
|
||||
|
||||
single_str_clear(p1);
|
||||
|
||||
M_LET(r, rtuple_t) {
|
||||
string_set_str(r->name, "Hello");
|
||||
rtuple_clean(r);
|
||||
rtuple_reset(r);
|
||||
assert(string_equal_str_p (r->name, ""));
|
||||
}
|
||||
|
||||
M_LET( (r, ("Hello"), 4), TUPLE_OPLIST(pair2_str, STRING_OPLIST, M_DEFAULT_OPLIST) ) {
|
||||
assert(string_equal_str_p (r->str, "Hello"));
|
||||
assert(r->value == 4);
|
||||
pair2_str_reset(r);
|
||||
assert(string_equal_str_p (r->str, ""));
|
||||
}
|
||||
|
||||
M_LET( (s, ("Goldy") ), STRING_OPLIST)
|
||||
M_LET( (r, s, 46), TUPLE_OPLIST(pair2_str, STRING_OPLIST, M_DEFAULT_OPLIST) )
|
||||
M_LET( (q, r), TUPLE_OPLIST(pair2_str, STRING_OPLIST, M_DEFAULT_OPLIST) ) {
|
||||
assert(string_equal_str_p (q->str, "Goldy"));
|
||||
assert(q->value == 46);
|
||||
pair2_str_reset(q);
|
||||
assert(string_equal_str_p (q->str, ""));
|
||||
}
|
||||
|
||||
// Wrong oplist usage: fall back to _init_emplace.
|
||||
M_LET( (s, ("Goldy McDuck") ), STRING_OPLIST)
|
||||
M_LET((r, s, 460), TUPLE_OPLIST(pair2_str, STRING_OPLIST) ) {
|
||||
assert(string_equal_str_p (r->str, "Goldy McDuck"));
|
||||
assert(r->value == 460);
|
||||
pair2_str_reset(r);
|
||||
assert(string_equal_str_p (r->str, ""));
|
||||
}
|
||||
|
||||
// Two level of parenthesis needed:
|
||||
// one to perform an emplace with INIT_WITH for the tuple
|
||||
// another level to emplace the string_t
|
||||
M_LET( (r, (("Two emplace"))), TUPLE_OPLIST(single_str, STRING_OPLIST) ) {
|
||||
assert(string_equal_str_p (r->vala, "Two emplace"));
|
||||
single_str_reset(r);
|
||||
assert(string_equal_str_p (r->vala, ""));
|
||||
}
|
||||
|
||||
M_LET( (s, ("Goldy McDuck") ), STRING_OPLIST)
|
||||
M_LET( (r, (s)), TUPLE_OPLIST(single_str, STRING_OPLIST) ) {
|
||||
assert(string_equal_str_p (r->vala, "Goldy McDuck"));
|
||||
single_str_reset(r);
|
||||
assert(string_equal_str_p (r->vala, ""));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void check_io(void)
|
||||
@@ -215,6 +259,16 @@ static void check_chaining_tuple(void)
|
||||
// rtuple4_init is only defined if ALL oplists export the INIT method
|
||||
rtuple4_init(r);
|
||||
rtuple4_clear(r);
|
||||
|
||||
rtuple5_t t0, t1;
|
||||
rtuple5_init_emplace(t0, 1, 0);
|
||||
rtuple5_init_emplace(t1, 1, 1);
|
||||
assert(rtuple5_equal_p(t0, t1));
|
||||
assert(rtuple5_cmp(t0, t1) == 0);
|
||||
assert(rtuple5_hash(t0) == rtuple5_hash(t1));
|
||||
assert(t0->priority != t1->priority);
|
||||
rtuple5_clear(t0);
|
||||
rtuple5_clear(t1);
|
||||
}
|
||||
|
||||
static void test_double(void)
|
||||
@@ -231,7 +285,7 @@ int main(void)
|
||||
test1();
|
||||
check_io();
|
||||
check_swap();
|
||||
check_clean();
|
||||
check_reset();
|
||||
check_chaining_tuple();
|
||||
test_double();
|
||||
exit(0);
|
||||
|
||||
@@ -90,7 +90,7 @@ static void test_pair(void)
|
||||
assert(f != NULL);
|
||||
assert (*f == 42.0);
|
||||
|
||||
pair_clean(p);
|
||||
pair_reset(p);
|
||||
assert (pair_empty_p(p));
|
||||
assert (!pair_key_p(p));
|
||||
assert (!pair_value_p(p));
|
||||
@@ -126,7 +126,7 @@ static void test_pair(void)
|
||||
assert(i != NULL);
|
||||
assert (*i == 42);
|
||||
|
||||
pair_clean(p);
|
||||
pair_reset(p);
|
||||
assert (pair_empty_p(p));
|
||||
|
||||
pair_clear(p2);
|
||||
@@ -140,8 +140,8 @@ static void test_pair(void)
|
||||
f = pair_get_value(p2);
|
||||
assert(f != NULL);
|
||||
assert (*f == 435.0);
|
||||
pair_clean(p);
|
||||
pair_clean(p2);
|
||||
pair_reset(p);
|
||||
pair_reset(p2);
|
||||
pair_set(p2, p);
|
||||
assert (pair_empty_p(p2));
|
||||
|
||||
|
||||
+1
-1
@@ -62,5 +62,5 @@ void increment(dict_t d, uint64_t key)
|
||||
extern void clean(dict_t d);
|
||||
void clean(dict_t d)
|
||||
{
|
||||
dict_clean(d);
|
||||
dict_reset(d);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "m-serial-json.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-string.h"
|
||||
|
||||
TUPLE_DEF2(entry,
|
||||
(x, float),
|
||||
(y, float),
|
||||
(name, string_t) )
|
||||
|
||||
void save(FILE *f, const entry_t ent)
|
||||
{
|
||||
m_serial_write_t serial;
|
||||
m_serial_json_write_init(serial, f);
|
||||
entry_out_serial(serial, ent);
|
||||
m_serial_json_write_clear(serial);
|
||||
}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
#include "gmp.h"
|
||||
#include "m-array.h"
|
||||
#include "m-list.h"
|
||||
#include "m-register.h"
|
||||
|
||||
ARRAY_DEF (mpz, mpz_t, (INIT(mpz_init), CLEAR(mpz_clear), SET(mpz_set), INIT_SET(mpz_init_set)))
|
||||
LIST_DEF (uint, unsigned int, M_DEFAULT_OPLIST)
|
||||
|
||||
// Register new class: mpz_t
|
||||
#define TYPE mpz_t
|
||||
#define OPLIST (INIT(mpz_init), CLEAR(mpz_clear), SET(mpz_set), INIT_SET(mpz_init_set))
|
||||
#include M_REGISTER_TYPE
|
||||
|
||||
void mpq_init_set(mpq_t q, const mpq_t p)
|
||||
{
|
||||
mpq_init(q);
|
||||
mpq_set(q, p);
|
||||
}
|
||||
|
||||
// Register new class: mpq_t
|
||||
#define TYPE mpq_t
|
||||
#define OPLIST (INIT(mpq_init), CLEAR(mpq_clear), SET(mpq_set), INIT_SET(mpq_init_set))
|
||||
#include M_REGISTER_TYPE
|
||||
|
||||
#define TYPE array_mpz_t
|
||||
#define OPLIST ARRAY_OPLIST(mpz)
|
||||
//#include M_REGISTER_TYPE
|
||||
|
||||
//#define TYPE list_uint_t
|
||||
//#define OPLIST LIST_OPLIST(unsigned int)
|
||||
//#include M_REGISTER_TYPE
|
||||
|
||||
bool is42(array_mpz_t array)
|
||||
{
|
||||
bool retval = false;
|
||||
mpz_t *z = new(mpz_t);
|
||||
mpz_set_ui (*z, 42);
|
||||
for_each (item, array) {
|
||||
if (equal(*item, *z)) {
|
||||
retval = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete(z);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void example(void)
|
||||
{
|
||||
list_uint_t list;
|
||||
init(list);
|
||||
push(list, 42);
|
||||
push(list, 17);
|
||||
for_each (item, list) {
|
||||
print(*item, "\n");
|
||||
}
|
||||
clear(list);
|
||||
}
|
||||
Reference in new issue
Block a user