Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43fdd10e77 | ||
|
|
b1183de0f8 | ||
|
|
3a3ef7454c | ||
|
|
5f946b728b | ||
|
|
9cc03ff81b | ||
|
|
89d4db174e | ||
|
|
f5bbc0a7fb | ||
|
|
9da0d1d94b | ||
|
|
fafaaafdbf | ||
|
|
38f4107b19 | ||
|
|
cbefdab4bb | ||
|
|
bcd0c46e8b | ||
|
|
f25bb73e58 | ||
|
|
ea3584e048 | ||
|
|
85473610a4 | ||
|
|
f9f0b307fc | ||
|
|
d17fa4530b | ||
|
|
3806495e2d | ||
|
|
15f58d5738 | ||
|
|
4de7da1c05 | ||
|
|
93229c61f2 | ||
|
|
3f0e8956b8 | ||
|
|
b82670b643 | ||
|
|
64800dbd3f | ||
|
|
2d9d9fbd9f | ||
|
|
f0ba5d17f4 | ||
|
|
e51c988222 | ||
|
|
0be3900beb | ||
|
|
f60ce0320a | ||
|
|
77008b8622 | ||
|
|
a7617002c5 | ||
|
|
bc73616bde | ||
|
|
d6b9b054c2 | ||
|
|
9eed4be97c | ||
|
|
2519927178 | ||
|
|
0fec33b38e | ||
|
|
dc2b6d2b2d | ||
|
|
bc63edc595 | ||
|
|
6241a3093c | ||
|
|
fb53a464d7 | ||
|
|
aba26b75a2 | ||
|
|
775ec6f91b | ||
|
|
95bc7063a0 | ||
|
|
731d3ecf1a | ||
|
|
0d1817e7ca | ||
|
|
1a5b428bfb | ||
|
|
bd49e31f3b | ||
|
|
2dba83e3c5 | ||
|
|
75e9766da9 | ||
|
|
d2f8aa1c0d | ||
|
|
4aa4b7693f | ||
|
|
d50b450927 | ||
|
|
5674cdbfc5 | ||
|
|
3641829198 | ||
|
|
10a759b09e | ||
|
|
b5a3b36c1b | ||
|
|
b0c3839f2b | ||
|
|
3aa3e95e4c | ||
|
|
87f1e53e13 | ||
|
|
d7b45cc220 | ||
|
|
d8142a9764 | ||
|
|
8780f58739 | ||
|
|
e352104df8 | ||
|
|
cbb2b452bb | ||
|
|
6e947c6262 | ||
|
|
18f04da4ec | ||
|
|
3dad6ef65c | ||
|
|
41c4f5fe5c | ||
|
|
cfeedf19f8 | ||
|
|
2ab410bd6a | ||
|
|
aefbc5b2f5 | ||
|
|
abec9c37fa | ||
|
|
442b0e7cea | ||
|
|
0b853c6d52 | ||
|
|
cc7fc66899 | ||
|
|
6b994c2928 | ||
|
|
e6fe36d3cd | ||
|
|
f45ededf8b | ||
|
|
ed27bedcb4 | ||
|
|
eb1a7a0435 | ||
|
|
de00fdc5f7 | ||
|
|
8febe12c5c | ||
|
|
1368b201eb | ||
|
|
4ca166b0b9 | ||
|
|
c13533cf21 | ||
|
|
9fdf0f76e7 | ||
|
|
308f513edc | ||
|
|
900bcc3819 | ||
|
|
b6e0994dfc | ||
|
|
121339d948 | ||
|
|
c5bb84013a | ||
|
|
65b49268d3 | ||
|
|
ecebd62f86 | ||
|
|
6a8c9a703d | ||
|
|
ad05ae9aa5 | ||
|
|
abffe201e5 | ||
|
|
ee2bc27bda | ||
|
|
14b94865b7 | ||
|
|
6e1ceafcc2 | ||
|
|
58746560e9 | ||
|
|
082adca3e6 | ||
|
|
ee1dc2a8e8 | ||
|
|
92e2d835bd | ||
|
|
22aba04b47 | ||
|
|
399c615915 | ||
|
|
cbdba0941a | ||
|
|
90c54a48d0 | ||
|
|
22b18830f7 | ||
|
|
dab085e3a7 | ||
|
|
66fac10a98 | ||
|
|
e5fb5ddde1 | ||
|
|
dcf20fbbd6 | ||
|
|
5d659877fe | ||
|
|
a30dd69aaa | ||
|
|
b1f698bb7b | ||
|
|
2323420a87 | ||
|
|
7e120a3615 | ||
|
|
804db294ca | ||
|
|
d12aa6c263 | ||
|
|
d59e87d2bf | ||
|
|
8f3c0af548 | ||
|
|
1f3013c445 | ||
|
|
f13e99ab1a | ||
|
|
fb8ad84675 | ||
|
|
12608afe10 | ||
|
|
f97e92b4cb | ||
|
|
a74e26e3de | ||
|
|
a30b783692 | ||
|
|
e64a6a22e7 | ||
|
|
76892afa13 | ||
|
|
dcb1eb0d94 | ||
|
|
950ea224ff | ||
|
|
b22a844007 | ||
|
|
502756c731 | ||
|
|
e38dc19ea1 | ||
|
|
2bebb2b4a1 | ||
|
|
5b7be93c1a | ||
|
|
d04270ae3f | ||
|
|
1bef7c1977 | ||
|
|
ae037ff7af | ||
|
|
a4267d60df | ||
|
|
47e32ab2b3 | ||
|
|
5ac08e42d8 | ||
|
|
9c59684b61 | ||
|
|
f26e1e5a12 | ||
|
|
1cde4633e6 | ||
|
|
1393f8e9aa | ||
|
|
bfffa1d245 | ||
|
|
3a6b568ccc | ||
|
|
453a920af8 | ||
|
|
1fd86ffc2e | ||
|
|
96a0639a8a | ||
|
|
c12d0a3f23 | ||
|
|
cac8790405 | ||
|
|
ccd9726e01 | ||
|
|
5516b50b3a | ||
|
|
b5a3e010d8 | ||
|
|
2d7d267252 | ||
|
|
bd5d7aaada | ||
|
|
18b6be8e00 | ||
|
|
958abfef93 | ||
|
|
198be1062b | ||
|
|
0cfee02641 | ||
|
|
48dc38508a | ||
|
|
e763204bf7 | ||
|
|
370baf56ab | ||
|
|
4fd6bcbf99 | ||
|
|
59d1e23dea | ||
|
|
cb173f2f81 | ||
|
|
d047174c2f | ||
|
|
df25159d03 | ||
|
|
99618a687e | ||
|
|
a1b226e185 | ||
|
|
e93df4332a | ||
|
|
5a1f768b03 | ||
|
|
e854bc8fc9 | ||
|
|
9ab958708d | ||
|
|
85ea92d83b | ||
|
|
22a406ac51 | ||
|
|
58eed79413 | ||
|
|
e83dea8212 | ||
|
|
c829827f48 | ||
|
|
b47cf05a59 | ||
|
|
22a93514ff | ||
|
|
154865f0f1 | ||
|
|
71151770fd | ||
|
|
72623ce13e | ||
|
|
94f20d56e9 | ||
|
|
9e8ad9bfd9 | ||
|
|
e51a5be776 | ||
|
|
7d647340c6 | ||
|
|
c6ea3c0616 | ||
|
|
9ab90be6d4 | ||
|
|
10440320d1 | ||
|
|
fc7e93403a | ||
|
|
b0c4418584 | ||
|
|
5f73eb7788 | ||
|
|
a554312573 | ||
|
|
8a1fd391d1 | ||
|
|
95b104ee48 | ||
|
|
c3df69d011 | ||
|
|
73468a3e24 | ||
|
|
f254f98e42 | ||
|
|
d37076dd37 | ||
|
|
5ef9376148 | ||
|
|
d8abda7583 | ||
|
|
892c755389 | ||
|
|
aba2f90c9d | ||
|
|
dc487c7e64 | ||
|
|
18b1bd9518 | ||
|
|
845ab1fef0 | ||
|
|
94bfac3f75 | ||
|
|
bd5c9ce2a7 | ||
|
|
f5934a6274 | ||
|
|
c6f71fddc7 | ||
|
|
74764e2d6f | ||
|
|
9b00a8c54e | ||
|
|
66735e99c3 | ||
|
|
80acbb4343 | ||
|
|
2fb912d43d | ||
|
|
8c8dc6de7c | ||
|
|
677acdd14e | ||
|
|
6caeea98b9 | ||
|
|
c5d37ce028 | ||
|
|
112b405df6 | ||
|
|
47385d58e5 | ||
|
|
c8275c8f63 | ||
|
|
0c1e888a78 | ||
|
|
6a1ff3e080 | ||
|
|
6d41eba5ed | ||
|
|
c0abcc6d60 | ||
|
|
da71c81195 | ||
|
|
8e0d17e85c | ||
|
|
6d98c273c1 | ||
|
|
85f6ff34aa | ||
|
|
759c24be63 | ||
|
|
d85955ef60 | ||
|
|
3a53044198 | ||
|
|
4d5cd9c635 | ||
|
|
57b88160ae | ||
|
|
33ba602aef | ||
|
|
3632388315 | ||
|
|
6ee82e885b | ||
|
|
2f92cee416 | ||
|
|
9269473e10 | ||
|
|
c8611ce708 | ||
|
|
d8fd43e9e9 | ||
|
|
a2e471620d | ||
|
|
ffa3821acf | ||
|
|
5c98d47d8c | ||
|
|
0875eaac03 | ||
|
|
60734bdb2b | ||
|
|
e71b19424b | ||
|
|
daac0169d5 | ||
|
|
baacc0df52 | ||
|
|
c6921536f7 | ||
|
|
4abf0ad2b2 | ||
|
|
379d555d35 | ||
|
|
8c01acb8d2 | ||
|
|
2c2c3c21ba | ||
|
|
50fd27e07b | ||
|
|
3309035814 | ||
|
|
b691758fa9 | ||
|
|
7c9afcec8b | ||
|
|
06ac05526a | ||
|
|
69cef8249a | ||
|
|
473df16a5a | ||
|
|
e1abf0528c | ||
|
|
ef0b335f67 | ||
|
|
1a866a3dc4 | ||
|
|
ed437b9e05 | ||
|
|
eea85872fd | ||
|
|
9d33e4cd5a | ||
|
|
530cc8d2a2 | ||
|
|
9baca84825 | ||
|
|
58538e4822 | ||
|
|
e31a8dc407 | ||
|
|
7875263092 | ||
|
|
de3b8509bf | ||
|
|
a19e1acfff | ||
|
|
e613b5c624 | ||
|
|
ccfddb0685 | ||
|
|
b8cd679679 | ||
|
|
fc26e472ab | ||
|
|
fc8c7349d6 | ||
|
|
a4d9b8df17 | ||
|
|
f26da68aa4 | ||
|
|
144182b540 | ||
|
|
a834ca4921 | ||
|
|
d1fc216836 | ||
|
|
5e57338928 | ||
|
|
f3376b6f0e | ||
|
|
5e001fdd9d | ||
|
|
9fda06276c | ||
|
|
df79c306d9 | ||
|
|
e4955e6851 | ||
|
|
0fec9e7ac4 | ||
|
|
5be8bb435b | ||
|
|
35b915ab10 | ||
|
|
80c57e996d | ||
|
|
511293d580 | ||
|
|
fe2b816447 | ||
|
|
093b7dc1e8 | ||
|
|
811fa57cbc | ||
|
|
359ad20a6a | ||
|
|
ac9989e4ff | ||
|
|
7268551737 | ||
|
|
823b1974bb | ||
|
|
382f636206 | ||
|
|
9a1b4abcf9 | ||
|
|
a0fc57687b | ||
|
|
02897f982f | ||
|
|
07a5d0ed0a | ||
|
|
017995ade6 | ||
|
|
9711b2280c | ||
|
|
619331916f | ||
|
|
d7909f7312 | ||
|
|
22674f2b46 | ||
|
|
845736c489 | ||
|
|
501f9db465 | ||
|
|
8dd440a582 | ||
|
|
dd7f090b4b | ||
|
|
dc14a2677b | ||
|
|
8b1ed7f0ae | ||
|
|
19b01b404d | ||
|
|
ec780d2d4d | ||
|
|
07790f6711 | ||
|
|
f72d2b6c67 | ||
|
|
e35d631012 | ||
|
|
3499a08207 | ||
|
|
0ac23e512e | ||
|
|
1852fabcd2 | ||
|
|
7b6bfac7cb | ||
|
|
e72aa5fb79 | ||
|
|
f4b02b92cc | ||
|
|
39edcc560f | ||
|
|
50669a320c | ||
|
|
d22c0b05ef | ||
|
|
689be30803 | ||
|
|
b393a83d38 | ||
|
|
1a1339da6b | ||
|
|
9926b51da0 | ||
|
|
761447dea3 | ||
|
|
829c20ba8a | ||
|
|
9ac734e191 | ||
|
|
5420fc6c51 |
No files matched your search
@@ -11,6 +11,8 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: CPU Information
|
||||
run: lscpu || sysctl -a|grep cpu || echo "CPU information not available"
|
||||
- name: make check C99
|
||||
run: make clean && make check -j 2 CC="cc -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C11
|
||||
@@ -29,6 +31,8 @@ jobs:
|
||||
run: sudo apt-get update
|
||||
- name: install multilib
|
||||
run: sudo apt-get install gcc-multilib g++-multilib
|
||||
- name: CPU Information
|
||||
run: lscpu || echo "CPU information not available"
|
||||
- name: make check C99 (32bits)
|
||||
working-directory: ./tests
|
||||
run: make clean && make check -j 2 CC="gcc -m32 -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
@@ -47,6 +51,8 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: CPU Information
|
||||
run: lscpu || echo "CPU information not available"
|
||||
- name: Clone TCC
|
||||
shell: bash
|
||||
run: git clone https://repo.or.cz/tinycc.git
|
||||
@@ -60,6 +66,15 @@ jobs:
|
||||
shell: bash
|
||||
run: make CC="/tmp/tcc/bin/tcc -std=c99" check
|
||||
|
||||
build_linux_sanitize:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make sanitize
|
||||
working-directory: ./tests
|
||||
run: make sanitize -j 2
|
||||
|
||||
build_windows_mingw:
|
||||
runs-on: windows-latest
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2017-2021, Patrick Pelissier
|
||||
Copyright (c) 2017-2022, Patrick Pelissier
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2021, Patrick Pelissier
|
||||
# Copyright (c) 2017-2022, Patrick Pelissier
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@@ -34,14 +34,14 @@ DESTDIR=
|
||||
|
||||
# Package name & version.
|
||||
PACKAGE=m_lib-$(VERSION)
|
||||
VERSION=0.6.0
|
||||
VERSION=0.7.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
|
||||
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-tree.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 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
|
||||
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/ex11-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 example/ex-no-stdio.c example/ex11-count-lines.c example/ex11-json-net.c example/ex11-rbtree02.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 tests/test-mtree.c tests/check-bptree-map.cpp tests/check-bptree-set.cpp tests/check-prioqueue.cpp tests/check-umap.cpp
|
||||
|
||||
.PHONY: all test check doc clean distclean depend install uninstall dist
|
||||
|
||||
@@ -68,8 +68,8 @@ clean:
|
||||
cd example && $(MAKE) clean
|
||||
cd bench && $(MAKE) clean
|
||||
$(RM) README.html depend.dot
|
||||
$(RM) -r 'm*lib-$(VERSION)'
|
||||
$(RM) 'm*lib-$(VERSION).tar.bz2'
|
||||
$(RM) -r 'm_lib-$(VERSION)'
|
||||
$(RM) 'm_lib-$(VERSION).tar.bz2'
|
||||
|
||||
distclean: clean
|
||||
cd tests && $(MAKE) distclean
|
||||
|
||||
+50
-9
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2021, Patrick Pelissier
|
||||
# Copyright (c) 2017-2022, Patrick Pelissier
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@@ -29,7 +29,7 @@ N=4
|
||||
BENCH_DEF=
|
||||
RM=rm -rf
|
||||
|
||||
.PHONY: all pgo container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain bench-rigtorp-mpmc-queue bench-cmc
|
||||
.PHONY: all pgo container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-emhash bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain bench-rigtorp-mpmc-queue bench-cmc
|
||||
|
||||
all: container queue mempool string plain
|
||||
|
||||
@@ -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 bench-ctl
|
||||
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-emhash bench-hopscotchmap bench-uthash bench-qlibc bench-libsrt bench-nedtries bench-rigtorp-hashmap bench-ctl bench-stc bench-pottery
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-rigtorp-mpmc-queue
|
||||
@@ -118,7 +118,7 @@ bench-stl:
|
||||
bench-qt:
|
||||
@if test -n "$${QT}" ; then $(MAKE) bench-qt0 ; else echo "Nothing to be done for QT." ; fi
|
||||
bench-qt0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -fPIC `PKG_CONFIG_PATH="$${QT}" pkg-config --libs --cflags Qt5Core` bench-qt.cpp common.c -o bench-qt.exe
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -fPIC bench-qt.cpp common.c -o bench-qt.exe `PKG_CONFIG_PATH="$${QT}" pkg-config --libs --cflags Qt5Core`
|
||||
@./bench-qt.exe 10
|
||||
@./bench-qt.exe 20
|
||||
@./bench-qt.exe 30
|
||||
@@ -162,12 +162,12 @@ bench-cmc0:
|
||||
@./bench-cmc.exe 30
|
||||
@./bench-cmc.exe 40
|
||||
|
||||
# LIBDYNAMIC shall point to the the directory containing the file libdynamic.pc
|
||||
# LIBDYNAMIC shall point to the the source directory where the source is built
|
||||
bench-libdynamic:
|
||||
@if test -n "$${LIBDYNAMIC}" ; then $(MAKE) bench-libdynamic0 ; else echo "Nothing to be done for LIBDYNAMIC." ; fi
|
||||
|
||||
bench-libdynamic0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-libdynamic.c common.c -o bench-libdynamic.exe `PKG_CONFIG_PATH="$${LIBDYNAMIC}" pkg-config --libs --cflags libdynamic`
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-libdynamic.c common.c -o bench-libdynamic.exe -I$${LIBDYNAMIC}/src $${LIBDYNAMIC}/.libs/libdynamic.a
|
||||
@./bench-libdynamic.exe 20
|
||||
@./bench-libdynamic.exe 40
|
||||
@./bench-libdynamic.exe 41
|
||||
@@ -239,6 +239,17 @@ bench-emilib0:
|
||||
@./bench-emilib.exe 46
|
||||
@./bench-emilib.exe 43
|
||||
|
||||
# EMHASh shall point to the directory where the headers are
|
||||
bench-emhash:
|
||||
@if test -n "$${EMHASH}" ; then $(MAKE) bench-emhash0 ; else echo "Nothing to be done for EMHASH." ; fi
|
||||
|
||||
bench-emhash0:
|
||||
$(CXX) -std=c++14 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${EMHASH}" bench-emhash.cpp common.c -o bench-emhash.exe
|
||||
@./bench-emhash.exe 41
|
||||
@./bench-emhash.exe 42
|
||||
@./bench-emhash.exe 46
|
||||
@./bench-emhash.exe 43
|
||||
|
||||
# HOPSCOTCHMAP shall point to the directory where the source are
|
||||
bench-hopscotchmap:
|
||||
@if test -n "$${HOPSCOTCHMAP}" ; then $(MAKE) bench-hopscotchmap0 ; else echo "Nothing to be done for HOPSCOTCHMAP." ; fi
|
||||
@@ -276,7 +287,7 @@ bench-libsrt:
|
||||
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-libsrt0 ; else echo "Nothing to be done for LIBSRT." ; fi
|
||||
|
||||
bench-libsrt0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/include/libsrt" bench-libsrt.c common.c -o bench-libsrt.exe $${LIBSRT}/lib/libsrt.a
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/src" bench-libsrt.c common.c -o bench-libsrt.exe $${LIBSRT}/src/.libs/libsrt.a
|
||||
@./bench-libsrt.exe 20
|
||||
@./bench-libsrt.exe 50
|
||||
|
||||
@@ -351,6 +362,32 @@ bench-ctl0:
|
||||
@./bench-ctl.exe 40
|
||||
@./bench-ctl.exe 50
|
||||
|
||||
# STC shall point to the source directory (not where the headers are)
|
||||
bench-stc:
|
||||
@if test -n "$${STC}" ; then $(MAKE) bench-stc0 ; else echo "Nothing to be done for STC." ; fi
|
||||
|
||||
bench-stc0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${STC}/include bench-stc.c common.c -o bench-stc.exe
|
||||
@./bench-stc.exe 10
|
||||
@./bench-stc.exe 20
|
||||
@./bench-stc.exe 30
|
||||
@./bench-stc.exe 40
|
||||
@./bench-stc.exe 41
|
||||
@./bench-stc.exe 50
|
||||
|
||||
# POTTERY shall point to the source directory (not where the headers are)
|
||||
bench-pottery:
|
||||
@if test -n "$${POTTERY}" ; then $(MAKE) bench-pottery0 ; else echo "Nothing to be done for POTTERY." ; fi
|
||||
|
||||
bench-pottery0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -DPOTTERY_AVAILABLE=1 -I $${POTTERY}/include bench-pottery.c common.c -o bench-pottery.exe
|
||||
@./bench-pottery.exe 10
|
||||
@./bench-pottery.exe 20
|
||||
@./bench-pottery.exe 30
|
||||
@./bench-pottery.exe 40
|
||||
@./bench-pottery.exe 41
|
||||
@./bench-pottery.exe 50
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-mlib-json: bench-mlib
|
||||
@@ -389,12 +426,12 @@ bench-maxdict:
|
||||
############################################################################
|
||||
|
||||
# BSTRLIB shall point to the BSTRLIB sources
|
||||
# LIBSRT shall point to the LIBSRT install directory
|
||||
# LIBSRT shall point to the LIBSRT sources
|
||||
bench-string:
|
||||
@if test -n "$${BSTRLIB}" ; then $(MAKE) bench-string-step1 BENCH_DEF="-DBENCH_CAN_USE_BSTRLIB -I ${BSTRLIB} $${BSTRLIB}/obj/bstrlib.o $${BSTRLIB}/obj/bstraux.o $${BSTRLIB}/obj/bstrwrap.o" ; else $(MAKE) bench-string-step1 ; fi
|
||||
|
||||
bench-string-step1:
|
||||
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/include/libsrt $${LIBSRT}/lib/libsrt.a" ; else $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/src $${LIBSRT}/src/.libs/libsrt.a" ; else $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
#NOTE: Need to build by hand sds.o since it is not build by default and sds.c is not compatible with C++
|
||||
bench-string-step2:
|
||||
@@ -404,6 +441,9 @@ bench-string-step4:
|
||||
@if test -n "$${GLIB}" ; then $(MAKE) bench-string-step5 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_GLIB $$(pkg-config --cflags --libs glib-2.0)" ; else $(MAKE) bench-string-step5 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
bench-string-step5:
|
||||
@if test -n "$${POTTERY}" ; then $(MAKE) bench-string-step6 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_POTTERY -I$${POTTERY}/include -I$${POTTERY}/util/ $${POTTERY}/util/pottery/string/string.c" ; else $(MAKE) bench-string-step6 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
bench-string-step6:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -DBENCH_CAN_USE_STL -DBENCH_CAN_USE_MSTARLIB bench-string.cpp common.c $(BENCH_DEF) -o bench-string.exe
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -DBENCH_CAN_USE_STL -DBENCH_CAN_USE_MSTARLIB bench-string-2.cpp common.c $(BENCH_DEF) -o bench-string-2.exe
|
||||
@./bench-string.exe
|
||||
@@ -411,6 +451,7 @@ bench-string-step5:
|
||||
@./bench-string-2.exe 2000000 1
|
||||
@./bench-string-2.exe 2000000 2
|
||||
@./bench-string-2.exe 2000000 4
|
||||
@./bench-string-2.exe 2000000 5
|
||||
|
||||
bench-string-pgo:
|
||||
$(MAKE) bench-string XCFLAGS="-fprofile-generate=pgo"
|
||||
|
||||
+3
-2
@@ -125,14 +125,15 @@ pair_ulong_copy(pair_ulong *self) {
|
||||
#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() });
|
||||
unsigned long value = rand_get();
|
||||
unsigned long key = rand_get();
|
||||
umap_pair_ulong_insert(&dict, (pair_ulong) { key, value });
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hash_table7.hpp"
|
||||
|
||||
using namespace emhash7;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[rand_get()] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict2_linear(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[i] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long>::iterator it = dict.find(i);
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
struct char_array_s {
|
||||
char a[256];
|
||||
char_array_s () { a[0] = 0 ; }
|
||||
char_array_s ( const char_array_s & other) { strcpy(a, other.a); }
|
||||
bool operator==(const char_array_s &other) const { return strcmp(a, other.a) == 0; }
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <> struct hash<char_array_s> {
|
||||
std::size_t operator()(const char_array_s &k) const {
|
||||
size_t hash = 0;
|
||||
const char *s = k.a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
HashMap<char_array_s, char_array_s> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
HashMap<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
HashMap<string, string> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
HashMap<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict", 1000000, 0, test_dict2, 0},
|
||||
{ 43, "DictStr", 1000000, 0, test_dict_str, 0},
|
||||
{ 46, "DictLinear", 1000000, 0, test_dict2_linear, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("EMHASH", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
+24
-28
@@ -55,12 +55,8 @@ static void test_deque(size_t n)
|
||||
}
|
||||
unsigned int s = 0;
|
||||
deque_uint_it_t it1, it2;
|
||||
deque_uint_it(it1, a1);
|
||||
deque_uint_it(it2, a2);
|
||||
while (!deque_uint_end_p(it1)) {
|
||||
for(deque_uint_it(it1, a1), deque_uint_it(it2, a2) ; !deque_uint_end_p(it1) ; deque_uint_next(it1), deque_uint_next(it2)) {
|
||||
s += *deque_uint_cref(it1 ) * *deque_uint_cref(it2 );
|
||||
deque_uint_next(it1);
|
||||
deque_uint_next(it2);
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
@@ -876,8 +872,8 @@ bench_vector_string_init(size_t n)
|
||||
{
|
||||
vector_string_init(vstring);
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
M_LET( (s, "%zu", i, i, i, i), string_t) {
|
||||
{
|
||||
M_LET( (s, "%zu", i), string_t) {
|
||||
vector_string_push_back(vstring, s);
|
||||
}
|
||||
}
|
||||
@@ -901,8 +897,8 @@ static void
|
||||
bench_vector_string_bin_run(size_t n)
|
||||
{
|
||||
if (vector_string_size(vstring) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring));
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.dat", "wb");
|
||||
@@ -920,8 +916,8 @@ bench_vector_string_bin_run(size_t n)
|
||||
fclose(f);
|
||||
|
||||
if (vector_string_size(vstring2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring2));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -929,8 +925,8 @@ static void
|
||||
bench_vector_string_json_run(size_t n)
|
||||
{
|
||||
if (vector_string_size(vstring) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring));
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
@@ -948,8 +944,8 @@ bench_vector_string_json_run(size_t n)
|
||||
fclose(f);
|
||||
|
||||
if (vector_string_size(vstring2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring2));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -957,8 +953,8 @@ static void
|
||||
bench_vector_string_clear(void)
|
||||
{
|
||||
if (!vector_string_equal_p(vstring, vstring2)) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Array are different after deserialization!\n");
|
||||
abort();
|
||||
}
|
||||
vector_string_clear(vstring);
|
||||
vector_string_clear(vstring2);
|
||||
@@ -986,8 +982,8 @@ static void
|
||||
bench_vector_ulong_bin_run(size_t n)
|
||||
{
|
||||
if (vector_ulong_size(vulong) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.dat", "wb");
|
||||
@@ -1005,8 +1001,8 @@ bench_vector_ulong_bin_run(size_t n)
|
||||
fclose(f);
|
||||
|
||||
if (vector_ulong_size(vulong2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1014,8 +1010,8 @@ static void
|
||||
bench_vector_ulong_json_run(size_t n)
|
||||
{
|
||||
if (vector_ulong_size(vulong) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
@@ -1033,8 +1029,8 @@ bench_vector_ulong_json_run(size_t n)
|
||||
fclose(f);
|
||||
|
||||
if (vector_ulong_size(vulong2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1042,8 +1038,8 @@ static void
|
||||
bench_vector_ulong_clear(void)
|
||||
{
|
||||
if (!vector_ulong_equal_p(vulong, vulong2)) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Array are different after deserialization!\n");
|
||||
abort();
|
||||
}
|
||||
vector_ulong_clear(vulong);
|
||||
vector_ulong_clear(vulong2);
|
||||
@@ -1085,6 +1081,6 @@ const config_func_t table[] = {
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("M-LIB", numberof(table), table, argc, argv);
|
||||
test("M*LIB", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -32,7 +32,7 @@ struct Pixel
|
||||
unsigned char r, g, b;
|
||||
};
|
||||
|
||||
ARRAY_DEF(array_pixel, struct Pixel, (INIT(M_NOTHING_DEFAULT)) )
|
||||
ARRAY_DEF(array_pixel, struct Pixel, (INIT(M_NOTHING_DEFAULT), INIT_SET(M_MEMCPY_DEFAULT) ))
|
||||
|
||||
void UseMlib(void)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POTTERY_VECTOR_PREFIX vec_uint
|
||||
#define POTTERY_VECTOR_VALUE_TYPE unsigned int
|
||||
#define POTTERY_VECTOR_LIFECYCLE_BY_VALUE 1
|
||||
#include "pottery/vector/pottery_vector_static.t.h"
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
vec_uint_t a1, a2;
|
||||
|
||||
vec_uint_init(&a1);
|
||||
vec_uint_init(&a2);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
vec_uint_insert_last(&a1, rand_get() );
|
||||
vec_uint_insert_last(&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_destroy(&a1);
|
||||
vec_uint_destroy(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct foo_s {
|
||||
struct foo_s* next;
|
||||
struct foo_s* previous;
|
||||
int data;
|
||||
} foo_t;
|
||||
|
||||
#define POTTERY_DOUBLY_LINKED_LIST_PREFIX foo_list
|
||||
#define POTTERY_DOUBLY_LINKED_LIST_VALUE_TYPE foo_t
|
||||
#include "pottery/doubly_linked_list/pottery_doubly_linked_list_static.t.h"
|
||||
|
||||
static void test_list(size_t n)
|
||||
{
|
||||
foo_list_t a1, a2;
|
||||
foo_list_init(&a1);
|
||||
foo_list_init(&a2);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
foo_t *tmp = malloc(sizeof (foo_t));
|
||||
if (tmp == NULL) abort();
|
||||
tmp->data = rand_get();
|
||||
foo_list_link_last(&a1, tmp);
|
||||
|
||||
tmp = malloc(sizeof (foo_t));
|
||||
if (tmp == NULL) abort();
|
||||
tmp->data = rand_get();
|
||||
foo_list_link_last(&a2, tmp);
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(foo_t *it1 = foo_list_first(&a1), *it2 = foo_list_first(&a2) ;
|
||||
foo_list_entry_exists(&a1, it1) ;
|
||||
it1 = foo_list_next(&a1, it1), it2 = foo_list_next(&a2, it2)) {
|
||||
s += it1->data * it2->data;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
for(foo_t *it1 = foo_list_first(&a1);
|
||||
foo_list_entry_exists(&a1, it1) ;
|
||||
) {
|
||||
foo_t *tmp = it1;
|
||||
it1 = foo_list_next(&a1, it1);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
for(foo_t *it1 = foo_list_first(&a2);
|
||||
foo_list_entry_exists(&a2, it1) ;
|
||||
) {
|
||||
foo_t *tmp = it1;
|
||||
it1 = foo_list_next(&a2, it1);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
// ERROR: it returns the wrong result.
|
||||
#define POTTERY_TREE_MAP_PREFIX set_ulong
|
||||
#define POTTERY_TREE_MAP_VALUE_TYPE unsigned long
|
||||
#define POTTERY_TREE_MAP_LIFECYCLE_MOVE_BY_VALUE 1
|
||||
#define POTTERY_TREE_MAP_COMPARE_THREE_WAY(a,b) ((a) < (b) ? -1 : (a) > (b))
|
||||
#define POTTERY_TREE_MAP_LIFECYCLE_DESTROY(a) (void) a
|
||||
#include "pottery/tree_map/pottery_tree_map_static.t.h"
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
set_ulong_t tree;
|
||||
set_ulong_init(&tree);
|
||||
|
||||
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(&tree, &j ) != NULL)
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
set_ulong_destroy(&tree);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#include "m-core.h" // For M_HASH_DEFAULT
|
||||
typedef struct bar_s {
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
} bar_t;
|
||||
|
||||
#define POTTERY_OPEN_HASH_MAP_PREFIX map_ulong
|
||||
|
||||
#define POTTERY_OPEN_HASH_MAP_VALUE_TYPE bar_t
|
||||
#define POTTERY_OPEN_HASH_MAP_KEY_TYPE unsigned long
|
||||
#define POTTERY_OPEN_HASH_MAP_REF_KEY(v) v->key
|
||||
#define POTTERY_OPEN_HASH_MAP_KEY_HASH(x) M_HASH_DEFAULT(x)
|
||||
#define POTTERY_OPEN_HASH_MAP_KEY_EQUAL(x, y) x == y
|
||||
#define POTTERY_OPEN_HASH_MAP_LIFECYCLE_MOVE(p,q) memcpy(p, q, sizeof (bar_t))
|
||||
|
||||
#include "pottery/open_hash_map/pottery_open_hash_map_static.t.h"
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
map_ulong_t dict;
|
||||
map_ulong_init(&dict);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long value = rand_get();
|
||||
unsigned long key = rand_get();
|
||||
bar_t * kyle = pottery_null;
|
||||
map_ulong_emplace_key(&dict, key, &kyle, pottery_null);
|
||||
kyle->key = key;
|
||||
kyle->value = value;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
bar_t *kyle = map_ulong_find(&dict, rand_get());
|
||||
if (kyle != NULL)
|
||||
s += kyle->value;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
map_ulong_destroy(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
char a[256];
|
||||
} char_array_t;
|
||||
static inline void char_init (char_array_t *a) { a->a[0] = 0; }
|
||||
static inline void char_set (char_array_t *a, const char_array_t b) { strcpy(a->a, b.a); }
|
||||
static inline bool char_equal_p (const char_array_t a, const char_array_t b) { return strcmp(a.a,b.a)==0; }
|
||||
static inline void char_clear (char_array_t *a) { (void)a; }
|
||||
static inline size_t char_hash(const char_array_t *a) {
|
||||
size_t hash = 0;
|
||||
const char *s = a->a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
|
||||
typedef struct bars_s {
|
||||
char_array_t key;
|
||||
char_array_t value;
|
||||
} bars_t;
|
||||
|
||||
#define POTTERY_OPEN_HASH_MAP_PREFIX map_achar
|
||||
|
||||
#define POTTERY_OPEN_HASH_MAP_VALUE_TYPE bars_t
|
||||
#define POTTERY_OPEN_HASH_MAP_KEY_TYPE char_array_t
|
||||
#define POTTERY_OPEN_HASH_MAP_REF_KEY(v) v->key
|
||||
#define POTTERY_OPEN_HASH_MAP_KEY_HASH(x) char_hash(&x)
|
||||
#define POTTERY_OPEN_HASH_MAP_KEY_EQUAL(x, y) char_equal_p(x, y)
|
||||
#define POTTERY_OPEN_HASH_MAP_LIFECYCLE_MOVE(p,q) memcpy(p, q, sizeof (bars_t))
|
||||
|
||||
#include "pottery/open_hash_map/pottery_open_hash_map_static.t.h"
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
map_achar_t dict;
|
||||
map_achar_init(&dict);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
bars_t * kyle = pottery_null;
|
||||
map_achar_emplace_key(&dict, s1, &kyle, pottery_null);
|
||||
char_set(&kyle->key, s1);
|
||||
char_set(&kyle->value, s2);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
bars_t *kyle = map_achar_find(&dict, s1);
|
||||
if (kyle != NULL)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
map_achar_destroy(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POTTERY_VECTOR_PREFIX vec_float
|
||||
#define POTTERY_VECTOR_VALUE_TYPE float
|
||||
#define POTTERY_VECTOR_LIFECYCLE_BY_VALUE 1
|
||||
#include "pottery/vector/pottery_vector_static.t.h"
|
||||
|
||||
#define POTTERY_INTRO_SORT_PREFIX sort_float
|
||||
#define POTTERY_INTRO_SORT_VALUE_TYPE float
|
||||
#define POTTERY_INTRO_SORT_LIFECYCLE_MOVE_BY_VALUE 1
|
||||
#define POTTERY_INTRO_SORT_COMPARE_THREE_WAY(x, y) ( *x < *y ? -1 : *x > *y)
|
||||
#include "pottery/intro_sort/pottery_intro_sort_static.t.h"
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
vec_float_t a1;
|
||||
vec_float_init(&a1);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
vec_float_insert_last(&a1, rand_get() );
|
||||
}
|
||||
sort_float(vec_float_at(&a1, 0), n);
|
||||
g_result = *vec_float_at(&a1, 0);
|
||||
vec_float_destroy(&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},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 50, "Sort",10000000, 0, test_sort, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("POTTERY", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define i_val unsigned int
|
||||
#define i_tag uint
|
||||
#include <stc/cvec.h>
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
cvec_uint a1 = cvec_uint_init(), a2 = cvec_uint_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
cvec_uint_push_back(&a1, rand_get() );
|
||||
cvec_uint_push_back(&a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *cvec_uint_at(&a1, i ) * *cvec_uint_at(&a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
cvec_uint_drop(&a1);
|
||||
cvec_uint_drop(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
#define i_val unsigned int
|
||||
#define i_tag uint
|
||||
#include <stc/clist.h>
|
||||
|
||||
static void test_list(size_t n)
|
||||
{
|
||||
clist_uint a1 = clist_uint_init(), a2 = clist_uint_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
clist_uint_push_front(&a1, rand_get() );
|
||||
clist_uint_push_front(&a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(clist_uint_iter it1 = clist_uint_begin(&a1), it2 = clist_uint_begin(&a2) ;
|
||||
it1.ref != clist_uint_end(&a1).ref ;
|
||||
clist_uint_next(&it1), clist_uint_next(&it2) ) {
|
||||
s += *it1.ref * *it2.ref;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
clist_uint_drop(&a1);
|
||||
clist_uint_drop(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define i_tag ulong
|
||||
#define i_key unsigned long
|
||||
#include <stc/csset.h>
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
csset_ulong tree = csset_ulong_init();
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
csset_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 (csset_ulong_get(&tree, j ) != NULL)
|
||||
s+= j;
|
||||
}
|
||||
g_result = s;
|
||||
csset_ulong_drop(&tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define i_tag ulong
|
||||
#define i_key unsigned long
|
||||
#define i_val unsigned long
|
||||
#include <stc/cmap.h>
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
cmap_ulong dict = cmap_ulong_init();
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long value = rand_get();
|
||||
unsigned long key = rand_get();
|
||||
cmap_ulong_insert_or_assign(&dict, key, value);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
const cmap_ulong_value*val = cmap_ulong_get(&dict, rand_get());
|
||||
if (val != NULL)
|
||||
s += val->second;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
cmap_ulong_drop(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
char a[256];
|
||||
} char_array_t;
|
||||
static inline void char_init (char_array_t *a) { a->a[0] = 0; }
|
||||
static inline void char_set (char_array_t *a, const char_array_t b) { strcpy(a->a, b.a); }
|
||||
static inline bool char_equal_p (const char_array_t *a, const char_array_t *b) { return strcmp(a->a,b->a)==0; }
|
||||
static inline void char_clear (char_array_t *a) { (void)a; }
|
||||
static inline size_t char_hash(const char_array_t *a) {
|
||||
size_t hash = 0;
|
||||
const char *s = a->a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
|
||||
#define i_tag achar
|
||||
#define i_key char_array_t
|
||||
#define i_val char_array_t
|
||||
#define i_hash char_hash
|
||||
#define i_eq char_equal_p
|
||||
#include <stc/cmap.h>
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
cmap_achar dict = cmap_achar_init();
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
cmap_achar_insert_or_assign(&dict, s1, s2);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
const cmap_achar_value*val = cmap_achar_get(&dict, s1);
|
||||
if (val != NULL)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
cmap_achar_drop(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define i_val float
|
||||
#define i_tag float
|
||||
#include <stc/cvec.h>
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
cvec_float a1 = cvec_float_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
cvec_float_push_back(&a1, rand_get() );
|
||||
}
|
||||
cvec_float_sort(&a1);
|
||||
g_result = *cvec_float_at(&a1, 0);
|
||||
cvec_float_drop(&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},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 50, "Sort",10000000, 0, test_sort, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("STC", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
+77
-12
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - String Bench
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -22,11 +22,14 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#define NDEBUG
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define M_USE_SMALL_NAME 0
|
||||
#include "common.h"
|
||||
|
||||
#include "m-string.h"
|
||||
@@ -43,6 +46,10 @@ extern "C" {
|
||||
#include "bstraux.h"
|
||||
#endif
|
||||
|
||||
#if defined(BENCH_CAN_USE_POTTERY)
|
||||
#include "pottery/string/string.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* BENCH
|
||||
* 2000000
|
||||
@@ -104,27 +111,28 @@ size_t bench_stl(unsigned n)
|
||||
|
||||
size_t bench_mlib(unsigned n)
|
||||
{
|
||||
string_t *tab = (string_t*) malloc (n * sizeof (string_t));
|
||||
m_string_t *tab = (m_string_t*) malloc (n * sizeof (m_string_t));
|
||||
assert (tab != 0);
|
||||
// P1
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
string_init(tab[i]);
|
||||
string_printf(tab[i], "%u", rand_get());
|
||||
m_string_init(tab[i]);
|
||||
m_string_set_ui(tab[i], rand_get());
|
||||
}
|
||||
// P2
|
||||
string_t str;
|
||||
string_init(str);
|
||||
m_string_t str;
|
||||
m_string_init(str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
string_cat(str, tab[permutation_tab[i]]);
|
||||
m_string_cat(str, tab[permutation_tab[i]]);
|
||||
}
|
||||
// P3
|
||||
string_replace_all_str(str, "1234", "WELL");
|
||||
string_replace_all_str(str, "56789", "DONE");
|
||||
size_t length = string_size(str);
|
||||
m_string_replace_all_cstr(str, "1234", "WELL");
|
||||
m_string_replace_all_cstr(str, "56789", "DONE");
|
||||
size_t length = m_string_size(str);
|
||||
|
||||
// Clean
|
||||
string_clear(str);
|
||||
m_string_clear(str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
string_clear(tab[i]);
|
||||
m_string_clear(tab[i]);
|
||||
}
|
||||
free(tab);
|
||||
return length;
|
||||
@@ -217,6 +225,57 @@ size_t bench_sds(unsigned n)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BENCH_CAN_USE_POTTERY)
|
||||
|
||||
size_t pottery_find_cstr(string_t *b, size_t index, const char *pattern)
|
||||
{
|
||||
// I cannot find such function in the API
|
||||
const char *s = string_cstr(b);
|
||||
const char *r = strstr(&s[index], pattern);
|
||||
return r == NULL ? SIZE_MAX : r - s;
|
||||
}
|
||||
|
||||
void pottery_replace_all_str(string_t *str, const char *s, const char *d)
|
||||
{
|
||||
size_t i = 0;
|
||||
while (true) {
|
||||
i = pottery_find_cstr(str, i, s);
|
||||
if (i==SIZE_MAX) return;
|
||||
string_remove(str, i, strlen(s));
|
||||
string_insert_cstr(str, i, d);
|
||||
}
|
||||
}
|
||||
|
||||
size_t bench_pottery(unsigned n)
|
||||
{
|
||||
string_t *tab = (string_t*) malloc (n * sizeof (string_t));
|
||||
assert (tab != 0);
|
||||
// P1
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
string_init(&tab[i]);
|
||||
string_append_format(&tab[i], "%u", rand_get());
|
||||
}
|
||||
// P2
|
||||
string_t str;
|
||||
string_init(&str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
string_append_string(&str, &tab[permutation_tab[i]]);
|
||||
}
|
||||
// P3
|
||||
|
||||
pottery_replace_all_str(&str, "1234", "WELL");
|
||||
pottery_replace_all_str(&str, "56789", "DONE");
|
||||
size_t length = string_length(&str);
|
||||
|
||||
// Clean
|
||||
string_clear(&str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
string_clear(&tab[i]);
|
||||
}
|
||||
free(tab);
|
||||
return length;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
@@ -247,6 +306,12 @@ int main(int argc, const char *argv[])
|
||||
length = bench_bstrlib(n);
|
||||
name = "BSTRLIB";
|
||||
break;
|
||||
#endif
|
||||
#if defined(BENCH_CAN_USE_POTTERY)
|
||||
case 5:
|
||||
length = bench_pottery(n);
|
||||
name = "POTTERY";
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
exit(0);
|
||||
|
||||
+197
-48
@@ -35,8 +35,8 @@
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Update of integrating M*LIB, LIBSRT, SDS & GLIB
|
||||
Copyright (c) 2018-2021 Patrick Pelissier
|
||||
/* Update of integrating M*LIB, LIBSRT, SDS, GLIB & POTTERY
|
||||
Copyright (c) 2018-2022 Patrick Pelissier
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -48,11 +48,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define NDEBUG
|
||||
#define M_USE_SMALL_NAME 0
|
||||
#include "common.h"
|
||||
|
||||
#ifdef BENCH_CAN_USE_MSTARLIB
|
||||
@@ -83,6 +85,10 @@ extern "C" {
|
||||
#include "gmodule.h"
|
||||
#endif
|
||||
|
||||
#if defined(BENCH_CAN_USE_POTTERY)
|
||||
#include "pottery/string/string.h"
|
||||
#endif
|
||||
|
||||
/* Time of a test */
|
||||
#define TEST_SECONDS (5)
|
||||
|
||||
@@ -433,11 +439,11 @@ int testSRT_concat (int count) {
|
||||
int testMLIB_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init(b);
|
||||
m_string_t b;
|
||||
m_string_init(b);
|
||||
BARRIER(&b);
|
||||
c += string_size(b) ^i;
|
||||
string_clear(b);
|
||||
c += m_string_size(b) ^i;
|
||||
m_string_clear(b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
@@ -445,11 +451,11 @@ int testMLIB_emptyCtor (int count) {
|
||||
int testMLIB_nonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init_set_str(b, TESTSTRING1);
|
||||
m_string_t b;
|
||||
m_string_init_set_cstr(b, TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_size(b) ^i;
|
||||
string_clear(b);
|
||||
c += m_string_size(b) ^i;
|
||||
m_string_clear(b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
@@ -457,93 +463,93 @@ int testMLIB_nonemptyCtor (int count) {
|
||||
int testMLIB_smallnonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init_set_str(b, SMALLTESTSTRING1);
|
||||
m_string_t b;
|
||||
m_string_init_set_cstr(b, SMALLTESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_size(b) ^i;
|
||||
string_clear(b);
|
||||
c += m_string_size(b) ^i;
|
||||
m_string_clear(b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testMLIB_cstrAssignment (int count) {
|
||||
int i, c = 0;
|
||||
string_t b;
|
||||
string_init(b);
|
||||
m_string_t b;
|
||||
m_string_init(b);
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_set_str(b, TESTSTRING1);
|
||||
m_string_set_cstr(b, TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_size(b) ^i;
|
||||
c += m_string_size(b) ^i;
|
||||
}
|
||||
string_clear(b);
|
||||
m_string_clear(b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testMLIB_extraction (int count) {
|
||||
int i, c = 0;
|
||||
|
||||
string_t b;
|
||||
string_init_set_str(b, TESTSTRING1);
|
||||
m_string_t b;
|
||||
m_string_init_set_cstr(b, TESTSTRING1);
|
||||
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += string_get_char(b, (i & 7));
|
||||
c += string_get_char(b, (i & 7) ^ 8);
|
||||
c += string_get_char(b, (i & 7) ^ 4) ^i;
|
||||
c += m_string_get_char(b, (i & 7));
|
||||
c += m_string_get_char(b, (i & 7) ^ 8);
|
||||
c += m_string_get_char(b, (i & 7) ^ 4) ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
string_clear(b);
|
||||
m_string_clear(b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testMLIB_scan (int count) {
|
||||
int i, c = 0;
|
||||
string_t b;
|
||||
string_init_set_str(b, "Dot. 123. Some more data.");
|
||||
m_string_t b;
|
||||
m_string_init_set_cstr(b, "Dot. 123. Some more data.");
|
||||
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += string_search_char (b, '.');
|
||||
c += string_search_str (b, "123");
|
||||
c += string_search_pbrk (b, "sm") ^i;
|
||||
c += m_string_search_char (b, '.');
|
||||
c += m_string_search_cstr (b, "123");
|
||||
c += m_string_search_pbrk (b, "sm") ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
string_clear(b);
|
||||
m_string_clear(b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testMLIB_concat (int count) {
|
||||
int i, j, c = 0;
|
||||
string_t a, accum;
|
||||
string_init_set_str(a, TESTSTRING1);
|
||||
string_init (accum);
|
||||
m_string_t a, accum;
|
||||
m_string_init_set_cstr(a, TESTSTRING1);
|
||||
m_string_init (accum);
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
string_set_str(accum, "");
|
||||
m_string_set_cstr(accum, "");
|
||||
for (i=0; i < 250; i++) {
|
||||
string_cat(accum, a);
|
||||
string_cat_str(accum, "!!");
|
||||
m_string_cat(accum, a);
|
||||
m_string_cat_cstr(accum, "!!");
|
||||
BARRIER(&accum);
|
||||
c += string_size(accum) ^i;
|
||||
c += m_string_size(accum) ^i;
|
||||
}
|
||||
}
|
||||
string_clear(a);
|
||||
string_clear(accum);
|
||||
m_string_clear(a);
|
||||
m_string_clear(accum);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testMLIB_replace (int count) {
|
||||
int j, c = 0;
|
||||
string_t a;
|
||||
string_init_set_str(a, TESTSTRING1);
|
||||
m_string_t a;
|
||||
m_string_init_set_cstr(a, TESTSTRING1);
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
string_replace_at(a, 11, 4, "XXXXXX");
|
||||
string_replace_at(a, 23, 2, "XXXXXX");
|
||||
string_replace_at(a, 4, 8, "XX");
|
||||
m_string_replace_at(a, 11, 4, "XXXXXX");
|
||||
m_string_replace_at(a, 23, 2, "XXXXXX");
|
||||
m_string_replace_at(a, 4, 8, "XX");
|
||||
BARRIER(&a);
|
||||
c += string_size(a) ^j;
|
||||
c += m_string_size(a) ^j;
|
||||
}
|
||||
|
||||
string_clear(a);
|
||||
m_string_clear(a);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
@@ -774,6 +780,118 @@ int testGLIB_concat (int count) {
|
||||
//int testGLIB_replace (int count): not available
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_POTTERY
|
||||
int testPOTTERY_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init(&b);
|
||||
BARRIER(&b);
|
||||
c += string_length(&b) ^i;
|
||||
string_clear(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testPOTTERY_nonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init_cstr(&b, TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_length(&b) ^i;
|
||||
string_clear(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testPOTTERY_smallnonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init_cstr(&b, SMALLTESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_length(&b) ^i;
|
||||
string_clear(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testPOTTERY_cstrAssignment (int count) {
|
||||
int i, c = 0;
|
||||
string_t b;
|
||||
string_init(&b);
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_set_cstr(&b, TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_length(&b) ^i;
|
||||
}
|
||||
string_clear(&b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testPOTTERY_extraction (int count) {
|
||||
int i, c = 0;
|
||||
|
||||
string_t b;
|
||||
string_init_cstr(&b, TESTSTRING1);
|
||||
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += string_cstr(&b)[(i & 7)];
|
||||
c += string_cstr(&b)[(i & 7) ^ 8];
|
||||
c += string_cstr(&b)[(i & 7) ^ 4] ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
string_clear(&b);
|
||||
return c;
|
||||
}
|
||||
|
||||
size_t pottery_find_cstr(string_t *b, const char *pattern)
|
||||
{
|
||||
// I cannot find such function in the API
|
||||
const char *s = string_cstr(b);
|
||||
const char *r = strstr(s, pattern);
|
||||
return r == NULL ? SIZE_MAX : r - s;
|
||||
}
|
||||
|
||||
int testPOTTERY_scan (int count) {
|
||||
int i, c = 0;
|
||||
string_t b;
|
||||
string_init_cstr(&b, "Dot. 123. Some more data.");
|
||||
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += string_find_char (&b, 0, '.');
|
||||
c += pottery_find_cstr (&b, "123");
|
||||
c += string_find_chars_cstr (&b, 0, "sm") ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
string_clear(&b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testPOTTERY_concat (int count) {
|
||||
int i, j, c = 0;
|
||||
string_t a, accum;
|
||||
string_init_cstr(&a, TESTSTRING1);
|
||||
string_init (&accum);
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
string_set_cstr(&accum, "");
|
||||
for (i=0; i < 250; i++) {
|
||||
string_append_string(&accum, &a);
|
||||
string_append_cstr(&accum, "!!");
|
||||
BARRIER(&accum);
|
||||
c += string_length(&accum) ^i;
|
||||
}
|
||||
}
|
||||
string_clear(&a);
|
||||
string_clear(&accum);
|
||||
return c;
|
||||
}
|
||||
|
||||
// No replace function available
|
||||
#endif
|
||||
|
||||
|
||||
#define NTESTS 8
|
||||
struct flags {
|
||||
@@ -999,6 +1117,37 @@ int benchTest (const struct flags * runflags) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_POTTERY
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testPOTTERY_emptyCtor, 100000);
|
||||
print ("POTTERY", "empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[1]) {
|
||||
c += timeTest (cps, testPOTTERY_nonemptyCtor, 100000);
|
||||
print ("POTTERY", "non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[2]) {
|
||||
c += timeTest (cps, testPOTTERY_smallnonemptyCtor, 100000);
|
||||
print ("POTTERY", "small non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[3]) {
|
||||
c += timeTest (cps, testPOTTERY_cstrAssignment, 100000);
|
||||
print ("POTTERY", "Char * assignment", cps);
|
||||
}
|
||||
if (runflags->runtest[4]) {
|
||||
c += timeTest (cps, testPOTTERY_extraction, 100000);
|
||||
print ("POTTERY", "char extraction", cps);
|
||||
}
|
||||
if (runflags->runtest[5]) {
|
||||
c += timeTest (cps, testPOTTERY_scan, 100000);
|
||||
print ("POTTERY", "scan", cps);
|
||||
}
|
||||
if (runflags->runtest[6]) {
|
||||
c += timeTest (cps, testPOTTERY_concat, 10);
|
||||
print ("POTTERY", "concatenation", cps * 250);
|
||||
}
|
||||
#endif
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -147,7 +147,7 @@ select_config(int func, size_t n, const config_func_t functions[])
|
||||
fprintf(stderr, " %d: %s\n", functions[i].num, functions[i].funcname);
|
||||
}
|
||||
fprintf(stderr,
|
||||
"USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--grapĥ]\n"
|
||||
"USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--graph]\n"
|
||||
"[--repeat number] [--best|--average|--best-within] [--quiet]\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MLIB - TEST module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
|
||||
@@ -73,3 +73,11 @@ V0.5.*: * M_INVERT is renamed into M_REVERSE to be more coherent with the REVERS
|
||||
* Rename CLEAN operator in RESET operator.
|
||||
* Rename GET_SET_KEY operator in SAFE_GET_KEY operator.
|
||||
|
||||
V0.6.*: * Rename M_DEFAULT_OPLIST in M_BASIC_OPLIST
|
||||
* Remove experimental macro M_IF_DEFAULT1.
|
||||
* Remove M_INVERT
|
||||
* String functions with _str suffix for C strings have been renamed with _cstr suffix (like string_cat_str ==> m_string_cat_cstr)
|
||||
Note: the compatible layer still keeps the old naming,
|
||||
so except if you are using the prefixed version of the strings
|
||||
or the bounded strings API, you won't need to upgrade your code.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 113 KiB |
+6
-3
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2021, Patrick Pelissier
|
||||
# Copyright (c) 2017-2022, Patrick Pelissier
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@@ -23,6 +23,7 @@
|
||||
CC=cc -std=c99
|
||||
CFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -g
|
||||
GMP_DIR=
|
||||
MPFR_DIR=$(GMP_DIR)
|
||||
CPPFLAGS=-I..
|
||||
LDFLAGS=-pthread
|
||||
RM=rm -f
|
||||
@@ -30,7 +31,7 @@ RM=rm -f
|
||||
.SUFFIXES: .c .exe
|
||||
|
||||
.c.exe:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) `cat config` $< -o $@
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@ `cat config`
|
||||
|
||||
all: config
|
||||
$(MAKE) `ls ex-*.c|sed -e 's/\.c/\.exe/g'`
|
||||
@@ -38,7 +39,9 @@ all: config
|
||||
|
||||
config:
|
||||
printf "#include <gmp.h>\nint main(void){mpz_t z; mpz_init(z); return 0;}\n" > config-test.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp config-test.c -o config-test.exe 2> /dev/null && echo "-DHAVE_GMP=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0" > config
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib config-test.c -lgmp -o config-test.exe 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=0 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0 -DHAVE_MPFR=0 " > config
|
||||
printf "#include <mpfr.h>\nint main(void){mpfr_t z; mpfr_init(z); return 0;}\n" > config-test.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -I$(GMP_DIR)/include -I$(MPFR_DIR)/include -L$(GMP_DIR)/lib -L$(MPFR_DIR)/lib config-test.c -lmpfr -lgmp -o config-test.exe 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -I$(MPFR_DIR)/include -L$(MPFR_DIR)/lib -lmpfr -lgmp" > config || echo "MPFR not available"
|
||||
$(RM) config-test.c config-test.exe
|
||||
|
||||
clean:
|
||||
|
||||
+3
-3
@@ -3,11 +3,11 @@
|
||||
#include "m-algo.h"
|
||||
#include "m-string.h"
|
||||
|
||||
/* Define a dictionnary (or hash_map or undordered_map)
|
||||
/* Define a dictionnary (or hash_map or unordered_map)
|
||||
* from a string_t to int */
|
||||
DICT_DEF2(dict, string_t, int)
|
||||
/* Register the oplist of this dictionnary globally */
|
||||
#define M_OPL_dict_t() DICT_OPLIST(dict, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_dict_t() DICT_OPLIST(dict, STRING_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
/* Define an array of integer */
|
||||
ARRAY_DEF(vector_int, int)
|
||||
@@ -23,7 +23,7 @@ ARRAY_DEF(vector_int, int)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int s;
|
||||
int s = 0;
|
||||
// Init keys as a vector_int_t, initialize it (and prepare its destruction)
|
||||
M_LET(keys, vector_int_t)
|
||||
// Initialize m as a dictionnary and initialize it with the given database
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ int main(void)
|
||||
M_LET(s, string_t)
|
||||
// Let v be a vector of integer and initialize it.
|
||||
M_LET( (v, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), vector_int_t) {
|
||||
int sum, product;
|
||||
int sum = 0, product = 0;
|
||||
|
||||
// Compute the sum of theses integers.
|
||||
ALGO_REDUCE(sum, v, vector_int_t, add);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
/* Generate prototypes and inline functions
|
||||
for basic types.
|
||||
For integer and floats, there is no need to specify
|
||||
an oplist. M_DEFAULT_OPLIST will be used.
|
||||
an oplist. M_BASIC_OPLIST will be used.
|
||||
*/
|
||||
ARRAY_DEF(r_bool, bool)
|
||||
|
||||
@@ -105,7 +105,7 @@ test_int(int n)
|
||||
But with an explicit oplist.
|
||||
This generates exactly the same code than r_int
|
||||
*/
|
||||
ARRAY_DEF(r_int2, signed int, M_DEFAULT_OPLIST)
|
||||
ARRAY_DEF(r_int2, signed int, M_BASIC_OPLIST)
|
||||
|
||||
static int
|
||||
test_int2(int n)
|
||||
@@ -180,7 +180,7 @@ test_float(int n)
|
||||
|
||||
|
||||
/* Same with type double and an explicit oplist*/
|
||||
ARRAY_DEF(r_double, double, M_DEFAULT_OPLIST)
|
||||
ARRAY_DEF(r_double, double, M_BASIC_OPLIST)
|
||||
|
||||
static int
|
||||
test_double(int n)
|
||||
@@ -231,7 +231,7 @@ test_cstring(int n)
|
||||
|
||||
r_cstring_init(array);
|
||||
for(int i = 0; i < n; i++) {
|
||||
char buffer[10];
|
||||
char buffer[16];
|
||||
// Create a string from the integer
|
||||
sprintf(buffer, "%d", i);
|
||||
// We need to make an explicit copy of the string
|
||||
@@ -478,7 +478,7 @@ test_rockme2b(int n)
|
||||
/* Same with a structure type defined as a tuple.
|
||||
|
||||
We first define a tuple. No need to specify the oplist as it uses basic C types
|
||||
so M_DEFAULT_OPLIST is used.
|
||||
so M_BASIC_OPLIST is used.
|
||||
|
||||
Then we define the array, giving it the oplist definition of the tuple:
|
||||
the macro TUPLE_OPLIST is used to build it based on the tuple name,
|
||||
@@ -486,7 +486,7 @@ test_rockme2b(int n)
|
||||
*/
|
||||
TUPLE_DEF2(rock_you, (n, int), (other, float))
|
||||
|
||||
ARRAY_DEF(r_rockme3, rock_you_t, TUPLE_OPLIST(rock_you, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
ARRAY_DEF(r_rockme3, rock_you_t, TUPLE_OPLIST(rock_you, M_BASIC_OPLIST, M_BASIC_OPLIST))
|
||||
|
||||
static int
|
||||
test_rockme3(int n)
|
||||
@@ -520,7 +520,7 @@ test_rockme3(int n)
|
||||
/* Same with a structure type defined as a tuple using global registeration.
|
||||
|
||||
We first define a tuple. No need to specify the oplist as it uses basic C types
|
||||
so M_DEFAULT_OPLIST is used.
|
||||
so M_BASIC_OPLIST is used.
|
||||
|
||||
Then we register the oplist of rock_us_t by defining a macro based
|
||||
on M_OPL_ + type name + () which expands with the oplist of the type.
|
||||
@@ -533,7 +533,7 @@ test_rockme3(int n)
|
||||
*/
|
||||
TUPLE_DEF2(rock_us, (n, int), (other, float))
|
||||
|
||||
#define M_OPL_rock_us_t() TUPLE_OPLIST(rock_us, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_rock_us_t() TUPLE_OPLIST(rock_us, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
ARRAY_DEF(r_rockme4, rock_us_t)
|
||||
|
||||
@@ -612,7 +612,7 @@ int main (int argc, const char *argv[])
|
||||
s = test_rockme3(n);
|
||||
printf ("S[rockme3] = %d\n", s);
|
||||
|
||||
s = test_rockme3(n);
|
||||
s = test_rockme4(n);
|
||||
printf ("S[rockme4] = %d\n", s);
|
||||
|
||||
exit(0);
|
||||
|
||||
@@ -96,6 +96,7 @@ static void data_node_clear(data_node *obj)
|
||||
and gives the minimum oplist allowing M*LIB to handle
|
||||
properly the object 'data_node' with the API convention
|
||||
to respect for calling the methods.
|
||||
The Manual defines the different supported API.
|
||||
*/
|
||||
ARRAY_DEF(/* the array prefix */ array_data_node,
|
||||
/* the object type */ data_node,
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
// The number 5 is the number of elements in a node of the B+TREE
|
||||
BPTREE_DEF2(map_employee_id, 5, int, string_t)
|
||||
// Register the oplist of this map globally.
|
||||
#define M_OPL_map_employee_id_t() BPTREE_OPLIST2(map_employee_id, M_DEFAULT_OPLIST, STRING_OPLIST)
|
||||
#define M_OPL_map_employee_id_t() BPTREE_OPLIST2(map_employee_id, M_BASIC_OPLIST, STRING_OPLIST)
|
||||
|
||||
// Define a map string -> int named map_employee_name
|
||||
// The number 5 is the number of elements in a node of the B+TREE
|
||||
BPTREE_DEF2(map_employee_name, 5, string_t, int)
|
||||
// Register the oplist of this map globally.
|
||||
#define M_OPL_map_employee_name_t() BPTREE_OPLIST2(map_employee_name, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_map_employee_name_t() BPTREE_OPLIST2(map_employee_name, STRING_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include "m-core.h"
|
||||
|
||||
/* This example show how to use the M_LET_IF macro
|
||||
that enables to construct an object and continue
|
||||
if the construction succeeds.
|
||||
*/
|
||||
|
||||
// Stubs defined for the example. Real code will use soundio library.
|
||||
struct SoundIo { int x; };
|
||||
struct SoundIoDevice { int x; };
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
// Define a dictionnary of string --> int
|
||||
// named 'dict_str'
|
||||
DICT_DEF2(dict_str, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
DICT_DEF2(dict_str, string_t, STRING_OPLIST, int, M_BASIC_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
+3
-3
@@ -1,10 +1,10 @@
|
||||
#include "m-dict.h"
|
||||
|
||||
// Let's define a dictionary of 'unsigned int' --> 'char
|
||||
DICT_DEF2(dict_m32, unsigned int, M_DEFAULT_OPLIST, char, M_DEFAULT_OPLIST)
|
||||
DICT_DEF2(dict_m32, unsigned int, M_BASIC_OPLIST, char, M_BASIC_OPLIST)
|
||||
|
||||
// Let's create a synonym for its oplist.
|
||||
#define M32_OPLIST DICT_OPLIST(dict_m32, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M32_OPLIST DICT_OPLIST(dict_m32, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
#if 1 // Non macro version.
|
||||
|
||||
@@ -14,7 +14,7 @@ int main(void) {
|
||||
dict_m32_set_at (h, 5, 10); // h[5] = 10
|
||||
char *k = dict_m32_get(h, 10); // No 10 in h, so k == NULL
|
||||
int is_missing = (k != NULL); // true
|
||||
assert (is_missing);
|
||||
assert (is_missing); (void) is_missing;
|
||||
dict_m32_erase(h, 5); // h is now empty
|
||||
dict_m32_it_t it; // iterate over all dictionnary
|
||||
for (dict_m32_it (it, h) ; !dict_m32_end_p (it); dict_m32_next(it)) {
|
||||
|
||||
+3
-2
@@ -28,11 +28,11 @@ int main(void)
|
||||
M_LET (grow, list_string_t)
|
||||
M_LET (tmpstr, string_t) { // And let's create also a string_t
|
||||
|
||||
// add string elements to the list
|
||||
// add string elements to the list in different ways
|
||||
list_string_push_back (grow, STRING_CTE("AB"));
|
||||
string_printf(tmpstr, "%d", 12);
|
||||
list_string_push_back (grow, tmpstr);
|
||||
list_string_push_back (grow, STRING_CTE("CD"));
|
||||
list_string_emplace_back (grow, "CD");
|
||||
|
||||
// Serialize the list of string into a big string.
|
||||
list_string_get_str (tmpstr, grow, false);
|
||||
@@ -75,6 +75,7 @@ int main(void)
|
||||
// Split a string into a list.
|
||||
string_set_str(tmpstr, "HELLO;JOHN;HOW;ARE;YOU");
|
||||
astring_split(grow, tmpstr, ';');
|
||||
// Iterate over the splitted list
|
||||
for M_EACH (item, grow, list_string_t) {
|
||||
printf ("Split Item = %s\n", string_get_cstr(*item) );
|
||||
}
|
||||
|
||||
+2
-2
@@ -25,8 +25,8 @@
|
||||
/* Define the needed data structure : */
|
||||
|
||||
// Define a dictionnary of constant string --> integer and register it.
|
||||
DICT_DEF2(dict_mph, const char *, M_CSTR_OPLIST, uint32_t, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_dict_mph_t() DICT_OPLIST(dict_mph, M_CSTR_OPLIST, M_DEFAULT_OPLIST)
|
||||
DICT_DEF2(dict_mph, const char *, M_CSTR_OPLIST, uint32_t, M_BASIC_OPLIST)
|
||||
#define M_OPL_dict_mph_t() DICT_OPLIST(dict_mph, M_CSTR_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
// Define an array of integer to store the value and register it.
|
||||
ARRAY_DEF(array_value, uint32_t) // Start from 1. 0 is 'None'
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
#if HAVE_GMP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gmp.h>
|
||||
|
||||
#include "m-variant.h"
|
||||
#include "m-string.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
|
||||
/* Define a variant over two integers named integer_t
|
||||
Notice than mpz_t has special init & clear functions
|
||||
mpz_init & mpz_clear.
|
||||
This is handle by the library.
|
||||
*/
|
||||
VARIANT_DEF2(my_integer,
|
||||
(n, long long, M_DEFAULT_OPLIST),
|
||||
(z, mpz_t, M_CLASSIC_OPLIST(mpz)))
|
||||
/* Define the oplist associated to this variant */
|
||||
#define MY_INTEGER_OPLIST VARIANT_OPLIST(my_integer, M_DEFAULT_OPLIST, M_CLASSIC_OPLIST(mpz))
|
||||
|
||||
/* Define a dictionary of string --> integer named dict_my_t */
|
||||
DICT_DEF2(my_dict,
|
||||
string_t, STRING_OPLIST,
|
||||
my_integer_t, MY_INTEGER_OPLIST)
|
||||
/* Define the oplist associated to this dictionary */
|
||||
#define MY_DICT_OPLIST DICT_OPLIST(my_dict, STRING_OPLIST, MY_INTEGER_OPLIST)
|
||||
|
||||
/* Define an array of such dictionary named array_my_t */
|
||||
ARRAY_DEF(my_array, my_dict_t, MY_DICT_OPLIST)
|
||||
/* Define the oplist associated to this array of dictionary of variant */
|
||||
#define MY_ARRAY_OPLIST ARRAY_OPLIST(my_array, MY_DICT_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET(z, MY_INTEGER_OPLIST) /* Define & init & clear an instance of a variant of integer */
|
||||
M_LET(dict, MY_DICT_OPLIST) /* Define & init & clear an instance of a dictionary of variant */
|
||||
M_LET(array, MY_ARRAY_OPLIST) /* Define & init & clear an intance of an array of dictionary of variant */
|
||||
M_LET(gmp, M_CLASSIC_OPLIST(mpz)) /* M_LET allows even with non container type */
|
||||
{
|
||||
my_integer_set_n (z, 17LL); // Set z as the long long 17
|
||||
my_dict_set_at(dict, STRING_CTE("n1"), z); // Push it in the dictionary
|
||||
mpz_set_str(gmp, "25446846874687468746874687468746874686874", 10); // Set gmp to a very long integer.
|
||||
my_integer_set_z (z, gmp); // Set z as the mpz_t variable
|
||||
my_dict_set_at(dict, STRING_CTE("n2"), z); // Push it in the dictionary
|
||||
my_array_push_back (array, dict); // Push the dictionary in the array
|
||||
|
||||
// Iterate over the array container
|
||||
for M_EACH(item, array, MY_ARRAY_OPLIST) {
|
||||
// Iterate over the dictionary container
|
||||
for M_EACH(p, *item, MY_DICT_OPLIST) {
|
||||
// Dictionary iterator are pair (key,value)
|
||||
if (my_integer_n_p(p->value)) {
|
||||
printf ("It is a long long, value = %lld\n",
|
||||
*my_integer_cget_n(p->value));
|
||||
}
|
||||
if (my_integer_z_p(p->value)) {
|
||||
printf ("It is a mpz_t, value =");
|
||||
mpz_out_str(stdout, 10, *my_integer_cget_z(p->value));
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* All variables are automatically cleared beyond this point */
|
||||
}
|
||||
|
||||
#else
|
||||
// Nothing to do
|
||||
int main(void) { return 0; }
|
||||
#endif
|
||||
@@ -84,8 +84,8 @@ DICT_DEF2(dict_json, string_t, STRING_OPLIST, json_t, JSON_OPLIST)
|
||||
ARRAY_DEF(array_json, json_t, JSON_OPLIST)
|
||||
|
||||
VARIANT_DEF2(variant_json,
|
||||
(boolean, bool, M_OPEXTEND(M_DEFAULT_OPLIST, OUT_STR(boolean_out_str), IN_STR(boolean_in_str M_IPTR)) ),
|
||||
(real, float, M_OPEXTEND (M_DEFAULT_OPLIST, OUT_STR(real_out_str), IN_STR(real_in_str M_IPTR))),
|
||||
(boolean, bool, M_OPEXTEND(M_BASIC_OPLIST, OUT_STR(boolean_out_str), IN_STR(boolean_in_str M_IPTR)) ),
|
||||
(real, float, M_OPEXTEND (M_BASIC_OPLIST, OUT_STR(real_out_str), IN_STR(real_in_str M_IPTR))),
|
||||
(array, array_json_t, ARRAY_OPLIST(array_json, JSON_OPLIST)),
|
||||
(dict, dict_json_t, DICT_OPLIST(dict_json, STRING_OPLIST, JSON_OPLIST)))
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
order to show/test the good chaining of the structures */
|
||||
|
||||
TUPLE_DEF2(symbol, (type, int), (name, string_t))
|
||||
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_DEFAULT_OPLIST, STRING_OPLIST)
|
||||
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_BASIC_OPLIST, STRING_OPLIST)
|
||||
|
||||
ARRAY_DEF(symbol_list, symbol_t)
|
||||
#define M_OPL_symbol_list_t() ARRAY_OPLIST(symbol_list, M_OPL_symbol_t())
|
||||
@@ -19,13 +19,13 @@ TUPLE_DEF2(record, (fields, symbol_list_t))
|
||||
#define M_OPL_record_t() TUPLE_OPLIST(record, M_OPL_symbol_list_t())
|
||||
|
||||
TUPLE_DEF2(my_tuple, (name, string_t), (value, int))
|
||||
#define M_OPL_my_tuple_t() TUPLE_OPLIST(my_tuple)
|
||||
#define M_OPL_my_tuple_t() TUPLE_OPLIST(my_tuple, STRING_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
ARRAY_DEF(my_list_of_tuple, my_tuple_t)
|
||||
#define M_OPL_my_list_of_tuple_t() ARRAY_OPLIST(my_list_of_tuple)
|
||||
|
||||
TUPLE_DEF2(my_tuple_of_tuple, (name, string_t), (inner_tuple, my_tuple_t))
|
||||
#define M_OPL_my_tuple_of_tuple_t() TUPLE_OPLIST(my_tuple_of_tuple)
|
||||
#define M_OPL_my_tuple_of_tuple_t() TUPLE_OPLIST(my_tuple_of_tuple, STRING_OPLIST, M_OPL_my_tuple_t() )
|
||||
|
||||
LIST_DEF(list_of_tuple_of_tuple, my_tuple_of_tuple_t)
|
||||
#define M_OPL_list_of_tuple_of_tuple_t() LIST_OPLIST(list_of_tuple_of_tuple, M_OPL_my_tuple_of_tuple_t() )
|
||||
@@ -37,11 +37,11 @@ BUFFER_DEF(trbuff, my_triple_tuple_t, 100, BUFFER_QUEUE)
|
||||
#define M_OPL_trbuff_t() BUFFER_OPLIST(trbuff, M_OPL_my_triple_tuple_t())
|
||||
|
||||
TUPLE_DEF2(my_junction, (active, bool), (buffer, trbuff_t))
|
||||
#define M_OPL_my_junction_t() TUPLE_OPLIST(my_junction, M_DEFAULT_OPLIST, M_OPL_trbuff_t())
|
||||
#define M_OPL_my_junction_t() TUPLE_OPLIST(my_junction, M_BASIC_OPLIST, M_OPL_trbuff_t())
|
||||
|
||||
TUPLE_DEF2(mlib_point, (x, int), (y, int))
|
||||
#define M_OPL_mlib_point_t() \
|
||||
TUPLE_OPLIST(mlib_point, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
TUPLE_OPLIST(mlib_point, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
TUPLE_DEF2(mlib_points, (first_ref, mlib_point_ptr, M_PTR_OPLIST),
|
||||
(second_ref, mlib_point_ptr, M_PTR_OPLIST),
|
||||
|
||||
@@ -3,7 +3,14 @@
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Let's create an array of string_t and register it globaly
|
||||
/* This example show ARRAY_DEF usage with string,
|
||||
M_LET macro usage with complex initialization condition:
|
||||
how to initialize a dynamic array and initialize it with the given arguments.
|
||||
It show also the M_EACH keywork
|
||||
*/
|
||||
|
||||
// Let's create a dynamic array of string_t and register it globaly
|
||||
// a so called std::vector<std::string> in C++
|
||||
ARRAY_DEF(vector_string, string_t)
|
||||
#define M_OPL_vector_string_t() ARRAY_OPLIST(vector_string, STRING_OPLIST)
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Micro example to test if M*LIB supports not using stdio.h
|
||||
*/
|
||||
#define M_USE_STDIO 0
|
||||
#define M_RAISE_FATAL(...) abort()
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF(arr, int)
|
||||
|
||||
int main(void) {
|
||||
arr_t a;
|
||||
arr_init(a);
|
||||
arr_push_back(a, 4);
|
||||
arr_clear(a);
|
||||
return 0;
|
||||
}
|
||||
@@ -5,8 +5,7 @@
|
||||
#include "m-rbtree.h"
|
||||
|
||||
// Let's define one utility function.
|
||||
void *xmalloc(size_t n);
|
||||
void *xmalloc(size_t n)
|
||||
static void *xmalloc(size_t n)
|
||||
{
|
||||
void *p = malloc (n);
|
||||
if (!p) abort();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
/* 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)
|
||||
#define M_OPL_dict_str_t() DICT_OPLIST(dict_str, STRING_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
/* Definition of an array of string_t */
|
||||
ARRAY_DEF(vector_str, string_t)
|
||||
@@ -26,13 +26,14 @@ int main(void)
|
||||
|
||||
// Count the words.
|
||||
M_LET(map, dict_str_t) {
|
||||
// Count the words:
|
||||
// Count the words into the dictionnary 'map'
|
||||
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) {
|
||||
// In C11 version we can use the M_PRINT macro that simplifies formatting.
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
|
||||
M_PRINT(p->value, " occurences of ", p->key, "\n");
|
||||
#else
|
||||
|
||||
@@ -11,7 +11,7 @@ TUPLE_DEF2(employee,
|
||||
(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 M_OPL_employee_t() TUPLE_OPLIST(employee, STRING_OPLIST, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
/* Define an array of employee, register the oplist and define further algorithms on it */
|
||||
ARRAY_DEF(vector_employee, employee_t)
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "m-tuple.h"
|
||||
#include "m-tree.h"
|
||||
#include "m-worker.h"
|
||||
#include "m-string.h"
|
||||
#include "m-atomic.h"
|
||||
|
||||
/* Sort the atomic unsigned int with the biggest value first. */
|
||||
static inline int atomic_uint_cmp(const atomic_uint *a, const atomic_uint *b)
|
||||
{
|
||||
unsigned ai = atomic_load(a), bi = atomic_load(b);
|
||||
return ai > bi ? -1 : ai < bi;
|
||||
}
|
||||
/* Disable HASH for atomic as the default hash method won't work */
|
||||
#define M_OPL_atomic_uint() M_OPEXTEND(M_BASIC_OPLIST, HASH(0), CMP(API_6(atomic_uint_cmp)))
|
||||
|
||||
/* Define a directory as the number of lines of the files in this directory
|
||||
and the name of the directory
|
||||
(Only sort with the number value by disable the sort compare for the string).
|
||||
*/
|
||||
TUPLE_DEF2( dir, (nlines, atomic_uint), (name, string_t, M_OPEXTEND(STRING_OPLIST, CMP(0))))
|
||||
#define M_OPL_dir_t() TUPLE_OPLIST(dir, M_BASIC_OPLIST, M_STRING_OPLIST)
|
||||
|
||||
/* A hierarchical tree of directory */
|
||||
M_TREE_DEF(tree, dir_t)
|
||||
|
||||
/* Maximum number of characters read by file */
|
||||
#define MAX_READ_BUFFER 8192
|
||||
|
||||
/* Maximum number of directory to scan */
|
||||
#define MAX_DIRECTORY 100000
|
||||
|
||||
static tree_it_t
|
||||
add_directory(tree_it_t parent, const string_t dirname)
|
||||
{
|
||||
// TODO: return dir_emplace_child(parent, 0, dirname); to simplify this function.
|
||||
// which is too complex for what she does.
|
||||
dir_t data;
|
||||
tree_it_t it;
|
||||
dir_init_emplace(data, 0, dirname);
|
||||
if (tree_end_p(parent)) {
|
||||
it = tree_set_root( tree_tree(parent), data);
|
||||
} else {
|
||||
it = tree_insert_child(parent, data);
|
||||
}
|
||||
dir_clear(data);
|
||||
return it;
|
||||
}
|
||||
|
||||
/* count the number of end of line character in the buffer */
|
||||
static unsigned
|
||||
count_eol(const char buffer[], size_t num)
|
||||
{
|
||||
unsigned count = 0;
|
||||
for(size_t i = 0; i < num; i++) {
|
||||
count += buffer[i] == '\n';
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_a_c_file(const string_t filename)
|
||||
{
|
||||
return (string_end_with_str_p(filename, ".c")
|
||||
|| string_end_with_str_p(filename, ".h")
|
||||
|| string_end_with_str_p(filename, ".cpp")
|
||||
|| string_end_with_str_p(filename, ".hpp"));
|
||||
}
|
||||
|
||||
static void
|
||||
scan_file(tree_it_t parent, const string_t filename)
|
||||
{
|
||||
if (!is_a_c_file(filename)) return;
|
||||
|
||||
FILE *f = fopen(string_get_cstr(filename), "rt");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s as a text file.\n", string_get_cstr(filename) );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Read the FILE per bulk of MAX_READ_BUFFER */
|
||||
char buffer[MAX_READ_BUFFER];
|
||||
unsigned count = 0;
|
||||
size_t num;
|
||||
do {
|
||||
num = fread (buffer, 1, MAX_READ_BUFFER, f);
|
||||
count += count_eol(buffer, num);
|
||||
} while (num == MAX_READ_BUFFER);
|
||||
fclose(f);
|
||||
|
||||
/* Adding the number of lines to the parent directory */
|
||||
dir_t *d = tree_ref(parent);
|
||||
atomic_fetch_add( &(*d)->nlines, count );
|
||||
}
|
||||
|
||||
static void
|
||||
scan_directories(tree_it_t parent, const string_t dirname)
|
||||
{
|
||||
tree_it_t it = add_directory(parent, dirname);
|
||||
|
||||
string_t filename;
|
||||
string_init(filename);
|
||||
DIR *dir = opendir(string_get_cstr(dirname));
|
||||
if (dir == NULL) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s as a directory.\n", string_get_cstr(dirname) );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Scan all entries in the directory
|
||||
struct dirent *entry = readdir(dir);
|
||||
while (entry) {
|
||||
// Ignore hidden entries (including '.' and '..')
|
||||
if (entry->d_name[0] != '.') {
|
||||
// Construct the path to the filename
|
||||
string_sets(filename, dirname, "/", entry->d_name);
|
||||
// Get the property of this filename
|
||||
struct stat buf;
|
||||
int err = stat(string_get_cstr(filename), &buf);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ERROR: Cannot stat %s\n", string_get_cstr(filename));
|
||||
exit(2);
|
||||
}
|
||||
// Further scanning in function of the kind of entry
|
||||
if (S_ISDIR(buf.st_mode)) {
|
||||
scan_directories(it, filename);
|
||||
} else {
|
||||
scan_file(it, filename);
|
||||
}
|
||||
}
|
||||
// Next entry in the directory
|
||||
entry = readdir(dir);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
string_clear(filename);
|
||||
}
|
||||
|
||||
static void
|
||||
consolidate_directories(tree_t directories)
|
||||
{
|
||||
// Scan all entries, first the childreen, then the parent
|
||||
for(tree_it_t it = tree_it_post(directories) ; !tree_end_p(it) ; tree_next_post(&it) ) {
|
||||
dir_t *parent = tree_up_ref(it);
|
||||
dir_t *myself = tree_ref(it);
|
||||
if (parent != NULL) {
|
||||
// Add the child number of lines to the parent
|
||||
atomic_fetch_add_explicit(&(*parent)->nlines, (*myself)->nlines, memory_order_relaxed);
|
||||
}
|
||||
// Sort the data of the childreen by the number of lines
|
||||
tree_sort_child(it);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_result(tree_t directories)
|
||||
{
|
||||
// Scan all entries, first the parent, then the childreen
|
||||
for(tree_it_t it = tree_it(directories) ; !tree_end_p(it) ; tree_next(&it) ) {
|
||||
int i, depth = tree_depth(it);
|
||||
for(i = 0; i < depth; i++) printf("+");
|
||||
for( ; i < 8; i++) printf(" ");
|
||||
const dir_t *d = tree_cref(it);
|
||||
printf("%6u %s\n", (unsigned) (*d)->nlines, string_get_cstr( (*d)->name ) );
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
tree_t directories;
|
||||
string_t str;
|
||||
|
||||
printf("Count the number of C/C++ lines of code\n");
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "ERROR. Usage is '%s <directory>'.\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Init the tree, reserve for at least the number of max directory
|
||||
and prevent any further increase of allocation:
|
||||
this is to ensure that other threads can deref a dir safely */
|
||||
tree_init(directories);
|
||||
tree_reserve(directories, MAX_DIRECTORY);
|
||||
tree_lock(directories, true);
|
||||
string_init_set_str(str, argv[1]);
|
||||
tree_it_t it = tree_it_end(directories);
|
||||
|
||||
/* Main processing */
|
||||
scan_directories(it, str);
|
||||
consolidate_directories(directories);
|
||||
print_result(directories);
|
||||
|
||||
/* Clear everything & quit */
|
||||
string_clear(str);
|
||||
tree_clear(directories);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
// Based on https://github.com/nanopb/nanopb/blob/master/examples/simple/simple.c
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m-serial-json.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Define a structure with one field
|
||||
TUPLE_DEF2(SimpleMessage,
|
||||
(lucky_number, int))
|
||||
|
||||
int main(void)
|
||||
{
|
||||
string_t buffer;
|
||||
m_serial_return_code_t status;
|
||||
|
||||
string_init(buffer);
|
||||
/* Encode our message */
|
||||
{
|
||||
SimpleMessage_t message;
|
||||
SimpleMessage_init(message);
|
||||
|
||||
/* Create a stream that will write to our buffer. */
|
||||
m_serial_str_json_write_t stream;
|
||||
m_serial_str_json_write_init(stream, buffer);
|
||||
|
||||
/* Fill in the lucky number */
|
||||
message->lucky_number = 13;
|
||||
|
||||
/* Now we are ready to encode the message! */
|
||||
status = SimpleMessage_out_serial(stream, message);
|
||||
|
||||
/* Then just check for any errors.. */
|
||||
if (status != M_SERIAL_OK_DONE)
|
||||
{
|
||||
printf("Encoding failed: %d\n", status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Clear the objets */
|
||||
m_serial_str_json_write_clear(stream);
|
||||
SimpleMessage_clear(message);
|
||||
}
|
||||
|
||||
/* Now we could transmit the message over network, store it in a file
|
||||
* but we are doing it right now.
|
||||
*/
|
||||
|
||||
{
|
||||
/* Allocate another space for the decoded message. */
|
||||
SimpleMessage_t message;
|
||||
SimpleMessage_init(message);
|
||||
|
||||
/* Create a stream that reads from the buffer. */
|
||||
m_serial_str_json_read_t stream;
|
||||
m_serial_str_json_read_init(stream, string_get_cstr(buffer));
|
||||
|
||||
/* Now we are ready to decode the message. */
|
||||
status = SimpleMessage_in_serial(message, stream);
|
||||
|
||||
/* Check for errors... */
|
||||
if (status != M_SERIAL_OK_DONE)
|
||||
{
|
||||
printf("Decoding failed: %d\n", status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Print the data contained in the message. */
|
||||
printf("Your lucky number was %d!\n", message->lucky_number);
|
||||
|
||||
/* Clear the objets */
|
||||
m_serial_str_json_read_clear(stream);
|
||||
SimpleMessage_clear(message);
|
||||
}
|
||||
|
||||
string_clear(buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
#include "m-tuple.h"
|
||||
#include "m-array.h"
|
||||
|
||||
/* Basic example to show JSON serialization */
|
||||
|
||||
// Let's define a 'person' composed of several fields.
|
||||
TUPLE_DEF2(person,
|
||||
(surname, string_t),
|
||||
@@ -9,7 +11,7 @@ TUPLE_DEF2(person,
|
||||
(present, bool)
|
||||
)
|
||||
// Register the oplist of this tuple globaly
|
||||
#define M_OPL_person_t() TUPLE_OPLIST(person, M_DEFAULT_OPLIST, STRING_OPLIST, M_DEFAULT_OPLIST )
|
||||
#define M_OPL_person_t() TUPLE_OPLIST(person, STRING_OPLIST, M_BASIC_OPLIST, M_BOOL_OPLIST )
|
||||
|
||||
// Let's define an array of person
|
||||
ARRAY_DEF(base, person_t)
|
||||
@@ -48,6 +50,7 @@ int main(void)
|
||||
M_LET(base, base_t) {
|
||||
// Read the JSON file and fill-in base
|
||||
read(base, "ex11-json01.json");
|
||||
base_emplace_back(base, STRING_CTE("John"), 40, false);
|
||||
// Print the contents of base:
|
||||
printf ("List of presents:\n");
|
||||
for M_EACH(el, base, base_t) {
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
#if HAVE_GMP && HAVE_MPFR
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gmp.h>
|
||||
#include <mpfr.h>
|
||||
|
||||
#include "m-variant.h"
|
||||
#include "m-string.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
#include "m-algo.h"
|
||||
|
||||
// GMP doesn't provide a fast hash function (It is needed for being able to use mpz_t as key in a hashmap)
|
||||
static inline size_t
|
||||
mpz_fast_hash(const mpz_t z)
|
||||
{
|
||||
mp_size_t n = z->_mp_size;
|
||||
mp_limb_t *p = z->_mp_d;
|
||||
M_HASH_DECL(hash);
|
||||
|
||||
if (n <= 0) {
|
||||
M_HASH_UP (hash, 0x7F5C1458);
|
||||
if (n == 0) {
|
||||
return M_HASH_FINAL (hash);
|
||||
}
|
||||
n = -n;
|
||||
}
|
||||
while (n-- > 0) {
|
||||
M_HASH_UP (hash, *p++);
|
||||
}
|
||||
return M_HASH_FINAL (hash);
|
||||
}
|
||||
|
||||
/* Define the OPLIST of a mpz_t and register it globally */
|
||||
#define M_OPL_mpz_t() \
|
||||
(INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), \
|
||||
INIT_WITH(API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)), \
|
||||
EQUAL( API( mpz_cmp, EQ(0), ARG1, ARG2)), \
|
||||
CMP(mpz_cmp), \
|
||||
HASH(mpz_fast_hash), \
|
||||
OUT_STR( API( mpz_out_str, VOID, ARG1, 10, ARG2)), \
|
||||
IN_STR( API( mpz_inp_str, GT(0), ARG1, ARG2, 10)), \
|
||||
ADD(mpz_add), SUB(mpz_sub), MUL(mpz_mul), DIV(mpz_div), \
|
||||
EMPLACE_TYPE( LIST( (_si, mpz_init_set_si, int), \
|
||||
(_ui, mpz_init_set_ui, unsigned), \
|
||||
(_d, mpz_init_set_d, double), \
|
||||
(_cstr, API(mpz_init_set_str, VOID, ARG1, ARG2, 10), const char *), \
|
||||
(_str, API(mpz_init_set_str, VOID, ARG1, ARG2, 10), char *) )), \
|
||||
TYPE(mpz_t) )
|
||||
|
||||
|
||||
|
||||
// MPFR doesn't provide a fast hash function (It is needed for being able to use mpz_t as key in a hashmap)
|
||||
static size_t
|
||||
mpfr_fast_hash (const mpfr_t f)
|
||||
{
|
||||
mp_limb_t *p = f->_mpfr_d;
|
||||
mp_size_t n = (f->_mpfr_prec-1)/(sizeof(mp_limb_t)*CHAR_BIT)+1;
|
||||
M_HASH_DECL (h);
|
||||
|
||||
M_HASH_UP (h, f->_mpfr_exp);
|
||||
|
||||
if (MPFR_SIGN (f) < 0)
|
||||
M_HASH_UP (h, 1);
|
||||
|
||||
/* Special value: NAN, INF and ZERO */
|
||||
if (mpfr_nan_p (f) || mpfr_inf_p (f) || mpfr_zero_p (f))
|
||||
return M_HASH_FINAL (h);
|
||||
|
||||
/* Mantissa */
|
||||
do {
|
||||
M_HASH_UP (h, *p++);
|
||||
} while (--n > 0);
|
||||
return M_HASH_FINAL (h);
|
||||
}
|
||||
|
||||
/* Define the OPLIST of a mpfr_t and register it globally */
|
||||
#define M_OPL_mpfr_t() \
|
||||
(INIT(mpfr_init), INIT_SET(API(mpfr_init_set, VOID, ARG1, ARG2, MPFR_RNDN)), SET(API(mpfr_set, VOID, ARG1, ARG2, MPFR_RNDN)), CLEAR(mpfr_clear), \
|
||||
INIT_WITH(API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)), \
|
||||
EQUAL( API( mpfr_cmp, EQ(0), ARG1, ARG2)), \
|
||||
CMP(mpfr_cmp), \
|
||||
HASH(mpfr_fast_hash), \
|
||||
OUT_STR( API( mpfr_out_str, VOID, ARG1, 10, 0, ARG2, MPFR_RNDN)), \
|
||||
IN_STR( API( mpfr_inp_str, GT(0), ARG1, ARG2, 10, MPFR_RNDN)), \
|
||||
ADD( API(mpfr_add, VOID, ARG1, ARG2, ARG3, MPFR_RNDN)), \
|
||||
SUB( API(mpfr_sub, VOID, ARG1, ARG2, ARG3, MPFR_RNDN)), \
|
||||
MUL( API(mpfr_mul, VOID, ARG1, ARG2, ARG3, MPFR_RNDN)), \
|
||||
DIV( API(mpfr_div, VOID, ARG1, ARG2, ARG3, MPFR_RNDN)), \
|
||||
EMPLACE_TYPE( LIST( (_si, API(mpfr_init_set_si, VOID, ARG1, ARG2, MPFR_RNDN), int), \
|
||||
(_ui, API(mpfr_init_set_ui, VOID, ARG1, ARG2, MPFR_RNDN), unsigned), \
|
||||
(_d, API(mpfr_init_set_d, VOID, ARG1, ARG2, MPFR_RNDN), double), \
|
||||
(_ld, API(mpfr_init_set_ld, VOID, ARG1, ARG2, MPFR_RNDN), long double), \
|
||||
(_z, API(mpfr_init_set_z, VOID, ARG1, ARG2, MPFR_RNDN), mpz_t), \
|
||||
(_zptr, API(mpfr_init_set_z, VOID, ARG1, ARG2, MPFR_RNDN), mpz_ptr), \
|
||||
(_cstr, API(mpfr_init_set_str, VOID, ARG1, ARG2, 10, MPFR_RNDN), const char *), \
|
||||
(_str, API(mpfr_init_set_str, VOID, ARG1, ARG2, 10, MPFR_RNDN), char *) )), \
|
||||
TYPE(mpfr_t) )
|
||||
|
||||
|
||||
/* Define a variant over three kind of numbers named my_number_t
|
||||
Notice than mpz_t/mpfr_t has special init & clear functions.
|
||||
This is handle by the library.
|
||||
*/
|
||||
VARIANT_DEF2(my_number,
|
||||
(n, long long),
|
||||
(z, mpz_t),
|
||||
(fr, mpfr_t) )
|
||||
/* Define the oplist associated to this variant and register it */
|
||||
#define M_OPL_my_number_t() VARIANT_OPLIST(my_number, M_BASIC_OPLIST, M_OPL_mpz_t(), M_OPL_mpfr_t() )
|
||||
|
||||
|
||||
/* Define a dictionary of string_t --> my_number_t named my_dict_t */
|
||||
DICT_DEF2(my_dict, string_t, my_number_t)
|
||||
/* Define the oplist associated to this dictionary and register it */
|
||||
#define M_OPL_my_dict_t() DICT_OPLIST(my_dict, STRING_OPLIST, M_OPL_my_number_t() )
|
||||
|
||||
|
||||
/* Define an array of such dictionary named my_array_t */
|
||||
ARRAY_DEF(my_array, my_dict_t)
|
||||
/* Define the oplist associated to this array of dictionary of variant and register it */
|
||||
#define M_OPL_my_array_t() ARRAY_OPLIST(my_array, M_OPL_my_dict_t())
|
||||
|
||||
|
||||
// Show how to define an array of mpz_t & mpfr_t and some algorithms on then
|
||||
// (Not needed for the sequel of this example)
|
||||
ARRAY_DEF(array_mpz, mpz_t)
|
||||
#define M_OPL_array_mpz_t() ARRAY_OPLIST(array_mpz, M_OPL_mpz_t())
|
||||
ALGO_DEF(array_mpz, array_mpz_t)
|
||||
ARRAY_DEF(array_mpfr, mpfr_t)
|
||||
#define M_OPL_array_mpfr_t() ARRAY_OPLIST(array_mpfr, M_OPL_mpfr_t())
|
||||
ALGO_DEF(array_mpfr, array_mpfr_t)
|
||||
|
||||
static void
|
||||
compute_roots(array_mpfr_t roots, const array_mpz_t pol)
|
||||
{
|
||||
assert( array_mpz_size(pol) == 3);
|
||||
// Initialize mpfr_t variables from the mpz_t values in the array 'pol'
|
||||
// & clear then once the brackets end.
|
||||
M_LET( (a, (*array_mpz_get(pol, 0))),
|
||||
(b, (*array_mpz_get(pol, 1))),
|
||||
(c, (*array_mpz_get(pol, 2))),
|
||||
delta, tmp, mpfr_t) {
|
||||
// Reset the output array
|
||||
array_mpfr_reset(roots);
|
||||
// Compute the results
|
||||
mpfr_mul(delta, b, b, MPFR_RNDN);
|
||||
mpfr_mul_ui(tmp, a, 4, MPFR_RNDN);
|
||||
mpfr_mul(tmp, tmp, c, MPFR_RNDN);
|
||||
mpfr_sub(delta, delta, tmp, MPFR_RNDN);
|
||||
mpfr_sqrt(delta, delta, MPFR_RNDN);
|
||||
mpfr_neg(tmp, b, MPFR_RNDN);
|
||||
mpfr_add(tmp, tmp, delta, MPFR_RNDN);
|
||||
mpfr_div(tmp, tmp, a, MPFR_RNDN);
|
||||
mpfr_div_2ui(tmp, tmp, 1, MPFR_RNDN);
|
||||
// Push first root
|
||||
array_mpfr_push_back(roots, tmp);
|
||||
mpfr_neg(tmp, b, MPFR_RNDN);
|
||||
mpfr_sub(tmp, tmp, delta, MPFR_RNDN);
|
||||
mpfr_div(tmp, tmp, a, MPFR_RNDN);
|
||||
mpfr_div_2ui(tmp, tmp, 1, MPFR_RNDN);
|
||||
// Push second root
|
||||
array_mpfr_push_back(roots, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET(z, my_number_t) /* Define & init & clear an instance of a variant of my_number_t */
|
||||
M_LET(dict, my_dict_t) /* Define & init & clear an instance of a dictionary of variant */
|
||||
M_LET(array, my_array_t) /* Define & init & clear an intance of an array of dictionary of variant */
|
||||
M_LET(gmp, mpz_t) /* M_LET allows even with non container type */
|
||||
{
|
||||
my_number_set_n (z, 17LL); // Set z as the long long 17
|
||||
my_dict_set_at(dict, STRING_CTE("n1"), z); // Push it in the dictionary
|
||||
|
||||
mpz_set_str(gmp, "25446846874687468746874687468746874686874", 10); // Set gmp to a very long integer.
|
||||
my_number_set_z (z, gmp); // Set z as the mpz_t variable
|
||||
my_dict_set_at(dict, STRING_CTE("n2"), z); // Push it in the dictionary
|
||||
|
||||
my_array_push_back (array, dict); // Push the dictionary in the array
|
||||
|
||||
// Let's add a new element in the array through a mpfr_t set to 42.17
|
||||
M_LET( (fr, ("42.17")), mpfr_t) {
|
||||
my_number_set_fr(z, fr); // Set z as this variable.
|
||||
}
|
||||
my_dict_set_at(dict, STRING_CTE("n3"), z); // Push it in the dictionary
|
||||
|
||||
my_number_emplace_fr_si(z, 42); // Directly emplace the variant as a mpfr_t with a signed integer for init
|
||||
my_dict_set_at(dict, STRING_CTE("n4"), z); // Push it in the dictionary
|
||||
|
||||
my_number_emplace_z_ui(z, 189); // Directly emplace the variant as a mpz_t with an unsigned integer for init
|
||||
my_dict_set_at(dict, STRING_CTE("n5"), z); // Push it in the dictionary
|
||||
|
||||
my_array_push_back (array, dict); // Push the dictionary in the array
|
||||
|
||||
// Iterate over the array container
|
||||
for M_EACH(item, array, my_array_t) {
|
||||
// Iterate over the dictionary '*item' container which is of type my_dict_t
|
||||
for M_EACH(p, *item, my_dict_t) {
|
||||
// Dictionary iterator are pair (key,value)
|
||||
printf("Key is '%s'. ", string_get_cstr(p->key));
|
||||
// In function of the type of value
|
||||
if (my_number_n_p(p->value)) {
|
||||
printf ("It is a long long, value = %lld\n",
|
||||
*my_number_cget_n(p->value));
|
||||
}
|
||||
if (my_number_z_p(p->value)) {
|
||||
printf ("It is a mpz_t, value = ");
|
||||
mpz_out_str(stdout, 10, *my_number_cget_z(p->value));
|
||||
printf("\n");
|
||||
}
|
||||
if (my_number_fr_p(p->value)) {
|
||||
printf ("It is a mpfr_t, value = ");
|
||||
mpfr_out_str(stdout, 10, 0, *my_number_cget_fr(p->value), MPFR_RNDN);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
printf("Next element of array\n");
|
||||
}
|
||||
|
||||
// Print all the array in one step. Need to be done in C11 only
|
||||
M_PRINT("\nThe array is equal to ", (array, my_array_t), "\n");
|
||||
} /* All variables are automatically cleared beyond this point */
|
||||
|
||||
// Define an array of mpz_t as { 1, 2, 1 } (with auto promotion from integer)
|
||||
// The auto-promotion uses _Generic feature and is available only in C11.
|
||||
M_LET ( (az, (1), ("2"), (1.0)), array_mpz_t)
|
||||
M_LET ( roots, array_mpfr_t) {
|
||||
// Compute roots
|
||||
compute_roots(roots, az);
|
||||
// Display of roots:
|
||||
M_PRINT("Roots of ", (az, array_mpz_t), " are ", (roots, array_mpfr_t), "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
// Nothing to do
|
||||
int main(void) { return 0; }
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "m-rbtree.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Let's define a Red Black Tree over the constant C strings
|
||||
// Notice that we need to specify the oplist for this case
|
||||
// so that M*LIB handle the pointers to const char correctly.
|
||||
RBTREE_DEF(tree_cstr, const char *, M_CSTR_OPLIST)
|
||||
|
||||
// The classic C way
|
||||
// It is probably the best for beginner in M*LIB to start like this.
|
||||
static void classic1(void)
|
||||
{
|
||||
tree_cstr_t tree;
|
||||
|
||||
tree_cstr_init(tree);
|
||||
|
||||
tree_cstr_push (tree, "Hello");
|
||||
tree_cstr_push (tree, "World");
|
||||
tree_cstr_push (tree, "How");
|
||||
tree_cstr_push (tree, "Are");
|
||||
tree_cstr_push (tree, "You");
|
||||
|
||||
printf("\nUsing C string, the generated (sorted) tree is ");
|
||||
tree_cstr_out_str(stdout, tree);
|
||||
printf ("\n");
|
||||
|
||||
const char *present = tree_cstr_get(tree, "How") == NULL ? "not " : "";
|
||||
printf("The word 'How' is %spresent\n", present);
|
||||
|
||||
present = tree_cstr_get(tree, "Not") == NULL ? "not " : "";
|
||||
printf("The word 'Not' is %spresent\n", present);
|
||||
|
||||
tree_cstr_clear(tree);
|
||||
}
|
||||
|
||||
|
||||
// Let's define another Red Black Tree over the M*LIB strings
|
||||
// Notice that we don't need to specify the oplist for this case.
|
||||
RBTREE_DEF(tree_str, string_t)
|
||||
|
||||
// The classic C way
|
||||
// It is probably the best for beginner in M*LIB to start like this.
|
||||
static void classic2(void)
|
||||
{
|
||||
tree_str_t tree;
|
||||
|
||||
tree_str_init(tree);
|
||||
|
||||
// STRING_CTE enables to construct a temporary const string_t from a const char *
|
||||
// usable for function call.
|
||||
tree_str_push (tree, STRING_CTE("Hello"));
|
||||
tree_str_push (tree, STRING_CTE("World"));
|
||||
tree_str_push (tree, STRING_CTE("How"));
|
||||
tree_str_push (tree, STRING_CTE("Are"));
|
||||
tree_str_push (tree, STRING_CTE("You"));
|
||||
|
||||
printf("\nUsing M*LIB string_t, the generated (sorted) tree is ");
|
||||
tree_str_out_str(stdout, tree);
|
||||
printf ("\n");
|
||||
|
||||
const char *present = tree_str_get(tree, STRING_CTE("How")) == NULL ? "not " : "";
|
||||
printf("The word 'How' is %spresent\n", present);
|
||||
|
||||
present = tree_str_get(tree, STRING_CTE("Not")) == NULL ? "not " : "";
|
||||
printf("The word 'Not' is %spresent\n", present);
|
||||
|
||||
tree_str_clear(tree);
|
||||
}
|
||||
|
||||
|
||||
// Registering the oplist helps writting the macro
|
||||
// as we can only refer to the type in the macro.
|
||||
#define M_OPL_tree_str_t() RBTREE_OPLIST(tree_str, STRING_OPLIST)
|
||||
|
||||
static void macro(void)
|
||||
{
|
||||
// Using macro (shorter but may be unfamiliar syntax for novive with M*LIB)
|
||||
// This will declare the variable 'tree' as a 'tree_str_t' and initialize with
|
||||
// the given initialization list '("Hello"), ("World"), ("How"), ("Are"), ("You")'
|
||||
// The strings are given within '()' so that the constructor performs an emplace
|
||||
// of the value to push in the tree (to initialize a string_t with a const char * type)
|
||||
// instead of a push (which takes a compliant string_t as argument).
|
||||
// An alternative is to use STRING_CTE for the arguments.
|
||||
M_LET( (tree, ("Hello"), ("World"), ("How"), ("Are"), ("You")), tree_str_t) {
|
||||
// In C11, the M_PRINT macro allows the use of a simplified syntax for printing.
|
||||
M_PRINT("\nUsing M*LIB string_t + macro, the generated (sorted) tree is ", (tree, tree_str_t), "\n");
|
||||
|
||||
const char *present = tree_str_get(tree, STRING_CTE("How")) == NULL ? "not " : "";
|
||||
printf("The word 'How' is %spresent\n", present);
|
||||
|
||||
present = tree_str_get(tree, STRING_CTE("Not")) == NULL ? "not " : "";
|
||||
printf("The word 'Not' is %spresent\n", present);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
classic1();
|
||||
classic2();
|
||||
macro();
|
||||
return 0;
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
// Let's define a tuple composed of (offset, value) and register it
|
||||
TUPLE_DEF2(symbol, (offset, long), (value, long))
|
||||
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
// Let's define an array of such tuple and register it
|
||||
ARRAY_DEF(array_symbol, symbol_t)
|
||||
|
||||
+5
-5
@@ -12,14 +12,14 @@
|
||||
|
||||
// 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)
|
||||
#define M_OPL_Point_t() TUPLE_OPLIST(Point, M_BASIC_OPLIST, M_BASIC_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 M_OPL_cset_i_t() DICT_SET_OPLIST(cset_i, M_BASIC_OPLIST)
|
||||
|
||||
// Define an array of Point, register its oplist & include some basic algorithms
|
||||
ARRAY_DEF(cvec_p, Point_t)
|
||||
@@ -28,17 +28,17 @@ 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)
|
||||
#define M_OPL_cdeq_i_t() DEQUE_OPLIST(cdeq_i, M_BASIC_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)
|
||||
#define M_OPL_clist_i_t() LIST_OPLIST(clist_i, M_BASIC_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)
|
||||
#define M_OPL_csmap_i_t() DICT_OPLIST(csmap_i, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - ALGO module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -28,10 +28,10 @@
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define different kind of basic algorithms named 'name' over the container
|
||||
which oplist is 'contOp', as static inline functions.
|
||||
which oplist is 'cont_oplist', as static inline functions.
|
||||
USAGE:
|
||||
ALGO_DEF(algogName, containerOplist|type if oplist has been registered) */
|
||||
#define ALGO_DEF(name, cont_oplist) \
|
||||
#define M_ALGO_DEF(name, cont_oplist) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_ALG0_DEF_P1(name, M_GLOBAL_OPLIST(cont_oplist)) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -39,41 +39,45 @@
|
||||
|
||||
/* Map a function (or a macro) to all elements of a container.
|
||||
USAGE:
|
||||
ALGO_FOR_EACH(container, containerOplist, function[, extra arguments of function]) */
|
||||
#define ALGO_FOR_EACH(container, cont_oplist, ...) \
|
||||
ALGO_FOR_EACH(container, containerOplist|type_if_registered_oplist, function[, extra arguments of function]) */
|
||||
#define M_ALGO_FOR_EACH(container, cont_oplist, ...) \
|
||||
M_IF_NARGS_EQ1(__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__ ))
|
||||
(M_ALG0_FOR_EACH, 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
|
||||
into another container.
|
||||
and store it into another container.
|
||||
USAGE:
|
||||
ALGO_TRANSFORM(contDst, contDOplist, contSrc, contSrcOplist,
|
||||
ALGO_TRANSFORM(contDst, contDOplist|type_if_registered_oplist, contSrc, contSrcOplist|type_if_registered_oplist,
|
||||
function[, extra arguments of function]) */
|
||||
#define ALGO_TRANSFORM(contD, contDop, contS, contSop, ...) \
|
||||
#define M_ALGO_TRANSFORM(contD, contDop, contS, contSop, ...) \
|
||||
M_IF_NARGS_EQ1(__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__ ))
|
||||
(M_ALG0_TRANSFORM, 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
|
||||
ALGO_EXTRACT(contDst, contDstOplist|type_if_registered_oplist, contSrc, contSrcOplist|type_if_registered_oplist
|
||||
[, function [, extra arguments of function]]) */
|
||||
#define ALGO_EXTRACT(contD, contDop, contS, ...) \
|
||||
#define M_ALGO_EXTRACT(contD, contDop, contS, ...) \
|
||||
M_IF_NARGS_EQ1(__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__ )))
|
||||
(M_ALG0_EXTRACT, \
|
||||
M_IF_NARGS_EQ2(__VA_ARGS__)(M_ALG0_EXTRACT_FUNC, M_ALG0_EXTRACT_ARG)) \
|
||||
(contD, contDop, contS, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Perform a Reduce operation over a container.
|
||||
USAGE:
|
||||
ALGO_REDUCE(dstVar, container, contOplist, reduceFunc
|
||||
[, mapFunc[, extraParameters of map function]]) */
|
||||
#define ALGO_REDUCE(dest, cont, contOp, ...) \
|
||||
ALGO_REDUCE(dstVar, container, contOplist|type_if_registered_oplist, reduceFunc
|
||||
[, mapFunc[, extraParameters of map function]])
|
||||
or
|
||||
ALGO_REDUCE( (dstVar, dstOplist|type_if_registered_oplist), container, contOplist|type_if_registered_oplist, reduceFunc
|
||||
[, mapFunc[, extraParameters of map function]])
|
||||
if the destination variable is not of the same type than the elements of the containers.
|
||||
*/
|
||||
#define M_ALGO_REDUCE(dest, cont, contOp, ...) \
|
||||
M_IF(M_PARENTHESIS_P(dest)) \
|
||||
(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__)) \
|
||||
@@ -82,9 +86,9 @@
|
||||
/* 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)
|
||||
ALGO_INSERT_AT(containerDst, containerDstOPLIST|type_if_registered_oplist, containerDstIterator, containerSrc, containerSrcOPLIST|type_if_registered_oplist)
|
||||
*/
|
||||
#define ALGO_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) \
|
||||
#define M_ALGO_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) \
|
||||
M_ALG0_INSERT_AT(contDst, M_GLOBAL_OPLIST(contDstOp), position, contSrc, M_GLOBAL_OPLIST(contSrcOp) )
|
||||
|
||||
|
||||
@@ -505,7 +509,7 @@
|
||||
*/
|
||||
#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 */ \
|
||||
/* Find the next occurrence from it (included) of data */ \
|
||||
static inline void \
|
||||
M_C(name, _find_again) (it_t it, type_t const data) \
|
||||
{ \
|
||||
@@ -516,7 +520,7 @@
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Find the first occurence of data */ \
|
||||
/* Find the first occurrence of data */ \
|
||||
static inline void \
|
||||
M_C(name, _find) (it_t it, container_t const l, type_t const data) \
|
||||
{ \
|
||||
@@ -533,7 +537,7 @@
|
||||
return !M_CALL_IT_END_P(cont_oplist, it); \
|
||||
} \
|
||||
\
|
||||
/* Find the last occurence of data in the container */ \
|
||||
/* Find the last occurrence of data in the container */ \
|
||||
/* For the definition of _find_last, if the methods \
|
||||
PREVIOUS & IT_LAST are defined, then search backwards */ \
|
||||
M_IF_METHOD2(PREVIOUS, IT_LAST, cont_oplist) \
|
||||
@@ -550,7 +554,7 @@
|
||||
} \
|
||||
} \
|
||||
, \
|
||||
/* Otherwise search forward, but don't stop on the first occurence */ \
|
||||
/* Otherwise search forward, but don't stop on the first occurrence */ \
|
||||
static inline void \
|
||||
M_C(name, _find_last) (it_t it, container_t const l, type_t const data) \
|
||||
{ \
|
||||
@@ -566,7 +570,7 @@
|
||||
} \
|
||||
) /* End of alternative of _find_last */ \
|
||||
\
|
||||
/* Count the number of occurence of data in the container */ \
|
||||
/* Count the number of occurrence of data in the container */ \
|
||||
static inline size_t \
|
||||
M_C(name, _count) (container_t const l, type_t const data) \
|
||||
{ \
|
||||
@@ -613,7 +617,7 @@
|
||||
*/
|
||||
#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 */ \
|
||||
/* Find the next occurrence that matches the condition */ \
|
||||
static inline void \
|
||||
M_C3(name, _find_again_, suffix) (it_t it, test_t func) \
|
||||
{ \
|
||||
@@ -624,7 +628,7 @@
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Find the first occurence that matches the condition */ \
|
||||
/* Find the first occurrence that matches the condition */ \
|
||||
static inline void \
|
||||
M_C3(name, _find_, suffix) (it_t it, container_t l, test_t func) \
|
||||
{ \
|
||||
@@ -632,7 +636,7 @@
|
||||
M_C3(name, _find_again_, suffix)(it, func); \
|
||||
} \
|
||||
\
|
||||
/* Count the number of occurence that matches the condition */ \
|
||||
/* Count the number of occurrence that matches the condition */ \
|
||||
static inline size_t \
|
||||
M_C3(name, _count_, suffix) (container_t const l, test_t func) \
|
||||
{ \
|
||||
@@ -685,7 +689,7 @@
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Fill the container with exactly 'n' occurence of 'value' */ \
|
||||
/* Fill the container with exactly 'n' occurrence of 'value' */ \
|
||||
M_IF_METHOD(PUSH, cont_oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _fill_n) (container_t l, size_t n, type_t const value) \
|
||||
@@ -961,7 +965,7 @@
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc), \
|
||||
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
|
||||
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
|
||||
type_t const *srcItem = M_CALL_IT_REF(cont_oplist, itSrc); \
|
||||
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
|
||||
M_CALL_ADD(type_oplist, *dstItem, *dstItem, *srcItem); \
|
||||
} \
|
||||
} \
|
||||
@@ -979,7 +983,7 @@
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc), \
|
||||
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
|
||||
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
|
||||
type_t const *srcItem = M_CALL_IT_REF(cont_oplist, itSrc); \
|
||||
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
|
||||
M_CALL_SUB(type_oplist, *dstItem, *dstItem, *srcItem); \
|
||||
} \
|
||||
} \
|
||||
@@ -997,7 +1001,7 @@
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc), \
|
||||
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
|
||||
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
|
||||
type_t const *srcItem = M_CALL_IT_REF(cont_oplist, itSrc); \
|
||||
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
|
||||
M_CALL_MUL(type_oplist, *dstItem, *dstItem, *srcItem); \
|
||||
} \
|
||||
} \
|
||||
@@ -1015,7 +1019,7 @@
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc), \
|
||||
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
|
||||
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
|
||||
type_t const *srcItem = M_CALL_IT_REF(cont_oplist, itSrc); \
|
||||
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
|
||||
M_CALL_DIV(type_oplist, *dstItem, *dstItem, *srcItem); \
|
||||
} \
|
||||
} \
|
||||
@@ -1067,8 +1071,9 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
#define M_ALG0_EXTRACT(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist) do { \
|
||||
#define M_ALG0_EXTRACT(contDst, contDstOplist, contSrc, contSrcOplist) \
|
||||
M_ALG0_EXTRACT_P1(contDst, M_GLOBAL_OPLIST(contDstOplist), contSrc, M_GLOBAL_OPLIST(contSrcOplist))
|
||||
#define M_ALG0_EXTRACT_P1(contDst, contDstOplist, contSrc, contSrcOplist) do{ \
|
||||
M_CALL_RESET(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
M_IF_METHOD(PUSH, contDstOplist)( \
|
||||
@@ -1080,8 +1085,9 @@
|
||||
M_IF_METHOD(REVERSE, contDstOplist) (M_CALL_REVERSE(contDstOplist, contDst);, ) \
|
||||
} while (0)
|
||||
|
||||
#define M_ALG0_EXTRACT_FUNC(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist, \
|
||||
#define M_ALG0_EXTRACT_FUNC(contDst, contDstOplist, contSrc, contSrcOplist, condFunc) \
|
||||
M_ALG0_EXTRACT_FUNC_P1(contDst, M_GLOBAL_OPLIST(contDstOplist), contSrc, M_GLOBAL_OPLIST(contSrcOplist), condFunc)
|
||||
#define M_ALG0_EXTRACT_FUNC_P1(contDst, contDstOplist, contSrc, contSrcOplist, \
|
||||
condFunc) do { \
|
||||
M_CALL_RESET(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
@@ -1096,8 +1102,11 @@
|
||||
M_IF_METHOD(REVERSE, contDstOplist) (M_CALL_REVERSE(contDstOplist, contDst);, ) \
|
||||
} while (0)
|
||||
|
||||
#define M_ALG0_EXTRACT_ARG(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist, \
|
||||
#define M_ALG0_EXTRACT_ARG(contDst, contDstOplist, contSrc, contSrcOplist, \
|
||||
condFunc, ...) \
|
||||
M_ALG0_EXTRACT_ARG_P1(contDst, M_GLOBAL_OPLIST(contDstOplist), contSrc, M_GLOBAL_OPLIST(contSrcOplist), \
|
||||
condFunc, __VA_ARGS__)
|
||||
#define M_ALG0_EXTRACT_ARG_P1(contDst, contDstOplist, contSrc, contSrcOplist, \
|
||||
condFunc, ...) do { \
|
||||
M_CALL_RESET(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
@@ -1200,4 +1209,14 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define ALGO_DEF M_ALGO_DEF
|
||||
#define ALGO_FOR_EACH M_ALGO_FOR_EACH
|
||||
#define ALGO_TRANSFORM M_ALGO_TRANSFORM
|
||||
#define ALGO_EXTRACT M_ALGO_EXTRACT
|
||||
#define ALGO_REDUCE M_ALGO_REDUCE
|
||||
#define ALGO_INSERT_AT M_ALGO_INSERT_AT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - dynamic ARRAY module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -29,14 +29,14 @@
|
||||
|
||||
/* 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, ...) \
|
||||
ARRAY_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
#define M_ARRAY_DEF(name, ...) \
|
||||
M_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
|
||||
as the provided type name_t with the iterator named it_t
|
||||
USAGE: ARRAY_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define ARRAY_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_ARRAY_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_ARRA4_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
@@ -45,11 +45,11 @@
|
||||
|
||||
|
||||
/* Define the oplist of a dynamic array given its name and its oplist.
|
||||
If no oplist is given it is assumed to be M_DEFAULT_OPLIST
|
||||
If no oplist is given it is assumed to be M_BASIC_OPLIST
|
||||
USAGE: ARRAY_OPLIST(name[, oplist of the type]) */
|
||||
#define ARRAY_OPLIST(...) \
|
||||
#define M_ARRAY_OPLIST(...) \
|
||||
M_ARRA4_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
USAGE:
|
||||
array_t global_variable = ARRAY_INIT_VALUE();
|
||||
*/
|
||||
#define ARRAY_INIT_VALUE() \
|
||||
#define M_ARRAY_INIT_VALUE() \
|
||||
{ { 0, 0, NULL } }
|
||||
|
||||
/********************************************************************************/
|
||||
@@ -109,7 +109,7 @@
|
||||
,RESET(M_C(name,_reset)) \
|
||||
,KEY_TYPE(size_t) \
|
||||
,VALUE_TYPE(M_C(name, _subtype_ct)) \
|
||||
,KEY_OPLIST(M_DEFAULT_OPLIST) \
|
||||
,KEY_OPLIST(M_BASIC_OPLIST) \
|
||||
,VALUE_OPLIST(oplist) \
|
||||
,M_IF_METHOD(SET, oplist)(SET_KEY(M_C(name, _set_at)) ,) \
|
||||
,GET_KEY(M_C(name, _get)) \
|
||||
@@ -144,8 +144,12 @@
|
||||
} while (0)
|
||||
|
||||
/* Deferred evaluation for the array definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_ARRA4_DEF_P1(arg) M_ARRA4_DEF_P2 arg
|
||||
so that all arguments are fully evaluated before further expansion
|
||||
(ensuring good performance)
|
||||
and performed a final step evaluation of the returning expansion
|
||||
(ensuring delayed evaluation are still expanded)
|
||||
*/
|
||||
#define M_ARRA4_DEF_P1(arg) M_ID( M_ARRA4_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_ARRA4_DEF_P2(name, type, oplist, array_t, it_t) \
|
||||
@@ -207,12 +211,6 @@
|
||||
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) \
|
||||
{ \
|
||||
@@ -483,11 +481,6 @@
|
||||
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)( \
|
||||
@@ -821,10 +814,9 @@
|
||||
if (m_core_clz64(size-1) & 1) \
|
||||
th += th; \
|
||||
\
|
||||
/* Pass 1: insertion sort (stable) */ \
|
||||
/* Pass 1: Partial insertion sort (stable) up to 'th' size */ \
|
||||
for(size_t k = 0 ; k < size; ) { \
|
||||
size_t max = size - k < 2*th ? size - k : th; \
|
||||
M_ASSUME(max >= th); \
|
||||
for(size_t i = 1; i < max; i++) { \
|
||||
size_t j = i; \
|
||||
while (j > 0 && M_CALL_CMP(oplist, tab[k+j-1], tab[k+j]) > 0) { \
|
||||
@@ -838,7 +830,7 @@
|
||||
/* N Pass of merge sort (stable) */ \
|
||||
while (th < size) { \
|
||||
type *dest = tmp; \
|
||||
/* Pass n: Merge */ \
|
||||
/* Pass n: Merge 2 sections of 'th' elements */ \
|
||||
for(size_t k = 0 ; k < size; ) { \
|
||||
type *el1 = &tab[k]; \
|
||||
type *el2 = &tab[k+th]; \
|
||||
@@ -850,10 +842,10 @@
|
||||
k += n1+n2; \
|
||||
for (;;) { \
|
||||
if (M_CALL_CMP(oplist, *el1, *el2) <= 0) { \
|
||||
M_CALL_SET(oplist, *dest, *el1); \
|
||||
M_DO_INIT_MOVE(oplist, *dest, *el1); \
|
||||
dest++; \
|
||||
el1++; \
|
||||
if (-- n1 == 0) { \
|
||||
if (M_UNLIKELY(-- n1 == 0)) { \
|
||||
if (n2 > 0) { \
|
||||
memcpy (dest, el2, n2 * sizeof (type)); \
|
||||
dest += n2; \
|
||||
@@ -861,10 +853,10 @@
|
||||
break; \
|
||||
} \
|
||||
} else { \
|
||||
M_CALL_SET(oplist, *dest, *el2); \
|
||||
M_DO_INIT_MOVE(oplist, *dest, *el2); \
|
||||
dest++; \
|
||||
el2++; \
|
||||
if (-- n2 == 0) { \
|
||||
if (M_UNLIKELY(-- n2 == 0)) { \
|
||||
if (n1 > 0) { \
|
||||
memcpy (dest, el1, n1 * sizeof (type)); \
|
||||
dest += n1; \
|
||||
@@ -903,11 +895,11 @@
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, array_t const array, \
|
||||
M_C(name, _get_str)(m_string_t str, array_t const array, \
|
||||
bool append) \
|
||||
{ \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
|
||||
it_t it; \
|
||||
for (M_C(name, _it)(it, array) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
@@ -915,9 +907,9 @@
|
||||
type const *item = M_C(name, _cref)(it); \
|
||||
M_CALL_GET_STR(oplist, str, *item, true); \
|
||||
if (!M_C(name, _last_p)(it)) \
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
m_string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
m_string_push_back (str, ']'); \
|
||||
} \
|
||||
, /* no GET_STR */ ) \
|
||||
\
|
||||
@@ -1105,5 +1097,26 @@
|
||||
a1->size = newSize; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, array_t, M_C(name, _emplace_back), oplist, M_ARRA4_EMPLACE_DEF)
|
||||
|
||||
/* Definition of the emplace_back function for arrays */
|
||||
#define M_ARRA4_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
static inline void \
|
||||
function_name(name_t v \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_C(name, _subtype_ct) *data = M_C(name, _push_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
} \
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define ARRAY_DEF M_ARRAY_DEF
|
||||
#define ARRAY_DEF_AS M_ARRAY_DEF_AS
|
||||
#define ARRAY_OPLIST M_ARRAY_OPLIST
|
||||
#define ARRAY_INIT_VALUE M_ARRAY_INIT_VALUE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin stdatomic wrapper for C++ compatibility
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
|
||||
+244
-162
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - BITSET module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -33,9 +33,9 @@
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
// Define the basic limb of a bitset
|
||||
typedef uint64_t bitset_limb_ct;
|
||||
typedef uint64_t m_b1tset_limb_ct;
|
||||
// And its size in bits
|
||||
#define M_B1TSET_LIMB_BIT (sizeof(bitset_limb_ct) * CHAR_BIT)
|
||||
#define M_B1TSET_LIMB_BIT (sizeof(m_b1tset_limb_ct) * CHAR_BIT)
|
||||
|
||||
// bitset grow policy. n is limb size
|
||||
#define M_B1TSET_INC_ALLOC_SIZE(n) ((n) < 4 ? 4 : (n) * 2)
|
||||
@@ -54,35 +54,35 @@ typedef uint64_t bitset_limb_ct;
|
||||
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); \
|
||||
M_ASSERT ((t->size % M_B1TSET_LIMB_BIT) == 0 || (t->ptr[ (t->size-1) / M_B1TSET_LIMB_BIT] & ~(((((m_b1tset_limb_ct)1)<<(t->size % M_B1TSET_LIMB_BIT))<<1)-1)) == 0); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/********************************** EXTERNAL ************************************/
|
||||
|
||||
/* Define a type of variable 'bits' or array of packed booleans */
|
||||
typedef struct bitset_s {
|
||||
typedef struct m_bitset_s {
|
||||
size_t size; // Size is the number of bits
|
||||
size_t alloc; // Alloc is the number of allocated limbs
|
||||
bitset_limb_ct *ptr; // Pointer to the allocated limbs
|
||||
} bitset_t[1];
|
||||
m_b1tset_limb_ct *ptr; // Pointer to the allocated limbs
|
||||
} m_bitset_t[1];
|
||||
|
||||
/* Pointer to a bitset_t */
|
||||
typedef struct bitset_s *bitset_ptr;
|
||||
/* Pointer to a m_bitset_t */
|
||||
typedef struct m_bitset_s *m_bitset_ptr;
|
||||
|
||||
/* Constant Pointer to a bitset_t */
|
||||
typedef const struct bitset_s *bitset_srcptr;
|
||||
/* Constant Pointer to a m_bitset_t */
|
||||
typedef const struct m_bitset_s *m_bitset_srcptr;
|
||||
|
||||
/* Iterator on a bitset */
|
||||
typedef struct bitset_it_s {
|
||||
typedef struct m_bitset_it_s {
|
||||
size_t index; // index to the array of bit
|
||||
bool value; // value used for _ref & _cref to store the value
|
||||
struct bitset_s *set; // the associated bitset
|
||||
} bitset_it_t[1];
|
||||
struct m_bitset_s *set; // the associated bitset
|
||||
} m_bitset_it_t[1];
|
||||
|
||||
/* Initialize a bitset (CONSTRUCTOR) */
|
||||
static inline void
|
||||
bitset_init(bitset_t t)
|
||||
m_bitset_init(m_bitset_t t)
|
||||
{
|
||||
M_ASSERT (t != NULL);
|
||||
M_STATIC_ASSERT (M_POWEROF2_P(M_B1TSET_LIMB_BIT), MLIB_INTERNAL, "M*LIB: BITSET LIMB shall be a power of 2.");
|
||||
@@ -94,23 +94,17 @@ bitset_init(bitset_t t)
|
||||
|
||||
/* Clean a bitset */
|
||||
static inline void
|
||||
bitset_reset(bitset_t t)
|
||||
m_bitset_reset(m_bitset_t t)
|
||||
{
|
||||
M_B1TSET_CONTRACT(t);
|
||||
t->size = 0;
|
||||
}
|
||||
|
||||
static inline void M_ATTR_DEPRECATED
|
||||
bitset_clean(bitset_t t)
|
||||
{
|
||||
bitset_reset(t);
|
||||
}
|
||||
|
||||
/* Clear a bitset (DESTRUCTOR) */
|
||||
static inline void
|
||||
bitset_clear(bitset_t t)
|
||||
m_bitset_clear(m_bitset_t t)
|
||||
{
|
||||
bitset_reset(t);
|
||||
m_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.
|
||||
@@ -121,14 +115,14 @@ bitset_clear(bitset_t t)
|
||||
|
||||
/* Set a bitset to another one */
|
||||
static inline void
|
||||
bitset_set(bitset_t d, const bitset_t s)
|
||||
m_bitset_set(m_bitset_t d, const m_bitset_t s)
|
||||
{
|
||||
M_B1TSET_CONTRACT(d);
|
||||
M_B1TSET_CONTRACT(s);
|
||||
if (M_UNLIKELY (d == s)) return;
|
||||
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);
|
||||
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, d->ptr, needAlloc);
|
||||
if (M_UNLIKELY (ptr == NULL)) {
|
||||
M_MEMORY_FULL(needAlloc);
|
||||
return ;
|
||||
@@ -136,23 +130,23 @@ bitset_set(bitset_t d, const bitset_t s)
|
||||
d->ptr = ptr;
|
||||
d->alloc = needAlloc;
|
||||
}
|
||||
memcpy (d->ptr, s->ptr, needAlloc * sizeof(bitset_limb_ct) );
|
||||
memcpy (d->ptr, s->ptr, needAlloc * sizeof(m_b1tset_limb_ct) );
|
||||
d->size = s->size;
|
||||
M_B1TSET_CONTRACT(d);
|
||||
}
|
||||
|
||||
/* Initialize & set a bitset to another one (CONSTRUCTOR) */
|
||||
static inline void
|
||||
bitset_init_set(bitset_t d, const bitset_t s)
|
||||
m_bitset_init_set(m_bitset_t d, const m_bitset_t s)
|
||||
{
|
||||
M_ASSERT (d != s);
|
||||
bitset_init(d);
|
||||
bitset_set(d, s);
|
||||
m_bitset_init(d);
|
||||
m_bitset_set(d, s);
|
||||
}
|
||||
|
||||
/* Initialize & move a bitset (CONSTRUCTOR) from another one (DESTRUCTOR) */
|
||||
static inline void
|
||||
bitset_init_move(bitset_t d, bitset_t s)
|
||||
m_bitset_init_move(m_bitset_t d, m_bitset_t s)
|
||||
{
|
||||
M_B1TSET_CONTRACT(s);
|
||||
d->size = s->size;
|
||||
@@ -166,15 +160,15 @@ bitset_init_move(bitset_t d, bitset_t s)
|
||||
|
||||
/* Move a bitset from another one (DESTRUCTOR) */
|
||||
static inline void
|
||||
bitset_move(bitset_t d, bitset_t s)
|
||||
m_bitset_move(m_bitset_t d, m_bitset_t s)
|
||||
{
|
||||
bitset_clear(d);
|
||||
bitset_init_move (d, s);
|
||||
m_bitset_clear(d);
|
||||
m_bitset_init_move (d, s);
|
||||
}
|
||||
|
||||
/* Set the bit 'i' in the bitset to the value 'x' */
|
||||
static inline void
|
||||
bitset_set_at(bitset_t v, size_t i, bool x)
|
||||
m_bitset_set_at(m_bitset_t v, size_t i, bool x)
|
||||
{
|
||||
M_B1TSET_CONTRACT(v);
|
||||
M_ASSERT (v->ptr != NULL);
|
||||
@@ -182,27 +176,27 @@ bitset_set_at(bitset_t v, size_t i, bool x)
|
||||
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));
|
||||
const m_b1tset_limb_ct mask = ((m_b1tset_limb_ct)1)<<index;
|
||||
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (0-(m_b1tset_limb_ct)x));
|
||||
M_B1TSET_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Flip the bit 'i' in the bitset */
|
||||
static inline void
|
||||
bitset_flip_at(bitset_t v, size_t i)
|
||||
m_bitset_flip_at(m_bitset_t v, size_t i)
|
||||
{
|
||||
M_B1TSET_CONTRACT(v);
|
||||
M_ASSERT (v->ptr != NULL);
|
||||
M_ASSERT_INDEX(i, v->size);
|
||||
size_t offset = i / M_B1TSET_LIMB_BIT;
|
||||
size_t index = i % M_B1TSET_LIMB_BIT;
|
||||
v->ptr[offset] ^= ((bitset_limb_ct)1)<<index;
|
||||
v->ptr[offset] ^= ((m_b1tset_limb_ct)1)<<index;
|
||||
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)
|
||||
m_bitset_push_back (m_bitset_t v, bool x)
|
||||
{
|
||||
M_B1TSET_CONTRACT (v);
|
||||
if (M_UNLIKELY (v->size >= M_B1TSET_FROM_ALLOC (v->alloc))) {
|
||||
@@ -210,14 +204,14 @@ bitset_push_back (bitset_t v, bool x)
|
||||
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));
|
||||
M_MEMORY_FULL(needAlloc * sizeof(m_b1tset_limb_ct));
|
||||
return;
|
||||
}
|
||||
// Alloc memory
|
||||
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, v->ptr, needAlloc);
|
||||
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, needAlloc);
|
||||
// Check if success
|
||||
if (M_UNLIKELY (ptr == NULL) ) {
|
||||
M_MEMORY_FULL(needAlloc * sizeof(bitset_limb_ct));
|
||||
M_MEMORY_FULL(needAlloc * sizeof(m_b1tset_limb_ct));
|
||||
return;
|
||||
}
|
||||
v->ptr = ptr;
|
||||
@@ -233,15 +227,15 @@ bitset_push_back (bitset_t v, bool x)
|
||||
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));
|
||||
const m_b1tset_limb_ct mask = ((m_b1tset_limb_ct)1)<<index;
|
||||
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (0-(m_b1tset_limb_ct)x));
|
||||
v->size ++;
|
||||
M_B1TSET_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Resize the bitset to have exactly 'size' bits */
|
||||
static inline void
|
||||
bitset_resize (bitset_t v, size_t size)
|
||||
m_bitset_resize (m_bitset_t v, size_t size)
|
||||
{
|
||||
M_B1TSET_CONTRACT (v);
|
||||
// Check for overflow
|
||||
@@ -253,9 +247,9 @@ bitset_resize (bitset_t v, size_t 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);
|
||||
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, newAlloc);
|
||||
if (M_UNLIKELY (ptr == NULL) ) {
|
||||
M_MEMORY_FULL(newAlloc * sizeof(bitset_limb_ct));
|
||||
M_MEMORY_FULL(newAlloc * sizeof(m_b1tset_limb_ct));
|
||||
return;
|
||||
}
|
||||
v->ptr = ptr;
|
||||
@@ -265,7 +259,7 @@ bitset_resize (bitset_t v, size_t size)
|
||||
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;
|
||||
const m_b1tset_limb_ct mask = (((m_b1tset_limb_ct)1)<<index)-1;
|
||||
if (size < old_size) {
|
||||
// Resize down the bitset: clear unused bits
|
||||
if (M_LIKELY(index != 0)) {
|
||||
@@ -274,8 +268,8 @@ bitset_resize (bitset_t v, size_t size)
|
||||
}
|
||||
} 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++) {
|
||||
const size_t old_offset = (old_size + M_B1TSET_LIMB_BIT - 1)/ M_B1TSET_LIMB_BIT;
|
||||
for(size_t i = old_offset ; i < offset; i++) {
|
||||
v->ptr[i] = 0;
|
||||
}
|
||||
if (M_LIKELY(index != 0)) {
|
||||
@@ -289,7 +283,7 @@ bitset_resize (bitset_t v, size_t size)
|
||||
|
||||
/* Reserve allocation in the bitset to accomodate at least 'size' bits without reallocation */
|
||||
static inline void
|
||||
bitset_reserve (bitset_t v, size_t alloc)
|
||||
m_bitset_reserve (m_bitset_t v, size_t alloc)
|
||||
{
|
||||
M_B1TSET_CONTRACT (v);
|
||||
size_t oldAlloc = M_B1TSET_TO_ALLOC (v->size);
|
||||
@@ -305,9 +299,9 @@ bitset_reserve (bitset_t v, size_t alloc)
|
||||
v->ptr = NULL;
|
||||
} else {
|
||||
// Allocate more memory or reduce memory usage
|
||||
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, v->ptr, newAlloc);
|
||||
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, newAlloc);
|
||||
if (M_UNLIKELY (ptr == NULL) ) {
|
||||
M_MEMORY_FULL(newAlloc * sizeof(bitset_limb_ct));
|
||||
M_MEMORY_FULL(newAlloc * sizeof(m_b1tset_limb_ct));
|
||||
return;
|
||||
}
|
||||
v->ptr = ptr;
|
||||
@@ -321,22 +315,22 @@ bitset_reserve (bitset_t v, size_t alloc)
|
||||
* It doesn't return a pointer to the data, but the data itself.
|
||||
*/
|
||||
static inline bool
|
||||
bitset_get(const bitset_t v, size_t i)
|
||||
m_bitset_get(const m_bitset_t v, size_t i)
|
||||
{
|
||||
M_B1TSET_CONTRACT(v);
|
||||
M_ASSERT (v->ptr != NULL);
|
||||
M_ASSERT_INDEX(i, v->size);
|
||||
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;
|
||||
return ( v->ptr[offset] & (((m_b1tset_limb_ct)1) << index) ) != 0;
|
||||
}
|
||||
|
||||
/* bitset_cget is the exact same service than bitset_get */
|
||||
#define bitset_cget bitset_get
|
||||
/* m_bitset_cget is the exact same service than m_bitset_get */
|
||||
#define m_bitset_cget m_bitset_get
|
||||
|
||||
/* Pop back the last bit in the bitset */
|
||||
static inline void
|
||||
bitset_pop_back(bool *dest, bitset_t v)
|
||||
m_bitset_pop_back(bool *dest, m_bitset_t v)
|
||||
{
|
||||
M_B1TSET_CONTRACT (v);
|
||||
M_ASSERT_INDEX (0, v->size);
|
||||
@@ -345,7 +339,7 @@ bitset_pop_back(bool *dest, bitset_t 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;
|
||||
const m_b1tset_limb_ct mask = ((m_b1tset_limb_ct)1)<<index;
|
||||
if (dest) {
|
||||
// Read popped bit
|
||||
*dest = (v->ptr[offset] & mask) != 0;
|
||||
@@ -356,25 +350,25 @@ bitset_pop_back(bool *dest, bitset_t v)
|
||||
|
||||
/* Return the front bit value in the bitset */
|
||||
static inline bool
|
||||
bitset_front(bitset_t v)
|
||||
m_bitset_front(m_bitset_t v)
|
||||
{
|
||||
M_B1TSET_CONTRACT (v);
|
||||
M_ASSERT_INDEX (0, v->size);
|
||||
return bitset_get(v, 0);
|
||||
return m_bitset_get(v, 0);
|
||||
}
|
||||
|
||||
/* Return the back bit value in the bitset */
|
||||
static inline bool
|
||||
bitset_back(bitset_t v)
|
||||
m_bitset_back(m_bitset_t v)
|
||||
{
|
||||
M_B1TSET_CONTRACT (v);
|
||||
M_ASSERT_INDEX (0, v->size);
|
||||
return bitset_get(v, v->size-1);
|
||||
return m_bitset_get(v, v->size-1);
|
||||
}
|
||||
|
||||
/* Test if the bitset is empty (no bits stored)*/
|
||||
static inline bool
|
||||
bitset_empty_p(bitset_t v)
|
||||
m_bitset_empty_p(m_bitset_t v)
|
||||
{
|
||||
M_B1TSET_CONTRACT (v);
|
||||
return v->size == 0;
|
||||
@@ -382,7 +376,7 @@ bitset_empty_p(bitset_t v)
|
||||
|
||||
/* Return the number of bits of the bitset */
|
||||
static inline size_t
|
||||
bitset_size(bitset_t v)
|
||||
m_bitset_size(m_bitset_t v)
|
||||
{
|
||||
M_B1TSET_CONTRACT (v);
|
||||
return v->size;
|
||||
@@ -390,7 +384,7 @@ bitset_size(bitset_t v)
|
||||
|
||||
/* Return the capacity in limbs of the bitset */
|
||||
static inline size_t
|
||||
bitset_capacity(bitset_t v)
|
||||
m_bitset_capacity(m_bitset_t v)
|
||||
{
|
||||
M_B1TSET_CONTRACT (v);
|
||||
return M_B1TSET_FROM_ALLOC (v->alloc);
|
||||
@@ -398,26 +392,26 @@ bitset_capacity(bitset_t v)
|
||||
|
||||
/* 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)
|
||||
m_bitset_swap_at (m_bitset_t v, size_t i, size_t j)
|
||||
{
|
||||
M_ASSERT_INDEX(i, v->size);
|
||||
M_ASSERT_INDEX(j, v->size);
|
||||
|
||||
bool i_val = bitset_get(v, i);
|
||||
bool j_val = bitset_get(v, j);
|
||||
bitset_set_at (v, i, j_val);
|
||||
bitset_set_at (v, j, i_val);
|
||||
bool i_val = m_bitset_get(v, i);
|
||||
bool j_val = m_bitset_get(v, j);
|
||||
m_bitset_set_at (v, i, j_val);
|
||||
m_bitset_set_at (v, j, i_val);
|
||||
}
|
||||
|
||||
/* Swap the bitsets */
|
||||
static inline void
|
||||
bitset_swap (bitset_t v1, bitset_t v2)
|
||||
m_bitset_swap (m_bitset_t v1, m_bitset_t 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_SWAP (m_b1tset_limb_ct *, v1->ptr, v2->ptr);
|
||||
M_B1TSET_CONTRACT (v1);
|
||||
M_B1TSET_CONTRACT (v2);
|
||||
}
|
||||
@@ -426,11 +420,11 @@ bitset_swap (bitset_t v1, bitset_t v2)
|
||||
* integrating the carry in the lowest position.
|
||||
* Return the new carry.
|
||||
*/
|
||||
static inline bitset_limb_ct
|
||||
m_b1tset_lshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
|
||||
static inline m_b1tset_limb_ct
|
||||
m_b1tset_lshift(m_b1tset_limb_ct ptr[], size_t n, m_b1tset_limb_ct carry)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
bitset_limb_ct v = ptr[i];
|
||||
m_b1tset_limb_ct v = ptr[i];
|
||||
ptr[i] = (v << 1) | carry;
|
||||
carry = (v >> (M_B1TSET_LIMB_BIT-1) );
|
||||
}
|
||||
@@ -441,11 +435,11 @@ m_b1tset_lshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
|
||||
* integrating the carry in the lowest position.
|
||||
* Return the new carry.
|
||||
*/
|
||||
static inline bitset_limb_ct
|
||||
m_b1tset_rshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
|
||||
static inline m_b1tset_limb_ct
|
||||
m_b1tset_rshift(m_b1tset_limb_ct ptr[], size_t n, m_b1tset_limb_ct carry)
|
||||
{
|
||||
for(size_t i = n - 1; i < n; i--) {
|
||||
bitset_limb_ct v = ptr[i];
|
||||
m_b1tset_limb_ct v = ptr[i];
|
||||
ptr[i] = (v >> 1) | (carry << (M_B1TSET_LIMB_BIT-1) );
|
||||
carry = v & 1;
|
||||
}
|
||||
@@ -455,20 +449,20 @@ m_b1tset_rshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
|
||||
/* 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)
|
||||
m_bitset_push_at(m_bitset_t set, size_t key, bool value)
|
||||
{
|
||||
M_B1TSET_CONTRACT (set);
|
||||
// First push another value to extend the array to the right size
|
||||
bitset_push_back(set, false);
|
||||
m_bitset_push_back(set, false);
|
||||
M_ASSERT (set->ptr != NULL);
|
||||
M_ASSERT_INDEX(key, set->size);
|
||||
|
||||
// Then shift it
|
||||
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 >> (M_B1TSET_LIMB_BIT-1) );
|
||||
m_b1tset_limb_ct v = set->ptr[offset];
|
||||
m_b1tset_limb_ct mask = (((m_b1tset_limb_ct)1)<<index)-1;
|
||||
m_b1tset_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 + M_B1TSET_LIMB_BIT - 1) / M_B1TSET_LIMB_BIT;
|
||||
@@ -483,23 +477,23 @@ bitset_push_at(bitset_t set, size_t key, bool value)
|
||||
/* Pop a new bit at position 'key' in the bitset
|
||||
* and return in *dest its value if *dest exists */
|
||||
static inline void
|
||||
bitset_pop_at(bool *dest, bitset_t set, size_t key)
|
||||
m_bitset_pop_at(bool *dest, m_bitset_t set, size_t key)
|
||||
{
|
||||
M_B1TSET_CONTRACT (set);
|
||||
M_ASSERT (set->ptr != NULL);
|
||||
M_ASSERT_INDEX(key, set->size);
|
||||
|
||||
if (dest) {
|
||||
*dest = bitset_get (set, key);
|
||||
*dest = m_bitset_get (set, key);
|
||||
}
|
||||
// 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;
|
||||
m_b1tset_limb_ct v, mask, carry;
|
||||
carry = m_b1tset_rshift(&set->ptr[offset+1], size - offset - 1, false);
|
||||
v = set->ptr[offset];
|
||||
mask = (((bitset_limb_ct)1)<<index)-1;
|
||||
mask = (((m_b1tset_limb_ct)1)<<index)-1;
|
||||
v = (v & mask) | ((v>>1) & ~mask) | (carry << (M_B1TSET_LIMB_BIT-1)) ;
|
||||
set->ptr[offset] = v;
|
||||
// Decrease size
|
||||
@@ -509,7 +503,7 @@ bitset_pop_at(bool *dest, bitset_t set, size_t key)
|
||||
|
||||
/* Test if two bitsets are equal */
|
||||
static inline bool
|
||||
bitset_equal_p (const bitset_t set1, const bitset_t set2)
|
||||
m_bitset_equal_p (const m_bitset_t set1, const m_bitset_t set2)
|
||||
{
|
||||
M_B1TSET_CONTRACT (set1);
|
||||
M_B1TSET_CONTRACT (set2);
|
||||
@@ -526,7 +520,7 @@ bitset_equal_p (const bitset_t set1, const bitset_t set2)
|
||||
|
||||
/* Initialize an iterator to the first bit of the biset */
|
||||
static inline void
|
||||
bitset_it(bitset_it_t it, bitset_t set)
|
||||
m_bitset_it(m_bitset_it_t it, m_bitset_t set)
|
||||
{
|
||||
M_B1TSET_CONTRACT (set);
|
||||
it->index = 0;
|
||||
@@ -535,7 +529,7 @@ bitset_it(bitset_it_t it, bitset_t set)
|
||||
|
||||
/* Initialize an iterator to reference the same bit as the given one*/
|
||||
static inline void
|
||||
bitset_it_set(bitset_it_t it, const bitset_it_t itorg)
|
||||
m_bitset_it_set(m_bitset_it_t it, const m_bitset_it_t itorg)
|
||||
{
|
||||
M_ASSERT (it != NULL && itorg != NULL);
|
||||
it->index = itorg->index;
|
||||
@@ -544,7 +538,7 @@ bitset_it_set(bitset_it_t it, const bitset_it_t itorg)
|
||||
|
||||
/* Initialize an iterator to reference the last bit of the bitset*/
|
||||
static inline void
|
||||
bitset_it_last(bitset_it_t it, bitset_t set)
|
||||
m_bitset_it_last(m_bitset_it_t it, m_bitset_t set)
|
||||
{
|
||||
M_B1TSET_CONTRACT (set);
|
||||
it->index = set->size-1;
|
||||
@@ -553,7 +547,7 @@ bitset_it_last(bitset_it_t it, bitset_t set)
|
||||
|
||||
/* Initialize an iterator to reference no valid bit of the bitset*/
|
||||
static inline void
|
||||
bitset_it_end(bitset_it_t it, bitset_t set)
|
||||
m_bitset_it_end(m_bitset_it_t it, m_bitset_t set)
|
||||
{
|
||||
M_B1TSET_CONTRACT (set);
|
||||
it->index = set->size;
|
||||
@@ -562,7 +556,7 @@ bitset_it_end(bitset_it_t it, bitset_t set)
|
||||
|
||||
/* Test if an iterator references no valid bit of the bitset anymore */
|
||||
static inline bool
|
||||
bitset_end_p(const bitset_it_t it)
|
||||
m_bitset_end_p(const m_bitset_it_t it)
|
||||
{
|
||||
M_ASSERT (it != NULL && it->set != NULL);
|
||||
return (it->index) >= (it->set->size);
|
||||
@@ -570,7 +564,7 @@ bitset_end_p(const bitset_it_t it)
|
||||
|
||||
/* Test if an iterator references the last (or end) bit of the bitset anymore */
|
||||
static inline bool
|
||||
bitset_last_p(const bitset_it_t it)
|
||||
m_bitset_last_p(const m_bitset_it_t it)
|
||||
{
|
||||
M_ASSERT (it != NULL && it->set != NULL);
|
||||
/* NOTE: Can not compute 'size-1' due to potential overflow
|
||||
@@ -580,7 +574,7 @@ bitset_last_p(const bitset_it_t it)
|
||||
|
||||
/* Test if both iterators reference the same bit */
|
||||
static inline bool
|
||||
bitset_it_equal_p(const bitset_it_t it1, const bitset_it_t it2)
|
||||
m_bitset_it_equal_p(const m_bitset_it_t it1, const m_bitset_it_t it2)
|
||||
{
|
||||
M_ASSERT (it1 != NULL && it2 != NULL);
|
||||
return it1->index == it2->index && it1->set == it2->set;
|
||||
@@ -588,7 +582,7 @@ bitset_it_equal_p(const bitset_it_t it1, const bitset_it_t it2)
|
||||
|
||||
/* Move the iterator to the next bit */
|
||||
static inline void
|
||||
bitset_next(bitset_it_t it)
|
||||
m_bitset_next(m_bitset_it_t it)
|
||||
{
|
||||
M_ASSERT (it != NULL && it->set != NULL);
|
||||
it->index++;
|
||||
@@ -596,7 +590,7 @@ bitset_next(bitset_it_t it)
|
||||
|
||||
/* Move the iterator to the previous bit */
|
||||
static inline void
|
||||
bitset_previous(bitset_it_t it)
|
||||
m_bitset_previous(m_bitset_it_t it)
|
||||
{
|
||||
M_ASSERT (it != NULL && it->set != NULL);
|
||||
it->index--;
|
||||
@@ -607,22 +601,22 @@ bitset_previous(bitset_it_t it)
|
||||
/* Return a pointer to the bit referenced by the iterator
|
||||
* Only one reference is possible at a time per iterator */
|
||||
static inline const bool *
|
||||
bitset_cref(bitset_it_t it)
|
||||
m_bitset_cref(m_bitset_it_t it)
|
||||
{
|
||||
M_ASSERT (it != NULL && it->set != NULL);
|
||||
it->value = bitset_get(it->set, it->index);
|
||||
it->value = m_bitset_get(it->set, it->index);
|
||||
return &it->value;
|
||||
}
|
||||
|
||||
/* Output the bitset as a formatted text in a FILE */
|
||||
static inline void
|
||||
bitset_out_str(FILE *file, const bitset_t set)
|
||||
m_bitset_out_str(FILE *file, const m_bitset_t set)
|
||||
{
|
||||
M_B1TSET_CONTRACT (set);
|
||||
M_ASSERT(file != NULL);
|
||||
fputc ('[', file);
|
||||
for(size_t i = 0; i < set->size; i++) {
|
||||
const bool b = bitset_get (set, i);
|
||||
const bool b = m_bitset_get (set, i);
|
||||
const char c = b ? '1' : '0';
|
||||
fputc (c, file);
|
||||
}
|
||||
@@ -631,17 +625,17 @@ bitset_out_str(FILE *file, const bitset_t set)
|
||||
|
||||
/* Input the bitset from a formatted text in a FILE */
|
||||
static inline bool
|
||||
bitset_in_str(bitset_t set, FILE *file)
|
||||
m_bitset_in_str(m_bitset_t set, FILE *file)
|
||||
{
|
||||
M_B1TSET_CONTRACT (set);
|
||||
M_ASSERT(file != NULL);
|
||||
bitset_reset(set);
|
||||
m_bitset_reset(set);
|
||||
int c = fgetc(file);
|
||||
if (M_UNLIKELY (c != '[')) return false;
|
||||
c = fgetc(file);
|
||||
while (c == '0' || c == '1') {
|
||||
const bool b = (c == '1');
|
||||
bitset_push_back (set, b);
|
||||
m_bitset_push_back (set, b);
|
||||
c = fgetc(file);
|
||||
}
|
||||
M_B1TSET_CONTRACT (set);
|
||||
@@ -650,19 +644,19 @@ bitset_in_str(bitset_t set, FILE *file)
|
||||
|
||||
/* Parse the bitset from a formatted text in a C string */
|
||||
static inline bool
|
||||
bitset_parse_str(bitset_t set, const char str[], const char **endptr)
|
||||
m_bitset_parse_str(m_bitset_t set, const char str[], const char **endptr)
|
||||
{
|
||||
M_B1TSET_CONTRACT (set);
|
||||
M_ASSERT(str != NULL);
|
||||
bool success = false;
|
||||
bitset_reset(set);
|
||||
m_bitset_reset(set);
|
||||
char c = *str++;
|
||||
if (M_UNLIKELY(c != '[')) goto exit;
|
||||
c = *str++;
|
||||
do {
|
||||
if (M_UNLIKELY(c != '0' && c != '1')) goto exit;
|
||||
const bool b = (c == '1');
|
||||
bitset_push_back (set, b);
|
||||
m_bitset_push_back (set, b);
|
||||
c = *str++;
|
||||
} while (c != ']' && c != 0);
|
||||
M_B1TSET_CONTRACT (set);
|
||||
@@ -674,15 +668,15 @@ bitset_parse_str(bitset_t set, const char str[], const char **endptr)
|
||||
|
||||
/* Set the bitset from a formatted text in a C string */
|
||||
static inline bool
|
||||
bitset_set_str(bitset_t dest, const char str[])
|
||||
m_bitset_set_str(m_bitset_t dest, const char str[])
|
||||
{
|
||||
return bitset_parse_str(dest, str, NULL);
|
||||
return m_bitset_parse_str(dest, str, NULL);
|
||||
}
|
||||
|
||||
/* Perform an AND operation between the bitsets,
|
||||
* up to the minimum size of both bitsets */
|
||||
static inline void
|
||||
bitset_and(bitset_t dest, const bitset_t src)
|
||||
m_bitset_and(m_bitset_t dest, const m_bitset_t src)
|
||||
{
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
M_B1TSET_CONTRACT(src);
|
||||
@@ -698,7 +692,7 @@ bitset_and(bitset_t dest, const bitset_t src)
|
||||
/* Perform an OR operation between the bitsets,
|
||||
* up to the minimum size of both bitsets */
|
||||
static inline void
|
||||
bitset_or(bitset_t dest, const bitset_t src)
|
||||
m_bitset_or(m_bitset_t dest, const m_bitset_t src)
|
||||
{
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
M_B1TSET_CONTRACT(src);
|
||||
@@ -714,7 +708,7 @@ bitset_or(bitset_t dest, const bitset_t src)
|
||||
/* Perform an XOR operation between the bitsets,
|
||||
* up to the minimum size of both bitsets */
|
||||
static inline void
|
||||
bitset_xor(bitset_t dest, const bitset_t src)
|
||||
m_bitset_xor(m_bitset_t dest, const m_bitset_t src)
|
||||
{
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
M_B1TSET_CONTRACT(src);
|
||||
@@ -725,7 +719,7 @@ bitset_xor(bitset_t dest, const bitset_t src)
|
||||
dest->ptr[i] ^= src->ptr[i];
|
||||
if (M_LIKELY(m)) {
|
||||
// Last limb needs to be masked too
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
m_b1tset_limb_ct mask = (((m_b1tset_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
|
||||
@@ -735,7 +729,7 @@ bitset_xor(bitset_t dest, const bitset_t src)
|
||||
|
||||
/* Perform a NOT operation of the bitset */
|
||||
static inline void
|
||||
bitset_not(bitset_t dest)
|
||||
m_bitset_not(m_bitset_t dest)
|
||||
{
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
size_t s = dest->size;
|
||||
@@ -745,7 +739,7 @@ bitset_not(bitset_t dest)
|
||||
dest->ptr[i] = ~ (dest->ptr[i]);
|
||||
if (M_LIKELY(m)) {
|
||||
// Last limb needs to be masked too
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
m_b1tset_limb_ct mask = (((m_b1tset_limb_ct)1) << m) - 1;
|
||||
dest->ptr[n] = (~ dest->ptr[n]) & mask;
|
||||
}
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
@@ -753,7 +747,7 @@ bitset_not(bitset_t dest)
|
||||
|
||||
/* Copute a hash of the bitset */
|
||||
static inline size_t
|
||||
bitset_hash(const bitset_t set)
|
||||
m_bitset_hash(const m_bitset_t set)
|
||||
{
|
||||
M_B1TSET_CONTRACT(set);
|
||||
size_t s = set->size;
|
||||
@@ -766,7 +760,7 @@ bitset_hash(const bitset_t set)
|
||||
|
||||
/* Count the number of leading zero */
|
||||
static inline size_t
|
||||
bitset_clz(const bitset_t set)
|
||||
m_bitset_clz(const m_bitset_t set)
|
||||
{
|
||||
M_B1TSET_CONTRACT(set);
|
||||
size_t s = set->size;
|
||||
@@ -775,9 +769,9 @@ bitset_clz(const bitset_t set)
|
||||
}
|
||||
size_t n = (s -1) / M_B1TSET_LIMB_BIT;
|
||||
size_t m = s % M_B1TSET_LIMB_BIT;
|
||||
bitset_limb_ct limb = set->ptr[n];
|
||||
m_b1tset_limb_ct limb = set->ptr[n];
|
||||
if (m) {
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
m_b1tset_limb_ct mask = (((m_b1tset_limb_ct)1) << m) - 1;
|
||||
limb &= mask;
|
||||
} else {
|
||||
m = M_B1TSET_LIMB_BIT;
|
||||
@@ -792,16 +786,42 @@ bitset_clz(const bitset_t set)
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Count the number of trailing zero */
|
||||
static inline size_t
|
||||
m_bitset_ctz(const m_bitset_t set)
|
||||
{
|
||||
M_B1TSET_CONTRACT(set);
|
||||
size_t s = set->size;
|
||||
if (M_UNLIKELY (s == 0)) {
|
||||
return 0;
|
||||
}
|
||||
size_t i = 0, n = (s -1) / M_B1TSET_LIMB_BIT;
|
||||
size_t m = s % M_B1TSET_LIMB_BIT;
|
||||
m_b1tset_limb_ct limb = set->ptr[0];
|
||||
s = 0;
|
||||
while (limb == 0 && i < n) {
|
||||
s += M_B1TSET_LIMB_BIT;
|
||||
limb = set->ptr[++i];
|
||||
}
|
||||
if (i == n && m != 0) {
|
||||
m_b1tset_limb_ct mask = (((m_b1tset_limb_ct)1) << m) - 1;
|
||||
limb &= mask;
|
||||
}
|
||||
unsigned ctz = m_core_ctz64(limb);
|
||||
s += (ctz == 64) ? m : ctz;
|
||||
return s;
|
||||
}
|
||||
|
||||
// For GCC or CLANG or ICC
|
||||
#if defined(__GNUC__)
|
||||
static inline size_t m_b1tset_popcount64(bitset_limb_ct limb)
|
||||
static inline size_t m_b1tset_popcount64(m_b1tset_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)
|
||||
static inline size_t m_b1tset_popcount64(m_b1tset_limb_ct limb)
|
||||
{
|
||||
limb = limb - ((limb >> 1) & 0x5555555555555555ULL);
|
||||
limb = (limb & 0x3333333333333333ULL) + ((limb >> 2) & 0x3333333333333333ULL);
|
||||
@@ -812,7 +832,7 @@ static inline size_t m_b1tset_popcount64(bitset_limb_ct limb)
|
||||
|
||||
/* Count the number of 1 */
|
||||
static inline size_t
|
||||
bitset_popcount(const bitset_t set)
|
||||
m_bitset_popcount(const m_bitset_t set)
|
||||
{
|
||||
M_B1TSET_CONTRACT(set);
|
||||
size_t s = 0;
|
||||
@@ -823,46 +843,108 @@ bitset_popcount(const bitset_t set)
|
||||
}
|
||||
|
||||
/* Oplist for a bitset */
|
||||
#define BITSET_OPLIST \
|
||||
(INIT(bitset_init) \
|
||||
,INIT_SET(bitset_init_set) \
|
||||
#define M_BITSET_OPLIST \
|
||||
(INIT(m_bitset_init) \
|
||||
,INIT_SET(m_bitset_init_set) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
,SET(bitset_set) \
|
||||
,CLEAR(bitset_clear) \
|
||||
,INIT_MOVE(bitset_init_move) \
|
||||
,MOVE(bitset_move) \
|
||||
,SWAP(bitset_swap) \
|
||||
,TYPE(bitset_t) \
|
||||
,SET(m_bitset_set) \
|
||||
,CLEAR(m_bitset_clear) \
|
||||
,INIT_MOVE(m_bitset_init_move) \
|
||||
,MOVE(m_bitset_move) \
|
||||
,SWAP(m_bitset_swap) \
|
||||
,TYPE(m_bitset_t) \
|
||||
,SUBTYPE(bool) \
|
||||
,EMPTY_P(bitset_empty_p), \
|
||||
,GET_SIZE(bitset_size) \
|
||||
,IT_TYPE(bitset_it_t) \
|
||||
,IT_FIRST(bitset_it) \
|
||||
,IT_SET(bitset_it_set) \
|
||||
,IT_LAST(bitset_it_last) \
|
||||
,IT_END(bitset_it_end) \
|
||||
,IT_END_P(bitset_end_p) \
|
||||
,IT_LAST_P(bitset_last_p) \
|
||||
,IT_EQUAL_P(bitset_it_equal_p) \
|
||||
,IT_NEXT(bitset_next) \
|
||||
,IT_PREVIOUS(bitset_previous) \
|
||||
,IT_CREF(bitset_cref) \
|
||||
,RESET(bitset_reset) \
|
||||
,PUSH(bitset_push_back) \
|
||||
,POP(bitset_pop_back) \
|
||||
,HASH(bitset_hash) \
|
||||
,GET_STR(bitset_get_str) \
|
||||
,OUT_STR(bitset_out_str) \
|
||||
,PARSE_STR(bitset_parse_str) \
|
||||
,IN_STR(bitset_in_str) \
|
||||
,EQUAL(bitset_equal_p) \
|
||||
,EMPTY_P(m_bitset_empty_p), \
|
||||
,GET_SIZE(m_bitset_size) \
|
||||
,IT_TYPE(m_bitset_it_t) \
|
||||
,IT_FIRST(m_bitset_it) \
|
||||
,IT_SET(m_bitset_it_set) \
|
||||
,IT_LAST(m_bitset_it_last) \
|
||||
,IT_END(m_bitset_it_end) \
|
||||
,IT_END_P(m_bitset_end_p) \
|
||||
,IT_LAST_P(m_bitset_last_p) \
|
||||
,IT_EQUAL_P(m_bitset_it_equal_p) \
|
||||
,IT_NEXT(m_bitset_next) \
|
||||
,IT_PREVIOUS(m_bitset_previous) \
|
||||
,IT_CREF(m_bitset_cref) \
|
||||
,RESET(m_bitset_reset) \
|
||||
,PUSH(m_bitset_push_back) \
|
||||
,POP(m_bitset_pop_back) \
|
||||
,HASH(m_bitset_hash) \
|
||||
,GET_STR(m_bitset_get_str) \
|
||||
,OUT_STR(m_bitset_out_str) \
|
||||
,PARSE_STR(m_bitset_parse_str) \
|
||||
,IN_STR(m_bitset_in_str) \
|
||||
,EQUAL(m_bitset_equal_p) \
|
||||
)
|
||||
|
||||
/* Register the OPLIST as a global one */
|
||||
#define M_OPL_bitset_t() BITSET_OPLIST
|
||||
#define M_OPL_m_bitset_t() M_BITSET_OPLIST
|
||||
|
||||
// TODO: set_at2, insert_v, remove_v
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
|
||||
#define bitset_s m_bitset_s
|
||||
#define bitset_t m_bitset_t
|
||||
#define bitset_ptr m_bitset_ptr
|
||||
#define bitset_srcptr m_bitset_srcptr
|
||||
#define bitset_it_s m_bitset_it_s
|
||||
#define bitset_it_t m_bitset_it_t
|
||||
|
||||
#define bitset_init m_bitset_init
|
||||
#define bitset_reset m_bitset_reset
|
||||
#define bitset_clear m_bitset_clear
|
||||
#define bitset_set m_bitset_set
|
||||
#define bitset_init_set m_bitset_init_set
|
||||
#define bitset_init_move m_bitset_init_move
|
||||
#define bitset_move m_bitset_move
|
||||
#define bitset_set_at m_bitset_set_at
|
||||
#define bitset_flip_at m_bitset_flip_at
|
||||
#define bitset_push_back m_bitset_push_back
|
||||
#define bitset_resize m_bitset_resize
|
||||
#define bitset_reserve m_bitset_reserve
|
||||
#define bitset_get m_bitset_get
|
||||
#define bitset_pop_back m_bitset_pop_back
|
||||
#define bitset_front m_bitset_front
|
||||
#define bitset_back m_bitset_back
|
||||
#define bitset_empty_p m_bitset_empty_p
|
||||
#define bitset_size m_bitset_size
|
||||
#define bitset_capacity m_bitset_capacity
|
||||
#define bitset_swap_at m_bitset_swap_at
|
||||
#define bitset_swap m_bitset_swap
|
||||
#define bitset_push_at m_bitset_push_at
|
||||
#define bitset_pop_at m_bitset_pop_at
|
||||
#define bitset_equal_p m_bitset_equal_p
|
||||
#define bitset_it m_bitset_it
|
||||
#define bitset_it_set m_bitset_it_set
|
||||
#define bitset_it_last m_bitset_it_last
|
||||
#define bitset_it_end m_bitset_it_end
|
||||
#define bitset_end_p m_bitset_end_p
|
||||
#define bitset_last_p m_bitset_last_p
|
||||
#define bitset_it_equal_p m_bitset_it_equal_p
|
||||
#define bitset_next m_bitset_next
|
||||
#define bitset_previous m_bitset_previous
|
||||
#define bitset_cref m_bitset_cref
|
||||
#define bitset_out_str m_bitset_out_str
|
||||
#define bitset_in_str m_bitset_in_str
|
||||
#define bitset_parse_str m_bitset_parse_str
|
||||
#define bitset_set_str m_bitset_set_str
|
||||
#define bitset_and m_bitset_and
|
||||
#define bitset_or m_bitset_or
|
||||
#define bitset_xor m_bitset_xor
|
||||
#define bitset_not m_bitset_not
|
||||
#define bitset_hash m_bitset_hash
|
||||
#define bitset_clz m_bitset_clz
|
||||
#define bitset_ctz m_bitset_ctz
|
||||
#define bitset_popcount m_bitset_popcount
|
||||
#define bitset_get_str m_bitset_get_str
|
||||
|
||||
#define BITSET_OPLIST M_BITSET_OPLIST
|
||||
#define M_OPL_bitset_t M_OPL_m_bitset_t
|
||||
|
||||
#endif
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
@@ -873,20 +955,20 @@ M_END_PROTECTED_CODE
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Output to a string_t 'str' the formatted text representation of the bitset 'set'
|
||||
/* Output to a m_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)
|
||||
m_bitset_get_str(m_string_t str, const m_bitset_t set, bool append)
|
||||
{
|
||||
M_B1TSET_CONTRACT (set);
|
||||
M_ASSERT(str != NULL);
|
||||
(append ? string_cat_str : string_set_str) (str, "[");
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "[");
|
||||
for(size_t i = 0; i < set->size; i++) {
|
||||
const bool b = bitset_get (set, i);
|
||||
const bool b = m_bitset_get (set, i);
|
||||
const char c = b ? '1' : '0';
|
||||
string_push_back (str, c);
|
||||
m_string_push_back (str, c);
|
||||
}
|
||||
string_push_back (str, ']');
|
||||
m_string_push_back (str, ']');
|
||||
}
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
+43
-38
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - B+TREE module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -34,8 +34,8 @@
|
||||
OR
|
||||
BPTREE_DEF2(name, N, key_t, value_t)
|
||||
*/
|
||||
#define BPTREE_DEF2(name, N, key_type, ...) \
|
||||
BPTREE_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name, _itref_t), N, key_type, __VA_ARGS__)
|
||||
#define M_BPTREE_DEF2(name, N, key_type, ...) \
|
||||
M_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'
|
||||
@@ -45,7 +45,7 @@
|
||||
OR
|
||||
BPTREE_DEF2_AS(name, name_t, it_t, itref_t, N, key_t, value_t)
|
||||
*/
|
||||
#define BPTREE_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \
|
||||
#define M_BPTREE_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
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 ), \
|
||||
@@ -56,14 +56,14 @@
|
||||
/* Define a B+tree of a given type, of size N.
|
||||
with its associated functions
|
||||
USAGE: BPTREE_DEF(name, N, type, [, oplist_of_the_type]) */
|
||||
#define BPTREE_DEF(name, N, ...) \
|
||||
BPTREE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), N, __VA_ARGS__)
|
||||
#define M_BPTREE_DEF(name, N, ...) \
|
||||
M_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.
|
||||
as the given name name_t with its associated functions
|
||||
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, ...) \
|
||||
#define M_BPTREE_DEF_AS(name, name_t, it_t, N, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
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) ), \
|
||||
@@ -79,8 +79,8 @@
|
||||
OR
|
||||
BPTREE_MULTI_DEF2(name, N, key_t, value_t)
|
||||
*/
|
||||
#define BPTREE_MULTI_DEF2(name, N, key_type, ...) \
|
||||
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 M_BPTREE_MULTI_DEF2(name, N, key_type, ...) \
|
||||
M_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',
|
||||
@@ -91,7 +91,7 @@
|
||||
OR
|
||||
BPTREE_MULTI_DEF2_AS(name, name_t, it_t, itref_t, N, key_t, value_t)
|
||||
*/
|
||||
#define BPTREE_MULTI_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \
|
||||
#define M_BPTREE_MULTI_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
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 ), \
|
||||
@@ -103,15 +103,15 @@
|
||||
allowing multiple equal keys to exist,
|
||||
with its associated functions
|
||||
USAGE: BPTREE_MULTI_DEF(name, N, type, [, oplist_of_the_type]) */
|
||||
#define BPTREE_MULTI_DEF(name, N, ...) \
|
||||
BPTREE_MULTI_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), N, __VA_ARGS__)
|
||||
#define M_BPTREE_MULTI_DEF(name, N, ...) \
|
||||
M_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.
|
||||
allowing multiple equal keys to exist,
|
||||
as the given name name_t with its associated functions
|
||||
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, ...) \
|
||||
#define M_BPTREE_MULTI_DEF_AS(name, name_t, it_t, N, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
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) ), \
|
||||
@@ -120,21 +120,22 @@
|
||||
|
||||
|
||||
/* 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(...) \
|
||||
USAGE: BPTREE_OPLIST(name [, oplist_of_the_type])
|
||||
NOTE: IT_REF is not exported so that the container appears as not modifiable
|
||||
by algorithm. */
|
||||
#define M_BPTREE_OPLIST(...) \
|
||||
M_BPTR33_KEY_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define the oplist of a B+TREE used as a map of a key type to a value type (from BPTREE_DEF2).
|
||||
USAGE: BPTREE_OPLIST2(name[, key_oplist, value_oplist])
|
||||
NOTE: IT_REF is not exported so that the contained appears as not modifiable
|
||||
by algorithm.
|
||||
*/
|
||||
#define BPTREE_OPLIST2(...) \
|
||||
NOTE: IT_REF is not exported so that the container appears as not modifiable
|
||||
by algorithm. */
|
||||
#define M_BPTREE_OPLIST2(...) \
|
||||
M_BPTR33_OPLIST2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST ), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST, M_BASIC_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -173,7 +174,6 @@
|
||||
IT_END_P(M_C(name,_end_p)), \
|
||||
IT_EQUAL_P(M_C(name,_it_equal_p)), \
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_REF(M_C(name,_ref)), \
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
RESET(M_C(name,_reset)), \
|
||||
PUSH(M_C(name,_push)), \
|
||||
@@ -304,7 +304,7 @@
|
||||
|
||||
/* Deferred evaluation for the b+tree definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_BPTR33_DEF_P1(arg) M_BPTR33_DEF_P2 arg
|
||||
#define M_BPTR33_DEF_P1(arg) M_ID( M_BPTR33_DEF_P2 arg )
|
||||
|
||||
/* Validate the key oplist before going further */
|
||||
#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) \
|
||||
@@ -475,11 +475,6 @@
|
||||
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) \
|
||||
{ \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
@@ -776,17 +771,13 @@
|
||||
value_t v; \
|
||||
M_CALL_INIT(value_oplist, v); \
|
||||
M_C(name, _set_at)(b, key, v); \
|
||||
M_CALL_CLEAR(value_oplist, 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 \
|
||||
@@ -1256,11 +1247,11 @@
|
||||
, /* NO HASH METHOD */ ) \
|
||||
\
|
||||
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
static inline void M_C(name, _get_str)(m_string_t str, \
|
||||
const tree_t t1, bool append) { \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT(str != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
|
||||
/* NOTE: The print is really naive, and not really efficient */ \
|
||||
bool commaToPrint = false; \
|
||||
it_t it; \
|
||||
@@ -1268,18 +1259,18 @@
|
||||
!M_C(name, _end_p)(it); \
|
||||
M_C(name, _next)(it)) { \
|
||||
if (commaToPrint) \
|
||||
string_push_back (str, M_GET_SEPARATOR key_oplist); \
|
||||
m_string_push_back (str, M_GET_SEPARATOR key_oplist); \
|
||||
commaToPrint = true; \
|
||||
subtype_t const *ref1 = M_C(name, _cref)(it); \
|
||||
M_IF(isMap)( \
|
||||
M_CALL_GET_STR(key_oplist, str, *ref1->key_ptr, true); \
|
||||
string_cat_str(str, ":"); \
|
||||
m_string_cat_cstr(str, ":"); \
|
||||
M_CALL_GET_STR(value_oplist,str, *ref1->value_ptr, true) \
|
||||
, \
|
||||
M_CALL_GET_STR(key_oplist, str, *ref1, true); \
|
||||
); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
m_string_push_back (str, ']'); \
|
||||
} \
|
||||
, /* NO GET_STR */ ) \
|
||||
\
|
||||
@@ -1478,5 +1469,19 @@
|
||||
} \
|
||||
, /* no in_serial */ ) \
|
||||
\
|
||||
M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF(M_INV(isMap), name, tree_t, key_oplist, value_oplist)
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define BPTREE_DEF2 M_BPTREE_DEF2
|
||||
#define BPTREE_DEF2_AS M_BPTREE_DEF2_AS
|
||||
#define BPTREE_DEF M_BPTREE_DEF
|
||||
#define BPTREE_DEF_AS M_BPTREE_DEF_AS
|
||||
#define BPTREE_MULTI_DEF2 M_BPTREE_MULTI_DEF2
|
||||
#define BPTREE_MULTI_DEF2_AS M_BPTREE_MULTI_DEF2_AS
|
||||
#define BPTREE_MULTI_DEF M_BPTREE_MULTI_DEF
|
||||
#define BPTREE_MULTI_DEF_AS M_BPTREE_MULTI_DEF_AS
|
||||
#define BPTREE_OPLIST M_BPTREE_OPLIST
|
||||
#define BPTREE_OPLIST2 M_BPTREE_OPLIST2
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+124
-93
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Fixed size (Bounded) QUEUE & STACK interface
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -40,29 +40,29 @@
|
||||
* - if the pop of an element is not complete until the call to pop_release (preventing push until this call).
|
||||
*/
|
||||
typedef enum {
|
||||
BUFFER_QUEUE = 0, BUFFER_STACK = 1,
|
||||
BUFFER_BLOCKING_PUSH = 0, BUFFER_UNBLOCKING_PUSH = 2,
|
||||
BUFFER_BLOCKING_POP = 0, BUFFER_UNBLOCKING_POP = 4,
|
||||
BUFFER_BLOCKING = 0, BUFFER_UNBLOCKING = 6,
|
||||
BUFFER_THREAD_SAFE = 0, BUFFER_THREAD_UNSAFE = 8,
|
||||
BUFFER_PUSH_INIT_POP_MOVE = 16,
|
||||
BUFFER_PUSH_OVERWRITE = 32,
|
||||
BUFFER_DEFERRED_POP = 64
|
||||
} buffer_policy_e;
|
||||
M_BUFFER_QUEUE = 0, M_BUFFER_STACK = 1,
|
||||
M_BUFFER_BLOCKING_PUSH = 0, M_BUFFER_UNBLOCKING_PUSH = 2,
|
||||
M_BUFFER_BLOCKING_POP = 0, M_BUFFER_UNBLOCKING_POP = 4,
|
||||
M_BUFFER_BLOCKING = 0, M_BUFFER_UNBLOCKING = 6,
|
||||
M_BUFFER_THREAD_SAFE = 0, M_BUFFER_THREAD_UNSAFE = 8,
|
||||
M_BUFFER_PUSH_INIT_POP_MOVE = 16,
|
||||
M_BUFFER_PUSH_OVERWRITE = 32,
|
||||
M_BUFFER_DEFERRED_POP = 64
|
||||
} m_buffer_policy_e;
|
||||
|
||||
|
||||
/* Define a lock based buffer.
|
||||
If size is 0, then the size will only be defined at run-time when initializing the buffer,
|
||||
otherwise the size will be a compile time constant.
|
||||
USAGE: BUFFER_DEF(name, type, size_of_buffer_or_0, policy[, oplist]) */
|
||||
#define BUFFER_DEF(name, type, m_size, ... ) \
|
||||
BUFFER_DEF_AS(name, M_C(name, _t), type, m_size, __VA_ARGS__)
|
||||
#define M_BUFFER_DEF(name, type, m_size, ... ) \
|
||||
M_BUFFER_DEF_AS(name, M_C(name, _t), type, m_size, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a lock based buffer
|
||||
as the provided type name_t.
|
||||
USAGE: BUFFER_DEF_AS(name, name_t, type, size_of_buffer_or_0, policy[, oplist of type]) */
|
||||
#define BUFFER_DEF_AS(name, name_t, type, m_size, ... ) \
|
||||
#define M_BUFFER_DEF_AS(name, name_t, type, m_size, ... ) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_BUFF3R_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, type, m_size,__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), name_t ), \
|
||||
@@ -72,9 +72,9 @@ typedef enum {
|
||||
|
||||
/* Define the oplist of a lock based buffer given its name and its oplist.
|
||||
USAGE: BUFFER_OPLIST(name[, oplist of the type]) */
|
||||
#define BUFFER_OPLIST(...) \
|
||||
#define M_BUFFER_OPLIST(...) \
|
||||
M_BUFF3R_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -84,8 +84,8 @@ typedef enum {
|
||||
Size of created queue shall be a power of 2 and is defined at run-time.
|
||||
USAGE: QUEUE_MPMC_DEF(name, type, policy, [oplist of type])
|
||||
*/
|
||||
#define QUEUE_MPMC_DEF(name, type, ...) \
|
||||
QUEUE_MPMC_DEF_AS(name, M_C(name,_t), type, __VA_ARGS__)
|
||||
#define M_QUEUE_MPMC_DEF(name, type, ...) \
|
||||
M_QUEUE_MPMC_DEF_AS(name, M_C(name,_t), type, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a nearly lock-free queue for Many Producer Many Consummer
|
||||
@@ -95,7 +95,7 @@ typedef enum {
|
||||
Size of created queue shall be a power of 2 and is defined at run-time.
|
||||
USAGE: QUEUE_MPMC_DEF_AS(name, name_t, type, policy, [oplist of type])
|
||||
*/
|
||||
#define QUEUE_MPMC_DEF_AS(name, name_t, type, ...) \
|
||||
#define M_QUEUE_MPMC_DEF_AS(name, name_t, type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_QU3UE_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), name_t ), \
|
||||
@@ -109,8 +109,8 @@ typedef enum {
|
||||
Size of created queue shall be a power of 2 and is defined at run-time.
|
||||
USAGE: QUEUE_SPSC_DEF(name, type, policy, [oplist of type])
|
||||
*/
|
||||
#define QUEUE_SPSC_DEF(name, type, ...) \
|
||||
QUEUE_SPSC_DEF_AS(name, M_C(name, _t), type, __VA_ARGS__)
|
||||
#define M_QUEUE_SPSC_DEF(name, type, ...) \
|
||||
M_QUEUE_SPSC_DEF_AS(name, M_C(name, _t), type, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a wait-free queue for Single Producer Single Consummer
|
||||
@@ -120,7 +120,7 @@ typedef enum {
|
||||
Size of created queue shall be a power of 2 and is defined at run-time.
|
||||
USAGE: QUEUE_SPSC_DEF_AS(name, name_t, type, policy, [oplist of type])
|
||||
*/
|
||||
#define QUEUE_SPSC_DEF_AS(name, name_t, type, ...) \
|
||||
#define M_QUEUE_SPSC_DEF_AS(name, name_t, type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_QU3UE_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), name_t ), \
|
||||
@@ -155,7 +155,7 @@ typedef union m_buff3r_number_s {
|
||||
static inline void
|
||||
m_buff3r_number_init(m_buff3r_number_ct n, unsigned int policy)
|
||||
{
|
||||
if (!M_BUFF3R_POLICY_P(policy, BUFFER_THREAD_UNSAFE))
|
||||
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
|
||||
atomic_init(&n->a, 0U);
|
||||
else
|
||||
n->u = 0UL;
|
||||
@@ -164,7 +164,7 @@ m_buff3r_number_init(m_buff3r_number_ct n, unsigned int policy)
|
||||
static inline unsigned int
|
||||
m_buff3r_number_load(m_buff3r_number_ct n, unsigned int policy)
|
||||
{
|
||||
if (!M_BUFF3R_POLICY_P(policy, BUFFER_THREAD_UNSAFE))
|
||||
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
|
||||
// Perform a memory acquire so that further usage of the buffer
|
||||
// is synchronized.
|
||||
return atomic_load_explicit(&n->a, memory_order_acquire);
|
||||
@@ -175,7 +175,7 @@ m_buff3r_number_load(m_buff3r_number_ct n, unsigned int policy)
|
||||
static inline void
|
||||
m_buff3r_number_store(m_buff3r_number_ct n, unsigned int v, unsigned int policy)
|
||||
{
|
||||
if (!M_BUFF3R_POLICY_P(policy, BUFFER_THREAD_UNSAFE))
|
||||
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
|
||||
// This function is used in context where a relaxed access is sufficient.
|
||||
atomic_store_explicit(&n->a, v, memory_order_relaxed);
|
||||
else
|
||||
@@ -185,7 +185,7 @@ m_buff3r_number_store(m_buff3r_number_ct n, unsigned int v, unsigned int policy)
|
||||
static inline void
|
||||
m_buff3r_number_set(m_buff3r_number_ct n, m_buff3r_number_ct v, unsigned int policy)
|
||||
{
|
||||
if (!M_BUFF3R_POLICY_P(policy, BUFFER_THREAD_UNSAFE))
|
||||
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
|
||||
// This function is used in context where a relaxed access is sufficient.
|
||||
atomic_store_explicit(&n->a, atomic_load_explicit(&v->a, memory_order_relaxed), memory_order_relaxed);
|
||||
else
|
||||
@@ -195,7 +195,7 @@ m_buff3r_number_set(m_buff3r_number_ct n, m_buff3r_number_ct v, unsigned int pol
|
||||
static inline unsigned int
|
||||
m_buff3r_number_inc(m_buff3r_number_ct n, unsigned int policy)
|
||||
{
|
||||
if (!M_BUFF3R_POLICY_P(policy, BUFFER_THREAD_UNSAFE))
|
||||
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
|
||||
return atomic_fetch_add(&n->a, 1U);
|
||||
else
|
||||
return n->u ++;
|
||||
@@ -204,7 +204,7 @@ m_buff3r_number_inc(m_buff3r_number_ct n, unsigned int policy)
|
||||
static inline unsigned int
|
||||
m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
|
||||
{
|
||||
if (!M_BUFF3R_POLICY_P(policy, BUFFER_THREAD_UNSAFE))
|
||||
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
|
||||
return atomic_fetch_sub(&n->a, 1U);
|
||||
else
|
||||
return n->u --;
|
||||
@@ -235,7 +235,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
|
||||
|
||||
/* Deferred evaluation for the definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_BUFF3R_DEF_P1(arg) M_BUFF3R_DEF_P2 arg
|
||||
#define M_BUFF3R_DEF_P1(arg) M_ID( M_BUFF3R_DEF_P2 arg )
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define M_BUFF3R_DEF_P2(name, type, m_size, policy, oplist, buffer_t) \
|
||||
@@ -243,7 +243,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define M_BUFF3R_DEF_FAILURE(name, type, m_size, policy, oplist, buffer_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(BUFFER_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(M_BUFFER_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
|
||||
|
||||
/* Define the buffer type using mutex lock and its functions.
|
||||
- name: main prefix of the container
|
||||
@@ -259,7 +259,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
|
||||
by multiple writing threads. No need to align if there is no thread */ \
|
||||
typedef union M_C(name, _el_s) { \
|
||||
type x; \
|
||||
char align[M_BUFF3R_POLICY_P(policy, BUFFER_THREAD_UNSAFE) ? 1 : M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
|
||||
char align[M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE) ? 1 : M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
|
||||
} M_C(name, _el_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
@@ -276,7 +276,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
|
||||
size_t idx_cons; /* Index of the consumption threads */ \
|
||||
/* number[0] := Number of elements in the buffer */ \
|
||||
/* number[1] := [OPTION] Number of elements being deferred in the buffer */ \
|
||||
m_buff3r_number_ct number[1 + M_BUFF3R_POLICY_P(policy, BUFFER_DEFERRED_POP)]; \
|
||||
m_buff3r_number_ct number[1 + M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)]; \
|
||||
/* If fixed size, array of elements, otherwise pointer to element */ \
|
||||
M_C(name, _el_ct) M_BUFF3R_IF_CTE_SIZE(m_size)(data[m_size], *data); \
|
||||
} buffer_t[1]; \
|
||||
@@ -298,15 +298,15 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_ASSERT(size <= UINT_MAX); \
|
||||
v->idx_prod = v->idx_cons = v->overwrite = 0; \
|
||||
m_buff3r_number_init (v->number[0], policy); \
|
||||
if (M_BUFF3R_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
|
||||
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
|
||||
m_buff3r_number_init (v->number[1], policy); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_init(v->mutexPush); \
|
||||
m_mutex_init(v->mutexPop); \
|
||||
m_cond_init(v->there_is_data); \
|
||||
m_cond_init(v->there_is_room_for_data); \
|
||||
} else { \
|
||||
M_ASSERT(M_BUFF3R_POLICY_P((policy), BUFFER_UNBLOCKING)); \
|
||||
M_ASSERT(M_BUFF3R_POLICY_P((policy), M_BUFFER_UNBLOCKING)); \
|
||||
} \
|
||||
\
|
||||
M_BUFF3R_IF_CTE_SIZE(m_size)( /* Statically allocated */ , \
|
||||
@@ -316,7 +316,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
return; \
|
||||
} \
|
||||
) \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
for(size_t i = 0; i < size; i++) { \
|
||||
M_CALL_INIT(oplist, v->data[i].x); \
|
||||
} \
|
||||
@@ -336,22 +336,22 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_C3(m_buff3r_,name,_clear_obj)(buffer_t v) \
|
||||
{ \
|
||||
M_BUFF3R_CONTRACT(v,m_size); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
for(size_t i = 0; i < M_BUFF3R_SIZE(m_size); i++) { \
|
||||
M_CALL_CLEAR(oplist, v->data[i].x); \
|
||||
} \
|
||||
} else { \
|
||||
size_t i = M_BUFF3R_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \
|
||||
size_t i = M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK) ? 0 : v->idx_cons; \
|
||||
while (i != v->idx_prod) { \
|
||||
M_CALL_CLEAR(oplist, v->data[i].x); \
|
||||
i++; \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_STACK) && i >= M_BUFF3R_SIZE(m_size)) \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK) && i >= M_BUFF3R_SIZE(m_size)) \
|
||||
i = 0; \
|
||||
} \
|
||||
} \
|
||||
v->idx_prod = v->idx_cons = 0; \
|
||||
m_buff3r_number_store (v->number[0], 0U, policy); \
|
||||
if (M_BUFF3R_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
|
||||
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
|
||||
m_buff3r_number_store(v->number[1], 0U, policy); \
|
||||
M_BUFF3R_CONTRACT(v,m_size); \
|
||||
} \
|
||||
@@ -366,7 +366,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
v->data = NULL; \
|
||||
) \
|
||||
v->overwrite = 0; \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_clear(v->mutexPush); \
|
||||
m_mutex_clear(v->mutexPop); \
|
||||
m_cond_clear(v->there_is_data); \
|
||||
@@ -378,18 +378,18 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_C(name, _reset)(buffer_t v) \
|
||||
{ \
|
||||
M_BUFF3R_CONTRACT(v,m_size); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_lock(v->mutexPush); \
|
||||
m_mutex_lock(v->mutexPop); \
|
||||
} \
|
||||
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
|
||||
if (M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) \
|
||||
if (M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) \
|
||||
M_C3(m_buff3r_,name,_clear_obj)(v); \
|
||||
v->idx_prod = v->idx_cons = 0; \
|
||||
m_buff3r_number_store (v->number[0], 0U, policy); \
|
||||
if (M_BUFF3R_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
|
||||
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
|
||||
m_buff3r_number_store(v->number[1], 0U, policy); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
|
||||
m_cond_broadcast(v->there_is_room_for_data); \
|
||||
m_mutex_unlock(v->mutexPop); \
|
||||
m_mutex_unlock(v->mutexPush); \
|
||||
@@ -413,22 +413,22 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_ASSERT (dest != v); \
|
||||
M_BUFF3R_CONTRACT(v,m_size); \
|
||||
M_C(name, _init)(dest, M_BUFF3R_SIZE(m_size)); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_lock(v->mutexPush); \
|
||||
m_mutex_lock(v->mutexPop); \
|
||||
} \
|
||||
\
|
||||
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
for(size_t i = 0; i < M_BUFF3R_SIZE(m_size); i++) { \
|
||||
M_CALL_INIT_SET(oplist, dest->data[i].x, v->data[i].x); \
|
||||
} \
|
||||
} else { \
|
||||
size_t i = M_BUFF3R_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \
|
||||
size_t i = M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK) ? 0 : v->idx_cons; \
|
||||
while (i != v->idx_prod) { \
|
||||
M_CALL_INIT_SET(oplist, dest->data[i].x, v->data[i].x); \
|
||||
i++; \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_STACK) && i >= M_BUFF3R_SIZE(m_size)) \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK) && i >= M_BUFF3R_SIZE(m_size)) \
|
||||
i = 0; \
|
||||
} \
|
||||
} \
|
||||
@@ -436,10 +436,10 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
dest->idx_prod = v->idx_prod; \
|
||||
dest->idx_cons = v->idx_cons; \
|
||||
m_buff3r_number_set (dest->number[0], v->number[0], policy); \
|
||||
if (M_BUFF3R_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
|
||||
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
|
||||
m_buff3r_number_set(dest->number[1], v->number[1], policy); \
|
||||
\
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_unlock(v->mutexPop); \
|
||||
m_mutex_unlock(v->mutexPush); \
|
||||
} \
|
||||
@@ -458,7 +458,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_BUFF3R_CONTRACT(v,m_size); \
|
||||
\
|
||||
if (dest == v) return; \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
|
||||
/* Case of deadlock: A := B, B:=C, C:=A (all in //) \
|
||||
Solution: order the lock by increasing memory */ \
|
||||
if (dest < v) { \
|
||||
@@ -477,16 +477,16 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
|
||||
M_C3(m_buff3r_,name,_clear_obj)(dest); \
|
||||
\
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
for(size_t i = 0; i < M_BUFF3R_SIZE(m_size); i++) { \
|
||||
M_CALL_INIT_SET(oplist, dest->data[i].x, v->data[i].x); \
|
||||
} \
|
||||
} else { \
|
||||
size_t i = M_BUFF3R_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \
|
||||
size_t i = M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK) ? 0 : v->idx_cons; \
|
||||
while (i != v->idx_prod) { \
|
||||
M_CALL_INIT_SET(oplist, dest->data[i].x, v->data[i].x); \
|
||||
i++; \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_STACK) && i >= M_BUFF3R_SIZE(m_size)) \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK) && i >= M_BUFF3R_SIZE(m_size)) \
|
||||
i = 0; \
|
||||
} \
|
||||
} \
|
||||
@@ -494,10 +494,10 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
dest->idx_prod = v->idx_prod; \
|
||||
dest->idx_cons = v->idx_cons; \
|
||||
m_buff3r_number_set (dest->number[0], v->number[0], policy); \
|
||||
if (M_BUFF3R_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
|
||||
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
|
||||
m_buff3r_number_set(dest->number[1], v->number[1], policy); \
|
||||
\
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
|
||||
/* It may be false, but it is not wrong! */ \
|
||||
m_cond_broadcast(v->there_is_room_for_data); \
|
||||
m_cond_broadcast(v->there_is_data); \
|
||||
@@ -525,7 +525,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
we considered the queue as empty when the number of \
|
||||
deferred pop has reached 0, not the number of items in the \
|
||||
buffer is 0. */ \
|
||||
if (M_BUFF3R_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
|
||||
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
|
||||
return m_buff3r_number_load (v->number[1], policy) == 0; \
|
||||
else \
|
||||
return m_buff3r_number_load (v->number[0], policy) == 0; \
|
||||
@@ -552,9 +552,9 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_BUFF3R_CONTRACT(v,m_size); \
|
||||
\
|
||||
/* Producer Mutex lock (mutex lock performs an acquire memory barrier) */ \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_lock(v->mutexPush); \
|
||||
while (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \
|
||||
while (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_OVERWRITE) \
|
||||
&& M_C(name, _full_p)(v)) { \
|
||||
if (!blocking) { \
|
||||
m_mutex_unlock(v->mutexPush); \
|
||||
@@ -562,20 +562,20 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
} \
|
||||
m_cond_wait(v->there_is_room_for_data, v->mutexPush); \
|
||||
} \
|
||||
} else if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \
|
||||
} else if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_OVERWRITE) \
|
||||
&& M_C(name, _full_p)(v)) \
|
||||
return false; \
|
||||
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
|
||||
\
|
||||
size_t previousSize, idx = v->idx_prod; \
|
||||
/* INDEX computation if we have to overwrite the last element */ \
|
||||
if (M_UNLIKELY (M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \
|
||||
if (M_UNLIKELY (M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_OVERWRITE) \
|
||||
&& M_C(name, _full_p)(v))) { \
|
||||
v->overwrite++; \
|
||||
/* Let's overwrite the last element */ \
|
||||
/* Compute the index of the last push element */ \
|
||||
idx--; \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_STACK)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK)) { \
|
||||
idx = idx >= M_BUFF3R_SIZE(m_size) ? M_BUFF3R_SIZE(m_size)-1 : idx; \
|
||||
} \
|
||||
/* Update data in the buffer */ \
|
||||
@@ -584,7 +584,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
} else { \
|
||||
/* Add a new item in the buffer */ \
|
||||
/* PUSH data in the buffer */ \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_CALL_SET(oplist, v->data[idx].x, data); \
|
||||
} else { \
|
||||
M_CALL_INIT_SET(oplist, v->data[idx].x, data); \
|
||||
@@ -592,7 +592,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
\
|
||||
/* Increment production INDEX of the buffer */ \
|
||||
idx++; \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_STACK)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK)) { \
|
||||
idx = (idx == M_BUFF3R_SIZE(m_size)) ? 0 : idx; \
|
||||
} \
|
||||
v->idx_prod = idx; \
|
||||
@@ -603,14 +603,14 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
that performs a release memory barrier. */ \
|
||||
/* Increment number of elements of the buffer */ \
|
||||
previousSize = m_buff3r_number_inc (v->number[0], policy); \
|
||||
if (M_BUFF3R_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \
|
||||
if (M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) { \
|
||||
previousSize = m_buff3r_number_inc (v->number[1], policy); \
|
||||
} \
|
||||
/* From this point, consummer may read the data in the table */ \
|
||||
} \
|
||||
\
|
||||
/* Producer unlock (mutex unlock performs a release memory barrier) */ \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_unlock(v->mutexPush); \
|
||||
/* If the number of items in the buffer was 0, some consummer \
|
||||
may be waiting. Signal to them the availibility of the data \
|
||||
@@ -633,7 +633,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_ASSERT (data != NULL); \
|
||||
\
|
||||
/* Consummer lock (mutex lock performs an acquire memory barrier) */ \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_lock(v->mutexPop); \
|
||||
while (M_C(name, _empty_p)(v)) { \
|
||||
if (!blocking) { \
|
||||
@@ -647,9 +647,9 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
|
||||
\
|
||||
/* POP data from the buffer and update INDEX */ \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_STACK)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK)) { \
|
||||
/* FIFO queue */ \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_CALL_SET(oplist, *data, v->data[v->idx_cons].x); \
|
||||
} else { \
|
||||
M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_cons].x); \
|
||||
@@ -658,7 +658,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
} else { \
|
||||
/* STACK queue */ \
|
||||
v->idx_prod --; \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_CALL_SET(oplist, *data, v->data[v->idx_prod].x); \
|
||||
} else { \
|
||||
M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_prod].x); \
|
||||
@@ -671,7 +671,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
that performs a release memory barrier. */ \
|
||||
/* Decrement number of elements in the buffer */ \
|
||||
size_t previousSize; \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) { \
|
||||
previousSize = m_buff3r_number_dec (v->number[0], policy); \
|
||||
} else { \
|
||||
m_buff3r_number_dec (v->number[1], policy); \
|
||||
@@ -679,12 +679,12 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
/* Space may be reused by a producer thread from this point */ \
|
||||
\
|
||||
/* Consummer unlock (mutex unlock perfoms a release memory barrier) */ \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_unlock(v->mutexPop); \
|
||||
/* If the number of items in the buffer was the max, some producer \
|
||||
may be waiting. Signal to them the availibility of the free room \
|
||||
We cannot only signal one thread. */ \
|
||||
if ((!M_BUFF3R_POLICY_P((policy), BUFFER_DEFERRED_POP)) \
|
||||
if ((!M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) \
|
||||
&& previousSize == M_BUFF3R_SIZE(m_size)) { \
|
||||
m_mutex_lock(v->mutexPush); \
|
||||
m_cond_broadcast(v->there_is_room_for_data); \
|
||||
@@ -701,14 +701,14 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_C(name, _push)(buffer_t v, type const data) \
|
||||
{ \
|
||||
return M_C(name, _push_blocking)(v, data, \
|
||||
!M_BUFF3R_POLICY_P((policy), BUFFER_UNBLOCKING_PUSH)); \
|
||||
!M_BUFF3R_POLICY_P((policy), M_BUFFER_UNBLOCKING_PUSH)); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _pop)(type *data, buffer_t v) \
|
||||
{ \
|
||||
return M_C(name, _pop_blocking)(data, v, \
|
||||
!M_BUFF3R_POLICY_P((policy), BUFFER_UNBLOCKING_POP)); \
|
||||
!M_BUFF3R_POLICY_P((policy), M_BUFFER_UNBLOCKING_POP)); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
@@ -728,7 +728,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_C(name, _pop_release)(buffer_t v) \
|
||||
{ \
|
||||
/* Decrement the effective number of elements in the buffer */ \
|
||||
if (M_BUFF3R_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \
|
||||
if (M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) { \
|
||||
size_t previousSize = m_buff3r_number_dec (v->number[0], policy); \
|
||||
if (previousSize == M_BUFF3R_SIZE(m_size)) { \
|
||||
m_mutex_lock(v->mutexPush); \
|
||||
@@ -737,6 +737,8 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, buffer_t, M_C(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
|
||||
|
||||
|
||||
|
||||
@@ -752,7 +754,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
|
||||
/* Deferred evaluation for the definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_QU3UE_MPMC_DEF_P1(arg) M_QU3UE_MPMC_DEF_P2 arg
|
||||
#define M_QU3UE_MPMC_DEF_P1(arg) M_ID( M_QU3UE_MPMC_DEF_P2 arg )
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define M_QU3UE_MPMC_DEF_P2(name, type, policy, oplist, buffer_t) \
|
||||
@@ -832,8 +834,12 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
/* Thread has been preempted by another one. */ \
|
||||
return false; \
|
||||
} \
|
||||
/* If it is interrupted here, it may block pop method (not push) */ \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
/* If it is interrupted here, it may block all pop methods (not push) \
|
||||
even if there is other threads that have pushed data later in the \
|
||||
queue as all pop threads will try to enqueue this particular element \
|
||||
but always fail. The won't try to enqueue other elements. \
|
||||
As such, this queue is not strictly lock-free.*/ \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_CALL_SET(oplist, table->Tab[i].x, x); \
|
||||
} else { \
|
||||
M_CALL_INIT_SET(oplist, table->Tab[i].x, x); \
|
||||
@@ -863,7 +869,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
/* Thread has been preempted by another one */ \
|
||||
return false; \
|
||||
} \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_CALL_SET(oplist, *ptr, table->Tab[i].x); \
|
||||
} else { \
|
||||
M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \
|
||||
@@ -879,7 +885,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_ASSERT (buffer != NULL); \
|
||||
M_ASSERT( M_POWEROF2_P(size)); \
|
||||
M_ASSERT (0 < size && size <= UINT_MAX); \
|
||||
M_ASSERT(((policy) & (BUFFER_STACK|BUFFER_THREAD_UNSAFE|BUFFER_PUSH_OVERWRITE)) == 0); \
|
||||
M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_THREAD_UNSAFE|M_BUFFER_PUSH_OVERWRITE)) == 0); \
|
||||
atomic_init(&buffer->ProdIdx, (unsigned int) size); \
|
||||
atomic_init(&buffer->ConsoIdx, (unsigned int) size); \
|
||||
buffer->size = (unsigned int) size; \
|
||||
@@ -890,7 +896,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
} \
|
||||
for(unsigned int j = 0; j < (unsigned int) size; j++) { \
|
||||
atomic_init(&buffer->Tab[j].seq, 2*j+1U); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_CALL_INIT(oplist, buffer->Tab[j].x); \
|
||||
} \
|
||||
} \
|
||||
@@ -901,7 +907,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_C(name, _clear)(buffer_t buffer) \
|
||||
{ \
|
||||
M_QU3UE_MPMC_CONTRACT(buffer); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
for(unsigned int j = 0; j < buffer->size; j++) { \
|
||||
M_CALL_CLEAR(oplist, buffer->Tab[j].x); \
|
||||
} \
|
||||
@@ -974,7 +980,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
|
||||
/* Deferred evaluation for the definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_QU3UE_SPSC_DEF_P1(arg) M_QU3UE_SPSC_DEF_P2 arg
|
||||
#define M_QU3UE_SPSC_DEF_P1(arg) M_ID( M_QU3UE_SPSC_DEF_P2 arg )
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define M_QU3UE_SPSC_DEF_P2(name, type, policy, oplist, buffer_t) \
|
||||
@@ -1037,7 +1043,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
if (w-r >= table->size) \
|
||||
return false; \
|
||||
unsigned int i = w & (table->size -1); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_CALL_SET(oplist, table->Tab[i].x, x); \
|
||||
} else { \
|
||||
M_CALL_INIT_SET(oplist, table->Tab[i].x, x); \
|
||||
@@ -1058,7 +1064,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
if (w-r >= table->size) \
|
||||
return false; \
|
||||
unsigned int i = w & (table->size -1); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_DO_MOVE(oplist, table->Tab[i].x, *x); \
|
||||
} else { \
|
||||
M_DO_INIT_MOVE(oplist, table->Tab[i].x, *x); \
|
||||
@@ -1080,7 +1086,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
if (w-r == 0) \
|
||||
return false; \
|
||||
unsigned int i = r & (table->size -1); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_CALL_SET(oplist, *ptr , table->Tab[i].x); \
|
||||
} else { \
|
||||
M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \
|
||||
@@ -1105,7 +1111,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
return 0; \
|
||||
for(unsigned int k = 0; k < max; k++) { \
|
||||
unsigned int i = (w+k) & (table->size -1); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_CALL_SET(oplist, table->Tab[i].x, x[k]); \
|
||||
} else { \
|
||||
M_CALL_INIT_SET(oplist, table->Tab[i].x, x[k]); \
|
||||
@@ -1131,7 +1137,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
unsigned int max = M_MIN(w-r, n); \
|
||||
for(unsigned int k = 0; k < max; k++) { \
|
||||
unsigned int i = (r+k) & (table->size -1); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_CALL_SET(oplist, ptr[k], table->Tab[i].x); \
|
||||
} else { \
|
||||
M_DO_INIT_MOVE (oplist, ptr[k], table->Tab[i].x); \
|
||||
@@ -1156,7 +1162,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
r += b; \
|
||||
} \
|
||||
unsigned int i = w & (table->size -1); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_CALL_SET(oplist, table->Tab[i].x, x); \
|
||||
} else { \
|
||||
M_CALL_INIT_SET(oplist, table->Tab[i].x, x); \
|
||||
@@ -1210,7 +1216,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_ASSERT (buffer != NULL); \
|
||||
M_ASSERT( M_POWEROF2_P(size)); \
|
||||
M_ASSERT (0 < size && size <= UINT_MAX); \
|
||||
M_ASSERT(((policy) & (BUFFER_STACK|BUFFER_THREAD_UNSAFE|BUFFER_PUSH_OVERWRITE)) == 0); \
|
||||
M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_THREAD_UNSAFE|M_BUFFER_PUSH_OVERWRITE)) == 0); \
|
||||
atomic_init(&buffer->prodIdx, (unsigned int) size); \
|
||||
atomic_init(&buffer->consoIdx, (unsigned int) size); \
|
||||
buffer->size = (unsigned int) size; \
|
||||
@@ -1219,7 +1225,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_MEMORY_FULL (size*sizeof(M_C(name, _el_ct) )); \
|
||||
return; \
|
||||
} \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
for(unsigned int j = 0; j < (unsigned int) size; j++) { \
|
||||
M_CALL_INIT(oplist, buffer->Tab[j].x); \
|
||||
} \
|
||||
@@ -1231,7 +1237,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_C(name, _clear)(buffer_t buffer) \
|
||||
{ \
|
||||
M_QU3UE_SPSC_CONTRACT(buffer); \
|
||||
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
for(unsigned int j = 0; j < buffer->size; j++) { \
|
||||
M_CALL_CLEAR(oplist, buffer->Tab[j].x); \
|
||||
} \
|
||||
@@ -1282,5 +1288,30 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
,GET_SIZE(M_C(name, _size)) \
|
||||
)
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define BUFFER_DEF M_BUFFER_DEF
|
||||
#define BUFFER_DEF_AS M_BUFFER_DEF_AS
|
||||
#define BUFFER_OPLIST M_BUFFER_OPLIST
|
||||
#define QUEUE_MPMC_DEF M_QUEUE_MPMC_DEF
|
||||
#define QUEUE_MPMC_DEF_AS M_QUEUE_MPMC_DEF_AS
|
||||
#define QUEUE_SPSC_DEF M_QUEUE_SPSC_DEF
|
||||
#define QUEUE_SPSC_DEF_AS M_QUEUE_SPSC_DEF_AS
|
||||
|
||||
#define buffer_policy_e m_buffer_policy_e
|
||||
#define BUFFER_QUEUE M_BUFFER_QUEUE
|
||||
#define BUFFER_STACK M_BUFFER_STACK
|
||||
#define BUFFER_BLOCKING_PUSH M_BUFFER_BLOCKING_PUSH
|
||||
#define BUFFER_UNBLOCKING_PUSH M_BUFFER_UNBLOCKING_PUSH
|
||||
#define BUFFER_BLOCKING_POP M_BUFFER_BLOCKING_POP
|
||||
#define BUFFER_UNBLOCKING_POP M_BUFFER_UNBLOCKING_POP
|
||||
#define BUFFER_BLOCKING M_BUFFER_BLOCKING
|
||||
#define BUFFER_UNBLOCKING M_BUFFER_UNBLOCKING
|
||||
#define BUFFER_THREAD_SAFE M_BUFFER_THREAD_SAFE
|
||||
#define BUFFER_THREAD_UNSAFE M_BUFFER_THREAD_UNSAFE
|
||||
#define BUFFER_PUSH_INIT_POP_MOVE M_BUFFER_PUSH_INIT_POP_MOVE
|
||||
#define BUFFER_PUSH_OVERWRITE M_BUFFER_PUSH_OVERWRITE
|
||||
#define BUFFER_DEFERRED_POP M_BUFFER_DEFERRED_POP
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+23
-19
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Concurrent memory pool allocator
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -34,7 +34,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Minimum number of nodes per group of nodes */
|
||||
#define M_CMEMP00L_MIN_NODE_PER_GROUP 16
|
||||
|
||||
#define C_MEMPOOL_DEF(name, type_t) \
|
||||
#define M_C_MEMPOOL_DEF(name, type_t) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_CMEMP00L_DEF_SINGLY_LIST(name, type_t) \
|
||||
M_CMEMP00L_DEF_LF_QUEUE(name, type_t) \
|
||||
@@ -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_gM_CMEMP00L_list_ct mempool_node; \
|
||||
m_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_C3(m_cmemp00l_,name,_gc_on_sleep)(m_gc_t gc_mem, m_gM_CMEMP00L_list_ct *data, \
|
||||
M_C3(m_cmemp00l_,name,_gc_on_sleep)(m_gc_t gc_mem, m_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_gM_CMEMP00L_list_ct, mempool_node); \
|
||||
M_TYPE_FROM_FIELD(struct M_C(name, _s), data, m_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)) { \
|
||||
@@ -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_gM_CMEMP00L_list_s {
|
||||
struct m_gM_CMEMP00L_list_s *next;
|
||||
typedef struct m_cmemp00l_list_s {
|
||||
struct m_cmemp00l_list_s *next;
|
||||
void (*gc_on_sleep)(struct m_gc_s *gc_mem,
|
||||
struct m_gM_CMEMP00L_list_s *data, m_gc_tid_t id,
|
||||
struct m_cmemp00l_list_s *data, m_gc_tid_t id,
|
||||
m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket);
|
||||
void *data;
|
||||
} m_gM_CMEMP00L_list_ct;
|
||||
} m_cmemp00l_list_ct;
|
||||
|
||||
/* Define the Garbage collector thread data */
|
||||
typedef struct m_gc_lfmp_thread_s {
|
||||
@@ -574,9 +574,9 @@ typedef struct m_gc_lfmp_thread_s {
|
||||
typedef struct m_gc_s {
|
||||
m_gc_atomic_ticket_ct ticket;
|
||||
m_gc_tid_t max_thread;
|
||||
genint_t thread_alloc;
|
||||
m_genint_t thread_alloc;
|
||||
m_gc_lfmp_thread_ct *thread_data;
|
||||
m_gM_CMEMP00L_list_ct *mempool_list;
|
||||
m_cmemp00l_list_ct *mempool_list;
|
||||
} m_gc_t[1];
|
||||
|
||||
static inline void
|
||||
@@ -586,7 +586,7 @@ m_gc_init(m_gc_t gc_mem, size_t max_thread)
|
||||
M_ASSERT(max_thread > 0 && max_thread < INT_MAX);
|
||||
|
||||
atomic_init(&gc_mem->ticket, 0UL);
|
||||
genint_init(gc_mem->thread_alloc, (unsigned int) max_thread);
|
||||
m_genint_init(gc_mem->thread_alloc, (unsigned int) max_thread);
|
||||
gc_mem->thread_data = M_MEMORY_REALLOC(m_gc_lfmp_thread_ct, NULL, max_thread);
|
||||
if (gc_mem->thread_data == NULL) {
|
||||
M_MEMORY_FULL(max_thread * sizeof(m_gc_lfmp_thread_ct));
|
||||
@@ -610,7 +610,7 @@ m_gc_clear(m_gc_t gc_mem)
|
||||
}
|
||||
M_MEMORY_FREE(gc_mem->thread_data);
|
||||
gc_mem->thread_data = NULL;
|
||||
genint_clear(gc_mem->thread_alloc);
|
||||
m_genint_clear(gc_mem->thread_alloc);
|
||||
}
|
||||
|
||||
static inline m_gc_tid_t
|
||||
@@ -618,7 +618,7 @@ m_gc_attach_thread(m_gc_t gc_mem)
|
||||
{
|
||||
M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0);
|
||||
|
||||
unsigned id = genint_pop(gc_mem->thread_alloc);
|
||||
unsigned id = m_genint_pop(gc_mem->thread_alloc);
|
||||
return M_ASSIGN_CAST(m_gc_tid_t, id);
|
||||
}
|
||||
|
||||
@@ -629,7 +629,7 @@ m_gc_detach_thread(m_gc_t gc_mem, m_gc_tid_t id)
|
||||
M_ASSERT(id < gc_mem->max_thread);
|
||||
M_ASSERT(atomic_load(&gc_mem->thread_data[id].ticket) == ULONG_MAX);
|
||||
|
||||
genint_push(gc_mem->thread_alloc, id);
|
||||
m_genint_push(gc_mem->thread_alloc, id);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -662,7 +662,7 @@ m_gc_sleep(m_gc_t gc_mem, m_gc_tid_t id)
|
||||
atomic_store(&gc_mem->thread_data[id].ticket, t+1);
|
||||
const m_gc_ticket_ct min_ticket = m_cmemp00l_gc_min_ticket(gc_mem);
|
||||
/* Iterate over all registered mempools */
|
||||
m_gM_CMEMP00L_list_ct *it = gc_mem->mempool_list;
|
||||
m_cmemp00l_list_ct *it = gc_mem->mempool_list;
|
||||
|
||||
while (it) {
|
||||
/* Perform a garbage collect of the mempool */
|
||||
@@ -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_gM_CMEMP00L_list_ct mvla_node;
|
||||
m_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_cmemp00l_vlapool_on_sleep(m_gc_t gc_mem, m_gM_CMEMP00L_list_ct *data,
|
||||
m_cmemp00l_vlapool_on_sleep(m_gc_t gc_mem, m_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_gM_CMEMP00L_list_ct, mvla_node);
|
||||
M_TYPE_FROM_FIELD(struct m_vlapool_s, data, m_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)) {
|
||||
@@ -828,4 +828,8 @@ m_vlapool_del(m_vlapool_t mem, void *d, m_gc_tid_t id)
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define C_MEMPOOL_DEF M_C_MEMPOOL_DEF
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+21
-22
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Basic Protected Concurrent module over container.
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -32,14 +32,14 @@
|
||||
/* Define a protected concurrent container and its associated functions
|
||||
based on the given container.
|
||||
USAGE: CONCURRENT_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define CONCURRENT_DEF(name, ...) \
|
||||
CONCURRENT_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_CONCURRENT_DEF(name, ...) \
|
||||
M_CONCURRENT_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a protected concurrent container and its associated functions
|
||||
based on the given container as the given name name_t
|
||||
USAGE: CONCURRENT_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
|
||||
#define CONCURRENT_DEF_AS(name, name_t, ...) \
|
||||
#define M_CONCURRENT_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_C0NCURRENT_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
@@ -51,8 +51,8 @@
|
||||
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, ...) \
|
||||
CONCURRENT_RP_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_CONCURRENT_RP_DEF(name, ...) \
|
||||
M_CONCURRENT_RP_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a protected concurrent container and its associated functions
|
||||
@@ -60,7 +60,7 @@
|
||||
based on its given container. Operations that perform only read of the container
|
||||
can be done in parallel.
|
||||
USAGE: CONCURRENT_RP_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
|
||||
#define CONCURRENT_RP_DEF_AS(name, name_t, ...) \
|
||||
#define M_CONCURRENT_RP_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_C0NCURRENT_RP_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
@@ -70,9 +70,9 @@
|
||||
|
||||
/* 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(...) \
|
||||
#define M_CONCURRENT_OPLIST(...) \
|
||||
M_C0NCURRENT_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
|
||||
/* Deferred evaluation for the concurrent definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_C0NCURRENT_DEF_P1(arg) M_C0NCURRENT_DEF_P2 arg
|
||||
#define M_C0NCURRENT_DEF_P1(arg) M_ID( M_C0NCURRENT_DEF_P2 arg )
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define M_C0NCURRENT_DEF_P2(name, type, oplist, concurrent_t) \
|
||||
@@ -423,11 +423,6 @@
|
||||
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) \
|
||||
{ \
|
||||
M_C(name,_reset)(out); \
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
M_IF_METHOD(EMPTY_P, oplist)( \
|
||||
@@ -494,11 +489,6 @@
|
||||
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)( \
|
||||
@@ -525,6 +515,8 @@
|
||||
M_C(name, _write_signal)(out); \
|
||||
M_C(name, _write_unlock)(out); \
|
||||
} \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, concurrent_t, M_C(name, _emplace), M_GET_OPLIST oplist, M_EMPLACE_QUEUE_GENE) \
|
||||
,) \
|
||||
\
|
||||
M_IF_METHOD(POP, oplist)( \
|
||||
@@ -565,7 +557,7 @@
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, concurrent_t const out, bool a) \
|
||||
M_C(name, _get_str)(m_string_t str, concurrent_t const out, bool a) \
|
||||
{ \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
@@ -750,7 +742,7 @@
|
||||
|
||||
/* Deferred evaluation for the RP concurrent definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_C0NCURRENT_RP_DEF_P1(arg) M_C0NCURRENT_RP_DEF_P2 arg
|
||||
#define M_C0NCURRENT_RP_DEF_P1(arg) M_ID( M_C0NCURRENT_RP_DEF_P2 arg )
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define M_C0NCURRENT_RP_DEF_P2(name, type, oplist, concurrent_t) \
|
||||
@@ -905,5 +897,12 @@
|
||||
\
|
||||
M_C0NCURRENT_DEF_FUNC_P3(name, type, oplist, concurrent_t)
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define CONCURRENT_DEF M_CONCURRENT_DEF
|
||||
#define CONCURRENT_DEF_AS M_CONCURRENT_DEF_AS
|
||||
#define CONCURRENT_RP_DEF M_CONCURRENT_RP_DEF
|
||||
#define CONCURRENT_RP_DEF_AS M_CONCURRENT_RP_DEF_AS
|
||||
#define CONCURRENT_OPLIST M_CONCURRENT_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - DEQUE module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -29,14 +29,14 @@
|
||||
|
||||
/* Define a deque of a given type and its associated functions.
|
||||
USAGE: DEQUE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define DEQUE_DEF(name, ...) \
|
||||
DEQUE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
#define M_DEQUE_DEF(name, ...) \
|
||||
M_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.
|
||||
as the provided type name_t with the iterator named it_t.
|
||||
USAGE: DEQUE_DEF(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define DEQUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_DEQUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
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) ), \
|
||||
@@ -46,9 +46,9 @@
|
||||
|
||||
/* Define the oplist of a deque of a type.
|
||||
USAGE: DEQUE_OPLIST(name[, oplist of the type]) */
|
||||
#define DEQUE_OPLIST(...) \
|
||||
#define M_DEQUE_OPLIST(...) \
|
||||
M_D3QU3_OPLIST_P1 (M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
/* Default initial size of a bucket of items */
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
/* Deferred evaluation for the deque definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_D3QU3_DEF_P1(arg) M_D3QU3_DEF_P2 arg
|
||||
#define M_D3QU3_DEF_P1(arg) M_ID( M_D3QU3_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_D3QU3_DEF_P2(name, type, oplist, deque_t, it_t, node_t) \
|
||||
@@ -226,12 +226,6 @@
|
||||
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) \
|
||||
{ \
|
||||
@@ -902,10 +896,10 @@
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, deque_t const deque, bool append) \
|
||||
M_C(name, _get_str)(m_string_t str, deque_t const deque, bool append) \
|
||||
{ \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
|
||||
it_t it; \
|
||||
for (M_C(name, _it)(it, deque) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
@@ -913,9 +907,9 @@
|
||||
type const *item = M_C(name, _cref)(it); \
|
||||
M_CALL_GET_STR(oplist, str, *item, true); \
|
||||
if (!M_C(name, _last_p)(it)) \
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
m_string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
m_string_push_back (str, ']'); \
|
||||
} \
|
||||
, /* no GET_STR */ ) \
|
||||
\
|
||||
@@ -1048,6 +1042,35 @@
|
||||
} \
|
||||
, /* no IN_SERIAL & INIT */ ) \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, deque_t, M_C(name, _emplace_back), oplist, M_D3QUE_EMPLACE_BACK_DEF) \
|
||||
M_EMPLACE_QUEUE_DEF(name, deque_t, M_C(name, _emplace_front), oplist, M_D3QUE_EMPLACE_FRONT_DEF)
|
||||
|
||||
|
||||
/* Definition of the emplace_back function for deque */
|
||||
#define M_D3QUE_EMPLACE_BACK_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
static inline void \
|
||||
function_name(name_t v \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_C(name, _subtype_ct) *data = M_C(name, _push_back_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
}
|
||||
|
||||
|
||||
/* Definition of the emplace_front function for deque */
|
||||
#define M_D3QUE_EMPLACE_FRONT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
static inline void \
|
||||
function_name(name_t v \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_C(name, _subtype_ct) *data = M_C(name, _push_front_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
}
|
||||
|
||||
|
||||
/* Deferred evaluation for the oplist definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
@@ -1106,4 +1129,10 @@
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
)
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define DEQUE_DEF M_DEQUE_DEF
|
||||
#define DEQUE_DEF_AS M_DEQUE_DEF_AS
|
||||
#define DEQUE_OPLIST M_DEQUE_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - DICTIONARY Module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -36,8 +36,8 @@
|
||||
OR
|
||||
DICT_DEF2(name, key_type, value_type)
|
||||
*/
|
||||
#define DICT_DEF2(name, key_type, ...) \
|
||||
DICT_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), key_type, __VA_ARGS__)
|
||||
#define M_DICT_DEF2(name, key_type, ...) \
|
||||
M_DICT_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), key_type, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a dictionary associating the key key_type to the value value_type and its associated functions.
|
||||
@@ -47,7 +47,7 @@
|
||||
OR
|
||||
DICT_DEF2_AS(name, name_t, it_t, itref_t, key_type, value_type)
|
||||
*/
|
||||
#define DICT_DEF2_AS(name, name_t, it_t, itref_t, key_type, ...) \
|
||||
#define M_DICT_DEF2_AS(name, name_t, it_t, itref_t, key_type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_D1CT_DEF2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t, itref_t ), \
|
||||
@@ -63,8 +63,8 @@
|
||||
OR
|
||||
DICT_STOREHASH_DEF2(name, key_type[, key_oplist], value_type[, value_oplist])
|
||||
*/
|
||||
#define DICT_STOREHASH_DEF2(name, key_type, ...) \
|
||||
DICT_STOREHASH_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), key_type, __VA_ARGS__)
|
||||
#define M_DICT_STOREHASH_DEF2(name, key_type, ...) \
|
||||
M_DICT_STOREHASH_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), key_type, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a dictionary asssociating the key key_type to the value value_type and its associated functions.
|
||||
@@ -76,7 +76,7 @@
|
||||
OR
|
||||
DICT_STOREHASH_DEF2_AS(name, name_t, it_t, itref_t, key_type[, key_oplist], value_type[, value_oplist])
|
||||
*/
|
||||
#define DICT_STOREHASH_DEF2_AS(name, name_t, it_t, itref_t, key_type, ...) \
|
||||
#define M_DICT_STOREHASH_DEF2_AS(name, name_t, it_t, itref_t, key_type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_D1CT_SHASH_DEF2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t, itref_t ), \
|
||||
@@ -92,8 +92,8 @@
|
||||
OR
|
||||
DICT_OA_DEF2(name, key_type, value_type)
|
||||
*/
|
||||
#define DICT_OA_DEF2(name, key_type, ...) \
|
||||
DICT_OA_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), key_type, __VA_ARGS__)
|
||||
#define M_DICT_OA_DEF2(name, key_type, ...) \
|
||||
M_DICT_OA_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), key_type, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a dictionary associating the key key_type to the value value_type
|
||||
@@ -105,7 +105,7 @@
|
||||
OR
|
||||
DICT_OA_DEF2_AS(name, name_t, it_t, itref_t, key_type, value_type)
|
||||
*/
|
||||
#define DICT_OA_DEF2_AS(name, name_t, it_t, itref_t, key_type, ...) \
|
||||
#define M_DICT_OA_DEF2_AS(name, name_t, it_t, itref_t, key_type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_D1CT_OA_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t, itref_t ), \
|
||||
@@ -117,8 +117,8 @@
|
||||
The set is unordered.
|
||||
USAGE: DICT_SET_DEF(name, key_type[, key_oplist])
|
||||
*/
|
||||
#define DICT_SET_DEF(name, ...) \
|
||||
DICT_SET_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
#define M_DICT_SET_DEF(name, ...) \
|
||||
M_DICT_SET_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a set of the key key_type and its associated functions.
|
||||
@@ -126,7 +126,7 @@
|
||||
The set is unordered.
|
||||
USAGE: DICT_SET_DEF_AS(name, name_t, it_t, key_type[, key_oplist])
|
||||
*/
|
||||
#define DICT_SET_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_DICT_SET_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_D1CT_SET_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, _itref_ct) ), \
|
||||
@@ -139,8 +139,8 @@
|
||||
The set is unordered.
|
||||
USAGE: DICT_OASET_DEF(name, key_type[, key_oplist])
|
||||
*/
|
||||
#define DICT_OASET_DEF(name, ...) \
|
||||
DICT_OASET_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
#define M_DICT_OASET_DEF(name, ...) \
|
||||
M_DICT_OASET_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a set of the key key_type
|
||||
@@ -149,7 +149,7 @@
|
||||
The set is unordered.
|
||||
USAGE: DICT_OASET_DEF_AS(name, name_t, it_t, key_type[, key_oplist])
|
||||
*/
|
||||
#define DICT_OASET_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_DICT_OASET_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_D1CT_OASET_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, _itref_ct) ), \
|
||||
@@ -163,17 +163,17 @@
|
||||
OR
|
||||
DICT_OPLIST(name)
|
||||
*/
|
||||
#define DICT_OPLIST(...) \
|
||||
#define M_DICT_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(M_D1CT_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST )), \
|
||||
(M_D1CT_OPLIST_P1((__VA_ARGS__, M_BASIC_OPLIST, M_BASIC_OPLIST )), \
|
||||
M_D1CT_OPLIST_P1((__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define the oplist of a dictionnary (DICT_SET_DEF).
|
||||
USAGE: DICT_SET_OPLIST(name[, oplist of the key type]) */
|
||||
#define DICT_SET_OPLIST(...) \
|
||||
#define M_DICT_SET_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(M_D1CT_SET_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST)), \
|
||||
(M_D1CT_SET_OPLIST_P1((__VA_ARGS__, M_BASIC_OPLIST)), \
|
||||
M_D1CT_SET_OPLIST_P1((__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
current array size).
|
||||
*/
|
||||
/* Deferred evaluation for arg */
|
||||
#define M_D1CT_DEF2_P1(arg) M_D1CT_DEF2_P2 arg
|
||||
#define M_D1CT_DEF2_P1(arg) M_ID( M_D1CT_DEF2_P2 arg )
|
||||
|
||||
/* Validate the key oplist before going further */
|
||||
#define M_D1CT_DEF2_P2(name, key_type, key_oplist, value_type, value_oplist, dict_t, dict_it_t, it_deref_t) \
|
||||
@@ -218,7 +218,7 @@
|
||||
representing a bucket).
|
||||
*/
|
||||
/* Defered evaluation for arg */
|
||||
#define M_D1CT_SHASH_DEF2_P1(arg) M_D1CT_SHASH_DEF2_P2 arg
|
||||
#define M_D1CT_SHASH_DEF2_P1(arg) M_ID( M_D1CT_SHASH_DEF2_P2 arg )
|
||||
|
||||
/* Validate the key oplist before going further */
|
||||
#define M_D1CT_SHASH_DEF2_P2(name, key_type, key_oplist, value_type, value_oplist, dict_t, dict_it_t, it_deref_t) \
|
||||
@@ -237,10 +237,10 @@
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 2, value_type, value_oplist) \
|
||||
\
|
||||
TUPLE_DEF2(M_C(name, _pair), (hash, size_t, M_DEFAULT_OPLIST), (key, key_type, key_oplist), (value, value_type, value_oplist)) \
|
||||
TUPLE_DEF2(M_C(name, _pair), (hash, size_t, M_BASIC_OPLIST), (key, key_type, key_oplist), (value, value_type, value_oplist)) \
|
||||
\
|
||||
M_D1CT_FUNC_DEF2_P5(name, key_type, key_oplist, value_type, value_oplist, \
|
||||
M_C(name, _pair_ct), TUPLE_OPLIST(M_C(name, _pair), M_DEFAULT_OPLIST, key_oplist, value_oplist), 0, 1, \
|
||||
M_C(name, _pair_ct), TUPLE_OPLIST(M_C(name, _pair), M_BASIC_OPLIST, key_oplist, value_oplist), 0, 1, \
|
||||
dict_t, dict_it_t, it_deref_t )
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
It is defined as an array of singly linked list (each list
|
||||
representing a bucket).
|
||||
*/
|
||||
#define M_D1CT_SET_DEF_P1(arg) M_D1CT_SET_DEF_P2 arg
|
||||
#define M_D1CT_SET_DEF_P1(arg) M_ID( M_D1CT_SET_DEF_P2 arg )
|
||||
|
||||
/* Validate the key oplist before going further */
|
||||
#define M_D1CT_SET_DEF_P2(name, key_type, key_oplist, dict_t, dict_it_t, it_deref_t) \
|
||||
@@ -270,7 +270,7 @@
|
||||
|
||||
|
||||
|
||||
/* Define the structure of a chained dictionnary for all kind of dictionnaries
|
||||
/* Define the structure of a chained dictionnary for all kind of dictionaries
|
||||
* name: prefix of the container,
|
||||
* key_type: type of the key
|
||||
* key_oplist: oplist of the key
|
||||
@@ -421,12 +421,6 @@
|
||||
M_D1CT_CONTRACT(name, map); \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name,_clean)(dict_t map) \
|
||||
{ \
|
||||
M_C(name, _reset)(map); \
|
||||
} \
|
||||
\
|
||||
static inline value_type * \
|
||||
M_C(name, _get)(const dict_t map, key_type const key) \
|
||||
{ \
|
||||
@@ -456,7 +450,7 @@
|
||||
static inline void \
|
||||
M_C3(m_d1ct_,name,_resize_up)(dict_t map) \
|
||||
{ \
|
||||
/* NOTE: Contract may not be fullfilled here */ \
|
||||
/* NOTE: Contract may not be fulfilled here */ \
|
||||
size_t old_size = M_C(name, _array_list_pair_size)(map->table); \
|
||||
size_t new_size = old_size * 2; \
|
||||
if (M_UNLIKELY (new_size <= old_size)) { \
|
||||
@@ -496,7 +490,7 @@
|
||||
static inline void \
|
||||
M_C3(m_d1ct_,name,_resize_down)(dict_t map) \
|
||||
{ \
|
||||
/* NOTE: Contract may not be fullfilled here */ \
|
||||
/* NOTE: Contract may not be fulfilled here */ \
|
||||
size_t old_size = M_C(name, _array_list_pair_size)(map->table); \
|
||||
M_ASSERT ((old_size % 2) == 0); \
|
||||
size_t new_size = old_size / 2; \
|
||||
@@ -581,11 +575,6 @@
|
||||
} \
|
||||
M_D1CT_CONTRACT(name, map); \
|
||||
return &(*ref)->M_IF(isSet)(key, value); \
|
||||
} \
|
||||
static inline M_ATTR_DEPRECATED value_type * \
|
||||
M_C(name, _get_at)(dict_t map, key_type const key) \
|
||||
{ \
|
||||
return M_C(name, _safe_get)(map, key); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
@@ -719,7 +708,7 @@
|
||||
/* Define additional functions for dictionnary (Common for all kinds of dictionnary).
|
||||
Do not used any specific fields of the dictionnary but the public API
|
||||
|
||||
It is not possible to define the _remove method: we could easily define it
|
||||
It is not possible to define a method for IT_REMOVE: we could easily define it
|
||||
by performing an _erase of the key get by the _cref method. However,
|
||||
computing the next element is way harder. We could easily compute the next
|
||||
element of the iteration (using _next). However with the _erase method, the
|
||||
@@ -728,7 +717,18 @@
|
||||
'next' element impossible as the order of the elements in the dict
|
||||
has fundamentaly changed in this case. We could detect this and restart
|
||||
the iteration from the first element, but it wouldn't fit the contract
|
||||
of the IT\_REMOVE operator.
|
||||
of the IT_REMOVE operator.
|
||||
|
||||
HASH method for dictionnary itself seems hard to implement:
|
||||
we have to handle the case where two dictionaries are structuraly
|
||||
different, but functionnaly identical (seems they have the same
|
||||
members, but put in a different order).
|
||||
We cannot iterator over the dictionary to compute a hash, as the
|
||||
order of the items in the dictionnary is not specified: they more
|
||||
or less follow the hash of the keys, but if the low bits of the
|
||||
hash of the key is equal, they order may be different.
|
||||
Or if the table of the dictionnary has different values (this may
|
||||
be avoided).
|
||||
*/
|
||||
#define M_D1CT_FUNC_ADDITIONAL_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, dict_t, dict_it_t, it_deref_t) \
|
||||
\
|
||||
@@ -759,7 +759,7 @@
|
||||
return true; \
|
||||
/* Otherwise this is the slow path : \
|
||||
both dictionary may not have arrays with the same size, but \
|
||||
still the dictionnaries shall be equal as they contain the same \
|
||||
still the dictionaries shall be equal as they contain the same \
|
||||
items. */ \
|
||||
dict_it_t it; \
|
||||
for(M_C(name, _it)(it, dict1) ; \
|
||||
@@ -778,27 +778,27 @@
|
||||
\
|
||||
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, const dict_t dict, const bool append) \
|
||||
M_C(name, _get_str)(m_string_t str, const dict_t dict, const bool append) \
|
||||
{ \
|
||||
(append ? string_cat_str : string_set_str) (str, "{"); \
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "{"); \
|
||||
dict_it_t it; \
|
||||
bool print_comma = false; \
|
||||
for (M_C(name, _it)(it, dict) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
M_C(name, _next)(it)){ \
|
||||
if (print_comma) \
|
||||
string_push_back (str, ','); \
|
||||
m_string_push_back (str, ','); \
|
||||
const it_deref_t *item = M_C(name, _cref)(it); \
|
||||
M_IF(isSet)( \
|
||||
M_CALL_GET_STR(key_oplist, str, *item, true); \
|
||||
, \
|
||||
M_CALL_GET_STR(key_oplist, str, item->key, true); \
|
||||
string_push_back (str, ':'); \
|
||||
m_string_push_back (str, ':'); \
|
||||
M_CALL_GET_STR(value_oplist, str, item->value, true); \
|
||||
) \
|
||||
print_comma = true; \
|
||||
} \
|
||||
string_push_back (str, '}'); \
|
||||
m_string_push_back (str, '}'); \
|
||||
} \
|
||||
, /* no GET_STR */ ) \
|
||||
\
|
||||
@@ -1035,18 +1035,7 @@
|
||||
} \
|
||||
, /* NO UPDATE */) ) \
|
||||
\
|
||||
/* HASH method for dictionnary itself seems hard to implement: \
|
||||
we have to handle the case where two dictionnaries are structuraly \
|
||||
different, but functionnaly identical (seems they have the same \
|
||||
members, but put in a different order). \
|
||||
We cannot iterator over the dictionary to compute a hash, as the \
|
||||
order of the items in the dictionnary is not specified: they more \
|
||||
or less follow the hash of the keys, but if the low bits of the \
|
||||
hash of the key is equal, they order may be different. \
|
||||
Or if the table of the dictionnary has different values (this may \
|
||||
be avoided). */
|
||||
|
||||
|
||||
M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF(isSet, name, dict_t, key_oplist, value_oplist)
|
||||
|
||||
/* Deferred evaluation for the definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
@@ -1226,7 +1215,7 @@ enum m_d1ct_oa_element_e {
|
||||
M_ASSERT( (dict)->upper_limit <= (dict)->mask+1); \
|
||||
} while (0)
|
||||
|
||||
#define M_D1CT_OA_DEF_P1(args) M_D1CT_OA_DEF_P2 args
|
||||
#define M_D1CT_OA_DEF_P1(args) M_ID( M_D1CT_OA_DEF_P2 args )
|
||||
|
||||
/* Validate the key oplist before going further */
|
||||
#define M_D1CT_OA_DEF_P2(name, key_type, key_oplist, value_type, value_oplist, dict_t, dict_it_t, it_deref_t) \
|
||||
@@ -1245,7 +1234,7 @@ enum m_d1ct_oa_element_e {
|
||||
M_D1CT_OA_LOWER_BOUND, M_D1CT_OA_UPPER_BOUND, \
|
||||
dict_t, dict_it_t, it_deref_t)
|
||||
|
||||
#define M_D1CT_OASET_DEF_P1(args) M_D1CT_OASET_DEF_P2 args
|
||||
#define M_D1CT_OASET_DEF_P1(args) M_ID( M_D1CT_OASET_DEF_P2 args )
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define M_D1CT_OASET_DEF_P2(name, key_type, key_oplist, dict_t, dict_it_t, it_deref_t) \
|
||||
@@ -1339,7 +1328,7 @@ enum m_d1ct_oa_element_e {
|
||||
M_D1CT_OA_CONTRACT(dict); \
|
||||
for(size_t i = 0; i <= dict->mask; i++) { \
|
||||
if (!M_CALL_OOR_EQUAL(key_oplist, dict->data[i].key, M_D1CT_OA_EMPTY) \
|
||||
& !M_CALL_OOR_EQUAL(key_oplist, dict->data[i].key, M_D1CT_OA_DELETED)) { \
|
||||
&& !M_CALL_OOR_EQUAL(key_oplist, dict->data[i].key, M_D1CT_OA_DELETED)) { \
|
||||
M_CALL_CLEAR(key_oplist, dict->data[i].key); \
|
||||
M_CALL_CLEAR(value_oplist, dict->data[i].value); \
|
||||
} \
|
||||
@@ -1372,6 +1361,7 @@ enum m_d1ct_oa_element_e {
|
||||
size_t s = 1; \
|
||||
do { \
|
||||
p = (p + M_D1CT_OA_PROBING(s)) & mask; \
|
||||
/* data[p].key may be OA_DELETED or OA_EMPTY */ \
|
||||
if (M_CALL_EQUAL(key_oplist, data[p].key, key)) \
|
||||
return &data[p].M_IF(isSet)(key, value); \
|
||||
M_ASSERT (s <= dict->mask); \
|
||||
@@ -1435,10 +1425,12 @@ enum m_d1ct_oa_element_e {
|
||||
const size_t mask = (newSize -1); \
|
||||
\
|
||||
for(size_t i = 0 ; i < oldSize; i++) { \
|
||||
if (!M_CALL_OOR_EQUAL(key_oplist, data[i].key, M_D1CT_OA_DELETED) & !M_CALL_OOR_EQUAL(key_oplist, data[i].key, M_D1CT_OA_EMPTY)) { \
|
||||
if (!M_CALL_OOR_EQUAL(key_oplist, data[i].key, M_D1CT_OA_DELETED) \
|
||||
&& !M_CALL_OOR_EQUAL(key_oplist, data[i].key, M_D1CT_OA_EMPTY)) { \
|
||||
size_t p = M_CALL_HASH(key_oplist, data[i].key) & mask; \
|
||||
if (p != i) { \
|
||||
if (M_LIKELY (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) | M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED))) { \
|
||||
if (M_LIKELY (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) \
|
||||
|| M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED))) { \
|
||||
M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \
|
||||
M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \
|
||||
} else { \
|
||||
@@ -1512,7 +1504,10 @@ enum m_d1ct_oa_element_e {
|
||||
return; \
|
||||
} \
|
||||
M_ASSERT (s <= dict->mask); \
|
||||
if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED) & (delPos == (size_t)-1)) delPos = p; \
|
||||
if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED) \
|
||||
&& (delPos == (size_t)-1)) { \
|
||||
delPos = p; \
|
||||
} \
|
||||
} while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) ); \
|
||||
if (delPos != SIZE_MAX) { \
|
||||
p = delPos; \
|
||||
@@ -1563,7 +1558,10 @@ enum m_d1ct_oa_element_e {
|
||||
return &data[p].M_IF(isSet)(key, value); \
|
||||
} \
|
||||
M_ASSERT (s <= dict->mask); \
|
||||
if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED) & (delPos == (size_t)-1)) delPos = p; \
|
||||
if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED) \
|
||||
&& (delPos == (size_t)-1)) { \
|
||||
delPos = p; \
|
||||
} \
|
||||
} while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) ); \
|
||||
if (delPos != SIZE_MAX) { \
|
||||
p = delPos; \
|
||||
@@ -1619,7 +1617,8 @@ enum m_d1ct_oa_element_e {
|
||||
} \
|
||||
size_t p = M_CALL_HASH(key_oplist, data[i].key) & mask; \
|
||||
if (p != i) { \
|
||||
if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) || M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED)) { \
|
||||
if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) \
|
||||
|| M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED)) { \
|
||||
M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \
|
||||
M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \
|
||||
} else { \
|
||||
@@ -1833,7 +1832,7 @@ enum m_d1ct_oa_element_e {
|
||||
size_t i = 0; \
|
||||
while (i <= d->mask \
|
||||
&& (M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, M_D1CT_OA_EMPTY) \
|
||||
|| M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, M_D1CT_OA_DELETED))) { \
|
||||
|| M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, M_D1CT_OA_DELETED))) { \
|
||||
i++; \
|
||||
} \
|
||||
it->index = i; \
|
||||
@@ -1858,7 +1857,7 @@ enum m_d1ct_oa_element_e {
|
||||
size_t i = d->mask; \
|
||||
while (i <= d->mask \
|
||||
&& (M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, M_D1CT_OA_EMPTY) \
|
||||
|| M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, M_D1CT_OA_DELETED))) { \
|
||||
|| M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, M_D1CT_OA_DELETED))) { \
|
||||
i--; \
|
||||
} \
|
||||
it->index = i; \
|
||||
@@ -1970,5 +1969,19 @@ enum m_d1ct_oa_element_e {
|
||||
\
|
||||
M_D1CT_FUNC_ADDITIONAL_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, dict_t, dict_it_t, it_deref_t)
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define DICT_DEF2 M_DICT_DEF2
|
||||
#define DICT_DEF2_AS M_DICT_DEF2_AS
|
||||
#define DICT_STOREHASH_DEF2 M_DICT_STOREHASH_DEF2
|
||||
#define DICT_STOREHASH_DEF2_AS M_DICT_STOREHASH_DEF2_AS
|
||||
#define DICT_OA_DEF2 M_DICT_OA_DEF2
|
||||
#define DICT_OA_DEF2_AS M_DICT_OA_DEF2_AS
|
||||
#define DICT_SET_DEF M_DICT_SET_DEF
|
||||
#define DICT_SET_DEF_AS M_DICT_SET_DEF_AS
|
||||
#define DICT_OASET_DEF M_DICT_OASET_DEF
|
||||
#define DICT_OASET_DEF_AS M_DICT_OASET_DEF_AS
|
||||
#define DICT_OPLIST M_DICT_OPLIST
|
||||
#define DICT_SET_OPLIST M_DICT_SET_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+20
-11
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Function Object module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -32,8 +32,8 @@
|
||||
* USAGE:
|
||||
* FUNC_OBJ_ITF_DEF(name, retcode type, type of param1, type of param 2, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_ITF_DEF(name, ...) \
|
||||
FUNC_OBJ_ITF_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_FUNC_OBJ_ITF_DEF(name, ...) \
|
||||
M_FUNC_OBJ_ITF_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a function object interface of name 'name'
|
||||
@@ -41,7 +41,7 @@
|
||||
* USAGE:
|
||||
* FUNC_OBJ_ITF_DEF_AS(name, name_t, retcode type, type of param1, type of param 2, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_ITF_DEF_AS(name, name_t, ...) \
|
||||
#define M_FUNC_OBJ_ITF_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
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
|
||||
@@ -65,8 +65,8 @@
|
||||
* USAGE/EXAMPLE:
|
||||
* FUNC_OBJ_INS_DEF(name, base_name, (param1, ...), { return param1 * self->member1 }, (member1, int), ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_DEF(name, base_name, param_list, ...) \
|
||||
FUNC_OBJ_INS_DEF_AS(name, M_C(name,_t), base_name, param_list, __VA_ARGS__)
|
||||
#define M_FUNC_OBJ_INS_DEF(name, base_name, param_list, ...) \
|
||||
M_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'
|
||||
@@ -76,7 +76,7 @@
|
||||
* USAGE/EXAMPLE:
|
||||
* FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, (param1, ...), { return param1 * self->member1 }, (member1, int), ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, param_list, ...) \
|
||||
#define M_FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, param_list, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
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
|
||||
@@ -86,7 +86,7 @@
|
||||
* USAGE:
|
||||
* FUNC_OBJ_INS_OPLIST(name, oplist of the attr1, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_OPLIST(...) \
|
||||
#define M_FUNC_OBJ_INS_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(M_FUNC0BJ_INS_NO_ATTR_OPLIST, M_FUNC0BJ_INS_ATTR_OPLIST_P1)( __VA_ARGS__)
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
/* To be used by M_IF_FUNCOBJ macro defined in m-core.
|
||||
NOTE: It is reversed (0 instead of 1) so that it can be used in M_IF reliabely.
|
||||
*/
|
||||
#define M_FUNCOBJ_IS_NOT_DEFINED 0
|
||||
#define M_FUNC0BJ_IS_NOT_DEFINED 0
|
||||
|
||||
/* Design Constraints:
|
||||
* callback SHALL be the first member of the structures in all the definitions.
|
||||
@@ -266,7 +266,7 @@
|
||||
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 (x, type, M_BASIC_OPLIST) if there is no global one,
|
||||
or keep (x, type, oplist) if oplist was already present */
|
||||
#define M_FUNC0BJ_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
M_FUNC0BJ_INJECT_OPLIST_B duo_or_trio
|
||||
@@ -310,7 +310,9 @@
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
struct M_C(name, _s) *self = (struct M_C(name, _s) *)(void*)_self; \
|
||||
/* Let's go through an uintptr_t to avoid [broken] aliasing detection by compiler */ \
|
||||
uintptr_t __self = (uintptr_t) _self; \
|
||||
struct M_C(name, _s) *self = (struct M_C(name, _s) *)(void*)__self; \
|
||||
(void) self; /* maybe unused */ \
|
||||
callback_core; \
|
||||
} \
|
||||
@@ -395,5 +397,12 @@
|
||||
#define M_FUNC0BJ_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, M_RET_ARG1 a, M_RET_ARG2 a, M_RET_ARG3 a)
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define FUNC_OBJ_ITF_DEF M_FUNC_OBJ_ITF_DEF
|
||||
#define FUNC_OBJ_ITF_DEF_AS M_FUNC_OBJ_ITF_DEF_AS
|
||||
#define FUNC_OBJ_INS_DEF M_FUNC_OBJ_INS_DEF
|
||||
#define FUNC_OBJ_INS_DEF_AS M_FUNC_OBJ_INS_DEF_AS
|
||||
#define FUNC_OBJ_INS_OPLIST M_FUNC_OBJ_INS_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+32
-34
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Integer Generator (GENINT) module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -45,42 +45,40 @@ M_BEGIN_PROTECTED_CODE
|
||||
enough.
|
||||
*/
|
||||
|
||||
// TO DO: We may want a specialization with constant N value.
|
||||
|
||||
// Define the limb size used by genint
|
||||
typedef unsigned long long genint_limb_ct;
|
||||
typedef unsigned long long m_genint_limb_ct;
|
||||
|
||||
/* Define a generator of unique integer (Lock Free) */
|
||||
typedef struct genint_s {
|
||||
unsigned int n; // size of the container
|
||||
unsigned int max; // number of allocated limb - 1
|
||||
genint_limb_ct mask0; // mask of the last limb (constant)
|
||||
genint_limb_ct mask_master; // mask of the master limb that controls others (constant)
|
||||
atomic_ullong master; // master bitfield (which informs if a limb is full or not)
|
||||
atomic_ullong *data; // the bitfield which informs if an integer is used or not
|
||||
} genint_t[1];
|
||||
typedef struct m_genint_s {
|
||||
unsigned int n; // size of the container
|
||||
unsigned int max; // number of allocated limb - 1
|
||||
m_genint_limb_ct mask0; // mask of the last limb (constant)
|
||||
m_genint_limb_ct mask_master; // mask of the master limb that controls others (constant)
|
||||
atomic_ullong master; // master bitfield (which informs if a limb is full or not)
|
||||
atomic_ullong *data; // the bitfield which informs if an integer is used or not
|
||||
} m_genint_t[1];
|
||||
|
||||
// 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 M_GENINT_MAX_ALLOC (M_GEN1NT_LIMBSIZE * (M_GEN1NT_LIMBSIZE - M_GEN1NT_ABA_CPT))
|
||||
|
||||
// Define the size of a limb in bits.
|
||||
#define M_GEN1NT_LIMBSIZE ((unsigned)(sizeof(genint_limb_ct) * CHAR_BIT))
|
||||
#define M_GEN1NT_LIMBSIZE ((unsigned)(sizeof(m_genint_limb_ct) * CHAR_BIT))
|
||||
|
||||
// Define the contract of a genint
|
||||
#define M_GEN1NT_CONTRACT(s) do { \
|
||||
M_ASSERT (s != NULL); \
|
||||
M_ASSERT (s->n > 0 && s->n <= GENINT_MAX_ALLOC); \
|
||||
M_ASSERT (s->n > 0 && s->n <= M_GENINT_MAX_ALLOC); \
|
||||
M_ASSERT ((s->max+1) * M_GEN1NT_LIMBSIZE >= s->n); \
|
||||
M_ASSERT (s->data != NULL); \
|
||||
} while (0)
|
||||
|
||||
// Define the limb one
|
||||
#define M_GEN1NT_ONE ((genint_limb_ct)1)
|
||||
#define M_GEN1NT_ONE ((m_genint_limb_ct)1)
|
||||
|
||||
#define M_GEN1NT_FULL_MASK ULLONG_MAX
|
||||
|
||||
// Value returned in case of error (not integer available).
|
||||
#define GENINT_ERROR (UINT_MAX)
|
||||
#define M_GENINT_ERROR (UINT_MAX)
|
||||
|
||||
/* 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
|
||||
@@ -106,9 +104,9 @@ typedef struct genint_s {
|
||||
* for all threads.
|
||||
*/
|
||||
static inline void
|
||||
genint_init(genint_t s, unsigned int n)
|
||||
m_genint_init(m_genint_t s, unsigned int n)
|
||||
{
|
||||
M_ASSERT (s != NULL && n > 0 && n <= GENINT_MAX_ALLOC);
|
||||
M_ASSERT (s != NULL && n > 0 && n <= M_GENINT_MAX_ALLOC);
|
||||
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);
|
||||
@@ -121,15 +119,15 @@ genint_init(genint_t s, unsigned int n)
|
||||
s->max = (unsigned int) (alloc-1);
|
||||
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);
|
||||
atomic_init (&s->master, (m_genint_limb_ct)0);
|
||||
for(unsigned int i = 0; i < alloc; i++)
|
||||
atomic_init(&s->data[i], (genint_limb_ct)0);
|
||||
atomic_init(&s->data[i], (m_genint_limb_ct)0);
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
}
|
||||
|
||||
/* Clear an integer generator (Destructor) */
|
||||
static inline void
|
||||
genint_clear(genint_t s)
|
||||
m_genint_clear(m_genint_t s)
|
||||
{
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
M_MEMORY_FREE(s->data);
|
||||
@@ -138,7 +136,7 @@ genint_clear(genint_t s)
|
||||
|
||||
/* Return the maximum integer that the generator will provide */
|
||||
static inline size_t
|
||||
genint_size(genint_t s)
|
||||
m_genint_size(m_genint_t s)
|
||||
{
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
return s->n;
|
||||
@@ -147,22 +145,22 @@ genint_size(genint_t s)
|
||||
/* Get an unique integer from the integer generator.
|
||||
* NOTE: For a typical case, the amortized cost is one CAS per pop. */
|
||||
static inline unsigned int
|
||||
genint_pop(genint_t s)
|
||||
m_genint_pop(m_genint_t s)
|
||||
{
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
// First read master to see which limb is not full.
|
||||
genint_limb_ct master = atomic_load(&s->master);
|
||||
m_genint_limb_ct master = atomic_load(&s->master);
|
||||
// While master is not full
|
||||
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 < M_GEN1NT_LIMBSIZE);
|
||||
// Let's compute the mask of this limb representing the limb as being full
|
||||
genint_limb_ct mask = s->mask0;
|
||||
m_genint_limb_ct mask = s->mask0;
|
||||
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]);
|
||||
m_genint_limb_ct next, org = atomic_load(&s->data[i]);
|
||||
do {
|
||||
// If it is now full, we have been preempted by another.
|
||||
if (M_UNLIKELY (org == mask))
|
||||
@@ -181,7 +179,7 @@ genint_pop(genint_t s)
|
||||
// If the limb is now full, try to update master
|
||||
if (M_UNLIKELY(next == mask)) {
|
||||
while (true) {
|
||||
genint_limb_ct newMaster;
|
||||
m_genint_limb_ct newMaster;
|
||||
if (next == mask) {
|
||||
newMaster = M_GEN1NT_MASTER_SET(master, i);
|
||||
} else {
|
||||
@@ -201,21 +199,21 @@ genint_pop(genint_t s)
|
||||
master = atomic_load(&s->master);
|
||||
}
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
return GENINT_ERROR; // No more resource available
|
||||
return M_GENINT_ERROR; // No more resource available
|
||||
}
|
||||
|
||||
/* Restore a used integer in the integer generator.
|
||||
* NOTE: For a typical case, the amortized cost is one CAS per pop */
|
||||
static inline void
|
||||
genint_push(genint_t s, unsigned int n)
|
||||
m_genint_push(m_genint_t s, unsigned int n)
|
||||
{
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
M_ASSERT (n < s->n);
|
||||
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);
|
||||
m_genint_limb_ct master = atomic_load(&s->master);
|
||||
// Load the limb
|
||||
genint_limb_ct next, org = atomic_load(&s->data[i]);
|
||||
m_genint_limb_ct next, org = atomic_load(&s->data[i]);
|
||||
do {
|
||||
M_ASSERT ((org & (M_GEN1NT_ONE << bit)) != 0);
|
||||
// Reset it
|
||||
@@ -223,13 +221,13 @@ genint_push(genint_t s, unsigned int n)
|
||||
// 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;
|
||||
m_genint_limb_ct mask = s->mask0;
|
||||
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;
|
||||
m_genint_limb_ct newMaster;
|
||||
if (next == mask) {
|
||||
newMaster = M_GEN1NT_MASTER_SET(master, i);
|
||||
} else {
|
||||
|
||||
+49
-48
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Intrusive List module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -38,16 +38,16 @@
|
||||
...
|
||||
} tmp_str_t;
|
||||
*/
|
||||
#define ILIST_INTERFACE(name, type) \
|
||||
struct m_ilist_head_s name
|
||||
#define M_ILIST_INTERFACE(name, type) \
|
||||
struct m_il1st_head_s name
|
||||
|
||||
|
||||
/* Define a doubly-linked intrusive list of a given type.
|
||||
The type needs to have ILIST_INTERFACE().
|
||||
USAGE:
|
||||
ILIST_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define ILIST_DEF(name, ...) \
|
||||
ILIST_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
#define M_ILIST_DEF(name, ...) \
|
||||
M_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
|
||||
@@ -55,7 +55,7 @@
|
||||
The type needs to have ILIST_INTERFACE().
|
||||
USAGE:
|
||||
ILIST_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define ILIST_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_ILIST_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IL1ST_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
@@ -66,19 +66,19 @@
|
||||
/* Define the oplist of a doubly-linked instrusive list of type.
|
||||
USAGE:
|
||||
ILIST_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define ILIST_OPLIST(...) \
|
||||
#define M_ILIST_OPLIST(...) \
|
||||
M_IL1ST_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Define the basic structure to be added in all objects. */
|
||||
typedef struct m_ilist_head_s {
|
||||
struct m_ilist_head_s *next;
|
||||
struct m_ilist_head_s *prev;
|
||||
} m_ilist_head_ct;
|
||||
typedef struct m_il1st_head_s {
|
||||
struct m_il1st_head_s *next;
|
||||
struct m_il1st_head_s *prev;
|
||||
} m_il1st_head_ct;
|
||||
|
||||
/* Indirection call to allow expanding all arguments */
|
||||
#define M_IL1ST_OPLIST_P1(arg) M_IL1ST_OPLIST_P2 arg
|
||||
@@ -140,8 +140,8 @@ typedef struct m_ilist_head_s {
|
||||
M_ASSERT((node)->prev->next == node); \
|
||||
} while (0)
|
||||
|
||||
/* Indirection call to allow expanding all arguments (TBC) */
|
||||
#define M_IL1ST_DEF_P1(arg) M_IL1ST_DEF_P2 arg
|
||||
/* Indirection call to allow expanding all arguments */
|
||||
#define M_IL1ST_DEF_P1(arg) M_ID( M_IL1ST_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_IL1ST_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
@@ -164,7 +164,7 @@ typedef struct m_ilist_head_s {
|
||||
/* Define the list as a structure containing pointers \
|
||||
* to the front & back nodes */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
struct m_ilist_head_s name; \
|
||||
struct m_il1st_head_s name; \
|
||||
} list_t[1]; \
|
||||
\
|
||||
/* Define internal types pointers to such a list */ \
|
||||
@@ -173,10 +173,10 @@ typedef struct m_ilist_head_s {
|
||||
\
|
||||
/* Define iterator of such a list */ \
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
struct m_ilist_head_s *head; \
|
||||
struct m_ilist_head_s *previous; \
|
||||
struct m_ilist_head_s *current; \
|
||||
struct m_ilist_head_s *next; \
|
||||
struct m_il1st_head_s *head; \
|
||||
struct m_il1st_head_s *previous; \
|
||||
struct m_il1st_head_s *current; \
|
||||
struct m_il1st_head_s *next; \
|
||||
} it_t[1]; \
|
||||
\
|
||||
/* Define types used by oplist */ \
|
||||
@@ -199,11 +199,11 @@ typedef struct m_ilist_head_s {
|
||||
M_C(name, _reset)(list_t list) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
for(struct m_ilist_head_s *it = list->name.next, *next ; \
|
||||
for(struct m_il1st_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 m_ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
/* Read next now before the object is destroyed */ \
|
||||
next = it->next; \
|
||||
M_ASSERT (next != NULL); \
|
||||
@@ -217,12 +217,6 @@ typedef struct m_ilist_head_s {
|
||||
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) \
|
||||
{ \
|
||||
@@ -271,7 +265,7 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
size_t s = 0; \
|
||||
/* Scan the full list to count the number of elements */ \
|
||||
for(const struct m_ilist_head_s *it = list->name.next ; \
|
||||
for(const struct m_il1st_head_s *it = list->name.next ; \
|
||||
it != &list->name; it = it->next) { \
|
||||
M_IL1ST_NODE_CONTRACT(it); \
|
||||
s++; \
|
||||
@@ -284,7 +278,7 @@ typedef struct m_ilist_head_s {
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (obj != NULL); \
|
||||
struct m_ilist_head_s *prev = list->name.prev; \
|
||||
struct m_il1st_head_s *prev = list->name.prev; \
|
||||
list->name.prev = &obj->name; \
|
||||
obj->name.prev = prev; \
|
||||
obj->name.next = &list->name; \
|
||||
@@ -297,7 +291,7 @@ typedef struct m_ilist_head_s {
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (obj != NULL); \
|
||||
struct m_ilist_head_s *next = list->name.next; \
|
||||
struct m_il1st_head_s *next = list->name.next; \
|
||||
list->name.next = &obj->name; \
|
||||
obj->name.next = next; \
|
||||
obj->name.prev = &list->name; \
|
||||
@@ -311,7 +305,7 @@ typedef struct m_ilist_head_s {
|
||||
M_ASSERT (obj_pos != NULL && obj != NULL); \
|
||||
/* We don't have the list, so we have no contract at list level */ \
|
||||
M_IL1ST_NODE_CONTRACT(&obj_pos->name); \
|
||||
struct m_ilist_head_s *next = obj_pos->name.next; \
|
||||
struct m_il1st_head_s *next = obj_pos->name.next; \
|
||||
obj_pos->name.next = &obj->name; \
|
||||
obj->name.next = next; \
|
||||
obj->name.prev = &obj_pos->name; \
|
||||
@@ -333,8 +327,8 @@ typedef struct m_ilist_head_s {
|
||||
M_ASSERT (obj != NULL); \
|
||||
/* We don't have the list, so we have no contract at list level */ \
|
||||
M_IL1ST_NODE_CONTRACT(&obj->name); \
|
||||
struct m_ilist_head_s *next = obj->name.next; \
|
||||
struct m_ilist_head_s *prev = obj->name.prev; \
|
||||
struct m_il1st_head_s *next = obj->name.next; \
|
||||
struct m_il1st_head_s *prev = obj->name.prev; \
|
||||
next->prev = prev; \
|
||||
prev->next = next; \
|
||||
/* Note: not really needed, but safer */ \
|
||||
@@ -348,7 +342,7 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT(!M_C(name, _empty_p)(list)); \
|
||||
return M_TYPE_FROM_FIELD(type, list->name.prev, \
|
||||
struct m_ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
@@ -357,7 +351,7 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT(!M_C(name, _empty_p)(list)); \
|
||||
return M_TYPE_FROM_FIELD(type, list->name.next, \
|
||||
struct m_ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
@@ -368,7 +362,7 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_NODE_CONTRACT(&obj->name); \
|
||||
return obj->name.next == &list->name ? NULL : \
|
||||
M_TYPE_FROM_FIELD(type, obj->name.next, \
|
||||
struct m_ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
@@ -379,7 +373,7 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_NODE_CONTRACT(&obj->name); \
|
||||
return obj->name.prev == &list->name ? NULL : \
|
||||
M_TYPE_FROM_FIELD(type, obj->name.prev, \
|
||||
struct m_ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -492,7 +486,7 @@ typedef struct m_ilist_head_s {
|
||||
M_ASSERT (it->current->prev == it->previous); \
|
||||
M_ASSERT (!M_C(name, _end_p)(it)); \
|
||||
return M_TYPE_FROM_FIELD(type, it->current, \
|
||||
struct m_ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
@@ -509,14 +503,14 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
(void)list; /* list param is not used */ \
|
||||
type *obj = M_TYPE_FROM_FIELD(type, it->current, \
|
||||
struct m_ilist_head_s, name); \
|
||||
struct m_il1st_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); \
|
||||
M_C(name, _next)(it); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(NEW, oplist)( \
|
||||
M_IF_METHOD2(NEW, INIT_SET, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _insert)(list_t list, it_t it, type x) \
|
||||
{ \
|
||||
@@ -534,7 +528,7 @@ typedef struct m_ilist_head_s {
|
||||
(void) list; \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
, /* NEW not defined */) \
|
||||
, /* NEW & INIT_SET not defined */) \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _pop_back)(list_t list) \
|
||||
@@ -563,8 +557,8 @@ typedef struct m_ilist_head_s {
|
||||
{ \
|
||||
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; \
|
||||
struct m_il1st_head_s *midle1 = list1->name.prev; \
|
||||
struct m_il1st_head_s *midle2 = list2->name.next; \
|
||||
midle1->next = midle2; \
|
||||
midle2->prev = midle1; \
|
||||
list1->name.prev = list2->name.prev; \
|
||||
@@ -602,11 +596,11 @@ typedef struct m_ilist_head_s {
|
||||
/* npos may be end */ \
|
||||
(void) olist, (void) nlist; \
|
||||
type *obj = M_C(name, _ref)(opos); \
|
||||
struct m_ilist_head_s *ref = npos->current; \
|
||||
struct m_il1st_head_s *ref = npos->current; \
|
||||
/* Remove object */ \
|
||||
M_C(name, _unlink)(obj); \
|
||||
/* Push 'obj' after 'ref' */ \
|
||||
struct m_ilist_head_s *next = ref->next; \
|
||||
struct m_il1st_head_s *next = ref->next; \
|
||||
ref->next = &obj->name; \
|
||||
obj->name.next = next; \
|
||||
obj->name.prev = ref; \
|
||||
@@ -626,8 +620,8 @@ typedef struct m_ilist_head_s {
|
||||
{ \
|
||||
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; \
|
||||
struct m_il1st_head_s *d_item = d->name.next; \
|
||||
struct m_il1st_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; \
|
||||
@@ -648,7 +642,7 @@ typedef struct m_ilist_head_s {
|
||||
M_C(name, _reverse)(list_t list) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
struct m_ilist_head_s *next, *it; \
|
||||
struct m_il1st_head_s *next, *it; \
|
||||
for(it = list->name.next ; it != &list->name; it = next) { \
|
||||
next = it->next; \
|
||||
it->next = it->prev; \
|
||||
@@ -664,4 +658,11 @@ typedef struct m_ilist_head_s {
|
||||
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define ILIST_INTERFACE M_ILIST_INTERFACE
|
||||
#define ILIST_DEF M_ILIST_DEF
|
||||
#define ILIST_DEF_AS M_ILIST_DEF_AS
|
||||
#define ILIST_OPLIST M_ILIST_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+19
-16
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - INTRUSIVE SHARED PTR Module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -32,9 +32,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the oplist of a intrusive shared pointer.
|
||||
USAGE: ISHARED_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define ISHARED_PTR_OPLIST(...) \
|
||||
#define M_ISHARED_PTR_OPLIST(...) \
|
||||
M_ISHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -42,29 +42,29 @@ M_BEGIN_PROTECTED_CODE
|
||||
name: name of the intrusive shared pointer.
|
||||
type: name of the type of the structure (aka. struct test_s) - not used currently.
|
||||
NOTE: There can be only one interface of this kind in a type! */
|
||||
#define ISHARED_PTR_INTERFACE(name, type) \
|
||||
#define M_ISHARED_PTR_INTERFACE(name, type) \
|
||||
atomic_int M_C(name, _cpt)
|
||||
|
||||
|
||||
/* Value of the interface field for static intialization (Uses C99 designated element). */
|
||||
#define ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
|
||||
#define M_ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
|
||||
.M_C(name, _cpt) = ATOMIC_VAR_INIT(0)
|
||||
|
||||
/* Value of the interface field for static intialization (Uses C89 designated element). */
|
||||
#define ISHARED_PTR_STATIC_INIT(name, type) \
|
||||
#define M_ISHARED_PTR_STATIC_INIT(name, type) \
|
||||
ATOMIC_VAR_INIT(0)
|
||||
|
||||
|
||||
/* Define the intrusive shared pointer type and its static inline functions.
|
||||
USAGE: ISHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define ISHARED_PTR_DEF(name, ...) \
|
||||
ISHARED_PTR_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_ISHARED_PTR_DEF(name, ...) \
|
||||
M_ISHARED_PTR_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define the intrusive shared pointer type and its static inline functions
|
||||
as the name name_t
|
||||
USAGE: ISHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
|
||||
#define ISHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
#define M_ISHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_ISHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
@@ -102,7 +102,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
)
|
||||
|
||||
// Deferred evaluatioin
|
||||
#define M_ISHAR3D_PTR_DEF_P1(arg) M_ISHAR3D_PTR_DEF_P2 arg
|
||||
#define M_ISHAR3D_PTR_DEF_P1(arg) M_ID( M_ISHAR3D_PTR_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_ISHAR3D_PTR_DEF_P2(name, type, oplist, shared_t) \
|
||||
@@ -219,12 +219,6 @@ M_BEGIN_PROTECTED_CODE
|
||||
*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) \
|
||||
{ \
|
||||
@@ -238,4 +232,13 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define ISHARED_PTR_OPLIST M_ISHARED_PTR_OPLIST
|
||||
#define ISHARED_PTR_INTERFACE M_ISHARED_PTR_INTERFACE
|
||||
#define ISHARED_PTR_STATIC_DESIGNATED_INIT M_ISHARED_PTR_STATIC_DESIGNATED_INIT
|
||||
#define ISHARED_PTR_STATIC_INIT M_ISHARED_PTR_STATIC_INIT
|
||||
#define ISHARED_PTR_DEF M_ISHARED_PTR_DEF
|
||||
#define ISHARED_PTR_DEF_AS M_ISHARED_PTR_DEF_AS
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - LIST module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -29,14 +29,14 @@
|
||||
|
||||
/* Define a singly linked list of a given type.
|
||||
USAGE: LIST_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define LIST_DEF(name, ...) \
|
||||
LIST_DEF_AS(name, M_C(name, _t), M_C(name, _it_t), __VA_ARGS__)
|
||||
#define M_LIST_DEF(name, ...) \
|
||||
M_LIST_DEF_AS(name, M_C(name, _t), M_C(name, _it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a singly linked list of a given type
|
||||
as the provided type name_t with the iterator named it_t
|
||||
USAGE: LIST_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define LIST_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_LIST_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_L1ST_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
@@ -46,14 +46,14 @@
|
||||
|
||||
/* 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, ...) \
|
||||
LIST_DUAL_PUSH_DEF_AS(name, M_C(name,_t), M_C(name, _it_t), __VA_ARGS__)
|
||||
#define M_LIST_DUAL_PUSH_DEF(name, ...) \
|
||||
M_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.
|
||||
as the provided type name_t with the iterator named it_t
|
||||
USAGE: LIST_DUAL_PUSH_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define LIST_DUAL_PUSH_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_LIST_DUAL_PUSH_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
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 ), \
|
||||
@@ -63,16 +63,16 @@
|
||||
|
||||
/* Define the oplist of a list of the given type.
|
||||
USAGE: LIST_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define LIST_OPLIST(...) \
|
||||
#define M_LIST_OPLIST(...) \
|
||||
M_L1ST_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
((__VA_ARGS__, M_BASIC_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() \
|
||||
#define M_LIST_INIT_VALUE() \
|
||||
{ NULL }
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
USAGE:
|
||||
list_t global_variable = LIST_DUAL_PUSH_INIT_VALUE();
|
||||
*/
|
||||
#define LIST_DUAL_PUSH_INIT_VALUE() \
|
||||
#define M_LIST_DUAL_PUSH_INIT_VALUE() \
|
||||
{ { NULL, NULL } }
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
|
||||
/* Deferred evaluation for the list definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_L1ST_DEF_P1(arg) M_L1ST_DEF_P2 arg
|
||||
#define M_L1ST_DEF_P1(arg) M_ID( M_L1ST_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_L1ST_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
@@ -256,12 +256,6 @@
|
||||
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) \
|
||||
{ \
|
||||
@@ -672,6 +666,8 @@
|
||||
} \
|
||||
*list = previous; \
|
||||
} \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, list_t, M_C(name, _emplace_back), oplist, M_L1ST_EMPLACE_DEF)
|
||||
|
||||
|
||||
/* Internal list function definition using only iterator functions
|
||||
@@ -688,11 +684,11 @@
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, const list_t list, \
|
||||
M_C(name, _get_str)(m_string_t str, const list_t list, \
|
||||
bool append) \
|
||||
{ \
|
||||
M_ASSERT (str != NULL && list != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
|
||||
it_t it; \
|
||||
for (M_C(name, _it)(it, list) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
@@ -700,9 +696,9 @@
|
||||
type const *item = M_C(name, _cref)(it); \
|
||||
M_CALL_GET_STR(oplist, str, *item, true); \
|
||||
if (!M_C(name, _last_p)(it)) \
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
m_string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
m_string_push_back (str, ']'); \
|
||||
} \
|
||||
, /* no str */ ) \
|
||||
\
|
||||
@@ -876,9 +872,48 @@
|
||||
, /* no hash */ ) \
|
||||
|
||||
|
||||
/* Definition of the emplace_back function for single list */
|
||||
#define M_L1ST_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
static inline void \
|
||||
function_name(name_t v \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_C(name, _subtype_ct) *data = M_C(name, _push_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
}
|
||||
|
||||
|
||||
/* Definition of the emplace_back function for dual push list */
|
||||
#define M_L1ST_EMPLACE_BACK_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
static inline void \
|
||||
function_name(name_t v \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_C(name, _subtype_ct) *data = M_C(name, _push_back_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
}
|
||||
|
||||
|
||||
/* Definition of the emplace_front function for dual push list */
|
||||
#define M_L1ST_EMPLACE_FRONT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
static inline void \
|
||||
function_name(name_t v \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_C(name, _subtype_ct) *data = M_C(name, _push_front_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
}
|
||||
|
||||
|
||||
/* Deferred evaluation for the dual-push list definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_L1ST_DUAL_PUSH_DEF_P1(arg) M_L1ST_DUAL_PUSH_DEF_P2 arg
|
||||
#define M_L1ST_DUAL_PUSH_DEF_P1(arg) M_ID( M_L1ST_DUAL_PUSH_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_L1ST_DUAL_PUSH_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
@@ -974,12 +1009,6 @@
|
||||
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) \
|
||||
{ \
|
||||
@@ -1475,5 +1504,18 @@
|
||||
list->back = previous; \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
} \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, list_t, M_C(name, _emplace_back), oplist, M_L1ST_EMPLACE_BACK_DEF) \
|
||||
M_EMPLACE_QUEUE_DEF(name, list_t, M_C(name, _emplace_front), oplist, M_L1ST_EMPLACE_FRONT_DEF)
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define LIST_DEF M_LIST_DEF
|
||||
#define LIST_DEF_AS M_LIST_DEF_AS
|
||||
#define LIST_DUAL_PUSH_DEF M_LIST_DUAL_PUSH_DEF
|
||||
#define LIST_DUAL_PUSH_DEF_AS M_LIST_DUAL_PUSH_DEF_AS
|
||||
#define LIST_OPLIST M_LIST_OPLIST
|
||||
#define LIST_INIT_VALUE M_LIST_INIT_VALUE
|
||||
#define LIST_DUAL_PUSH_INIT_VALUE M_LIST_DUAL_PUSH_INIT_VALUE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+26
-13
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - MEMPOOL module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -27,35 +27,42 @@
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/* Fast Fixed Size thread unsafe allocator based on memory region.
|
||||
/* Fast, fixed size, thread unsafe allocator based on memory regions.
|
||||
No oplist is needed.
|
||||
USAGE:
|
||||
MEMPOOL_DEF(memppol_uint, unsigned int)
|
||||
MEMPOOL_DEF(name, type)
|
||||
Example:
|
||||
MEMPOOL_DEF(mempool_uint, unsigned int)
|
||||
...
|
||||
memppol_uint_t m;
|
||||
mempool_uint_t m;
|
||||
mempool_uint_init(m);
|
||||
unsigned int *ptr = mempool_uint_alloc(m);
|
||||
*ptr = 17;
|
||||
mempool_uint_free(m, ptr);
|
||||
mempool_uint_clear(m); // Give back memory to system
|
||||
NOTE: Can not use m-list since it may be expanded from LIST_DEF
|
||||
Technically, it uses a list of memory regions, where multiple
|
||||
allocations are performed in each region. However, it
|
||||
can not use m-list since it may be expanded from LIST_DEF
|
||||
(recursive dependency problem).
|
||||
*/
|
||||
#define MEMPOOL_DEF(name, type) \
|
||||
MEMPOOL_DEF_AS(name, M_C(name,_t), type)
|
||||
#define M_MEMPOOL_DEF(name, type) \
|
||||
M_MEMPOOL_DEF_AS(name, M_C(name,_t), type)
|
||||
|
||||
|
||||
/* Fast Fixed Size thread unsafe allocator based on memory region.
|
||||
/* Fast, fixed Size, thread unsafe allocator based on memory region.
|
||||
USAGE:
|
||||
MEMPOOL_DEF_AS(memppol_uint, name_t, unsigned int)
|
||||
MEMPOOL_DEF_AS(name, name_t, type)
|
||||
*/
|
||||
#define MEMPOOL_DEF_AS(name, name_t, type) \
|
||||
#define M_MEMPOOL_DEF_AS(name, name_t, type) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_M3MPOOL_DEF_P2(name, type, name_t ) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* User shall be able to cutomize the size of the segment and/or
|
||||
/* User shall be able to cutomize the size of the region segment and/or
|
||||
the minimun number of elements.
|
||||
The default is the number of elements that fits in 16KB.
|
||||
The default is the number of elements that fits in 16KB, or 256
|
||||
is the size of the type is too big.
|
||||
*/
|
||||
#ifndef M_USE_MEMPOOL_MAX_PER_SEGMENT
|
||||
#define M_USE_MEMPOOL_MAX_PER_SEGMENT(type) \
|
||||
@@ -169,11 +176,17 @@
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
} \
|
||||
|
||||
/* MEMPOOL contract */
|
||||
/* MEMPOOL contract. We only control the current segment. */
|
||||
#define M_M3MPOOL_CONTRACT(mempool, type) do { \
|
||||
M_ASSERT((mempool) != NULL); \
|
||||
M_ASSERT((mempool)->current_segment != NULL); \
|
||||
M_ASSERT((mempool)->current_segment->count <= M_USE_MEMPOOL_MAX_PER_SEGMENT(type)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define MEMPOOL_DEF M_MEMPOOL_DEF
|
||||
#define MEMPOOL_DEF_AS M_MEMPOOL_DEF_AS
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin Mutex & Thread wrapper
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -152,14 +152,14 @@ static inline bool m_thread_sleep(unsigned long long usec)
|
||||
return retval == 0;
|
||||
}
|
||||
|
||||
// Internal type, not exported.
|
||||
typedef once_flag m_once_ct[1];
|
||||
// a helper structure for m_once_call
|
||||
typedef once_flag m_once_t[1];
|
||||
|
||||
// Initial value for m_once_ct
|
||||
#define M_ONCEI_INIT_VALUE { ONCE_FLAG_INIT }
|
||||
// Initial value for m_once_t
|
||||
#define M_ONCE_INIT_VALUE { ONCE_FLAG_INIT }
|
||||
|
||||
// Call the function exactly once
|
||||
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
|
||||
static inline void m_once_call(m_once_t o, void (*func)(void))
|
||||
{
|
||||
call_once(o,func);
|
||||
}
|
||||
@@ -315,10 +315,9 @@ static inline bool m_thread_sleep(unsigned long long usec)
|
||||
}
|
||||
|
||||
|
||||
// Internal type, not exported.
|
||||
typedef INIT_ONCE m_once_ct[1];
|
||||
#define M_ONCEI_INIT_VALUE { INIT_ONCE_STATIC_INIT }
|
||||
static inline BOOL CALLBACK m_oncei_callback( PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext)
|
||||
typedef INIT_ONCE m_once_t[1];
|
||||
#define M_ONCE_INIT_VALUE { INIT_ONCE_STATIC_INIT }
|
||||
static inline BOOL CALLBACK m_once_callback( PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext)
|
||||
{
|
||||
void (*func)(void);
|
||||
(void) InitOnce;
|
||||
@@ -327,9 +326,9 @@ static inline BOOL CALLBACK m_oncei_callback( PINIT_ONCE InitOnce, PVOID Paramet
|
||||
(*func)();
|
||||
return TRUE;
|
||||
}
|
||||
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
|
||||
static inline void m_once_call(m_once_t o, void (*func)(void))
|
||||
{
|
||||
InitOnceExecuteOnce(o, m_oncei_callback, (void*)(intptr_t)func, NULL);
|
||||
InitOnceExecuteOnce(o, m_once_callback, (void*)(intptr_t)func, NULL);
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
@@ -474,10 +473,9 @@ static inline bool m_thread_sleep(unsigned long long usec)
|
||||
return retval == 0;
|
||||
}
|
||||
|
||||
// Internal type, not exported.
|
||||
typedef pthread_once_t m_once_ct[1];
|
||||
#define M_ONCEI_INIT_VALUE { PTHREAD_ONCE_INIT }
|
||||
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
|
||||
typedef pthread_once_t m_once_t[1];
|
||||
#define M_ONCE_INIT_VALUE { PTHREAD_ONCE_INIT }
|
||||
static inline void m_once_call(m_once_t o, void (*func)(void))
|
||||
{
|
||||
pthread_once(o,func);
|
||||
}
|
||||
@@ -511,9 +509,9 @@ M_END_PROTECTED_CODE
|
||||
static void M_C(m_mutex_init_, name)(void) { \
|
||||
m_mutex_init(name); \
|
||||
} \
|
||||
m_once_ct M_C(m_once_, name) = M_ONCEI_INIT_VALUE
|
||||
m_once_t M_C(m_once_, name) = M_ONCE_INIT_VALUE
|
||||
# define M_LOCKI_BY_ONCE(name) \
|
||||
(m_oncei_call(M_C(m_once_, name), M_C(m_mutex_init_, name)), \
|
||||
(m_once_call(M_C(m_once_, name), M_C(m_mutex_init_, name)), \
|
||||
m_mutex_lock(name), (void) 0 )
|
||||
# define M_LOCK(name) \
|
||||
M_LOCKI_DO(name, M_C(local_cont_, __LINE__), M_LOCKI_BY_ONCE, m_mutex_unlock)
|
||||
|
||||
+79
-23
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - dynamic priority queue module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -32,14 +32,14 @@
|
||||
|
||||
/* Define a prioqueue of a given type and its associated functions.
|
||||
USAGE: PRIOQUEUE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define PRIOQUEUE_DEF(name, ...) \
|
||||
PRIOQUEUE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
#define M_PRIOQUEUE_DEF(name, ...) \
|
||||
M_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.
|
||||
as the name name_t with an iterator named it_t
|
||||
USAGE: PRIOQUEUE_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define PRIOQUEUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_PRIOQUEUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_PR1OQUEUE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
@@ -49,9 +49,9 @@
|
||||
|
||||
/* Define the oplist of a prioqueue of type.
|
||||
USAGE: PRIOQUEUE_OPLIST(name[, oplist of the type]) */
|
||||
#define PRIOQUEUE_OPLIST(...) \
|
||||
#define M_PRIOQUEUE_OPLIST(...) \
|
||||
M_PR1OQUEUE_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -87,23 +87,29 @@
|
||||
,PUSH(M_C(name,_push)) \
|
||||
,POP(M_C(name,_pop)) \
|
||||
,OPLIST(oplist) \
|
||||
,EMPTY_P(M_C(name, _empty_p)), \
|
||||
,EMPTY_P(M_C(name, _empty_p)) \
|
||||
,GET_SIZE(M_C(name, _size)) \
|
||||
,IT_TYPE(M_C(name, _it_ct)), \
|
||||
IT_FIRST(M_C(name,_it)), \
|
||||
IT_END(M_C(name,_it_end)), \
|
||||
IT_SET(M_C(name,_it_set)), \
|
||||
IT_END_P(M_C(name,_end_p)), \
|
||||
IT_EQUAL_P(M_C(name,_it_equal_p)), \
|
||||
IT_LAST_P(M_C(name,_last_p)), \
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
,IT_TYPE(M_C(name, _it_ct)) \
|
||||
,IT_FIRST(M_C(name,_it)) \
|
||||
,IT_END(M_C(name,_it_end)) \
|
||||
,IT_SET(M_C(name,_it_set)) \
|
||||
,IT_END_P(M_C(name,_end_p)) \
|
||||
,IT_EQUAL_P(M_C(name,_it_equal_p)) \
|
||||
,IT_LAST_P(M_C(name,_last_p)) \
|
||||
,IT_NEXT(M_C(name,_next)) \
|
||||
,IT_CREF(M_C(name,_cref)) \
|
||||
,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),) \
|
||||
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),) \
|
||||
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),) \
|
||||
,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),) \
|
||||
,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),) \
|
||||
,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),) \
|
||||
)
|
||||
|
||||
|
||||
/* Deferred evaluation for the definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_PR1OQUEUE_DEF_P1(arg) M_PR1OQUEUE_DEF_P2 arg
|
||||
#define M_PR1OQUEUE_DEF_P1(arg) M_ID( M_PR1OQUEUE_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_PR1OQUEUE_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
|
||||
@@ -191,12 +197,6 @@
|
||||
M_C(name, _array_reset)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name,_reset)(p); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_parent)(size_t i) \
|
||||
{ \
|
||||
@@ -435,8 +435,64 @@
|
||||
} \
|
||||
} \
|
||||
, /* No EQUAL */ ) \
|
||||
\
|
||||
M_IF_METHOD(OUT_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _out_str)(FILE *file, const prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_out_str)(file, p->array); \
|
||||
} \
|
||||
,/* No OUT_STR */) \
|
||||
\
|
||||
M_IF_METHOD(IN_STR, oplist)( \
|
||||
static inline bool \
|
||||
M_C(name, _in_str)(prioqueue_t p, FILE *file) \
|
||||
{ \
|
||||
return M_C(name, _array_in_str)(p->array, file); \
|
||||
} \
|
||||
,/* No IN_STR */) \
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, const prioqueue_t p, bool append) \
|
||||
{ \
|
||||
M_C(name, _array_get_str)(str, p->array, append); \
|
||||
} \
|
||||
,/* No GET_STR */) \
|
||||
\
|
||||
M_IF_METHOD(PARSE_STR, oplist)( \
|
||||
static inline bool \
|
||||
M_C(name, _parse_str)(prioqueue_t p, const char str[], const char **endp) \
|
||||
{ \
|
||||
return M_C(name, _array_parse_str)(p->array, str, endp); \
|
||||
} \
|
||||
,/* No PARSE_STR */) \
|
||||
\
|
||||
M_IF_METHOD(OUT_SERIAL, oplist)( \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, const prioqueue_t p) \
|
||||
{ \
|
||||
return M_C(name, _array_out_serial)(f, p->array); \
|
||||
} \
|
||||
,/* No OUT_SERIAL */) \
|
||||
\
|
||||
M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(prioqueue_t p, m_serial_read_t f) \
|
||||
{ \
|
||||
return M_C(name, _array_in_serial)(p->array, f); \
|
||||
} \
|
||||
,/* No in_SERIAL */) \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, prioqueue_t, M_C(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
|
||||
|
||||
|
||||
// TODO: set all & remove all function
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define PRIOQUEUE_DEF M_PRIOQUEUE_DEF
|
||||
#define PRIOQUEUE_DEF_AS M_PRIOQUEUE_DEF_AS
|
||||
#define PRIOQUEUE_OPLIST M_PRIOQUEUE_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+30
-30
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - RED BLACK TREE module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -29,14 +29,14 @@
|
||||
|
||||
/* Define a Red/Black binary tree of a given type.
|
||||
USAGE: RBTREE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define RBTREE_DEF(name, ...) \
|
||||
RBTREE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
#define M_RBTREE_DEF(name, ...) \
|
||||
M_RBTREE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Red/Black binary tree of a given type
|
||||
as the name name_t and the iterator it_t.
|
||||
USAGE: RBTREE_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define RBTREE_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_RBTREE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_RBTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, M_C(name, _node_ct), it_t ), \
|
||||
@@ -46,9 +46,9 @@
|
||||
|
||||
/* Define the oplist of a rbtree of type.
|
||||
USAGE: RBTREE_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define RBTREE_OPLIST(...) \
|
||||
#define M_RBTREE_OPLIST(...) \
|
||||
M_RBTR33_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
#define M_RBTR33_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_EMPLACE_VAI)), \
|
||||
SET(M_C(name, _set)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
@@ -122,10 +122,10 @@
|
||||
#define M_RBTR33_MAX_STACK (2*CHAR_BIT*sizeof (size_t))
|
||||
|
||||
/* Encapsulation of the color of the nodes. */
|
||||
#define M_RBTR33_SET_RED(x) ((x)->color = RBTREE_RED)
|
||||
#define M_RBTR33_SET_BLACK(x) ((x)->color = RBTREE_BLACK)
|
||||
#define M_RBTR33_IS_RED(x) ((x)->color == RBTREE_RED)
|
||||
#define M_RBTR33_IS_BLACK(x) ((x)->color == RBTREE_BLACK)
|
||||
#define M_RBTR33_SET_RED(x) ((x)->color = M_RBTR33_RED)
|
||||
#define M_RBTR33_SET_BLACK(x) ((x)->color = M_RBTR33_BLACK)
|
||||
#define M_RBTR33_IS_RED(x) ((x)->color == M_RBTR33_RED)
|
||||
#define M_RBTR33_IS_BLACK(x) ((x)->color == M_RBTR33_BLACK)
|
||||
#define M_RBTR33_COPY_COLOR(x,y) ((x)->color = (y)->color)
|
||||
#define M_RBTR33_GET_COLOR(x) (true ? (x)->color : (x)->color)
|
||||
#define M_RBTR33_SET_COLOR(x, c) ((x)->color = (c))
|
||||
@@ -134,8 +134,8 @@
|
||||
|
||||
// Color of a node of a Red/Black tree
|
||||
typedef enum {
|
||||
RBTREE_BLACK = 0, RBTREE_RED
|
||||
} rbtreei_color_e;
|
||||
M_RBTR33_BLACK = 0, M_RBTR33_RED
|
||||
} m_rbtr33_color_e;
|
||||
|
||||
// General contact of a Read/Black tree
|
||||
#define M_RBTR33_CONTRACT(tree) do { \
|
||||
@@ -156,7 +156,7 @@ typedef enum {
|
||||
|
||||
/* Deferred evaluation for the rbtree definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_RBTR33_DEF_P1(arg) M_RBTR33_DEF_P2 arg
|
||||
#define M_RBTR33_DEF_P1(arg) M_ID( M_RBTR33_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_RBTR33_DEF_P2(name, type, oplist, tree_t, node_t, it_t) \
|
||||
@@ -182,7 +182,7 @@ typedef enum {
|
||||
typedef struct M_C(name, _node_s) { \
|
||||
struct M_C(name, _node_s) *child[2]; \
|
||||
type data; \
|
||||
rbtreei_color_e color; \
|
||||
m_rbtr33_color_e color; \
|
||||
} node_t; \
|
||||
\
|
||||
/* Define the Red/Black tree */ \
|
||||
@@ -294,12 +294,6 @@ typedef enum {
|
||||
tree->size = 0; \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(tree_t tree) \
|
||||
{ \
|
||||
M_C(name,_reset)(tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(tree_t tree) \
|
||||
{ \
|
||||
@@ -480,6 +474,7 @@ typedef enum {
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
M_ASSERT (it != NULL); \
|
||||
(void) tree; /* parameter not used */ \
|
||||
it->cpt = 0; \
|
||||
} \
|
||||
\
|
||||
@@ -837,7 +832,7 @@ typedef enum {
|
||||
unsigned int cpt_n = cpt; \
|
||||
node_t *v = n; /* the replacement node */ \
|
||||
node_t *u; /* the deleted node */ \
|
||||
rbtreei_color_e v_color = M_RBTR33_GET_COLOR(v); \
|
||||
m_rbtr33_color_e v_color = M_RBTR33_GET_COLOR(v); \
|
||||
/* Classical removal of a node from a binary tree */ \
|
||||
if (v->child[0] != NULL && v->child[1] != NULL) { \
|
||||
/* node has 2 child. */ \
|
||||
@@ -883,7 +878,7 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
/* Rebalance from child to root */ \
|
||||
if (v_color == RBTREE_BLACK \
|
||||
if (v_color == M_RBTR33_BLACK \
|
||||
&& M_C3(m_rbtr33_,name,_black_p)(u)) { \
|
||||
/* tab[0] is NULL, tab[1] is root, u is double black */ \
|
||||
node_t *p = u, *s; \
|
||||
@@ -924,7 +919,7 @@ typedef enum {
|
||||
/* at least one child of 's' is red */ \
|
||||
/* perform rotation(s) */ \
|
||||
bool childIsRight = !M_C3(m_rbtr33_,name,_black_p)(s->child[1]); \
|
||||
rbtreei_color_e p_color = M_RBTR33_GET_COLOR (p); \
|
||||
m_rbtr33_color_e p_color = M_RBTR33_GET_COLOR (p); \
|
||||
if (childIsRight != nbChild) { \
|
||||
/* left-left or right-right case */ \
|
||||
p = M_C3(m_rbtr33_,name,_rotate) (p, tab[cpt-1], childIsRight); \
|
||||
@@ -1020,24 +1015,24 @@ typedef enum {
|
||||
, /* NO HASH METHOD */ ) \
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
static inline void M_C(name, _get_str)(m_string_t str, \
|
||||
tree_t const t1, bool append) { \
|
||||
M_RBTR33_CONTRACT(t1); \
|
||||
M_ASSERT(str != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
|
||||
/* NOTE: The print is really naive, and not really efficient */ \
|
||||
bool commaToPrint = false; \
|
||||
it_t it1; \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
while (!M_C(name, _end_p)(it1)) { \
|
||||
if (commaToPrint) \
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
m_string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
commaToPrint = true; \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
M_CALL_GET_STR(oplist, str, *ref1, true); \
|
||||
M_C(name, _next)(it1); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
m_string_push_back (str, ']'); \
|
||||
} \
|
||||
, /* NO GET_STR */ ) \
|
||||
\
|
||||
@@ -1170,9 +1165,14 @@ typedef enum {
|
||||
} \
|
||||
, /* no in_serial */ ) \
|
||||
\
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, tree_t, M_C(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
|
||||
|
||||
|
||||
// TODO: specialized _sort shall do nothing, but shall check the requested order. How ?
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define RBTREE_DEF M_RBTREE_DEF
|
||||
#define RBTREE_DEF_AS M_RBTREE_DEF_AS
|
||||
#define RBTREE_OPLIST M_RBTREE_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+74
-63
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Serial BIN
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -32,12 +32,17 @@
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/************************** FILE / WRITE / BIN *******************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/* Internal service:
|
||||
* Write size_t in the stream in a compact form to reduce consumption
|
||||
* (and I/O bandwidth)
|
||||
*/
|
||||
static inline bool
|
||||
m_serial_bin_write_size(FILE *f, const size_t size)
|
||||
m_ser1al_bin_write_size(FILE *f, const size_t size)
|
||||
{
|
||||
bool b;
|
||||
if (M_LIKELY(size < 253))
|
||||
@@ -84,7 +89,7 @@ m_serial_bin_write_size(FILE *f, const size_t size)
|
||||
* (and I/O bandwidth)
|
||||
*/
|
||||
static inline bool
|
||||
m_serial_bin_read_size(FILE *f, size_t *size)
|
||||
m_ser1al_bin_read_size(FILE *f, size_t *size)
|
||||
{
|
||||
int c;
|
||||
c = fgetc(f);
|
||||
@@ -94,7 +99,7 @@ m_serial_bin_read_size(FILE *f, size_t *size)
|
||||
return true;
|
||||
}
|
||||
size_t s = 0;
|
||||
int l = (c = 255) ? 8 : (c == 254) ? 4 : 2;
|
||||
int l = (c == 255) ? 8 : (c == 254) ? 4 : 2;
|
||||
for(int i = 0; i < l; i++) {
|
||||
c = fgetc(f);
|
||||
if (M_UNLIKELY(c == EOF)) return false;
|
||||
@@ -107,7 +112,7 @@ m_serial_bin_read_size(FILE *f, size_t *size)
|
||||
/* 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_bin_write_boolean(m_serial_write_t serial, const bool data)
|
||||
m_ser1al_bin_write_boolean(m_serial_write_t serial, const bool data)
|
||||
{
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
size_t n = fwrite (M_ASSIGN_CAST(const void*, &data), sizeof (bool), 1, f);
|
||||
@@ -117,7 +122,7 @@ m_serial_bin_write_boolean(m_serial_write_t serial, const bool data)
|
||||
/* 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_bin_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
|
||||
m_ser1al_bin_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
|
||||
{
|
||||
int8_t i8;
|
||||
int16_t i16;
|
||||
@@ -153,7 +158,7 @@ m_serial_bin_write_integer(m_serial_write_t serial,const long long data, const s
|
||||
/* 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_bin_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
|
||||
m_ser1al_bin_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
|
||||
{
|
||||
float f1;
|
||||
double f2;
|
||||
@@ -179,13 +184,13 @@ m_serial_bin_write_float(m_serial_write_t serial, const long double data, const
|
||||
/* 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_bin_write_string(m_serial_write_t serial, const char data[], size_t length)
|
||||
m_ser1al_bin_write_string(m_serial_write_t serial, const char data[], size_t length)
|
||||
{
|
||||
M_ASSERT_SLOW(length == strlen(data) );
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
M_ASSERT(f != NULL && data != NULL);
|
||||
// Write first the number of (non null) characters
|
||||
if (m_serial_bin_write_size(f, length) != true) return m_core_serial_fail();
|
||||
if (m_ser1al_bin_write_size(f, length) != true) return m_core_serial_fail();
|
||||
// Write the characters (excluding the final null char)
|
||||
// NOTE: fwrite supports length == 0.
|
||||
size_t n = fwrite (M_ASSIGN_CAST(const void*, data), 1, length, f);
|
||||
@@ -199,7 +204,7 @@ m_serial_bin_write_string(m_serial_write_t serial, const char data[], size_t len
|
||||
(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_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
|
||||
m_ser1al_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
|
||||
{
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
size_t n = fwrite (M_ASSIGN_CAST(const void*, &number_of_elements), sizeof number_of_elements, 1, f);
|
||||
@@ -210,7 +215,7 @@ m_serial_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial,
|
||||
/* 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_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
m_ser1al_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
// Need separator if we don't know the real size
|
||||
@@ -226,7 +231,7 @@ m_serial_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
/* 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_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
m_ser1al_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
// Need mark if we don't know the real size
|
||||
@@ -242,7 +247,7 @@ m_serial_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
/* 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_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
|
||||
m_ser1al_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -254,7 +259,7 @@ m_serial_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
|
||||
(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_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
|
||||
m_ser1al_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -264,7 +269,7 @@ m_serial_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
|
||||
/* 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_bin_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
|
||||
m_ser1al_bin_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) serial;
|
||||
@@ -277,7 +282,7 @@ m_serial_bin_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, con
|
||||
/* 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_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
m_ser1al_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -290,7 +295,7 @@ m_serial_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
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_bin_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
|
||||
m_ser1al_bin_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) field_name;
|
||||
(void) max;
|
||||
@@ -303,7 +308,7 @@ m_serial_bin_write_variant_start(m_serial_local_t local, m_serial_write_t serial
|
||||
/* 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_bin_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
m_ser1al_bin_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -311,28 +316,28 @@ m_serial_bin_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
}
|
||||
|
||||
/* The exported interface. */
|
||||
static const m_serial_write_interface_t m_serial_write_bin_interface = {
|
||||
m_serial_bin_write_boolean,
|
||||
m_serial_bin_write_integer,
|
||||
m_serial_bin_write_float,
|
||||
m_serial_bin_write_string,
|
||||
m_serial_bin_write_array_start,
|
||||
m_serial_bin_write_array_next,
|
||||
m_serial_bin_write_array_end,
|
||||
m_serial_bin_write_array_start,
|
||||
m_serial_bin_write_map_value,
|
||||
m_serial_bin_write_array_next,
|
||||
m_serial_bin_write_array_end,
|
||||
m_serial_bin_write_tuple_start,
|
||||
m_serial_bin_write_tuple_id,
|
||||
m_serial_bin_write_tuple_end,
|
||||
m_serial_bin_write_variant_start,
|
||||
m_serial_bin_write_variant_end
|
||||
static const m_serial_write_interface_t m_ser1al_bin_write_interface = {
|
||||
m_ser1al_bin_write_boolean,
|
||||
m_ser1al_bin_write_integer,
|
||||
m_ser1al_bin_write_float,
|
||||
m_ser1al_bin_write_string,
|
||||
m_ser1al_bin_write_array_start,
|
||||
m_ser1al_bin_write_array_next,
|
||||
m_ser1al_bin_write_array_end,
|
||||
m_ser1al_bin_write_array_start,
|
||||
m_ser1al_bin_write_map_value,
|
||||
m_ser1al_bin_write_array_next,
|
||||
m_ser1al_bin_write_array_end,
|
||||
m_ser1al_bin_write_tuple_start,
|
||||
m_ser1al_bin_write_tuple_id,
|
||||
m_ser1al_bin_write_tuple_end,
|
||||
m_ser1al_bin_write_variant_start,
|
||||
m_ser1al_bin_write_variant_end
|
||||
};
|
||||
|
||||
static inline void m_serial_bin_write_init(m_serial_write_t serial, FILE *f)
|
||||
{
|
||||
serial->m_interface = &m_serial_write_bin_interface;
|
||||
serial->m_interface = &m_ser1al_bin_write_interface;
|
||||
serial->data[0].p = M_ASSIGN_CAST(void*, f);
|
||||
}
|
||||
|
||||
@@ -344,16 +349,22 @@ 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), PROPERTIES(( LET_AS_INIT_WITH(1) )) )
|
||||
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/************************** FILE / READ / BIN *******************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/* 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_bin_read_boolean(m_serial_read_t serial, bool *b){
|
||||
m_ser1al_bin_read_boolean(m_serial_read_t serial, bool *b){
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
size_t n = fread (M_ASSIGN_CAST(void*, b), sizeof (bool), 1, f);
|
||||
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
@@ -363,7 +374,7 @@ m_serial_bin_read_boolean(m_serial_read_t serial, bool *b){
|
||||
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_bin_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
|
||||
m_ser1al_bin_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
|
||||
int8_t i8;
|
||||
int16_t i16;
|
||||
int32_t i32;
|
||||
@@ -398,7 +409,7 @@ m_serial_bin_read_integer(m_serial_read_t serial, long long *i, const size_t siz
|
||||
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_bin_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
|
||||
m_ser1al_bin_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
|
||||
float f1;
|
||||
double f2;
|
||||
long double f3;
|
||||
@@ -423,12 +434,12 @@ m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
|
||||
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_bin_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
m_ser1al_bin_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
M_ASSERT(f != NULL && s != NULL);
|
||||
// First read the number of non null characters
|
||||
size_t length;
|
||||
if (m_serial_bin_read_size(f, &length) != true) return m_core_serial_fail();
|
||||
if (m_ser1al_bin_read_size(f, &length) != true) return m_core_serial_fail();
|
||||
// Use of internal string interface to dimension the string
|
||||
char *p = m_str1ng_fit2size(s, length + 1);
|
||||
m_str1ng_set_size(s, length);
|
||||
@@ -448,7 +459,7 @@ m_serial_bin_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
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_bin_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
|
||||
m_ser1al_bin_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
|
||||
{
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
size_t n = fread (M_ASSIGN_CAST(void*, num), sizeof *num, 1, f);
|
||||
@@ -472,7 +483,7 @@ m_serial_bin_read_array_start(m_serial_local_t local, m_serial_read_t serial, si
|
||||
M_SERIAL_OK_DONE if it succeeds and the array ends,
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_read_array_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
m_ser1al_bin_read_array_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
if (local->data[0].b) {
|
||||
@@ -494,7 +505,7 @@ m_serial_bin_read_array_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
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_bin_read_map_value(m_serial_local_t local, m_serial_read_t serial)
|
||||
m_ser1al_bin_read_map_value(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -505,7 +516,7 @@ m_serial_bin_read_map_value(m_serial_local_t local, m_serial_read_t 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_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
|
||||
m_ser1al_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) serial;
|
||||
local->data[1].i = 0;
|
||||
@@ -519,7 +530,7 @@ m_serial_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
|
||||
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_bin_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const char *const field_name [], const int max, int *id)
|
||||
m_ser1al_bin_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const char *const field_name [], const int max, int *id)
|
||||
{
|
||||
(void) serial;
|
||||
(void) field_name;
|
||||
@@ -536,7 +547,7 @@ m_serial_bin_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const
|
||||
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_bin_read_variant_start(m_serial_local_t local, m_serial_read_t serial, const char *const field_name[], const int max, int*id)
|
||||
m_ser1al_bin_read_variant_start(m_serial_local_t local, m_serial_read_t serial, const char *const field_name[], const int max, int*id)
|
||||
{
|
||||
(void) field_name;
|
||||
(void) max;
|
||||
@@ -550,32 +561,32 @@ m_serial_bin_read_variant_start(m_serial_local_t local, m_serial_read_t 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_bin_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
|
||||
m_ser1al_bin_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
return M_SERIAL_OK_DONE;
|
||||
}
|
||||
|
||||
static const m_serial_read_interface_t m_serial_bin_read_interface = {
|
||||
m_serial_bin_read_boolean,
|
||||
m_serial_bin_read_integer,
|
||||
m_serial_bin_read_float,
|
||||
m_serial_bin_read_string,
|
||||
m_serial_bin_read_array_start,
|
||||
m_serial_bin_read_array_next,
|
||||
m_serial_bin_read_array_start,
|
||||
m_serial_bin_read_map_value,
|
||||
m_serial_bin_read_array_next,
|
||||
m_serial_bin_read_tuple_start,
|
||||
m_serial_bin_read_tuple_id,
|
||||
m_serial_bin_read_variant_start,
|
||||
m_serial_bin_read_variant_end
|
||||
static const m_serial_read_interface_t m_ser1al_bin_read_interface = {
|
||||
m_ser1al_bin_read_boolean,
|
||||
m_ser1al_bin_read_integer,
|
||||
m_ser1al_bin_read_float,
|
||||
m_ser1al_bin_read_string,
|
||||
m_ser1al_bin_read_array_start,
|
||||
m_ser1al_bin_read_array_next,
|
||||
m_ser1al_bin_read_array_start,
|
||||
m_ser1al_bin_read_map_value,
|
||||
m_ser1al_bin_read_array_next,
|
||||
m_ser1al_bin_read_tuple_start,
|
||||
m_ser1al_bin_read_tuple_id,
|
||||
m_ser1al_bin_read_variant_start,
|
||||
m_ser1al_bin_read_variant_end
|
||||
};
|
||||
|
||||
static inline void m_serial_bin_read_init(m_serial_read_t serial, FILE *f)
|
||||
{
|
||||
serial->m_interface = &m_serial_bin_read_interface;
|
||||
serial->m_interface = &m_ser1al_bin_read_interface;
|
||||
serial->data[0].p = M_ASSIGN_CAST(void*, f);
|
||||
}
|
||||
|
||||
|
||||
+215
-215
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Serial JSON
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -37,7 +37,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* 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_json_write_boolean(m_serial_write_t serial, const bool data)
|
||||
m_ser1al_json_write_boolean(m_serial_write_t serial, const bool data)
|
||||
{
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, "%s", data ? "true" : "false");
|
||||
@@ -47,7 +47,7 @@ m_serial_json_write_boolean(m_serial_write_t serial, const bool data)
|
||||
/* 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_json_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
|
||||
m_ser1al_json_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
|
||||
{
|
||||
(void) size_of_type; // Ignored
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
@@ -58,7 +58,7 @@ m_serial_json_write_integer(m_serial_write_t serial,const long long data, const
|
||||
/* 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_json_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
|
||||
m_ser1al_json_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
|
||||
{
|
||||
(void) size_of_type; // Ignored
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
@@ -69,18 +69,18 @@ m_serial_json_write_float(m_serial_write_t serial, const long double data, const
|
||||
/* 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_json_write_string(m_serial_write_t serial, const char data[], size_t length)
|
||||
m_ser1al_json_write_string(m_serial_write_t serial, const char data[], size_t length)
|
||||
{
|
||||
M_ASSERT_SLOW(length == strlen(data) );
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
M_ASSERT(f != NULL && data != NULL);
|
||||
/* HACK: Build dummy string to reuse string_out_str */
|
||||
string_t v2;
|
||||
/* HACK: Build dummy string to reuse m_string_out_str */
|
||||
m_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_out_str(f, v2);
|
||||
m_string_out_str(f, v2);
|
||||
return M_SERIAL_OK_DONE;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ m_serial_json_write_string(m_serial_write_t serial, const char data[], size_t le
|
||||
(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_json_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
|
||||
m_ser1al_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
|
||||
@@ -103,7 +103,7 @@ m_serial_json_write_array_start(m_serial_local_t local, m_serial_write_t serial,
|
||||
/* 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_json_write_array_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
m_ser1al_json_write_array_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
@@ -114,7 +114,7 @@ m_serial_json_write_array_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
/* 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_json_write_array_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
m_ser1al_json_write_array_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
@@ -129,7 +129,7 @@ m_serial_json_write_array_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
(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_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
|
||||
m_ser1al_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
|
||||
@@ -141,7 +141,7 @@ m_serial_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, c
|
||||
/* 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_json_write_map_value(m_serial_local_t local, m_serial_write_t serial)
|
||||
m_ser1al_json_write_map_value(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
@@ -152,7 +152,7 @@ m_serial_json_write_map_value(m_serial_local_t local, m_serial_write_t serial)
|
||||
/* 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_json_write_map_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
m_ser1al_json_write_map_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
@@ -163,7 +163,7 @@ m_serial_json_write_map_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
/* 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_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
m_ser1al_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
@@ -176,7 +176,7 @@ m_serial_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
(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_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
|
||||
m_ser1al_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
@@ -187,7 +187,7 @@ m_serial_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
|
||||
/* 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_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)
|
||||
m_ser1al_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
|
||||
@@ -199,7 +199,7 @@ m_serial_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, co
|
||||
/* 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_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
m_ser1al_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
@@ -213,7 +213,7 @@ m_serial_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
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_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)
|
||||
m_ser1al_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
|
||||
@@ -232,7 +232,7 @@ m_serial_json_write_variant_start(m_serial_local_t local, m_serial_write_t seria
|
||||
/* 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_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
m_ser1al_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
@@ -242,29 +242,29 @@ m_serial_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
|
||||
/* 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,
|
||||
m_serial_json_write_float,
|
||||
m_serial_json_write_string,
|
||||
m_serial_json_write_array_start,
|
||||
m_serial_json_write_array_next,
|
||||
m_serial_json_write_array_end,
|
||||
m_serial_json_write_map_start,
|
||||
m_serial_json_write_map_value,
|
||||
m_serial_json_write_map_next,
|
||||
m_serial_json_write_map_end,
|
||||
m_serial_json_write_tuple_start,
|
||||
m_serial_json_write_tuple_id,
|
||||
m_serial_json_write_tuple_end,
|
||||
m_serial_json_write_variant_start,
|
||||
m_serial_json_write_variant_end
|
||||
static const m_serial_write_interface_t m_ser1al_json_write_interface = {
|
||||
m_ser1al_json_write_boolean,
|
||||
m_ser1al_json_write_integer,
|
||||
m_ser1al_json_write_float,
|
||||
m_ser1al_json_write_string,
|
||||
m_ser1al_json_write_array_start,
|
||||
m_ser1al_json_write_array_next,
|
||||
m_ser1al_json_write_array_end,
|
||||
m_ser1al_json_write_map_start,
|
||||
m_ser1al_json_write_map_value,
|
||||
m_ser1al_json_write_map_next,
|
||||
m_ser1al_json_write_map_end,
|
||||
m_ser1al_json_write_tuple_start,
|
||||
m_ser1al_json_write_tuple_id,
|
||||
m_ser1al_json_write_tuple_end,
|
||||
m_ser1al_json_write_variant_start,
|
||||
m_ser1al_json_write_variant_end
|
||||
};
|
||||
|
||||
/* Initialize the JSON serial object for writing any object to JSON format in the given FILE */
|
||||
static inline void m_serial_json_write_init(m_serial_write_t serial, FILE *f)
|
||||
{
|
||||
serial->m_interface = &m_serial_write_json_interface;
|
||||
serial->m_interface = &m_ser1al_json_write_interface;
|
||||
serial->data[0].p = M_ASSIGN_CAST(void*, f);
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ typedef m_serial_write_t m_serial_json_write_t;
|
||||
|
||||
/* Helper function to skip a space */
|
||||
static inline int
|
||||
m_serial_json_read_skip (FILE *f)
|
||||
m_ser1al_json_read_skip (FILE *f)
|
||||
{
|
||||
int c;
|
||||
do {
|
||||
@@ -302,9 +302,9 @@ m_serial_json_read_skip (FILE *f)
|
||||
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_json_read_boolean(m_serial_read_t serial, bool *b){
|
||||
m_ser1al_json_read_boolean(m_serial_read_t serial, bool *b){
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
int c = m_serial_json_read_skip(f);
|
||||
int c = m_ser1al_json_read_skip(f);
|
||||
if (c == 't') {
|
||||
*b = true;
|
||||
c = fgetc(f);
|
||||
@@ -334,7 +334,7 @@ m_serial_json_read_boolean(m_serial_read_t serial, bool *b){
|
||||
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_json_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
|
||||
m_ser1al_json_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
|
||||
(void) size_of_type; // Ignored
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
return m_core_fscanf(f, " %lld", i) == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
@@ -344,7 +344,7 @@ m_serial_json_read_integer(m_serial_read_t serial, long long *i, const size_t si
|
||||
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_json_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
|
||||
m_ser1al_json_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
|
||||
(void) size_of_type; // Ignored
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
return m_core_fscanf(f, " %Lf", r) == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
@@ -354,11 +354,11 @@ m_serial_json_read_float(m_serial_read_t serial, long double *r, const size_t si
|
||||
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_json_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
m_ser1al_json_read_string(m_serial_read_t serial, struct m_string_s *s){
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
int n = m_core_fscanf(f, " "); // Skip any leading spaces.
|
||||
(void) n; // Unused return value.
|
||||
return string_in_str(s, f) ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
return m_string_in_str(s, f) ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start reading from the stream 'serial' an array.
|
||||
@@ -369,7 +369,7 @@ m_serial_json_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
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_json_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
|
||||
m_ser1al_json_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
@@ -387,7 +387,7 @@ m_serial_json_read_array_start(m_serial_local_t local, m_serial_read_t serial, s
|
||||
M_SERIAL_OK_DONE if it succeeds and the array ends,
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_json_read_array_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
m_ser1al_json_read_array_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
@@ -405,7 +405,7 @@ m_serial_json_read_array_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
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_json_read_map_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
|
||||
m_ser1al_json_read_map_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
@@ -422,7 +422,7 @@ m_serial_json_read_map_start(m_serial_local_t local, m_serial_read_t serial, siz
|
||||
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_json_read_map_value(m_serial_local_t local, m_serial_read_t serial)
|
||||
m_ser1al_json_read_map_value(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
@@ -437,7 +437,7 @@ m_serial_json_read_map_value(m_serial_local_t local, m_serial_read_t serial)
|
||||
M_SERIAL_OK_DONE if it succeeds and the map ends,
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_json_read_map_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
m_ser1al_json_read_map_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
@@ -451,7 +451,7 @@ m_serial_json_read_map_next(m_serial_local_t local, m_serial_read_t 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_json_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
|
||||
m_ser1al_json_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
@@ -468,11 +468,11 @@ m_serial_json_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
|
||||
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_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const char *const field_name [], const int max, int *id)
|
||||
m_ser1al_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
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
int c = m_serial_json_read_skip(f);
|
||||
int c = m_ser1al_json_read_skip(f);
|
||||
if (c == EOF) return m_core_serial_fail();
|
||||
if (c == '}') return M_SERIAL_OK_DONE;
|
||||
if (c == ',') {
|
||||
@@ -507,7 +507,7 @@ m_serial_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, cons
|
||||
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_json_read_variant_start(m_serial_local_t local, m_serial_read_t serial, const char *const field_name[], const int max, int*id)
|
||||
m_ser1al_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
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
@@ -542,7 +542,7 @@ m_serial_json_read_variant_start(m_serial_local_t local, m_serial_read_t 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_json_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
|
||||
m_ser1al_json_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
@@ -552,26 +552,26 @@ m_serial_json_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
|
||||
return final > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
static const m_serial_read_interface_t m_serial_json_read_interface = {
|
||||
m_serial_json_read_boolean,
|
||||
m_serial_json_read_integer,
|
||||
m_serial_json_read_float,
|
||||
m_serial_json_read_string,
|
||||
m_serial_json_read_array_start,
|
||||
m_serial_json_read_array_next,
|
||||
m_serial_json_read_map_start,
|
||||
m_serial_json_read_map_value,
|
||||
m_serial_json_read_map_next,
|
||||
m_serial_json_read_tuple_start,
|
||||
m_serial_json_read_tuple_id,
|
||||
m_serial_json_read_variant_start,
|
||||
m_serial_json_read_variant_end
|
||||
static const m_serial_read_interface_t m_ser1al_json_read_interface = {
|
||||
m_ser1al_json_read_boolean,
|
||||
m_ser1al_json_read_integer,
|
||||
m_ser1al_json_read_float,
|
||||
m_ser1al_json_read_string,
|
||||
m_ser1al_json_read_array_start,
|
||||
m_ser1al_json_read_array_next,
|
||||
m_ser1al_json_read_map_start,
|
||||
m_ser1al_json_read_map_value,
|
||||
m_ser1al_json_read_map_next,
|
||||
m_ser1al_json_read_tuple_start,
|
||||
m_ser1al_json_read_tuple_id,
|
||||
m_ser1al_json_read_variant_start,
|
||||
m_ser1al_json_read_variant_end
|
||||
};
|
||||
|
||||
/* Initialize the JSON serial object for reading any object from JSON format in the given FILE */
|
||||
static inline void m_serial_json_read_init(m_serial_read_t serial, FILE *f)
|
||||
{
|
||||
serial->m_interface = &m_serial_json_read_interface;
|
||||
serial->m_interface = &m_ser1al_json_read_interface;
|
||||
serial->data[0].p = M_ASSIGN_CAST(void*, f);
|
||||
}
|
||||
|
||||
@@ -597,50 +597,50 @@ typedef m_serial_read_t m_serial_json_read_t;
|
||||
/* 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)
|
||||
m_ser1al_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");
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
int n = m_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)
|
||||
m_ser1al_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);
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
int n = m_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)
|
||||
m_ser1al_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);
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
int n = m_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_ser1al_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;
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
M_ASSERT(f != NULL && data != NULL);
|
||||
/* HACK: Build dummy string to reuse string_get_str */
|
||||
string_t v2;
|
||||
/* HACK: Build dummy string to reuse m_string_get_str */
|
||||
m_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);
|
||||
m_string_get_str(f, v2, true);
|
||||
return M_SERIAL_OK_DONE;
|
||||
}
|
||||
|
||||
@@ -651,34 +651,34 @@ m_serial_str_json_write_string(m_serial_write_t serial, const char data[], size_
|
||||
(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)
|
||||
m_ser1al_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, '[');
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
m_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)
|
||||
m_ser1al_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, ',');
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
m_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)
|
||||
m_ser1al_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, ']');
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
m_string_push_back(f, ']');
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
@@ -689,45 +689,45 @@ m_serial_str_json_write_array_end(m_serial_local_t local, m_serial_write_t seria
|
||||
(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)
|
||||
m_ser1al_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, '{');
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
m_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)
|
||||
m_ser1al_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, ':');
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
m_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)
|
||||
m_ser1al_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, ',');
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
m_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)
|
||||
m_ser1al_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, '}');
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
m_string_push_back(f, '}');
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
@@ -736,34 +736,34 @@ m_serial_str_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
(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)
|
||||
m_ser1al_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, '{');
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
m_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)
|
||||
m_ser1al_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]);
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
int n = m_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)
|
||||
m_ser1al_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, '}');
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
m_string_push_back(f, '}');
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
@@ -773,18 +773,18 @@ m_serial_str_json_write_tuple_end(m_serial_local_t local, m_serial_write_t seria
|
||||
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)
|
||||
m_ser1al_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;
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
int n;
|
||||
if (index >= 0) {
|
||||
M_ASSERT (index < max);
|
||||
n = string_cat_printf(f, "{\"%s\":", field_name[index]);
|
||||
n = m_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, "{}");
|
||||
n = m_string_cat_printf(f, "{}");
|
||||
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
}
|
||||
@@ -792,39 +792,39 @@ m_serial_str_json_write_variant_start(m_serial_local_t local, m_serial_write_t s
|
||||
/* 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)
|
||||
m_ser1al_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, '}');
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
m_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
|
||||
static const m_serial_write_interface_t m_ser1al_str_json_write_interface = {
|
||||
m_ser1al_str_json_write_boolean,
|
||||
m_ser1al_str_json_write_integer,
|
||||
m_ser1al_str_json_write_float,
|
||||
m_ser1al_str_json_write_string,
|
||||
m_ser1al_str_json_write_array_start,
|
||||
m_ser1al_str_json_write_array_next,
|
||||
m_ser1al_str_json_write_array_end,
|
||||
m_ser1al_str_json_write_map_start,
|
||||
m_ser1al_str_json_write_map_value,
|
||||
m_ser1al_str_json_write_map_next,
|
||||
m_ser1al_str_json_write_map_end,
|
||||
m_ser1al_str_json_write_tuple_start,
|
||||
m_ser1al_str_json_write_tuple_id,
|
||||
m_ser1al_str_json_write_tuple_end,
|
||||
m_ser1al_str_json_write_variant_start,
|
||||
m_ser1al_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)
|
||||
static inline void m_serial_str_json_write_init(m_serial_write_t serial, m_string_t s)
|
||||
{
|
||||
serial->m_interface = &m_serial_str_json_write_interface;
|
||||
serial->data[0].p = M_ASSIGN_CAST(struct string_s *, s);
|
||||
serial->m_interface = &m_ser1al_str_json_write_interface;
|
||||
serial->data[0].p = M_ASSIGN_CAST(struct m_string_s *, s);
|
||||
}
|
||||
|
||||
/* CLear the JSON serial object for writing*/
|
||||
@@ -847,7 +847,7 @@ typedef m_serial_write_t m_serial_str_json_write_t;
|
||||
|
||||
/* Helper function to read a character and advance the stream */
|
||||
static inline char
|
||||
m_serial_str_json_getc(const char **p)
|
||||
m_ser1al_str_json_getc(const char **p)
|
||||
{
|
||||
char c = **p;
|
||||
// Once it reaches the end of string character (== 0), stop advancing the stream.
|
||||
@@ -857,7 +857,7 @@ m_serial_str_json_getc(const char **p)
|
||||
|
||||
/* Helper function to skip space(s) */
|
||||
static inline void
|
||||
m_serial_str_json_skip (const char **p)
|
||||
m_ser1al_str_json_skip (const char **p)
|
||||
{
|
||||
while (isspace (**p)) {
|
||||
(*p)++;
|
||||
@@ -866,7 +866,7 @@ m_serial_str_json_skip (const char **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_ser1al_str_json_gets(size_t alloc, char field[], const char reject[], const char **s)
|
||||
{
|
||||
M_ASSERT (alloc > 0);
|
||||
size_t length = strcspn(*s, reject);
|
||||
@@ -881,28 +881,28 @@ m_serial_str_json_gets(size_t alloc, char field[], const char reject[], const ch
|
||||
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){
|
||||
m_ser1al_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);
|
||||
m_ser1al_str_json_skip(f);
|
||||
char c = m_ser1al_str_json_getc(f);
|
||||
if (c == 't') {
|
||||
*b = true;
|
||||
c = m_serial_str_json_getc(f);
|
||||
c = m_ser1al_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != 'r')) return m_core_serial_fail();
|
||||
c = m_serial_str_json_getc(f);
|
||||
c = m_ser1al_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != 'u')) return m_core_serial_fail();
|
||||
c = m_serial_str_json_getc(f);
|
||||
c = m_ser1al_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);
|
||||
c = m_ser1al_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != 'a')) return m_core_serial_fail();
|
||||
c = m_serial_str_json_getc(f);
|
||||
c = m_ser1al_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != 'l')) return m_core_serial_fail();
|
||||
c = m_serial_str_json_getc(f);
|
||||
c = m_ser1al_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != 's')) return m_core_serial_fail();
|
||||
c = m_serial_str_json_getc(f);
|
||||
c = m_ser1al_str_json_getc(f);
|
||||
if (M_UNLIKELY(c != 'e')) return m_core_serial_fail();
|
||||
return M_SERIAL_OK_DONE;
|
||||
} else {
|
||||
@@ -914,7 +914,7 @@ m_serial_str_json_read_boolean(m_serial_read_t serial, bool *b){
|
||||
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){
|
||||
m_ser1al_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;
|
||||
@@ -928,7 +928,7 @@ m_serial_str_json_read_integer(m_serial_read_t serial, long long *i, const size_
|
||||
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){
|
||||
m_ser1al_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;
|
||||
@@ -942,11 +942,11 @@ m_serial_str_json_read_float(m_serial_read_t serial, long double *r, const size_
|
||||
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){
|
||||
m_ser1al_str_json_read_string(m_serial_read_t serial, struct m_string_s *s){
|
||||
const char **f = &serial->data[0].cstr;
|
||||
m_serial_str_json_skip(f);
|
||||
m_ser1al_str_json_skip(f);
|
||||
const char *e;
|
||||
bool b = string_parse_str(s, *f, &e);
|
||||
bool b = m_string_parse_str(s, *f, &e);
|
||||
serial->data[0].cstr = e;
|
||||
return b ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
@@ -959,19 +959,19 @@ m_serial_str_json_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
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)
|
||||
m_ser1al_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);
|
||||
m_ser1al_str_json_skip(f);
|
||||
char c = m_ser1al_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);
|
||||
m_ser1al_str_json_skip(f);
|
||||
if (M_UNLIKELY (**f == ']')) {
|
||||
c = m_serial_str_json_getc(f);
|
||||
c = m_ser1al_str_json_getc(f);
|
||||
return M_SERIAL_OK_DONE;
|
||||
} else {
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
@@ -983,12 +983,12 @@ m_serial_str_json_read_array_start(m_serial_local_t local, m_serial_read_t seria
|
||||
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)
|
||||
m_ser1al_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);
|
||||
m_ser1al_str_json_skip(f);
|
||||
char c = m_ser1al_str_json_getc(f);
|
||||
return c == ',' ? M_SERIAL_OK_CONTINUE : c == ']' ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
@@ -1000,19 +1000,19 @@ m_serial_str_json_read_array_next(m_serial_local_t local, m_serial_read_t serial
|
||||
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)
|
||||
m_ser1al_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);
|
||||
m_ser1al_str_json_skip(f);
|
||||
char c = m_ser1al_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);
|
||||
m_ser1al_str_json_skip(f);
|
||||
if (M_UNLIKELY (**f == '}')) {
|
||||
c = m_serial_str_json_getc(f);
|
||||
c = m_ser1al_str_json_getc(f);
|
||||
return M_SERIAL_OK_DONE;
|
||||
} else {
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
@@ -1023,12 +1023,12 @@ m_serial_str_json_read_map_start(m_serial_local_t local, m_serial_read_t serial,
|
||||
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)
|
||||
m_ser1al_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);
|
||||
m_ser1al_str_json_skip(f);
|
||||
char c = m_ser1al_str_json_getc(f);
|
||||
return c ==':' ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
@@ -1037,12 +1037,12 @@ m_serial_str_json_read_map_value(m_serial_local_t local, m_serial_read_t serial)
|
||||
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)
|
||||
m_ser1al_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);
|
||||
m_ser1al_str_json_skip(f);
|
||||
char c = m_ser1al_str_json_getc(f);
|
||||
return c == ',' ? M_SERIAL_OK_CONTINUE : c == '}' ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
@@ -1050,12 +1050,12 @@ m_serial_str_json_read_map_next(m_serial_local_t local, m_serial_read_t 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)
|
||||
m_ser1al_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);
|
||||
m_ser1al_str_json_skip(f);
|
||||
char c = m_ser1al_str_json_getc(f);
|
||||
return c == '{' ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
@@ -1066,28 +1066,28 @@ m_serial_str_json_read_tuple_start(m_serial_local_t local, m_serial_read_t seria
|
||||
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)
|
||||
m_ser1al_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);
|
||||
m_ser1al_str_json_skip(f);
|
||||
char c = m_ser1al_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);
|
||||
m_ser1al_str_json_skip(f);
|
||||
c = m_ser1al_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);
|
||||
m_ser1al_str_json_gets(M_USE_IDENTIFIER_ALLOC+1, field, " \t\n\"", f);
|
||||
c = m_ser1al_str_json_getc(f);
|
||||
if (M_UNLIKELY (c != '"')) return m_core_serial_fail();
|
||||
c = m_serial_str_json_getc(f);
|
||||
c = m_ser1al_str_json_getc(f);
|
||||
if (M_UNLIKELY (c != ':')) return m_core_serial_fail();
|
||||
|
||||
/* Search for field in field_name */
|
||||
@@ -1107,26 +1107,26 @@ m_serial_str_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial,
|
||||
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)
|
||||
m_ser1al_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);
|
||||
m_ser1al_str_json_skip(f);
|
||||
int c = m_ser1al_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);
|
||||
m_ser1al_str_json_skip(f);
|
||||
c = m_ser1al_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);
|
||||
m_ser1al_str_json_gets(M_USE_IDENTIFIER_ALLOC+1, field, " \t\n\"", f);
|
||||
c = m_ser1al_str_json_getc(f);
|
||||
if (M_UNLIKELY (c != '"')) return m_core_serial_fail();
|
||||
c = m_serial_str_json_getc(f);
|
||||
c = m_ser1al_str_json_getc(f);
|
||||
if (M_UNLIKELY (c != ':')) return m_core_serial_fail();
|
||||
|
||||
/* Linear Search for field in field_name */
|
||||
@@ -1144,35 +1144,35 @@ m_serial_str_json_read_variant_start(m_serial_local_t local, m_serial_read_t ser
|
||||
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)
|
||||
m_ser1al_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);
|
||||
m_ser1al_str_json_skip(f);
|
||||
int c = m_ser1al_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
|
||||
static const m_serial_read_interface_t m_ser1al_str_json_read_interface = {
|
||||
m_ser1al_str_json_read_boolean,
|
||||
m_ser1al_str_json_read_integer,
|
||||
m_ser1al_str_json_read_float,
|
||||
m_ser1al_str_json_read_string,
|
||||
m_ser1al_str_json_read_array_start,
|
||||
m_ser1al_str_json_read_array_next,
|
||||
m_ser1al_str_json_read_map_start,
|
||||
m_ser1al_str_json_read_map_value,
|
||||
m_ser1al_str_json_read_map_next,
|
||||
m_ser1al_str_json_read_tuple_start,
|
||||
m_ser1al_str_json_read_tuple_id,
|
||||
m_ser1al_str_json_read_variant_start,
|
||||
m_ser1al_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->m_interface = &m_ser1al_str_json_read_interface;
|
||||
serial->data[0].cstr = str;
|
||||
}
|
||||
|
||||
|
||||
+39
-33
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SHARED Module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -33,22 +33,22 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the oplist of a shared pointer.
|
||||
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define SHARED_PTR_OPLIST(...) \
|
||||
#define M_SHARED_PTR_OPLIST(...) \
|
||||
M_SHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define shared pointer and its function.
|
||||
USAGE: SHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_DEF(name, ...) \
|
||||
SHARED_PTR_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_SHARED_PTR_DEF(name, ...) \
|
||||
M_SHARED_PTR_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define shared pointer and its function
|
||||
as the given name name_t
|
||||
USAGE: SHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
|
||||
#define SHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
#define M_SHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
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 ), \
|
||||
@@ -58,14 +58,14 @@ M_BEGIN_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, ...) \
|
||||
SHARED_PTR_RELAXED_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_SHARED_PTR_RELAXED_DEF(name, ...) \
|
||||
M_SHARED_PTR_RELAXED_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define relaxed shared pointer and its function (thread unsafe)
|
||||
as the given name name_t
|
||||
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_RELAXED_DEF_AS(name, name_t, ...) \
|
||||
#define M_SHARED_PTR_RELAXED_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
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 ), \
|
||||
@@ -76,15 +76,15 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define shared resource and its function.
|
||||
This is a bounded pool of resource shared by multiple owners.
|
||||
USAGE: SHARED_RESOURCE_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_RESOURCE_DEF(name, ...) \
|
||||
SHARED_RESOURCE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
#define M_SHARED_RESOURCE_DEF(name, ...) \
|
||||
M_SHARED_RESOURCE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define shared resource and its function
|
||||
as the given name named_t and the iterator it_t
|
||||
This is a bounded pool of resource shared by multiple owners.
|
||||
USAGE: SHARED_RESOURCE_DEF_AS(name, name_t, it_t, type, [, oplist]) */
|
||||
#define SHARED_RESOURCE_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_SHARED_RESOURCE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
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 ), \
|
||||
@@ -149,7 +149,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
} while (0)
|
||||
|
||||
// deferred evaluation
|
||||
#define M_SHAR3D_PTR_DEF_P1(arg) M_SHAR3D_PTR_DEF_P2 arg
|
||||
#define M_SHAR3D_PTR_DEF_P1(arg) M_ID( M_SHAR3D_PTR_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_SHAR3D_PTR_DEF_P2(name, type, oplist, cpt_oplist, shared_t) \
|
||||
@@ -208,6 +208,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _init_new)(shared_t shared) \
|
||||
{ \
|
||||
@@ -227,6 +228,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
*shared = ptr; \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
, /* No INIT */ ) \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _NULL_p)(const shared_t shared) \
|
||||
@@ -277,12 +279,6 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
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) \
|
||||
@@ -366,7 +362,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
} while (0)
|
||||
|
||||
// deferred
|
||||
#define M_SHAR3D_RESOURCE_DEF_P1(arg) M_SHAR3D_RESOURCE_DEF_P2 arg
|
||||
#define M_SHAR3D_RESOURCE_DEF_P1(arg) M_ID( M_SHAR3D_RESOURCE_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_SHAR3D_RESOURCE_DEF_P2(name, type, oplist, shared_t, it_t) \
|
||||
@@ -386,7 +382,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
} M_C(name, _atype_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
genint_t core; \
|
||||
m_genint_t core; \
|
||||
M_C(name, _atype_ct) *buffer; \
|
||||
} shared_t[1]; \
|
||||
\
|
||||
@@ -412,7 +408,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
M_CALL_INIT(oplist, s->buffer[i].x); \
|
||||
atomic_init (&s->buffer[i].cpt, 0U); \
|
||||
} \
|
||||
genint_init(s->core, (unsigned int) n); \
|
||||
m_genint_init(s->core, (unsigned int) n); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(s); \
|
||||
} \
|
||||
\
|
||||
@@ -420,13 +416,13 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
M_C(name, _clear)(shared_t s) \
|
||||
{ \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(s); \
|
||||
size_t n = genint_size(s->core); \
|
||||
size_t n = m_genint_size(s->core); \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_CLEAR(oplist, s->buffer[i].x); \
|
||||
} \
|
||||
M_CALL_FREE(oplist, s->buffer); \
|
||||
s->buffer = NULL; \
|
||||
genint_clear(s->core); \
|
||||
m_genint_clear(s->core); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -434,10 +430,10 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
{ \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(s); \
|
||||
M_ASSERT (it != NULL); \
|
||||
unsigned int idx = genint_pop(s->core); \
|
||||
unsigned int idx = m_genint_pop(s->core); \
|
||||
it->idx = idx; \
|
||||
it->ref = s; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
|
||||
M_ASSERT(atomic_load(&s->buffer[idx].cpt) == 0); \
|
||||
atomic_store(&s->buffer[idx].cpt, 1U); \
|
||||
} \
|
||||
@@ -447,13 +443,13 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
M_C(name, _end_p)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
return it->idx == GENINT_ERROR; \
|
||||
return it->idx == M_GENINT_ERROR; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
M_ASSERT (it != NULL && it->ref != NULL && it->idx != M_GENINT_ERROR); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(it->ref); \
|
||||
return &it->ref->buffer[it->idx].x; \
|
||||
} \
|
||||
@@ -461,7 +457,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
M_ASSERT (it != NULL && it->ref != NULL && it->idx != M_GENINT_ERROR); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(it->ref); \
|
||||
return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \
|
||||
} \
|
||||
@@ -473,12 +469,12 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
M_ASSERT (it != NULL); \
|
||||
M_ASSERT (it->ref == s); \
|
||||
unsigned int idx = it->idx; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
|
||||
unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \
|
||||
if (c == 1) { \
|
||||
genint_push(it->ref->core, idx); \
|
||||
m_genint_push(it->ref->core, idx); \
|
||||
} \
|
||||
it->idx = GENINT_ERROR; \
|
||||
it->idx = M_GENINT_ERROR; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
@@ -490,7 +486,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
itd->ref = its->ref; \
|
||||
unsigned int idx = its->idx; \
|
||||
itd->idx = idx; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
|
||||
unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \
|
||||
M_ASSERT (c >= 1); \
|
||||
} \
|
||||
@@ -498,4 +494,14 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define SHARED_PTR_OPLIST M_SHARED_PTR_OPLIST
|
||||
#define SHARED_PTR_DEF M_SHARED_PTR_DEF
|
||||
#define SHARED_PTR_DEF_AS M_SHARED_PTR_DEF_AS
|
||||
#define SHARED_PTR_RELAXED_DEF M_SHARED_PTR_RELAXED_DEF
|
||||
#define SHARED_PTR_RELAXED_DEF_AS M_SHARED_PTR_RELAXED_DEF_AS
|
||||
#define SHARED_RESOURCE_DEF M_SHARED_RESOURCE_DEF
|
||||
#define SHARED_RESOURCE_DEF_AS M_SHARED_RESOURCE_DEF_AS
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+55
-45
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SNAPSHOT Module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -33,14 +33,14 @@ 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, ...) \
|
||||
SNAPSHOT_SPSC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_SNAPSHOT_SPSC_DEF(name, ...) \
|
||||
M_SNAPSHOT_SPSC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Single Producer Single Consummer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_SPSC_DEF_AS(name, name_t, type[, oplist]) */
|
||||
#define SNAPSHOT_SPSC_DEF_AS(name, name_t, ...) \
|
||||
#define M_SNAPSHOT_SPSC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_SNAPSH0T_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
@@ -50,14 +50,14 @@ 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, ...) \
|
||||
SNAPSHOT_SPMC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_SNAPSHOT_SPMC_DEF(name, ...) \
|
||||
M_SNAPSHOT_SPMC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Single Producer Multiple Consummer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_SPMC_DEF_AS(name, type[, oplist]) */
|
||||
#define SNAPSHOT_SPMC_DEF_AS(name, name_t, ...) \
|
||||
#define M_SNAPSHOT_SPMC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_SNAPSH0T_SPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
@@ -67,14 +67,14 @@ 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, ...) \
|
||||
SNAPSHOT_MPMC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_SNAPSHOT_MPMC_DEF(name, ...) \
|
||||
M_SNAPSHOT_MPMC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_MPMC_DEF_AS(name, name_t, type[, oplist]) */
|
||||
#define SNAPSHOT_MPMC_DEF_AS(name, name_t, ...) \
|
||||
#define M_SNAPSHOT_MPMC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_SNAPSH0T_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
@@ -84,7 +84,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the oplist of a snapshot (SPSC, SPMC or MPMC).
|
||||
USAGE: SNAPSHOT_OPLIST(name[, oplist]) */
|
||||
#define SNAPSHOT_OPLIST(...) \
|
||||
#define M_SNAPSHOT_OPLIST(...) \
|
||||
M_SNAPSH0T_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
|
||||
(__VA_ARGS__ )))
|
||||
@@ -156,7 +156,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define M_SNAPSH0T_SPSC_MAX_BUFFER 3
|
||||
|
||||
// Defered evaluation of the arguments.
|
||||
#define M_SNAPSH0T_SPSC_DEF_P1(arg) M_SNAPSH0T_SPSC_DEF_P2 arg
|
||||
#define M_SNAPSH0T_SPSC_DEF_P1(arg) M_ID( M_SNAPSH0T_SPSC_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_SNAPSH0T_SPSC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
@@ -347,7 +347,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
// 2 more buffer than the number of readers are needed
|
||||
#define M_SNAPSH0T_SPMC_EXTRA_BUFFER 2
|
||||
|
||||
#define M_SNAPSH0T_SPMC_MAX_READER (GENINT_MAX_ALLOC-M_SNAPSH0T_SPMC_EXTRA_BUFFER)
|
||||
#define M_SNAPSH0T_SPMC_MAX_READER (M_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 M_SNAPSH0T_SPMC_INT_FLAG)
|
||||
@@ -356,13 +356,13 @@ M_BEGIN_PROTECTED_CODE
|
||||
- cptTab: ref counter array to keep track of how many readers use the corresponding buffer.
|
||||
- freeList: a pool of free integers.
|
||||
*/
|
||||
typedef struct m_snapshot_mrsw_s {
|
||||
typedef struct m_snapsh0t_mrsw_s {
|
||||
atomic_uint lastNext;
|
||||
unsigned int currentWrite;
|
||||
size_t n_reader;
|
||||
atomic_uint *cptTab;
|
||||
genint_t freeList;
|
||||
} m_snapshot_mrsw_ct[1];
|
||||
m_genint_t freeList;
|
||||
} m_snapsh0t_mrsw_ct[1];
|
||||
|
||||
// can't check currentWrite due to potential data race on it
|
||||
#define M_SNAPSH0T_SPMC_INT_CONTRACT(s) do { \
|
||||
@@ -373,9 +373,9 @@ typedef struct m_snapshot_mrsw_s {
|
||||
M_ASSERT (s->cptTab != NULL); \
|
||||
} while (0)
|
||||
|
||||
/* Initialize m_snapshot_mrsw_ct for n readers (constructor) */
|
||||
/* Initialize m_snapsh0t_mrsw_ct for n readers (constructor) */
|
||||
static inline void
|
||||
m_snapsh0t_mrsw_init(m_snapshot_mrsw_ct s, size_t n)
|
||||
m_snapsh0t_mrsw_init(m_snapsh0t_mrsw_ct s, size_t n)
|
||||
{
|
||||
M_ASSERT (s != NULL);
|
||||
M_ASSERT (n >= 1 && n <= M_SNAPSH0T_SPMC_MAX_READER);
|
||||
@@ -391,35 +391,35 @@ m_snapsh0t_mrsw_init(m_snapshot_mrsw_ct s, size_t n)
|
||||
s->cptTab = ptr;
|
||||
for(size_t i = 0; i < n; i++)
|
||||
atomic_init(&s->cptTab[i], 0U);
|
||||
genint_init (s->freeList, (unsigned int) n);
|
||||
m_genint_init (s->freeList, (unsigned int) n);
|
||||
|
||||
// Get a free buffer and set it as available for readers
|
||||
unsigned int w = genint_pop(s->freeList);
|
||||
M_ASSERT (w != GENINT_ERROR);
|
||||
unsigned int w = m_genint_pop(s->freeList);
|
||||
M_ASSERT (w != M_GENINT_ERROR);
|
||||
atomic_store(&s->cptTab[w], 1U);
|
||||
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);
|
||||
s->currentWrite = m_genint_pop(s->freeList);
|
||||
M_ASSERT (s->currentWrite != M_GENINT_ERROR);
|
||||
atomic_store(&s->cptTab[s->currentWrite], 1U);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
|
||||
/* Clear m_snapshot_mrsw_ct (destructor) */
|
||||
/* Clear m_snapsh0t_mrsw_ct (destructor) */
|
||||
static inline void
|
||||
m_snapsh0t_mrsw_clear(m_snapshot_mrsw_ct s)
|
||||
m_snapsh0t_mrsw_clear(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
M_MEMORY_FREE (s->cptTab);
|
||||
genint_clear(s->freeList);
|
||||
m_genint_clear(s->freeList);
|
||||
s->cptTab = NULL;
|
||||
s->n_reader = 0;
|
||||
}
|
||||
|
||||
/* Return the current index that is written in the buffer */
|
||||
static inline unsigned int
|
||||
m_snapsh0t_mrsw_get_write_idx(m_snapshot_mrsw_ct s)
|
||||
m_snapsh0t_mrsw_get_write_idx(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return s->currentWrite;
|
||||
@@ -427,7 +427,7 @@ m_snapsh0t_mrsw_get_write_idx(m_snapshot_mrsw_ct s)
|
||||
|
||||
/* Return the number of readers */
|
||||
static inline unsigned int
|
||||
m_snapsh0t_mrsw_size(m_snapshot_mrsw_ct s)
|
||||
m_snapsh0t_mrsw_size(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return (unsigned int) s->n_reader;
|
||||
@@ -436,7 +436,7 @@ m_snapsh0t_mrsw_size(m_snapshot_mrsw_ct s)
|
||||
/* Give the current index that is written to the readers,
|
||||
and return new available index for the writer thread */
|
||||
static inline unsigned int
|
||||
m_snapsh0t_mrsw_write_idx(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
m_snapsh0t_mrsw_write_idx(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
|
||||
@@ -462,8 +462,8 @@ m_snapsh0t_mrsw_write_idx(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
if (c != 1) {
|
||||
// If someone else keeps a ref on the buffer, we can't reuse it
|
||||
// get another free one.
|
||||
idx = genint_pop(s->freeList);
|
||||
M_ASSERT(idx != GENINT_ERROR);
|
||||
idx = m_genint_pop(s->freeList);
|
||||
M_ASSERT(idx != M_GENINT_ERROR);
|
||||
} else {
|
||||
// No other thread keep track of this buffer.
|
||||
// Reuse it.
|
||||
@@ -478,7 +478,7 @@ m_snapsh0t_mrsw_write_idx(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
|
||||
/* Perform a swap of the current write buffer and return a new one */
|
||||
static inline unsigned int
|
||||
m_snapsh0t_mrsw_write(m_snapshot_mrsw_ct s)
|
||||
m_snapsh0t_mrsw_write(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
s->currentWrite = m_snapsh0t_mrsw_write_idx(s, s->currentWrite);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
@@ -487,12 +487,12 @@ m_snapsh0t_mrsw_write(m_snapshot_mrsw_ct s)
|
||||
|
||||
/* Start writing to the write buffer and return its index */
|
||||
static inline unsigned int
|
||||
m_snapsh0t_mrsw_write_start(m_snapshot_mrsw_ct s)
|
||||
m_snapsh0t_mrsw_write_start(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
// Get a new buffer.
|
||||
unsigned int idx = genint_pop(s->freeList);
|
||||
M_ASSERT (idx != GENINT_ERROR);
|
||||
unsigned int idx = m_genint_pop(s->freeList);
|
||||
M_ASSERT (idx != M_GENINT_ERROR);
|
||||
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);
|
||||
@@ -502,7 +502,7 @@ m_snapsh0t_mrsw_write_start(m_snapshot_mrsw_ct s)
|
||||
|
||||
/* End writing to the given write buffer */
|
||||
static inline void
|
||||
m_snapsh0t_mrsw_write_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
m_snapsh0t_mrsw_write_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
|
||||
@@ -517,14 +517,14 @@ m_snapsh0t_mrsw_write_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
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);
|
||||
m_genint_push(s->freeList, idx);
|
||||
}
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
|
||||
/* Start reading the latest written buffer and return the index to it */
|
||||
static inline unsigned int
|
||||
m_snapsh0t_mrsw_read_start(m_snapshot_mrsw_ct s)
|
||||
m_snapsh0t_mrsw_read_start(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
unsigned int idx, previous;
|
||||
@@ -558,7 +558,7 @@ m_snapsh0t_mrsw_read_start(m_snapshot_mrsw_ct s)
|
||||
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);
|
||||
m_genint_push(s->freeList, idx);
|
||||
}
|
||||
}
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
@@ -567,7 +567,7 @@ m_snapsh0t_mrsw_read_start(m_snapshot_mrsw_ct s)
|
||||
|
||||
/* End the reading the given buffer */
|
||||
static inline void
|
||||
m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
M_ASSERT (idx < s->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER);
|
||||
@@ -577,7 +577,7 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
if (c == 1) {
|
||||
// Buffer no longer used by any reader thread.
|
||||
// Push back index in free list
|
||||
genint_push(s->freeList, idx);
|
||||
m_genint_push(s->freeList, idx);
|
||||
}
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
@@ -591,7 +591,7 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
|
||||
|
||||
// Defered evaluation
|
||||
#define M_SNAPSH0T_SPMC_DEF_P1(arg) M_SNAPSH0T_SPMC_DEF_P2 arg
|
||||
#define M_SNAPSH0T_SPMC_DEF_P1(arg) M_ID( M_SNAPSH0T_SPMC_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_SNAPSH0T_SPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
@@ -612,7 +612,7 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _aligned_type_ct) *data; \
|
||||
m_snapshot_mrsw_ct core; \
|
||||
m_snapsh0t_mrsw_ct core; \
|
||||
} snapshot_t[1]; \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
@@ -700,7 +700,7 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
// MPMC is built upon SPMC
|
||||
|
||||
// Defered evaluation
|
||||
#define M_SNAPSH0T_MPMC_DEF_P1(arg) M_SNAPSH0T_MPMC_DEF_P2 arg
|
||||
#define M_SNAPSH0T_MPMC_DEF_P1(arg) M_ID( M_SNAPSH0T_MPMC_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_SNAPSH0T_MPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
@@ -730,7 +730,7 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_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; \
|
||||
snap->core->core->currentWrite = M_GENINT_ERROR; \
|
||||
m_snapsh0t_mrsw_write_end(snap->core->core, idx); \
|
||||
} \
|
||||
\
|
||||
@@ -778,4 +778,14 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define SNAPSHOT_SPSC_DEF M_SNAPSHOT_SPSC_DEF
|
||||
#define SNAPSHOT_SPSC_DEF_AS M_SNAPSHOT_SPSC_DEF_AS
|
||||
#define SNAPSHOT_SPMC_DEF M_SNAPSHOT_SPMC_DEF
|
||||
#define SNAPSHOT_SPMC_DEF_AS M_SNAPSHOT_SPMC_DEF_AS
|
||||
#define SNAPSHOT_MPMC_DEF M_SNAPSHOT_MPMC_DEF
|
||||
#define SNAPSHOT_MPMC_DEF_AS M_SNAPSHOT_MPMC_DEF_AS
|
||||
#define SNAPSHOT_OPLIST M_SNAPSHOT_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+809
-513
File diff suppressed because it is too large.
Load diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - TUPLE module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -32,15 +32,15 @@
|
||||
/* Define the tuple type and functions.
|
||||
USAGE:
|
||||
TUPLE_DEF2(name, [(field1, type1[, oplist1]), (field2, type2[, oplist2]), ...] ) */
|
||||
#define TUPLE_DEF2(name, ...) \
|
||||
TUPLE_DEF2_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_TUPLE_DEF2(name, ...) \
|
||||
M_TUPLE_DEF2_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define the tuple type and functions
|
||||
as the given name.
|
||||
USAGE:
|
||||
TUPLE_DEF2_AS(name, name_t, [(field1, type1[, oplist1]), (field2, type2[, oplist2]), ...] ) */
|
||||
#define TUPLE_DEF2_AS(name, name_t, ...) \
|
||||
#define M_TUPLE_DEF2_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_TUPL3_DEF2_P1( (name, name_t M_TUPL3_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -48,9 +48,9 @@
|
||||
|
||||
/* Define the oplist of a tuple.
|
||||
USAGE: TUPLE_OPLIST(name[, oplist of the first type, ...]) */
|
||||
#define TUPLE_OPLIST(...) \
|
||||
#define M_TUPLE_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(M_TUPL3_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST )), \
|
||||
(M_TUPL3_OPLIST_P1((__VA_ARGS__, M_BASIC_OPLIST )), \
|
||||
M_TUPL3_OPLIST_P1((__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
(shall be constexpr, but only supported in C++14).
|
||||
*/
|
||||
#ifndef __cplusplus
|
||||
#define TUPLE_ORDER(name, ...) \
|
||||
#define M_TUPLE_ORDER(name, ...) \
|
||||
( (const int[]) {M_MAP2_C(M_TUPL3_ORDER_CONVERT, name, __VA_ARGS__), 0})
|
||||
#else
|
||||
#include <initializer_list>
|
||||
@@ -76,7 +76,7 @@ namespace m_lib {
|
||||
}
|
||||
};
|
||||
}
|
||||
#define TUPLE_ORDER(name, ...) \
|
||||
#define M_TUPLE_ORDER(name, ...) \
|
||||
(m_lib::m_tupl3_integer_va<M_NARGS(__VA_ARGS__,0)>({M_MAP2_C(M_TUPL3_ORDER_CONVERT, name, __VA_ARGS__), 0}).data)
|
||||
#endif
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace m_lib {
|
||||
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 (x, type, M_BASIC_OPLIST) if there is no global one,
|
||||
or keep (x, type, oplist) if oplist was already present */
|
||||
#define M_TUPL3_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
M_TUPL3_INJECT_OPLIST_B duo_or_trio
|
||||
@@ -103,7 +103,7 @@ namespace m_lib {
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
|
||||
|
||||
// Deferred evaluation
|
||||
#define M_TUPL3_DEF2_P1(...) M_TUPL3_DEF2_P2 __VA_ARGS__
|
||||
#define M_TUPL3_DEF2_P1(...) M_ID( M_TUPL3_DEF2_P2 __VA_ARGS__ )
|
||||
|
||||
// Test if all third argument of all arguments is an oplist
|
||||
#define M_TUPL3_IF_ALL_OPLIST(...) \
|
||||
@@ -212,7 +212,12 @@ namespace m_lib {
|
||||
/* 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);
|
||||
} M_C3(m_tupl3_, name, _num_args_ct); \
|
||||
/* Save alias for the types of arguments */ \
|
||||
M_MAP3(M_TUPL3_DEFINE_TYPE_ELE, name, __VA_ARGS__)
|
||||
|
||||
#define M_TUPL3_DEFINE_TYPE_ELE(name, num, a) \
|
||||
typedef M_TUPL3_GET_TYPE a M_C4(name, _type_, num, _ct);
|
||||
|
||||
#define M_TUPL3_DEFINE_RECUR_TYPE_ELE(a) \
|
||||
M_TUPL3_GET_TYPE a M_TUPL3_GET_FIELD a ;
|
||||
@@ -394,15 +399,15 @@ namespace m_lib {
|
||||
|
||||
#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), \
|
||||
M_TUPL3_DEFINE_CMP_FIELD_FUNC(name, M_TUPL3_GET_FIELD a, M_TUPL3_GET_CMP a, M_TUPL3_GET_OPLIST a), \
|
||||
)
|
||||
|
||||
#define M_TUPL3_DEFINE_CMP_FIELD_FUNC(name, field, func_cmp) \
|
||||
#define M_TUPL3_DEFINE_CMP_FIELD_FUNC(name, field, func_cmp, oplist) \
|
||||
static inline int M_C3(name, _cmp_, field)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2) { \
|
||||
M_TUPL3_CONTRACT(e1); \
|
||||
M_TUPL3_CONTRACT(e2); \
|
||||
return func_cmp ( e1 -> field , e2 -> field ); \
|
||||
return M_APPLY_API(func_cmp, oplist, e1 -> field , e2 -> field ); \
|
||||
}
|
||||
|
||||
|
||||
@@ -441,19 +446,19 @@ namespace m_lib {
|
||||
|
||||
/* Define a GET_STR method by calling the GET_STR methods for all params */
|
||||
#define M_TUPL3_DEFINE_GET_STR(name, ...) \
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
static inline void M_C(name, _get_str)(m_string_t str, \
|
||||
M_C(name,_ct) const el, \
|
||||
bool append) { \
|
||||
bool comma = false; \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_ASSERT (str != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "("); \
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "("); \
|
||||
M_MAP(M_TUPL3_DEFINE_GET_STR_FUNC , __VA_ARGS__) \
|
||||
string_push_back (str, ')'); \
|
||||
m_string_push_back (str, ')'); \
|
||||
}
|
||||
|
||||
#define M_TUPL3_DEFINE_GET_STR_FUNC(a) \
|
||||
if (comma) string_push_back (str, ','); \
|
||||
if (comma) m_string_push_back (str, ','); \
|
||||
comma = true; \
|
||||
M_TUPL3_CALL_GET_STR(a, str, el -> M_TUPL3_GET_FIELD a, true); \
|
||||
|
||||
@@ -633,17 +638,13 @@ namespace m_lib {
|
||||
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 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> }
|
||||
tuple = { int, m_string_t, array<m_string_t> }
|
||||
USAGE:
|
||||
M_LET( (x, 2, ("John"), ( ("Bear"), ("Rabbit") )), tuple_t)
|
||||
|
||||
@@ -740,7 +741,18 @@ namespace m_lib {
|
||||
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__,)),), \
|
||||
EMPLACE_TYPE( ( M_REDUCE2(M_TUPL3_OPLIST_SUBTYPE, M_ID, name, M_SEQ(1, M_NARGS(__VA_ARGS__))) ) ) \
|
||||
)
|
||||
|
||||
/* Support for EMPLACE_TYPE in OPLIST. It refers the created internal type alias */
|
||||
#define M_TUPL3_OPLIST_SUBTYPE(name, num) \
|
||||
M_C4(name, _type_, num, _ct)
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define TUPLE_DEF2 M_TUPLE_DEF2
|
||||
#define TUPLE_DEF2_AS M_TUPLE_DEF2_AS
|
||||
#define TUPLE_OPLIST M_TUPLE_OPLIST
|
||||
#define TUPLE_ORDER M_TUPLE_ORDER
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+52
-17
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - VARIANT module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -33,15 +33,15 @@
|
||||
/* Define the variant type and functions.
|
||||
USAGE:
|
||||
VARIANT_DEF2(name, [(field1, type1, oplist1), (field2, type2, oplist2), ...] ) */
|
||||
#define VARIANT_DEF2(name, ...) \
|
||||
VARIANT_DEF2_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_VARIANT_DEF2(name, ...) \
|
||||
M_VARIANT_DEF2_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define the variant type and functions
|
||||
as the given name_t
|
||||
USAGE:
|
||||
VARIANT_DEF2_AS(name, name_t, [(field1, type1, oplist1), (field2, type2, oplist2), ...] ) */
|
||||
#define VARIANT_DEF2_AS(name, name_t, ...) \
|
||||
#define M_VARIANT_DEF2_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_VAR1ANT_DEF2_P1( (name, name_t M_VAR1ANT_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -49,9 +49,9 @@
|
||||
|
||||
/* Define the oplist of a variant.
|
||||
USAGE: VARIANT_OPLIST(name[, oplist of the first type, ...]) */
|
||||
#define VARIANT_OPLIST(...) \
|
||||
#define M_VARIANT_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(M_VAR1ANT_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST)), \
|
||||
(M_VAR1ANT_OPLIST_P1((__VA_ARGS__, M_BASIC_OPLIST)), \
|
||||
M_VAR1ANT_OPLIST_P1((__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
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 (x, type, M_BASIC_OPLIST) if there is no global one,
|
||||
or keep (x, type, oplist) if oplist was already present */
|
||||
#define M_VAR1ANT_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
M_VAR1ANT_INJECT_OPLIST_B duo_or_trio
|
||||
@@ -79,7 +79,7 @@
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
|
||||
|
||||
// Deferred evaluation
|
||||
#define M_VAR1ANT_DEF2_P1(...) M_VAR1ANT_DEF2_P2 __VA_ARGS__
|
||||
#define M_VAR1ANT_DEF2_P1(...) M_ID( M_VAR1ANT_DEF2_P2 __VA_ARGS__ )
|
||||
|
||||
// Test if all third argument of all arguments is an oplist
|
||||
#define M_VAR1ANT_IF_ALL_OPLIST(...) \
|
||||
@@ -105,6 +105,7 @@
|
||||
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_EMPLACE(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__),) \
|
||||
@@ -383,6 +384,39 @@
|
||||
}
|
||||
|
||||
|
||||
/* Define the EMPLACE of a given type function.
|
||||
NOTE: Use of a variant of MAP3 because of recursive use of MAP2/MAP3/REDUCE2 !
|
||||
*/
|
||||
#define M_VAR1ANT_DEFINE_EMPLACE(name, ...) \
|
||||
M_VAR1ANT_MAP3_ALT(M_VAR1ANT_DEFINE_EMPLACE_FUNC, name, __VA_ARGS__)
|
||||
// Variant of M_MAP3 using M_REDUCE3
|
||||
#define M_VAR1ANT_MAP3_ALT(f, d, ...) M_REDUCE3(f, M_VAR1ANT_MAP3_ALT_ID, d, __VA_ARGS__)
|
||||
#define M_VAR1ANT_MAP3_ALT_ID(a, b) a b
|
||||
|
||||
#define M_VAR1ANT_DEFINE_EMPLACE_FUNC(name, num, a) \
|
||||
M_EMPLACE_QUEUE_DEF( (name, M_VAR1ANT_GET_FIELD a), M_C(name,_ct), M_C3(name, _init_emplace_, M_VAR1ANT_GET_FIELD a), M_VAR1ANT_GET_OPLIST a, M_VAR1ANT_DEFINE_INIT_EMPLACE_DEF) \
|
||||
M_EMPLACE_QUEUE_DEF( (name, M_VAR1ANT_GET_FIELD a), M_C(name,_ct), M_C3(name, _emplace_, M_VAR1ANT_GET_FIELD a), M_VAR1ANT_GET_OPLIST a, M_VAR1ANT_DEFINE_EMPLACE_DEF)
|
||||
|
||||
#define M_VAR1ANT_DEFINE_INIT_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
static inline void \
|
||||
function_name(name_t my \
|
||||
M_EMPLACE_LIST_TYPE_VAR(ab, exp_emplace_type) ) \
|
||||
{ \
|
||||
my->type = M_C4(M_PAIR_1 name, _, M_PAIR_2 name, _value); \
|
||||
M_EMPLACE_CALL_FUNC(ab, init_func, oplist, my -> value. M_PAIR_2 name, exp_emplace_type); \
|
||||
} \
|
||||
|
||||
#define M_VAR1ANT_DEFINE_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
static inline void \
|
||||
function_name(name_t my \
|
||||
M_EMPLACE_LIST_TYPE_VAR(ab, exp_emplace_type) ) \
|
||||
{ \
|
||||
/* No optimization done */ \
|
||||
M_C(M_PAIR_1 name, _clear)(my); \
|
||||
my->type = M_C4(M_PAIR_1 name, _, M_PAIR_2 name, _value); \
|
||||
M_EMPLACE_CALL_FUNC(ab, init_func, oplist, my -> value. M_PAIR_2 name, exp_emplace_type); \
|
||||
} \
|
||||
|
||||
/* Define the EQUAL_P function. */
|
||||
#define M_VAR1ANT_DEFINE_EQUAL(name, ...) \
|
||||
static inline bool M_C(name, _equal_p)(M_C(name,_ct) const e1 , \
|
||||
@@ -517,19 +551,19 @@
|
||||
|
||||
/* Define the GET_STR function */
|
||||
#define M_VAR1ANT_DEFINE_GET_STR(name, ...) \
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
static inline void M_C(name, _get_str)(m_string_t str, \
|
||||
M_C(name,_ct) const el, \
|
||||
bool append) { \
|
||||
M_VAR1ANT_CONTRACT(name, el); \
|
||||
M_ASSERT (str != NULL); \
|
||||
void (*func)(string_t, const char *); \
|
||||
func = append ? string_cat_str : string_set_str; \
|
||||
void (*func)(m_string_t, const char *); \
|
||||
func = append ? m_string_cat_cstr : m_string_set_cstr; \
|
||||
switch (el->type) { \
|
||||
case M_C(name, _EMPTY): func(str, "@EMPTY@"); break; \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_GET_STR_FUNC , name, __VA_ARGS__) \
|
||||
default: M_ASSERT(false); break; \
|
||||
} \
|
||||
string_push_back (str, '@'); \
|
||||
m_string_push_back (str, '@'); \
|
||||
}
|
||||
|
||||
#define M_VAR1ANT_DEFINE_GET_STR_FUNC(name, a) \
|
||||
@@ -718,11 +752,6 @@
|
||||
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 M_VAR1ANT_OPLIST_P1(arg) M_VAR1ANT_OPLIST_P2 arg
|
||||
@@ -776,4 +805,10 @@
|
||||
#define M_VAR1ANT_IF_ALL2(method1, method2, ...) \
|
||||
M_IF(M_REDUCE2(M_VAR1ANT_TEST_METHOD2_P, M_AND, (method1, method2), __VA_ARGS__))
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define VARIANT_DEF2 M_VARIANT_DEF2
|
||||
#define VARIANT_DEF2_AS M_VARIANT_DEF2_AS
|
||||
#define VARIANT_OPLIST M_VARIANT_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+108
-90
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB / WORKER - Extra worker interface
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -40,7 +40,7 @@
|
||||
#include "m-buffer.h"
|
||||
#include "m-mutex.h"
|
||||
|
||||
/* Include needed system header for detection of how many core on the system */
|
||||
/* Include needed system header for detection of how many cores are available in the system */
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
#elif (defined(__APPLE__) && defined(__MACH__)) \
|
||||
@@ -96,8 +96,8 @@
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Definition of a work order */
|
||||
typedef struct work_order_s {
|
||||
struct worker_sync_s *block; // Reference to the shared Synchronization block
|
||||
typedef struct m_work3r_order_s {
|
||||
struct m_worker_sync_s *block; // Reference to the shared Synchronization block
|
||||
void * data; // The work order data
|
||||
void (*func) (void *data); // The work order function (for GCC)
|
||||
#if M_USE_WORKER_CLANG_BLOCK
|
||||
@@ -106,7 +106,7 @@ typedef struct work_order_s {
|
||||
#if M_USE_WORKER_CPP_FUNCTION
|
||||
std::function<void(void*)> function; // The work order function (for C++)
|
||||
#endif
|
||||
} worker_order_ct;
|
||||
} m_work3r_order_ct;
|
||||
|
||||
/* Define the macros needed to initialize an order.
|
||||
* * MACRO to be used to send an empty order to stop the thread
|
||||
@@ -120,38 +120,38 @@ typedef struct work_order_s {
|
||||
# define M_WORK3R_EXTRA_ORDER
|
||||
#endif
|
||||
|
||||
/* As in C++, it uses std::function, M_POD_OPLIST
|
||||
/* As it is 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 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 \
|
||||
# define M_WORK3R_CPP_INIT(x) (new (&(x)) m_work3r_order_ct())
|
||||
# define M_WORK3R_CPP_INIT_SET(x, y) (new (&(x)) m_work3r_order_ct(y))
|
||||
# define M_WORK3R_CPP_SET(x, y) ((x) = (y))
|
||||
# define M_WORK3R_CPP_CLEAR(x) ((&(x))->~m_work3r_order_ct())
|
||||
# define M_WORK3R_CPP_INIT_MOVE(x,y) (new (&(x)) m_work3r_order_ct(y), ((&(y))->~m_work3r_order_ct()))
|
||||
# define M_WORK3R_OPLIST \
|
||||
(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
|
||||
# define M_WORK3R_OPLIST M_POD_OPLIST
|
||||
#endif
|
||||
|
||||
/* Definition of a worker (implemented by a thread) */
|
||||
typedef struct worker_thread_s {
|
||||
/* Definition of the identity of a worker thread */
|
||||
typedef struct m_work3r_thread_s {
|
||||
m_thread_t id;
|
||||
} worker_thread_ct;
|
||||
} m_work3r_thread_ct;
|
||||
|
||||
/* Definition of the queue that will record the work orders */
|
||||
BUFFER_DEF_AS(worker_queue, m_worker_queue_ct, worker_order_ct, 0,
|
||||
BUFFER_QUEUE|BUFFER_UNBLOCKING_PUSH|BUFFER_BLOCKING_POP|BUFFER_THREAD_SAFE|BUFFER_DEFERRED_POP, WORKER_OPLIST)
|
||||
BUFFER_DEF(m_work3r_queue, m_work3r_order_ct, 0,
|
||||
BUFFER_QUEUE|BUFFER_UNBLOCKING_PUSH|BUFFER_BLOCKING_POP|BUFFER_THREAD_SAFE|BUFFER_DEFERRED_POP, M_WORK3R_OPLIST)
|
||||
|
||||
/* Definition the global pool of workers */
|
||||
typedef struct worker_s {
|
||||
typedef struct m_worker_s {
|
||||
/* The work order queue */
|
||||
m_worker_queue_ct queue_g;
|
||||
m_work3r_queue_t queue_g;
|
||||
|
||||
/* The table of available workers */
|
||||
worker_thread_ct *worker;
|
||||
m_work3r_thread_ct *worker;
|
||||
|
||||
/* Number of workers in the table */
|
||||
unsigned int numWorker_g;
|
||||
@@ -165,18 +165,18 @@ typedef struct worker_s {
|
||||
m_mutex_t lock;
|
||||
m_cond_t a_thread_ends; // EVENT: A worker has ended
|
||||
|
||||
} worker_t[1];
|
||||
} m_worker_t[1];
|
||||
|
||||
/* Definition of the synchronization point for workers */
|
||||
typedef struct worker_sync_s {
|
||||
typedef struct m_worker_sync_s {
|
||||
atomic_int num_spawn; // Number of spawned workers accord this synchronization point
|
||||
atomic_int num_terminated_spawn; // Number of terminated spawned workers
|
||||
struct worker_s *worker; // Reference to the pool of workers
|
||||
} worker_sync_t[1];
|
||||
struct m_worker_s *worker; // Reference to the pool of workers
|
||||
} m_worker_sync_t[1];
|
||||
|
||||
/* Return the number of CPU of the system */
|
||||
/* Return the number of cores available in the system */
|
||||
static inline int
|
||||
workeri_get_cpu_count(void)
|
||||
m_work3r_get_cpu_count(void)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
SYSTEM_INFO sysinfo;
|
||||
@@ -207,7 +207,7 @@ workeri_get_cpu_count(void)
|
||||
|
||||
/* Execute the registered work order **synchronously** */
|
||||
static inline void
|
||||
workeri_exec(worker_order_ct *w)
|
||||
m_work3r_exec(m_work3r_order_ct *w)
|
||||
{
|
||||
M_ASSERT (w!= NULL && w->block != NULL);
|
||||
M_WORK3R_DEBUG ("Starting thread with data %p\n", w->data);
|
||||
@@ -231,28 +231,28 @@ workeri_exec(worker_order_ct *w)
|
||||
|
||||
/* The worker thread main loop*/
|
||||
static inline void
|
||||
workeri_thread(void *arg)
|
||||
m_work3r_thread(void *arg)
|
||||
{
|
||||
// Get back the given argument
|
||||
struct worker_s *g = M_ASSIGN_CAST(struct worker_s *, arg);
|
||||
struct m_worker_s *g = M_ASSIGN_CAST(struct m_worker_s *, arg);
|
||||
while (true) {
|
||||
worker_order_ct w;
|
||||
m_work3r_order_ct w;
|
||||
// If needed, reset the global state of the worker
|
||||
if (g->resetFunc_g != NULL) {
|
||||
g->resetFunc_g();
|
||||
}
|
||||
// Waiting for data
|
||||
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);
|
||||
M_WORK3R_DEBUG ("Waiting for data (queue: %lu / %lu)\n", m_work3r_queue_size(g->queue_g), m_work3r_queue_capacity(g->queue_g));
|
||||
m_work3r_queue_pop(&w, g->queue_g);
|
||||
// We received a work order
|
||||
// Note: that the work order is still present in the queue
|
||||
// preventing further work order to be pushed in the queue until it finishes doing the work
|
||||
// If a stop request is received, terminate the thread
|
||||
if (w.block == NULL) break;
|
||||
// Execute the work order
|
||||
workeri_exec(&w);
|
||||
m_work3r_exec(&w);
|
||||
// Consumme fully the work order in the queue
|
||||
worker_queue_pop_release(g->queue_g);
|
||||
m_work3r_queue_pop_release(g->queue_g);
|
||||
// Signal that a worker has finished.
|
||||
m_mutex_lock(g->lock);
|
||||
m_cond_broadcast(g->a_thread_ends);
|
||||
@@ -272,23 +272,23 @@ workeri_thread(void *arg)
|
||||
@clearFunc: function to clear the state of a worker before terminaning (or NULL if none)
|
||||
*/
|
||||
static inline void
|
||||
worker_init(worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
|
||||
m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
|
||||
{
|
||||
M_ASSERT (numWorker >= -1);
|
||||
// Auto compute number of workers if the argument is 0
|
||||
if (numWorker <= 0)
|
||||
numWorker = (1 + (numWorker == -1))*workeri_get_cpu_count()-1;
|
||||
numWorker = (1 + (numWorker == -1))*m_work3r_get_cpu_count()-1;
|
||||
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);
|
||||
size_t numWorker_st = (size_t) numWorker;
|
||||
g->worker = M_MEMORY_REALLOC(worker_thread_ct, NULL, numWorker_st);
|
||||
g->worker = M_MEMORY_REALLOC(m_work3r_thread_ct, NULL, numWorker_st);
|
||||
if (g->worker == NULL) {
|
||||
M_MEMORY_FULL(sizeof (worker_thread_ct) * numWorker_st);
|
||||
M_MEMORY_FULL(sizeof (m_work3r_thread_ct) * numWorker_st);
|
||||
return;
|
||||
}
|
||||
worker_queue_init(g->queue_g, numWorker_st + extraQueue);
|
||||
m_work3r_queue_init(g->queue_g, numWorker_st + extraQueue);
|
||||
g->numWorker_g = (unsigned int) numWorker_st;
|
||||
g->resetFunc_g = resetFunc;
|
||||
g->clearFunc_g = clearFunc;
|
||||
@@ -297,30 +297,31 @@ worker_init(worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc
|
||||
|
||||
// Create & start the workers
|
||||
for(size_t i = 0; i < numWorker_st; i++) {
|
||||
m_thread_create(g->worker[i].id, workeri_thread, M_ASSIGN_CAST(void*, g));
|
||||
m_thread_create(g->worker[i].id, m_work3r_thread, M_ASSIGN_CAST(void*, g));
|
||||
}
|
||||
}
|
||||
/* Initialization of the worker module (constructor)
|
||||
Provide default values for the arguments.
|
||||
Input:
|
||||
@numWorker: number of worker to create (0=autodetect, -1=2*autodetect)
|
||||
@extraQueue: number of extra work order we can get if all workers are full
|
||||
@resetFunc: function to reset the state of a worker between work orders (optional)
|
||||
@clearFunc: function to clear the state of a worker before terminaning (optional)
|
||||
*/
|
||||
#define worker_init(...) worker_init(M_DEFAULT_ARGS(5, (0, 0, NULL, NULL), __VA_ARGS__))
|
||||
#define m_worker_init(...) m_worker_init(M_DEFAULT_ARGS(5, (0, 0, NULL, NULL), __VA_ARGS__))
|
||||
|
||||
/* Clear of the worker module (destructor) */
|
||||
static inline void
|
||||
worker_clear(worker_t g)
|
||||
m_worker_clear(m_worker_t g)
|
||||
{
|
||||
M_ASSERT (worker_queue_empty_p (g->queue_g));
|
||||
M_ASSERT (m_work3r_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 = M_WORK3R_EMPTY_ORDER;
|
||||
m_work3r_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.
|
||||
worker_queue_push_blocking (g->queue_g, w, true);
|
||||
m_work3r_queue_push_blocking (g->queue_g, w, true);
|
||||
}
|
||||
// Wait for thread terminanison
|
||||
for(unsigned int i = 0; i < g->numWorker_g; i++) {
|
||||
@@ -330,13 +331,13 @@ worker_clear(worker_t g)
|
||||
M_MEMORY_FREE(g->worker);
|
||||
m_mutex_clear(g->lock);
|
||||
m_cond_clear(g->a_thread_ends);
|
||||
worker_queue_clear(g->queue_g);
|
||||
m_work3r_queue_clear(g->queue_g);
|
||||
}
|
||||
|
||||
/* Start a new collaboration between workers of pool 'g'
|
||||
by defining the synchronization point 'block' */
|
||||
static inline void
|
||||
worker_start(worker_sync_t block, worker_t g)
|
||||
m_worker_start(m_worker_sync_t block, m_worker_t g)
|
||||
{
|
||||
atomic_init (&block->num_spawn, 0);
|
||||
atomic_init (&block->num_terminated_spawn, 0);
|
||||
@@ -349,11 +350,11 @@ worker_start(worker_sync_t block, worker_t g)
|
||||
The work order if composed of the function 'func' and its 'data'
|
||||
*/
|
||||
static inline void
|
||||
worker_spawn(worker_sync_t block, void (*func)(void *data), void *data)
|
||||
m_worker_spawn(m_worker_sync_t block, void (*func)(void *data), void *data)
|
||||
{
|
||||
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) {
|
||||
const m_work3r_order_ct w = { block, data, func M_WORK3R_EXTRA_ORDER };
|
||||
if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g))
|
||||
&& m_work3r_queue_push (block->worker->queue_g, w) == true) {
|
||||
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;
|
||||
@@ -367,11 +368,11 @@ worker_spawn(worker_sync_t block, void (*func)(void *data), void *data)
|
||||
/* Spawn or not the given work order to workers,
|
||||
or do it ourself if no worker is available */
|
||||
static inline void
|
||||
worker_spawn_block(worker_sync_t block, void (^func)(void *data), void *data)
|
||||
m_work3r_spawn_block(m_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) {
|
||||
const m_work3r_order_ct w = { block, data, NULL, func };
|
||||
if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g))
|
||||
&& m_work3r_queue_push (block->worker->queue_g, w) == true) {
|
||||
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;
|
||||
@@ -386,11 +387,11 @@ worker_spawn_block(worker_sync_t block, void (^func)(void *data), void *data)
|
||||
/* Spawn or not the given work order to workers,
|
||||
or do it ourself if no worker is available */
|
||||
static inline void
|
||||
worker_spawn_function(worker_sync_t block, std::function<void(void *data)> func, void *data)
|
||||
m_work3r_spawn_function(m_worker_sync_t block, std::function<void(void *data)> func, 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) {
|
||||
const m_work3r_order_ct w = { block, data, NULL, func };
|
||||
if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g))
|
||||
&& m_work3r_queue_push (block->worker->queue_g, w) == true) {
|
||||
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;
|
||||
@@ -403,7 +404,7 @@ worker_spawn_function(worker_sync_t block, std::function<void(void *data)> func,
|
||||
|
||||
/* Test if all work orders of the given synchronization point are finished */
|
||||
static inline bool
|
||||
worker_sync_p(worker_sync_t block)
|
||||
m_worker_sync_p(m_worker_sync_t block)
|
||||
{
|
||||
/* If the number of spawns is greated than the number
|
||||
of terminated spawns, some spawns are still working.
|
||||
@@ -413,14 +414,14 @@ worker_sync_p(worker_sync_t block)
|
||||
|
||||
/* Wait for all work orders of the given synchronization point to be finished */
|
||||
static inline void
|
||||
worker_sync(worker_sync_t block)
|
||||
m_worker_sync(m_worker_sync_t block)
|
||||
{
|
||||
M_WORK3R_DEBUG ("Waiting for thread terminasion.\n");
|
||||
// Fast case: all workers have finished
|
||||
if (worker_sync_p(block)) return;
|
||||
if (m_worker_sync_p(block)) return;
|
||||
// Slow case: perform a locked wait to put this thread to waiting state
|
||||
m_mutex_lock(block->worker->lock);
|
||||
while (!worker_sync_p(block)) {
|
||||
while (!m_worker_sync_p(block)) {
|
||||
m_cond_wait(block->worker->a_thread_ends, block->worker->lock);
|
||||
}
|
||||
m_mutex_unlock(block->worker->lock);
|
||||
@@ -428,19 +429,19 @@ worker_sync(worker_sync_t block)
|
||||
|
||||
/* Flush any work order in the queue ourself if some remains.*/
|
||||
static inline void
|
||||
worker_flush(worker_t g)
|
||||
m_worker_flush(m_worker_t g)
|
||||
{
|
||||
worker_order_ct w;
|
||||
while (worker_queue_pop_blocking (&w, g->queue_g, false) == true) {
|
||||
workeri_exec(&w);
|
||||
worker_queue_pop_release(g->queue_g);
|
||||
m_work3r_order_ct w;
|
||||
while (m_work3r_queue_pop_blocking (&w, g->queue_g, false) == true) {
|
||||
m_work3r_exec(&w);
|
||||
m_work3r_queue_pop_release(g->queue_g);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return the number of workers */
|
||||
static inline size_t
|
||||
worker_count(worker_t g)
|
||||
m_worker_count(m_worker_t g)
|
||||
{
|
||||
return g->numWorker_g + 1;
|
||||
}
|
||||
@@ -454,24 +455,24 @@ worker_count(worker_t g)
|
||||
TODO: Support oplist for input & outputs parameters
|
||||
*/
|
||||
#if M_USE_WORKER_CLANG_BLOCK
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
#define M_WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
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)
|
||||
m_work3r_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)
|
||||
#define M_WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
m_work3r_spawn_function ((_block), [&](void *param) {(void)param ; _core } , NULL)
|
||||
#else
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
#define M_WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
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)
|
||||
m_worker_spawn ((_block), M_WORK3R_SPAWN_SUBFUNC_NAME, &M_WORK3R_SPAWN_DATA_NAME)
|
||||
#endif
|
||||
|
||||
#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_SPAWN_STRUCT_NAME M_C(m_work3r_data_s_, __LINE__)
|
||||
#define M_WORK3R_SPAWN_DATA_NAME M_C(m_work3r_data_, __LINE__)
|
||||
#define M_WORK3R_SPAWN_SUBFUNC_NAME M_C(m_work3r_subfunc_, __LINE__)
|
||||
#define M_WORK3R_DEF_DATA(_input, _output) \
|
||||
struct M_WORK3R_SPAWN_STRUCT_NAME { \
|
||||
M_WORK3R_DEF_DATA_INPUT _input \
|
||||
@@ -533,22 +534,39 @@ M_END_PROTECTED_CODE
|
||||
|
||||
/* Define empty types and empty functions to not use any worker */
|
||||
|
||||
typedef struct worker_block_s {
|
||||
typedef struct m_worker_block_s {
|
||||
int x;
|
||||
} worker_sync_t[1];
|
||||
} m_worker_sync_t[1];
|
||||
|
||||
typedef struct worker_s {
|
||||
typedef struct m_worker_s {
|
||||
int x;
|
||||
} worker_t[1];
|
||||
} m_worker_t[1];
|
||||
|
||||
#define worker_init(g, numWorker, extraQueue, resetFunc) do { (void) g; } while (0)
|
||||
#define worker_clear(g) do { (void) g; } while (0)
|
||||
#define worker_start(b, w) do { (void) b; } while (0)
|
||||
#define worker_spawn(b, f, d) do { f(d); } while (0)
|
||||
#define worker_sync(b) do { (void) b; } while (0)
|
||||
#define worker_count(w) 1
|
||||
#define WORKER_SPAWN(b, i, c, o) do { c } while (0)
|
||||
#define m_worker_init(g, numWorker, extraQueue, resetFunc) do { (void) g; } while (0)
|
||||
#define m_worker_clear(g) do { (void) g; } while (0)
|
||||
#define m_worker_start(b, w) do { (void) b; } while (0)
|
||||
#define m_worker_spawn(b, f, d) do { f(d); } while (0)
|
||||
#define m_worker_sync_p(b) true
|
||||
#define m_worker_sync(b) do { (void) b; } while (0)
|
||||
#define m_worker_count(w) 1
|
||||
#define m_worker_flush(w) do { (void) w; } while (0)
|
||||
#define M_WORKER_SPAWN(b, i, c, o) do { c } while (0)
|
||||
|
||||
#endif /* M_USE_WORKER */
|
||||
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define worker_t m_worker_t
|
||||
#define worker_sync_t m_worker_sync_t
|
||||
#define worker_init m_worker_init
|
||||
#define worker_clear m_worker_clear
|
||||
#define worker_start m_worker_start
|
||||
#define worker_spawn m_worker_spawn
|
||||
#define worker_sync_p m_worker_sync_p
|
||||
#define worker_sync m_worker_sync
|
||||
#define worker_count m_worker_count
|
||||
#define worker_flush m_worker_flush
|
||||
#define WORKER_SPAWN M_WORKER_SPAWN
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
REM Copyright (c) 2017-2021, Patrick Pelissier
|
||||
REM Copyright (c) 2017-2022, Patrick Pelissier
|
||||
REM All rights reserved.
|
||||
REM
|
||||
REM Redistribution and use in source and binary forms, with or without
|
||||
@@ -22,7 +22,7 @@ REM SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
REM Execute the test suite for Microsoft Visual Studio
|
||||
REM
|
||||
REM Load Micosoft Visual Studio environement file.
|
||||
REM Load Micosoft Visual Studio environement file (2019 or 2022)
|
||||
IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" (
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
)
|
||||
@@ -30,6 +30,13 @@ IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxi
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
)
|
||||
|
||||
IF EXIST "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" (
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
)
|
||||
IF EXIST "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" (
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
)
|
||||
|
||||
REM Add clang-cl in the PATH. It is the default install of clang for MSVC:
|
||||
REM %VCINSTALLDIR%\Tools\Llvm\bin;%VCINSTALLDIR%\Tools\Llvm\x64\bin
|
||||
REM Adding x64 version
|
||||
|
||||
+25
-10
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2021, Patrick Pelissier
|
||||
# Copyright (c) 2017-2022, Patrick Pelissier
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@@ -45,7 +45,7 @@ all:
|
||||
.POSIX:
|
||||
.PHONY: scan-build sanitize check clean *.log coverage synthesis
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .exe .log .depend .gcov .analyzer .cpp
|
||||
.SUFFIXES: .c .exe .log .depend .gcov .analyzer .cpp .fuzz
|
||||
.SECONDARY:
|
||||
|
||||
.c.exe:
|
||||
@@ -68,13 +68,19 @@ all:
|
||||
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) -ftest-coverage -fprofile-arcs -g $<.c -o $<.exe
|
||||
$(CC) $(CPPFLAGS) $(LDFLAGS) -ftest-coverage -fprofile-arcs -O -g $<.c -o $<.exe
|
||||
$(LOG_COMPILER) ./$<.exe
|
||||
LANG=C gcov $<.gcno > `basename $< .c`.synt
|
||||
cat `basename $< .c`.synt
|
||||
mv $<.c.gcov `basename $< .c`.gcov
|
||||
$(RM) $<.first.c $<.end.c $<.middle.c $<.c $<.exe
|
||||
|
||||
.cpp.fuzz:
|
||||
afl-g++ $(WCFLAGS_CPP) $(CPPFLAGS) -Wno-sign-conversion -Wno-inline -Wno-conversion -O2 -fsanitize=address,undefined,leak -m32 $< -o $@.exe
|
||||
mkdir -p fuzzer-testsuite
|
||||
for i in $$(seq 1 1000) ; do printf "%d " $$RANDOM ; done > fuzzer-testsuite/t1
|
||||
afl-fuzz -i fuzzer-testsuite/ -o fuzzer-findings -m 800 ./$@.exe -1
|
||||
|
||||
-include depend
|
||||
|
||||
depend:
|
||||
@@ -87,7 +93,7 @@ depend:
|
||||
|
||||
|
||||
#####################################################################################################
|
||||
# Clean
|
||||
# Main target
|
||||
#####################################################################################################
|
||||
|
||||
# This target generates all executable to be tested by CodeQL
|
||||
@@ -107,6 +113,7 @@ 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 *.analyzer
|
||||
$(RMDIR) coverage coverage-dir mlib-report
|
||||
$(RMDIR) fuzzer-testsuite fuzzer-findings
|
||||
|
||||
distclean: clean
|
||||
$(RM) *.depend depend
|
||||
@@ -166,8 +173,8 @@ gene-serial:
|
||||
#####################################################################################################
|
||||
|
||||
coverage:
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.gcov/g'`
|
||||
$(MAKE) synthesis
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.gcov/g'` CC="cc -std=c11"
|
||||
$(MAKE) synthesis.synt check-synthesis
|
||||
|
||||
SYNTHESIS_DATA= M-ALGO test-malgo.c.c test-malgo.synt \
|
||||
M-ARRAY test-marray.c.c test-marray.synt \
|
||||
@@ -192,11 +199,12 @@ SYNTHESIS_DATA= M-ALGO test-malgo.c.c test-malgo.synt \
|
||||
M-SHARED test-mshared.c.c test-mshared.synt \
|
||||
M-SNAPSHOT test-msnapshot.c.c test-msnapshot.synt \
|
||||
M-STRING ../m-string.h test-mstring.synt \
|
||||
M-TREE test-mtree.c.c test-mtree.synt \
|
||||
M-TUPLE test-mtuple.c.c test-mtuple.synt \
|
||||
M-VARIANT test-mvariant.c.c test-mvariant.synt \
|
||||
M-WORKER ../m-worker.h test-mworker.synt
|
||||
|
||||
synthesis:
|
||||
synthesis.synt:
|
||||
@printf "+-------------------------------+-------------------------------+\n"
|
||||
@for i in $(SYNTHESIS_DATA) ; do \
|
||||
if test "$$j" = "" ; then j=$$i ; continue ; fi; \
|
||||
@@ -204,9 +212,14 @@ synthesis:
|
||||
printf "|\t%16.16s\t|\t%16.16s\t|\n" "$$j" "`grep -v Creating $$i|grep $$k -F -A1 |tail -1|cut -f2 -d':'`"; \
|
||||
j=""; \
|
||||
k=""; \
|
||||
done
|
||||
done > synthesis.synt
|
||||
@cat synthesis.synt
|
||||
@printf "+-------------------------------+-------------------------------+\n"
|
||||
|
||||
# Compare the computed coverage against the reference coverage (synthesis.ref), allowing only increase of coverage
|
||||
check-synthesis: synthesis.synt
|
||||
@paste synthesis.ref synthesis.synt |awk '($$2 != $$9) {err=1} { n1=$$4*$$6/100 ; n2=$$11*$$13/100; if (n1 > n2) { printf "ERROR for %s: new coverage (%d) is lower than reference (%d)\n",$$2,n2,n1 ; err=2 } } END {exit err}'
|
||||
|
||||
|
||||
#####################################################################################################
|
||||
# Code analyzer tools
|
||||
@@ -219,8 +232,10 @@ scan-build: clean
|
||||
|
||||
# Relaunch the test suite with the sanitizer.
|
||||
sanitize:
|
||||
$(MAKE) clean check XCFLAGS="-fsanitize=address,undefined,leak"
|
||||
$(MAKE) clean check XCFLAGS="-fsanitize=thread -pie -fPIE"
|
||||
$(MAKE) clean
|
||||
$(MAKE) check XCFLAGS="-fsanitize=address,undefined,leak"
|
||||
$(MAKE) clean
|
||||
$(MAKE) check XCFLAGS="-fsanitize=thread -pie -fPIE"
|
||||
|
||||
|
||||
# Static analysis of the code using GCC "-fanalyzer" option
|
||||
|
||||
+2
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Patrick Pelissier
|
||||
* Copyright (c) 2021-2022, 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:
|
||||
@@ -25,27 +25,18 @@
|
||||
|
||||
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);
|
||||
@@ -53,7 +44,7 @@ void cmp_cont(array_int_t a, std::vector<int> b)
|
||||
for(size_t i = 0; i < s; i++) {
|
||||
int *b0 = array_int_get(a, i);
|
||||
int &b1 = b.at(i);
|
||||
CMP_BASE(*b0, b1);
|
||||
assert(*b0 == b1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, 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 <map>
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF2(tree_int, 5, int, int)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL BPTREE_OPLIST2(tree_int, M_OPL_int(), M_OPL_int() )
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::map<int,int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
#define CLASS_IT_TO_INT(it) (it)->second
|
||||
#define TYPE_IT_TO_INT(it) (it)->value
|
||||
|
||||
void cmp_cont(const tree_int_t a, const std::map<int,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 *k0 = tree_int_cref(ita)->key_ptr;
|
||||
const int &k1 = itb->first;
|
||||
assert(*k0 == k1);
|
||||
const int *v0 = tree_int_cref(ita)->value_ptr;
|
||||
const int &v1 = itb->second;
|
||||
assert(*v0 == v1);
|
||||
itb++;
|
||||
tree_int_next(ita);
|
||||
}
|
||||
assert(tree_int_end_p(ita));
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 1000000
|
||||
|
||||
#define HAVE_GET_KEY_THROUGH_FIND
|
||||
#define HAVE_SET_KEY
|
||||
#define HAVE_KEY_PTR
|
||||
|
||||
#define push_back insert
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022-2022, 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-bptree.h"
|
||||
|
||||
BPTREE_DEF(tree_int, 5, int)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL BPTREE_OPLIST(tree_int, M_OPL_int())
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// 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)
|
||||
|
||||
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;
|
||||
assert(*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"
|
||||
+2
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Patrick Pelissier
|
||||
* Copyright (c) 2021-2022, 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:
|
||||
@@ -25,27 +25,18 @@
|
||||
|
||||
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;
|
||||
@@ -55,7 +46,7 @@ void cmp_cont(deque_float_t a, std::deque<float> b)
|
||||
assert(!deque_float_end_p(ita));
|
||||
const float *b0 = deque_float_cref(ita);
|
||||
float &b1 = *itb;
|
||||
CMP_BASE(*b0, b1);
|
||||
assert(*b0 == b1);
|
||||
itb++;
|
||||
deque_float_next(ita);
|
||||
}
|
||||
|
||||
+2
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Patrick Pelissier
|
||||
* Copyright (c) 2021-2022, 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:
|
||||
@@ -25,27 +25,18 @@
|
||||
|
||||
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;
|
||||
@@ -55,8 +46,7 @@ void cmp_cont(const list_int_t a, const std::list<int> &b)
|
||||
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);
|
||||
assert(*b0 == b1);
|
||||
itb++;
|
||||
list_int_next(ita);
|
||||
}
|
||||
|
||||
+149
-32
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Patrick Pelissier
|
||||
* Copyright (c) 2021-2022 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:
|
||||
@@ -37,14 +37,54 @@
|
||||
# define CONT_TYPE_(CONT_OPL) M_GET_TYPE CONT_OPL
|
||||
# define CONT_TYPE CONT_TYPE_(CONT_OPL)
|
||||
#endif
|
||||
|
||||
// Type used for M*LIB container. Default is the same as C++
|
||||
#ifndef BASE_TYPE
|
||||
# define BASE_TYPE_(CONT_OPL) M_GET_SUBTYPE CONT_OPL
|
||||
# define BASE_TYPE BASE_TYPE_(CONT_OPL)
|
||||
# define BASE_TYPE BASE_CLASS
|
||||
#endif
|
||||
|
||||
// Compare the M*LIB base object to the C++ base object
|
||||
#ifndef CMP_BASE
|
||||
# define CMP_BASE(a, b) assert( (a) == (b) )
|
||||
#endif
|
||||
|
||||
/* Get the affectation if needed to transform an integer into C++ class (resp. M*LIB type) */
|
||||
#ifndef CLASS_SET_INT
|
||||
# define CLASS_SET_INT(a, i) (a) = (i)
|
||||
#endif
|
||||
#ifndef TYPE_SET_INT
|
||||
# define TYPE_SET_INT(a, i) (a) = (i)
|
||||
#endif
|
||||
|
||||
/* Get the affectation if needed to transform a C++ iterator (resp. M*LIB) to an int */
|
||||
#ifndef CLASS_IT_TO_INT
|
||||
# define CLASS_IT_TO_INT(it) *(it)
|
||||
#endif
|
||||
#ifndef TYPE_IT_TO_INT
|
||||
# define TYPE_IT_TO_INT(it) *(it)
|
||||
#endif
|
||||
|
||||
/* Global properties of the container */
|
||||
// Use find to perform GET_KEY for C++
|
||||
//#define HAVE_GET_KEY_THROUGH_FIND
|
||||
// Container are nor ordered
|
||||
//#define DONT_HAVE_SEQUENCE_IT
|
||||
// associative array container
|
||||
//#define HAVE_SET_KEY
|
||||
// Container is in reverse
|
||||
//#define HAVE_REVERSE_IT
|
||||
// Have PUSH_FRONT operator
|
||||
//#define HAVE_PUSH_FRONT
|
||||
// Have POP_FRONT operator
|
||||
//#define HAVE_POP_FRONT
|
||||
|
||||
/*********************************************************************************/
|
||||
|
||||
// Define the container name, extracting it from its oplist
|
||||
#define CONT_NAME_(CONT_OPL) M_GET_NAME CONT_OPL
|
||||
#define CONT_NAME CONT_NAME_(CONT_OPL)
|
||||
|
||||
// Define the maximum number of tests
|
||||
#define MAX_TEST 28
|
||||
|
||||
#ifdef HAVE_REVERSE_IT
|
||||
@@ -128,37 +168,76 @@ void test(int select_test, int index,
|
||||
#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
|
||||
// GET_KEY takes an index which shall be within the range of the container
|
||||
index = index % c1.size();
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_GET_KEY(CONT_OPL, c0, index));
|
||||
b1 = c1[index];
|
||||
#else
|
||||
// GET_KEY takes a key
|
||||
index = index % (DEFAULT_NUMBER/4);
|
||||
BASE_TYPE *p = M_CALL_GET_KEY(CONT_OPL, c0, index);
|
||||
if (p!= NULL) {
|
||||
// Key found
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *p);
|
||||
auto i = c1.find(index);
|
||||
assert(i != c1.end());
|
||||
b1 = *i;
|
||||
b1 = CLASS_IT_TO_INT(i);
|
||||
} else {
|
||||
// Key not found
|
||||
auto i = c1.find(index);
|
||||
assert(i == c1.end());
|
||||
TYPE_SET_INT(b0, 0);
|
||||
CLASS_SET_INT(b1, 0);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
assert( M_CALL_EMPTY_P(CONT_OPL, c0) == true);
|
||||
}
|
||||
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;
|
||||
TYPE_SET_INT(b0, index);
|
||||
CLASS_SET_INT(b1, index);
|
||||
#ifndef HAVE_SET_KEY
|
||||
if (!c1.empty())
|
||||
{
|
||||
index = index % c1.size();
|
||||
M_CALL_SET_KEY(CONT_OPL, c0, index, b0);
|
||||
c1[index] = b1;
|
||||
}
|
||||
#else
|
||||
index = index % (DEFAULT_NUMBER/4);
|
||||
M_CALL_SET_KEY(CONT_OPL, c0, index, b0);
|
||||
c1[index] = b1;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 21:
|
||||
{
|
||||
unsigned n = index % 1000;
|
||||
unsigned offset = (index / 1027) % 1000;
|
||||
#ifndef HAVE_SET_KEY
|
||||
// If it is a sequence container, check it it fits, otherwise resize
|
||||
// without resize which may not be available, but push is assumed to be.
|
||||
if ((size_t) n+offset > c1.size() ) {
|
||||
TYPE_SET_INT(b0, 0);
|
||||
CLASS_SET_INT(b1, 0);
|
||||
for(unsigned i = c1.size() ; i < (size_t) n+offset; i++) {
|
||||
M_CALL_PUSH(CONT_OPL, c0, b0);
|
||||
c1.push_back(b1);
|
||||
}
|
||||
assert(c1.size() == (size_t) n+offset);
|
||||
}
|
||||
#endif
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
TYPE_SET_INT(b0, 3*i);
|
||||
CLASS_SET_INT(b1, 3*i);
|
||||
M_CALL_SET_KEY(CONT_OPL, c0, offset + i, b0);
|
||||
c1[offset + i] = b1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
@@ -228,7 +307,6 @@ void test(int select_test, int index,
|
||||
|
||||
#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
|
||||
@@ -240,10 +318,15 @@ void test(int select_test, int index,
|
||||
{
|
||||
auto i = c1.find(index);
|
||||
if (i == c1.end()) {
|
||||
#ifdef HAVE_SET_KEY
|
||||
c1[index] = 0;
|
||||
#else
|
||||
c1.insert(index);
|
||||
#endif
|
||||
i = c1.find(index);
|
||||
assert(i != c1.end());
|
||||
}
|
||||
b1 = *i;
|
||||
b1 = CLASS_IT_TO_INT(i);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@@ -254,15 +337,29 @@ void test(int select_test, int index,
|
||||
M_CALL_IT_FIRST(CONT_OPL, it0, c0);
|
||||
it1 = c1.begin();
|
||||
while (!M_CALL_IT_END_P(CONT_OPL, it0)) {
|
||||
#ifdef HAVE_KEY_PTR
|
||||
// Containers are key / value (through ptr)
|
||||
index = *M_CALL_IT_CREF(CONT_OPL, it0)->key_ptr;
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_IT_CREF(CONT_OPL, it0)->value_ptr);
|
||||
#elif defined(HAVE_SET_KEY)
|
||||
// Containers are key / value
|
||||
index = M_CALL_IT_CREF(CONT_OPL, it0)->key;
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, M_CALL_IT_CREF(CONT_OPL, it0)->value);
|
||||
#else
|
||||
// Containers are single key
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_IT_CREF(CONT_OPL, it0));
|
||||
index = b0;
|
||||
#endif
|
||||
#ifndef DONT_HAVE_SEQUENCE_IT
|
||||
// Container are ordered
|
||||
assert(it1 != c1.end());
|
||||
b1 = *it1;
|
||||
b1 = CLASS_IT_TO_INT(it1);
|
||||
it1++;
|
||||
#else
|
||||
it1 = c1.find(b0);
|
||||
// Containers are not ordered.
|
||||
it1 = c1.find(index);
|
||||
assert(it1 != c1.end());
|
||||
b1 = *it1;
|
||||
b1 = CLASS_IT_TO_INT(it1);
|
||||
#endif
|
||||
CMP_BASE(b0, b1);
|
||||
M_CALL_IT_NEXT(CONT_OPL, it0);
|
||||
@@ -281,7 +378,7 @@ void test(int select_test, int index,
|
||||
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);
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, TYPE_IT_TO_INT(M_CALL_IT_REF(CONT_OPL, it0)), b0);
|
||||
*it1 = b1;
|
||||
M_CALL_IT_NEXT(CONT_OPL, it0);
|
||||
it1++;
|
||||
@@ -298,8 +395,8 @@ void test(int select_test, int index,
|
||||
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;
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, TYPE_IT_TO_INT(M_CALL_IT_CREF(CONT_OPL, it0)));
|
||||
b1 = CLASS_IT_TO_INT(it1b);
|
||||
CMP_BASE(b0, b1);
|
||||
M_CALL_IT_PREVIOUS(CONT_OPL, it0);
|
||||
it1b++;
|
||||
@@ -387,13 +484,7 @@ void test(int select_test, int index,
|
||||
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;
|
||||
// 21 is above
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PUSH_FRONT
|
||||
@@ -451,6 +542,7 @@ void test(int select_test, int index,
|
||||
// Needs SPLICE ?
|
||||
|
||||
default:
|
||||
M_STATIC_ASSERT( 28 == MAX_TEST, MLIB_INTERNAL_ERROR, "Constant MAX_TEST is no coherent with the effective number of tests");
|
||||
// Nothing to do
|
||||
break;
|
||||
}
|
||||
@@ -482,6 +574,22 @@ static void init_rand(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int read_int(FILE *f)
|
||||
{
|
||||
int c = 0;
|
||||
while (true) {
|
||||
int n = fscanf(f, " %d", &c);
|
||||
if (n == 1) {
|
||||
return c;
|
||||
}
|
||||
if (feof(f)) {
|
||||
return 0;
|
||||
}
|
||||
// Skip next character
|
||||
c = fgetc(f);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int loop = argc >= 2 ? atoi(argv[1]) : DEFAULT_NUMBER;
|
||||
@@ -496,11 +604,20 @@ int main(int argc, const char *argv[])
|
||||
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);
|
||||
|
||||
if (loop < 0) {
|
||||
/* test input is provided from stdin */
|
||||
while (!feof(stdin)) {
|
||||
int t = read_int(stdin);
|
||||
int s = read_int(stdin);
|
||||
test(t, s, b0, b1, c0, c1);
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
|
||||
+2
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Patrick Pelissier
|
||||
* Copyright (c) 2021-2022, 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:
|
||||
@@ -25,27 +25,18 @@
|
||||
|
||||
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;
|
||||
@@ -55,7 +46,7 @@ void cmp_cont(list_int_t a, std::forward_list<int> b)
|
||||
assert(!list_int_end_p(ita));
|
||||
const int *b0 = list_int_cref(ita);
|
||||
int &b1 = *itb;
|
||||
CMP_BASE(*b0, b1);
|
||||
assert(*b0 == b1);
|
||||
itb++;
|
||||
list_int_next(ita);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022-2022, 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 <queue>
|
||||
#include "m-prioqueue.h"
|
||||
|
||||
// Invert the order of priority for the integers to match the C++ one
|
||||
#define CMP_REVERT(a,b) ((a) > (b) ? -1 : (a) < (b))
|
||||
PRIOQUEUE_DEF(prio_int, int, M_OPEXTEND(M_BASIC_OPLIST, CMP(CMP_REVERT) ))
|
||||
|
||||
// Container OPLIST (disable iterators & reset)
|
||||
#define CONT_OPL \
|
||||
M_OPEXTEND( PRIOQUEUE_OPLIST(prio_int, M_OPL_int()), \
|
||||
RESET(0), \
|
||||
IT_TYPE(0), \
|
||||
IT_FIRST(0), \
|
||||
IT_END(0), \
|
||||
IT_SET(0), \
|
||||
IT_END_P(0), \
|
||||
IT_EQUAL_P(0), \
|
||||
IT_LAST_P(0), \
|
||||
IT_NEXT(0), \
|
||||
IT_CREF(0) )
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::priority_queue<int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
void cmp_cont(const prio_int_t a, const std::priority_queue<int> &b)
|
||||
{
|
||||
std::priority_queue<int> cb = b;
|
||||
prio_int_t ca;
|
||||
prio_int_init_set(ca, a);
|
||||
while (!cb.empty()) {
|
||||
int n;
|
||||
prio_int_pop(&n, ca);
|
||||
assert(n == cb.top());
|
||||
cb.pop();
|
||||
}
|
||||
assert(prio_int_empty_p(ca));
|
||||
prio_int_clear(ca);
|
||||
}
|
||||
|
||||
// There is no reset, so the prioqueue keeps increasing ==> Limit the number of operation.
|
||||
#define DEFAULT_NUMBER 1500
|
||||
|
||||
#define push_back push
|
||||
#define pop_back pop
|
||||
#define back top
|
||||
#include "check-generic.hpp"
|
||||
+2
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Patrick Pelissier
|
||||
* Copyright (c) 2021-2022, 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:
|
||||
@@ -25,27 +25,18 @@
|
||||
|
||||
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;
|
||||
@@ -55,8 +46,7 @@ void cmp_cont(const tree_int_t a, const std::set<int> &b)
|
||||
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);
|
||||
assert(*b0 == b1);
|
||||
itb++;
|
||||
tree_int_next(ita);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, 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_map>
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_DEF2(dict_int, int, int)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL DICT_OPLIST(dict_int, M_OPL_int(), M_OPL_int() )
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::unordered_map<int,int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
// Get the value from the iterator
|
||||
#define CLASS_IT_TO_INT(it) (it)->second
|
||||
#define TYPE_IT_TO_INT(it) (it)->value
|
||||
|
||||
void cmp_cont(const dict_int_t a, const std::unordered_map<int,int> &b)
|
||||
{
|
||||
size_t n = 0;
|
||||
auto itb = b.begin();
|
||||
while (itb != b.end()) {
|
||||
const int *b0 = dict_int_get(a, itb->first);
|
||||
assert(b0 != nullptr);
|
||||
assert(*b0 == itb->second);
|
||||
itb++;
|
||||
n++;
|
||||
}
|
||||
assert(dict_int_size(a) == n);
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 1000000
|
||||
|
||||
// Use find to perform GET_KEY for C++
|
||||
#define HAVE_GET_KEY_THROUGH_FIND
|
||||
// Container are nor ordered
|
||||
#define DONT_HAVE_SEQUENCE_IT
|
||||
// associative array container
|
||||
#define HAVE_SET_KEY
|
||||
|
||||
#define push_back insert
|
||||
#include "check-generic.hpp"
|
||||
+2
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Patrick Pelissier
|
||||
* Copyright (c) 2021-2022, 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:
|
||||
@@ -25,27 +25,18 @@
|
||||
|
||||
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;
|
||||
@@ -54,7 +45,7 @@ void cmp_cont(const dict_int_t a, const std::unordered_set<int> &b)
|
||||
const int &b1 = *itb;
|
||||
const int *b0 = dict_int_get(a, b1);
|
||||
assert(b0 != nullptr);
|
||||
CMP_BASE(*b0, b1);
|
||||
assert(*b0 == b1);
|
||||
itb++;
|
||||
n++;
|
||||
}
|
||||
|
||||
+4
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -101,6 +101,9 @@
|
||||
#undef M_ASSIGN_CAST
|
||||
#undef M_CHECK_DEFAULT_TYPE
|
||||
#undef M_CHECK_SAME
|
||||
#undef M_TR33_NODE_CONTRACT
|
||||
#undef M_TR33_CONTRACT
|
||||
#undef M_TR33_IT_CONTRACT
|
||||
#else
|
||||
/* For normal builds, empty macros which does nothing */
|
||||
#define START_COVERAGE
|
||||
|
||||
+18
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -64,14 +64,14 @@ BPTREE_DEF(bptree2, 5, bptree_t, BPTREE_OPLIST(bptree, DEFAULT_OPLIST))
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF2(bptree, 4, int, int)
|
||||
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
|
||||
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, DEFAULT_OPLIST, M_BASIC_OPLIST), int, M_BASIC_OPLIST)
|
||||
|
||||
#elif TEST == 6
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF2(bptree, 4, int, int)
|
||||
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, M_DEFAULT_OPLIST, DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
|
||||
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, M_BASIC_OPLIST, DEFAULT_OPLIST), int, M_BASIC_OPLIST)
|
||||
|
||||
#elif TEST == 7
|
||||
|
||||
@@ -86,7 +86,7 @@ BUFFER_DEF(buffer2, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer, DEFAULT_OPL
|
||||
#include "m-concurrent.h"
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
CONCURRENT_DEF(array2, array_t, ARRAY_OPLIST(array, M_DEFAULT_OPLIST))
|
||||
CONCURRENT_DEF(array2, array_t, ARRAY_OPLIST(array, M_BASIC_OPLIST))
|
||||
ARRAY_DEF(array3, array2_t, CONCURRENT_OPLIST(array2, ARRAY_OPLIST(array, DEFAULT_OPLIST)))
|
||||
|
||||
#elif TEST == 9
|
||||
@@ -94,14 +94,14 @@ ARRAY_DEF(array3, array2_t, CONCURRENT_OPLIST(array2, ARRAY_OPLIST(array, DEFAUL
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_DEF2(dict, int, int)
|
||||
DICT_DEF2(dict2, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict, DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
|
||||
DICT_DEF2(dict2, int, M_BASIC_OPLIST, dict_t, DICT_OPLIST(dict, DEFAULT_OPLIST, M_BASIC_OPLIST) )
|
||||
|
||||
#elif TEST == 10
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_DEF2(dict, int, int)
|
||||
DICT_DEF2(dict2, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict, M_DEFAULT_OPLIST, DEFAULT_OPLIST) )
|
||||
DICT_DEF2(dict2, int, M_BASIC_OPLIST, dict_t, DICT_OPLIST(dict, M_BASIC_OPLIST, DEFAULT_OPLIST) )
|
||||
|
||||
#elif TEST == 11
|
||||
|
||||
@@ -140,64 +140,64 @@ CONCURRENT_DEF(array, tmpstr_t, ISHARED_PTR_OPLIST(tmpstr, X()))
|
||||
#include "m-prioqueue.h"
|
||||
|
||||
PRIOQUEUE_DEF(prioqueue, int)
|
||||
PRIOQUEUE_DEF(prioqueue2, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue, M_DEFAULT_OPLIST()))
|
||||
PRIOQUEUE_DEF(prioqueue2, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue, M_BASIC_OPLIST()))
|
||||
|
||||
#elif TEST == 15
|
||||
|
||||
#include "m-rbtree.h"
|
||||
|
||||
RBTREE_DEF(rbtree, int)
|
||||
RBTREE_DEF(rbtree2, rbtree_t, RBTREE_OPLIST(rbtree, M_DEFAULT_OPLIST2))
|
||||
RBTREE_DEF(rbtree2, rbtree_t, RBTREE_OPLIST(rbtree, M_BASIC_OPLIST2))
|
||||
|
||||
#elif TEST == 16
|
||||
|
||||
#include "m-shared.h"
|
||||
|
||||
SHARED_PTR_DEF(shared, int)
|
||||
SHARED_PTR_DEF(shared2, shared_t, SHARED_PTR_OPLIST(shared, M_DEFAULT_OPLISTop))
|
||||
SHARED_PTR_DEF(shared2, shared_t, SHARED_PTR_OPLIST(shared, M_BASIC_OPLISTop))
|
||||
|
||||
#elif TEST == 17
|
||||
|
||||
#include "m-snapshot.h"
|
||||
|
||||
SNAPSHOT_SPSC_DEF(shared, int)
|
||||
SNAPSHOT_SPSC_DEF(shared2, shared_t, SNAPSHOT_OPLIST(shared, M_DEFAULT_OPLIST x))
|
||||
SNAPSHOT_SPSC_DEF(shared2, shared_t, SNAPSHOT_OPLIST(shared, M_BASIC_OPLIST x))
|
||||
|
||||
#elif TEST == 18
|
||||
|
||||
#include "m-tuple.h"
|
||||
|
||||
TUPLE_DEF2(aggregate, (x, int), (z, float))
|
||||
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, DEFAULT_OPLIST, M_DEFAULT_OPLIST)))
|
||||
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, DEFAULT_OPLIST, M_BASIC_OPLIST)))
|
||||
|
||||
#elif TEST == 19
|
||||
|
||||
#include "m-tuple.h"
|
||||
|
||||
TUPLE_DEF2(aggregate, (x, int), (z, float))
|
||||
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST() )))
|
||||
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST() )))
|
||||
|
||||
#elif TEST == 20
|
||||
|
||||
#include "m-variant.h"
|
||||
|
||||
VARIANT_DEF2(aggregate, (x, int), (z, float))
|
||||
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, DEFAULT_OPLIST, M_DEFAULT_OPLIST)))
|
||||
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, DEFAULT_OPLIST, M_BASIC_OPLIST)))
|
||||
|
||||
#elif TEST == 21
|
||||
|
||||
#include "m-variant.h"
|
||||
|
||||
VARIANT_DEF2(aggregate, (x, int), (z, float))
|
||||
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, DEFAULT_OPLIST)))
|
||||
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, M_BASIC_OPLIST, DEFAULT_OPLIST)))
|
||||
|
||||
#elif TEST == 22
|
||||
|
||||
#include "m-funcobj.h"
|
||||
|
||||
FUNC_OBJ_ITF_DEF(itf, int, int)
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_DEFAULT_OPLIST), (b, int, M_DEFAULT_OPLIST))
|
||||
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, M_DEFAULT_OPLIST, DEFAULT_OPLIST)
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_BASIC_OPLIST), (b, int, M_BASIC_OPLIST))
|
||||
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, M_BASIC_OPLIST, DEFAULT_OPLIST)
|
||||
|
||||
int f(void) {
|
||||
int r;
|
||||
@@ -211,8 +211,8 @@ int f(void) {
|
||||
#include "m-funcobj.h"
|
||||
|
||||
FUNC_OBJ_ITF_DEF(itf, int, int)
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_DEFAULT_OPLIST), (b, int, M_DEFAULT_OPLIST))
|
||||
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_BASIC_OPLIST), (b, int, M_BASIC_OPLIST))
|
||||
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, DEFAULT_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
int f(void) {
|
||||
int r;
|
||||
|
||||
+26
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
ARRAY_DEF(array2, int)
|
||||
ARRAY_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
|
||||
ARRAY_DEF(array3, array_t, ARRAY_OPLIST(array2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 2
|
||||
|
||||
@@ -48,7 +48,7 @@ ARRAY_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
|
||||
|
||||
LIST_DEF(list, int)
|
||||
LIST_DEF(list2, int)
|
||||
LIST_DEF(list3, list_t, LIST_OPLIST(list2, M_DEFAULT_OPLIST))
|
||||
LIST_DEF(list3, list_t, LIST_OPLIST(list2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 3
|
||||
|
||||
@@ -56,7 +56,7 @@ LIST_DEF(list3, list_t, LIST_OPLIST(list2, M_DEFAULT_OPLIST))
|
||||
|
||||
DEQUE_DEF(deque, int)
|
||||
DEQUE_DEF(deque2, int)
|
||||
DEQUE_DEF(deque3, deque_t, DEQUE_OPLIST(deque2, M_DEFAULT_OPLIST))
|
||||
DEQUE_DEF(deque3, deque_t, DEQUE_OPLIST(deque2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 4
|
||||
|
||||
@@ -64,7 +64,7 @@ DEQUE_DEF(deque3, deque_t, DEQUE_OPLIST(deque2, M_DEFAULT_OPLIST))
|
||||
|
||||
BPTREE_DEF(bptree, 4, int)
|
||||
BPTREE_DEF(bptree2, 4, int)
|
||||
BPTREE_DEF(bptree3, 5, bptree_t, BPTREE_OPLIST(bptree2, M_DEFAULT_OPLIST))
|
||||
BPTREE_DEF(bptree3, 5, bptree_t, BPTREE_OPLIST(bptree2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 5
|
||||
|
||||
@@ -72,7 +72,7 @@ BPTREE_DEF(bptree3, 5, bptree_t, BPTREE_OPLIST(bptree2, M_DEFAULT_OPLIST))
|
||||
|
||||
BPTREE_DEF2(bptree, 4, int, int)
|
||||
BPTREE_DEF2(bptree2, 4, int, int)
|
||||
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
|
||||
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_BASIC_OPLIST, M_BASIC_OPLIST), int, M_BASIC_OPLIST)
|
||||
|
||||
#elif TEST == 6
|
||||
|
||||
@@ -80,7 +80,7 @@ BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DE
|
||||
|
||||
BPTREE_DEF2(bptree, 4, int, int)
|
||||
BPTREE_DEF2(bptree2, 4, int, int)
|
||||
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
|
||||
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_BASIC_OPLIST, M_BASIC_OPLIST), int, M_BASIC_OPLIST)
|
||||
|
||||
#elif TEST == 7
|
||||
|
||||
@@ -88,7 +88,7 @@ BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DE
|
||||
|
||||
BUFFER_DEF(buffer, int, 4, BUFFER_THREAD_UNSAFE)
|
||||
BUFFER_DEF(buffer2, int, 4, BUFFER_THREAD_UNSAFE)
|
||||
BUFFER_DEF(buffer3, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer2, M_DEFAULT_OPLIST))
|
||||
BUFFER_DEF(buffer3, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 8
|
||||
|
||||
@@ -97,7 +97,7 @@ BUFFER_DEF(buffer3, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer2, M_DEFAULT_
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
ARRAY_DEF(array2, int)
|
||||
CONCURRENT_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
|
||||
CONCURRENT_DEF(array3, array_t, ARRAY_OPLIST(array2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 9
|
||||
|
||||
@@ -105,7 +105,7 @@ CONCURRENT_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
|
||||
|
||||
DICT_DEF2(dict, int, int)
|
||||
DICT_DEF2(dict2, int, int)
|
||||
DICT_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
|
||||
DICT_DEF2(dict3, int, M_BASIC_OPLIST, dict_t, DICT_OPLIST(dict2, M_BASIC_OPLIST, M_BASIC_OPLIST) )
|
||||
|
||||
#elif TEST == 10
|
||||
|
||||
@@ -113,7 +113,7 @@ DICT_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_DEFAULT_OPL
|
||||
|
||||
DICT_STOREHASH_DEF2(dict, int, int)
|
||||
DICT_STOREHASH_DEF2(dict2, int, int)
|
||||
DICT_STOREHASH_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
|
||||
DICT_STOREHASH_DEF2(dict3, int, M_BASIC_OPLIST, dict_t, DICT_OPLIST(dict2, M_BASIC_OPLIST, M_BASIC_OPLIST) )
|
||||
|
||||
#elif TEST == 11
|
||||
|
||||
@@ -122,7 +122,7 @@ DICT_STOREHASH_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_D
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
ARRAY_DEF(array2, int)
|
||||
DICT_SET_DEF(dict, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST) )
|
||||
DICT_SET_DEF(dict, array_t, ARRAY_OPLIST(array2, M_BASIC_OPLIST) )
|
||||
|
||||
#elif TEST == 12
|
||||
|
||||
@@ -152,7 +152,7 @@ ISHARED_PTR_DEF(tmpstr, tmp_str_t, (TYPE(struct toto), CLEAR(M_NOTHING_DEFAULT))
|
||||
|
||||
PRIOQUEUE_DEF(prioqueue, int)
|
||||
PRIOQUEUE_DEF(prioqueue2, int)
|
||||
PRIOQUEUE_DEF(prioqueue3, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue2, M_DEFAULT_OPLIST ))
|
||||
PRIOQUEUE_DEF(prioqueue3, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue2, M_BASIC_OPLIST ))
|
||||
|
||||
#elif TEST == 15
|
||||
|
||||
@@ -160,7 +160,7 @@ PRIOQUEUE_DEF(prioqueue3, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue2, M_DEFAULT_OP
|
||||
|
||||
RBTREE_DEF(rbtree, int)
|
||||
RBTREE_DEF(rbtree2, int)
|
||||
RBTREE_DEF(rbtree3, rbtree_t, RBTREE_OPLIST(rbtree2, M_DEFAULT_OPLIST))
|
||||
RBTREE_DEF(rbtree3, rbtree_t, RBTREE_OPLIST(rbtree2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 16
|
||||
|
||||
@@ -168,7 +168,7 @@ RBTREE_DEF(rbtree3, rbtree_t, RBTREE_OPLIST(rbtree2, M_DEFAULT_OPLIST))
|
||||
|
||||
SHARED_PTR_DEF(shared, int)
|
||||
SHARED_PTR_DEF(shared2, int)
|
||||
SHARED_PTR_DEF(shared3, shared_t, SHARED_PTR_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
SHARED_PTR_DEF(shared3, shared_t, SHARED_PTR_OPLIST(shared2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 17
|
||||
|
||||
@@ -176,7 +176,7 @@ SHARED_PTR_DEF(shared3, shared_t, SHARED_PTR_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
|
||||
SNAPSHOT_SPSC_DEF(shared, int)
|
||||
SNAPSHOT_SPSC_DEF(shared2, int)
|
||||
SNAPSHOT_SPSC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
SNAPSHOT_SPSC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 18
|
||||
|
||||
@@ -184,7 +184,7 @@ SNAPSHOT_SPSC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
|
||||
SNAPSHOT_SPMC_DEF(shared, int)
|
||||
SNAPSHOT_SPMC_DEF(shared2, int)
|
||||
SNAPSHOT_SPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
SNAPSHOT_SPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 19
|
||||
|
||||
@@ -192,7 +192,7 @@ SNAPSHOT_SPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
|
||||
SNAPSHOT_MPMC_DEF(shared, int)
|
||||
SNAPSHOT_MPMC_DEF(shared2, int)
|
||||
SNAPSHOT_MPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
SNAPSHOT_MPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 20
|
||||
|
||||
@@ -201,8 +201,8 @@ SNAPSHOT_MPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
TUPLE_DEF2(aggregate, (x, int), (z, float))
|
||||
TUPLE_DEF2(aggregate2, (x, int), (z, float))
|
||||
TUPLE_DEF2(struct2,
|
||||
(a, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
|
||||
(b, aggregate_t, TUPLE_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
(a, aggregate_t, TUPLE_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST)),
|
||||
(b, aggregate_t, TUPLE_OPLIST(aggregate2, M_BASIC_OPLIST, M_BASIC_OPLIST))
|
||||
)
|
||||
|
||||
#elif TEST == 21
|
||||
@@ -212,8 +212,8 @@ TUPLE_DEF2(struct2,
|
||||
TUPLE_DEF2(aggregate, (x, int), (z, float))
|
||||
TUPLE_DEF2(aggregate2, (x, int), (z, float))
|
||||
TUPLE_DEF2(struct2,
|
||||
(a, aggregate_t, TUPLE_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
|
||||
(b, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
(a, aggregate_t, TUPLE_OPLIST(aggregate2, M_BASIC_OPLIST, M_BASIC_OPLIST)),
|
||||
(b, aggregate_t, TUPLE_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST))
|
||||
)
|
||||
|
||||
#elif TEST == 22
|
||||
@@ -223,8 +223,8 @@ TUPLE_DEF2(struct2,
|
||||
VARIANT_DEF2(aggregate, (x, int), (z, float))
|
||||
VARIANT_DEF2(aggregate2, (x, int), (z, float))
|
||||
VARIANT_DEF2(struct2,
|
||||
(a, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
|
||||
(b, aggregate_t, VARIANT_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
(a, aggregate_t, VARIANT_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST)),
|
||||
(b, aggregate_t, VARIANT_OPLIST(aggregate2, M_BASIC_OPLIST, M_BASIC_OPLIST))
|
||||
)
|
||||
|
||||
#elif TEST == 23
|
||||
@@ -234,8 +234,8 @@ VARIANT_DEF2(struct2,
|
||||
VARIANT_DEF2(aggregate, (x, int), (z, float))
|
||||
VARIANT_DEF2(aggregate2, (x, int), (z, float))
|
||||
VARIANT_DEF2(struct2,
|
||||
(a, aggregate_t, VARIANT_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
|
||||
(b, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
(a, aggregate_t, VARIANT_OPLIST(aggregate2, M_BASIC_OPLIST, M_BASIC_OPLIST)),
|
||||
(b, aggregate_t, VARIANT_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST))
|
||||
)
|
||||
|
||||
#elif TEST == 24
|
||||
|
||||
+23
-23
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -80,7 +80,7 @@ ILIST_DEF(tmpstr, tmp_str_t, DEFAULT_OPLIST)
|
||||
#include "m-string.h"
|
||||
void f(void)
|
||||
{
|
||||
M_LET(x, M_STRING_OPLIST) {
|
||||
M_LET(x, M_M_STRING_OPLIST) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ void f(void)
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
ALGO_DEF(array, M_ARRAY_OPLIST(array))
|
||||
ALGO_DEF(array, M_M_ARRAY_OPLIST(array))
|
||||
|
||||
#elif TEST == 12
|
||||
|
||||
@@ -123,13 +123,13 @@ ALGO_DEF(array, (OPLIST(array)))
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF2(tree, 4, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
|
||||
BPTREE_DEF2(tree, 4, int, M_BASIC_OPLIST, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 14
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF2(tree, 4, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
BPTREE_DEF2(tree, 4, int, DEFAULT_OPLIST, int, M_BASIC_OPLIST)
|
||||
|
||||
#elif TEST == 15
|
||||
|
||||
@@ -141,7 +141,7 @@ BPTREE_DEF(tree, 4, int, DEFAULT_OPLIST)
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_MULTI_DEF2(tree, 4, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
BPTREE_MULTI_DEF2(tree, 4, int, DEFAULT_OPLIST, int, M_BASIC_OPLIST)
|
||||
|
||||
#elif TEST == 17
|
||||
|
||||
@@ -173,7 +173,7 @@ QUEUE_SPSC_DEF(buffer, int, BUFFER_QUEUE, DEFAULT_OPLIST)
|
||||
#include "m-concurrent.h"
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
CONCURRENT_DEF(lock_array, array_t, M_ARRAY_OPLIST(array))
|
||||
CONCURRENT_DEF(lock_array, array_t, M_M_ARRAY_OPLIST(array))
|
||||
|
||||
#elif TEST == 22
|
||||
|
||||
@@ -187,37 +187,37 @@ CONCURRENT_RP_DEF(lock_array, array_t, MARRAY_OPLIST(array))
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_DEF2(array, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
|
||||
DICT_DEF2(array, int, M_BASIC_OPLIST, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 24
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_DEF2(array, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
DICT_DEF2(array, int, DEFAULT_OPLIST, int, M_BASIC_OPLIST)
|
||||
|
||||
#elif TEST == 25
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_STOREHASH_DEF2(array, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
DICT_STOREHASH_DEF2(array, int, DEFAULT_OPLIST, int, M_BASIC_OPLIST)
|
||||
|
||||
#elif TEST == 26
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_STOREHASH_DEF2(array, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
|
||||
DICT_STOREHASH_DEF2(array, int, M_BASIC_OPLIST, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 27
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_OA_DEF2(array, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
DICT_OA_DEF2(array, int, DEFAULT_OPLIST, int, M_BASIC_OPLIST)
|
||||
|
||||
#elif TEST == 28
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_OA_DEF2(array, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
|
||||
DICT_OA_DEF2(array, int, M_BASIC_OPLIST, int, DEFAULT_OPLIST)
|
||||
|
||||
#elif TEST == 29
|
||||
|
||||
@@ -252,43 +252,43 @@ PRIOQUEUE_DEF(prio, int, DEFAULT_OPLIST)
|
||||
|
||||
#include "m-rbtree.h"
|
||||
|
||||
RBTREE_DEF(tree, int, M_DEFAULT_OPLIST() )
|
||||
RBTREE_DEF(tree, int, M_BASIC_OPLIST() )
|
||||
|
||||
#elif TEST == 34
|
||||
|
||||
#include "m-shared.h"
|
||||
|
||||
SHARED_PTR_DEF(shared, int, M_DEFAULT_OPLIST2 )
|
||||
SHARED_PTR_DEF(shared, int, M_BASIC_OPLIST2 )
|
||||
|
||||
#elif TEST == 35
|
||||
|
||||
#include "m-shared.h"
|
||||
|
||||
SHARED_RESOURCE_DEF(shared, int, M_DEFAULT_OPLIST3 )
|
||||
SHARED_RESOURCE_DEF(shared, int, M_BASIC_OPLIST3 )
|
||||
|
||||
#elif TEST == 36
|
||||
|
||||
#include "m-snapshot.h"
|
||||
|
||||
SNAPSHOT_SPSC_DEF(snap, int, M_DEFAULT_OPLIST2 )
|
||||
SNAPSHOT_SPSC_DEF(snap, int, M_BASIC_OPLIST2 )
|
||||
|
||||
#elif TEST == 37
|
||||
|
||||
#include "m-snapshot.h"
|
||||
|
||||
SNAPSHOT_SPMC_DEF(snap, int, M_DEFAULT_OPLIST2 )
|
||||
SNAPSHOT_SPMC_DEF(snap, int, M_BASIC_OPLIST2 )
|
||||
|
||||
#elif TEST == 38
|
||||
|
||||
#include "m-snapshot.h"
|
||||
|
||||
SNAPSHOT_MPMC_DEF(snap, int, M_DEFAULT_OPLIST8 )
|
||||
SNAPSHOT_MPMC_DEF(snap, int, M_BASIC_OPLIST8 )
|
||||
|
||||
#elif TEST == 39
|
||||
|
||||
#include "m-tuple.h"
|
||||
|
||||
TUPLE_DEF2(agregate, (x, int, M_DEFAULT_OPLIST), (y, float, DEFAULT_OPLIST) )
|
||||
TUPLE_DEF2(agregate, (x, int, M_BASIC_OPLIST), (y, float, DEFAULT_OPLIST) )
|
||||
|
||||
#elif TEST == 40
|
||||
|
||||
@@ -300,7 +300,7 @@ TUPLE_DEF2(agregate, (x, int, DEFAULT_OPLIST), (y, float) )
|
||||
|
||||
#include "m-variant.h"
|
||||
|
||||
VARIANT_DEF2(agregate, (x, int, M_DEFAULT_OPLIST), (y, float, DEFAULT_OPLIST) )
|
||||
VARIANT_DEF2(agregate, (x, int, M_BASIC_OPLIST), (y, float, DEFAULT_OPLIST) )
|
||||
|
||||
#elif TEST == 42
|
||||
|
||||
@@ -314,7 +314,7 @@ VARIANT_DEF2(agregate, (x, int, DEFAULT_OPLIST), (y, float) )
|
||||
|
||||
FUNC_OBJ_ITF_DEF(itf, int, int)
|
||||
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, DEFAULT_OPLIST), (b, int, M_DEFAULT_OPLIST))
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, DEFAULT_OPLIST), (b, int, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 44
|
||||
|
||||
@@ -322,7 +322,7 @@ FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, DEFA
|
||||
|
||||
FUNC_OBJ_ITF_DEF(itf, int, int)
|
||||
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int), (b, int, M_DEFAULT_OPLIST() ))
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int), (b, int, M_BASIC_OPLIST() ))
|
||||
|
||||
|
||||
#else
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
| M-ALGO | 100.00% of 1160 |
|
||||
| M-ARRAY | 98.24% of 908 |
|
||||
| M-BITSET | 98.31% of 413 |
|
||||
| M-BBPTREE | 99.60% of 998 |
|
||||
| M-BUFFER | 98.86% of 877 |
|
||||
| M-CONCURRENT | 100.00% of 102 |
|
||||
| M-CORE | 100.00% of 268 |
|
||||
| M-DEQUE | 99.47% of 943 |
|
||||
| M-DICT | 93.00% of 1528 |
|
||||
| M-FUNCOBJ | 100.00% of 108 |
|
||||
| M-GENINT | 97.40% of 77 |
|
||||
| M-I-LIST | 98.10% of 474 |
|
||||
| M-I-SHARED | 100.00% of 112 |
|
||||
| M-LIST | 99.12% of 1368 |
|
||||
| M-MEMPOOL | 97.98% of 99 |
|
||||
| M-MUTEX | 100.00% of 19 |
|
||||
| M-PRIOQUEUE | 99.17% of 600 |
|
||||
| M-RBTREE | 99.04% of 937 |
|
||||
| M-SERIAL-BIN | 70.87% of 254 |
|
||||
| M-SERIAL-JSON | 100.00% of 494 |
|
||||
| M-SHARED | 99.07% of 324 |
|
||||
| M-SNAPSHOT | 99.54% of 439 |
|
||||
| M-STRING | 99.40% of 831 |
|
||||
| M-TREE | 98.46% of 1232 |
|
||||
| M-TUPLE | 100.00% of 186 |
|
||||
| M-VARIANT | 99.25% of 266 |
|
||||
| M-WORKER | 98.73% of 79 |
|
||||
+13
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -48,12 +48,12 @@ DEQUE_DEF(deque_obj, testobj_t, TESTOBJ_CMP_OPLIST)
|
||||
DICT_DEF2(dict_obj, string_t, STRING_OPLIST, testobj_t, TESTOBJ_OPLIST)
|
||||
LIST_DUAL_PUSH_DEF(dlist_int, int)
|
||||
DICT_DEF2(dict_int, string_t, int)
|
||||
#define M_OPL_dict_int_t() DICT_OPLIST(dict_int, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_dict_int_t() DICT_OPLIST(dict_int, STRING_OPLIST, M_BASIC_OPLIST)
|
||||
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)
|
||||
#define M_OPL_person_t() TUPLE_OPLIST(person, M_BASIC_OPLIST, STRING_OPLIST)
|
||||
ARRAY_DEF(array_person, person_t)
|
||||
#define M_OPL_array_person_t() ARRAY_OPLIST(array_person, M_OPL_person_t() )
|
||||
|
||||
@@ -225,32 +225,32 @@ static void test_list(void)
|
||||
|
||||
list_int_clear(l);
|
||||
|
||||
M_LET( (l1, 1, 3, 5), (l2, 1, 2, 4), (l3, 1, 2, 3, 4, 5), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
|
||||
M_LET( (l1, 1, 3, 5), (l2, 1, 2, 4), (l3, 1, 2, 3, 4, 5), LIST_OPLIST(list_int, M_BASIC_OPLIST)) {
|
||||
algo_list_sort_union(l1, l2);
|
||||
assert(list_int_equal_p (l1, l3));
|
||||
}
|
||||
|
||||
M_LET( (l1, 1, 30, 31), (l2, 2, 4, 31, 32), (l3, 1, 2, 4, 30, 31, 32), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
|
||||
M_LET( (l1, 1, 30, 31), (l2, 2, 4, 31, 32), (l3, 1, 2, 4, 30, 31, 32), LIST_OPLIST(list_int, M_BASIC_OPLIST)) {
|
||||
algo_list_sort_union(l1, l2);
|
||||
assert(list_int_equal_p (l1, l3));
|
||||
}
|
||||
|
||||
M_LET( (l1, 4, 28, 29, 30, 34), (l2, 1, 3, 31, 32, 33), (l3, 1, 3, 4, 28, 29, 30, 31, 32, 33, 34), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
|
||||
M_LET( (l1, 4, 28, 29, 30, 34), (l2, 1, 3, 31, 32, 33), (l3, 1, 3, 4, 28, 29, 30, 31, 32, 33, 34), LIST_OPLIST(list_int, M_BASIC_OPLIST)) {
|
||||
algo_list_sort_union(l1, l2);
|
||||
assert(list_int_equal_p (l1, l3));
|
||||
}
|
||||
|
||||
M_LET( (l1, 1, 4, 28, 29, 31, 34), (l2, 1, 3, 31, 32, 33), (l3, 1, 31), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
|
||||
M_LET( (l1, 1, 4, 28, 29, 31, 34), (l2, 1, 3, 31, 32, 33), (l3, 1, 31), LIST_OPLIST(list_int, M_BASIC_OPLIST)) {
|
||||
algo_list_sort_intersect(l1, l2);
|
||||
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_BASIC_OPLIST)) {
|
||||
algo_list_sort_intersect(l1, l2);
|
||||
assert(list_int_equal_p (l1, l3));
|
||||
}
|
||||
|
||||
M_LET( (l1, 1, 4, 28, 29, 31, 34), (l2, 3, 32, 33), l3, LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
|
||||
M_LET( (l1, 1, 4, 28, 29, 31, 34), (l2, 3, 32, 33), l3, LIST_OPLIST(list_int, M_BASIC_OPLIST)) {
|
||||
algo_list_sort_intersect(l1, l2);
|
||||
assert(list_int_equal_p (l1, l3));
|
||||
}
|
||||
@@ -646,25 +646,25 @@ FUNC_OBJ_INS_DEF(fo_test, algo_array_fo_test_obj,
|
||||
(a), {
|
||||
return a == self->x;
|
||||
}, (x, int))
|
||||
#define M_OPL_fo_test_t() FUNC_OBJ_INS_OPLIST(fo_test, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_fo_test_t() FUNC_OBJ_INS_OPLIST(fo_test, M_BASIC_OPLIST)
|
||||
|
||||
FUNC_OBJ_INS_DEF(fo_eq, algo_array_fo_eq_obj,
|
||||
(a, b), {
|
||||
return a == b && self->x != a;
|
||||
}, (x, int))
|
||||
#define M_OPL_fo_eq_t() FUNC_OBJ_INS_OPLIST(fo_eq, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_fo_eq_t() FUNC_OBJ_INS_OPLIST(fo_eq, M_BASIC_OPLIST)
|
||||
|
||||
FUNC_OBJ_INS_DEF(fo_cmp, algo_array_fo_cmp_obj,
|
||||
(a, b), {
|
||||
return a < b ? -self->x : a > b ? self->x : 0;
|
||||
}, (x, int))
|
||||
#define M_OPL_fo_cmp_t() FUNC_OBJ_INS_OPLIST(fo_cmp, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_fo_cmp_t() FUNC_OBJ_INS_OPLIST(fo_cmp, M_BASIC_OPLIST)
|
||||
|
||||
FUNC_OBJ_INS_DEF(fol_cmp, algo_list_fo_cmp_obj,
|
||||
(a, b), {
|
||||
return a < b ? -self->x : a > b ? self->x : 0;
|
||||
}, (x, int))
|
||||
#define M_OPL_fol_cmp_t() FUNC_OBJ_INS_OPLIST(fol_cmp, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_fol_cmp_t() FUNC_OBJ_INS_OPLIST(fol_cmp, M_BASIC_OPLIST)
|
||||
|
||||
static void test_fo(void)
|
||||
{
|
||||
|
||||
+140
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <stdio.h>
|
||||
#include "test-obj.h"
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
#include "coverage.h"
|
||||
|
||||
START_COVERAGE
|
||||
@@ -37,9 +38,9 @@ ARRAY_DEF(array_min2_z, testobj_t, (INIT(testobj_init), CLEAR(testobj_clear)))
|
||||
ARRAY_DEF(array_min3_z, testobj_t, (CLEAR(testobj_clear)))
|
||||
|
||||
ARRAY_DEF(array_ulong, uint64_t)
|
||||
|
||||
ARRAY_DEF(array_string, string_t)
|
||||
ARRAY_DEF_AS(array_double, ArrayDouble, ArrayDoubleIt, double)
|
||||
#define M_OPL_ArrayDouble() ARRAY_OPLIST(array_double, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_ArrayDouble() ARRAY_OPLIST(array_double, M_BASIC_OPLIST)
|
||||
|
||||
ArrayDouble g_array = ARRAY_INIT_VALUE();
|
||||
|
||||
@@ -279,11 +280,61 @@ static void test_mpz(void)
|
||||
// NOTE: Not the same order than list...
|
||||
}
|
||||
|
||||
testobj_clear (z);
|
||||
array_mpz_clear(array2);
|
||||
|
||||
array_mpz_reset(array1);
|
||||
/* Test of the emplace functions.
|
||||
* 3 functions have been generated for testobj:
|
||||
* one from unsigned int (suffix _ui)
|
||||
* one from C string (suffix _str)
|
||||
* one from testobj_t itself (no suffix)
|
||||
*/
|
||||
array_mpz_emplace_back_ui(array1, 42);
|
||||
assert(testobj_cmp_ui(*array_mpz_back(array1), 42) == 0);
|
||||
array_mpz_emplace_back_ui(array1, 426);
|
||||
assert(testobj_cmp_ui(*array_mpz_back(array1), 426) == 0);
|
||||
array_mpz_emplace_back_str(array1, "458");
|
||||
assert(testobj_cmp_ui(*array_mpz_back(array1), 458) == 0);
|
||||
testobj_set_ui(z, 789);
|
||||
array_mpz_emplace_back(array1, z);
|
||||
assert(testobj_cmp_ui(*array_mpz_back(array1), 789) == 0);
|
||||
|
||||
testobj_clear (z);
|
||||
array_mpz_clear(array1);
|
||||
}
|
||||
|
||||
static void test_str(void)
|
||||
{
|
||||
array_string_t a;
|
||||
array_string_init(a);
|
||||
|
||||
// Test of emplace with const char * ==> string_t
|
||||
array_string_emplace_back(a, "Hello");
|
||||
assert(string_equal_str_p(*array_string_back(a), "Hello"));
|
||||
|
||||
array_string_emplace_back(a, "world");
|
||||
assert(string_equal_str_p(*array_string_back(a), "world"));
|
||||
|
||||
array_string_emplace_back(a, "How");
|
||||
assert(string_equal_str_p(*array_string_back(a), "How"));
|
||||
|
||||
array_string_emplace_back(a, "are");
|
||||
assert(string_equal_str_p(*array_string_back(a), "are"));
|
||||
|
||||
array_string_emplace_back(a, "you");
|
||||
assert(string_equal_str_p(*array_string_back(a), "you"));
|
||||
|
||||
// Test stable sort with string_t
|
||||
array_string_special_stable_sort(a);
|
||||
|
||||
// Test INIT_WITH of array of string_t wihtin M_LET
|
||||
M_LET( (b, ("Hello"), ("How"), ("are"), ("world"), ("you")), ARRAY_OPLIST(array_string, STRING_OPLIST)){
|
||||
assert( array_string_equal_p(a, b));
|
||||
}
|
||||
|
||||
array_string_clear(a);
|
||||
}
|
||||
|
||||
static void test_d(void)
|
||||
{
|
||||
array_uint_t a1, a2;
|
||||
@@ -393,11 +444,96 @@ static void test_double(void)
|
||||
array_double_clear(g_array);
|
||||
}
|
||||
|
||||
// Test support of M*LIB for C++ class
|
||||
#if defined(__cplusplus)
|
||||
|
||||
/* For this, we need new placement support */
|
||||
#include <new>
|
||||
/* For std::move */
|
||||
#include <utility>
|
||||
|
||||
/* Some Simple Oplist for a C++ class (using new placement feature)
|
||||
Some features may not be always available (like comparison or I/O).
|
||||
It isn't exported, since there is no meaning to support for M*LIB
|
||||
C++ class officialy (use the STL instead!)
|
||||
*/
|
||||
#define M_CLASS_CPP_INIT(opl,x) (new (&(x)) (M_GET_NAME opl))
|
||||
#define M_CLASS_CPP_INIT_SET(opl,x, y) (new (&(x)) M_GET_NAME opl(y))
|
||||
#define M_CLASS_CPP_SET(opl, x, y) ((x) = (y))
|
||||
#define M_CLASS_CPP_CLEAR(opl, x) ((&(x))->~M_GET_NAME opl())
|
||||
#define M_CLASS_CPP_CLEAR2(x) ((&(x))->~opl())
|
||||
#define M_CLASS_CPP_INIT_MOVE(opl,x,y) (new (&(x)) M_GET_NAME opl(std::move(y)), ((&(y))->~M_GET_NAME opl()))
|
||||
#define M_CLASS_CPP_CMP(opl, x, y) ((x) < (y) ? -1 : (y) < (x) ? 1 : 0)
|
||||
#define M_CLASS_CPP_HASH(opl, x) (std::hash(x))
|
||||
#define M_CLASS_OPLIST(_class) \
|
||||
(NAME(_class), \
|
||||
TYPE(_class), \
|
||||
INIT(API_1(M_CLASS_CPP_INIT)), \
|
||||
INIT_SET(API_1(M_CLASS_CPP_INIT_SET)), \
|
||||
SET(API_1(M_CLASS_CPP_SET)), \
|
||||
CLEAR(API_1(M_CLASS_CPP_CLEAR)), \
|
||||
INIT_MOVE(API_1(M_CLASS_CPP_INIT_MOVE)) )
|
||||
|
||||
// Define a basic C++ class
|
||||
class Foo {
|
||||
int *x;
|
||||
public:
|
||||
Foo() { x = new (int); };
|
||||
Foo(int n) { x = new (int) ; *x = n; }
|
||||
Foo(const Foo &y) {x = new (int) ; *x = *y.x;};
|
||||
~Foo() { delete x; }
|
||||
void operator=(const Foo &y) { *x = *y.x; };
|
||||
void operator=(int n) { *x = n; }
|
||||
bool operator<(const Foo &y) const { return *x < *y.x; }
|
||||
bool operator==(int n) const { return *x == n; }
|
||||
};
|
||||
|
||||
// Disable the warning due to using memcpy/memmove with this C++ class
|
||||
#if defined(__GNUC__) && __GNUC__ >= 8
|
||||
_Pragma("GCC diagnostic push")
|
||||
_Pragma("GCC diagnostic ignored \"-Wclass-memaccess\"")
|
||||
#endif
|
||||
|
||||
// Define a M*LIB array of such class
|
||||
ARRAY_DEF_AS(array_foo, array_foo_t, array_foo_it_t, Foo, M_CLASS_OPLIST(Foo))
|
||||
#define M_OPL_array_foo_t() ARRAY_OPLIST(array_foo, M_CLASS_OPLIST(Foo))
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 8
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#endif
|
||||
|
||||
static void test_cplusplus(void)
|
||||
{
|
||||
int n = 100;
|
||||
M_LET(a, array_foo_t) {
|
||||
Foo b;
|
||||
for(int i = 0; i < n; i++) {
|
||||
b = i;
|
||||
array_foo_push_back(a, b);
|
||||
}
|
||||
array_foo_it_t it;
|
||||
int j = 0;
|
||||
for(array_foo_it(it, a); !array_foo_end_p(it); array_foo_next(it)) {
|
||||
assert( *array_foo_cref(it) == j);
|
||||
j++;
|
||||
}
|
||||
assert(j == n);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void test_cplusplus(void)
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_uint();
|
||||
test_mpz();
|
||||
test_d();
|
||||
test_str();
|
||||
test_double();
|
||||
test_cplusplus();
|
||||
exit(0);
|
||||
}
|
||||
+66
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -377,6 +377,70 @@ static void test_clz(void)
|
||||
bitset_set_str(s1, "[10000011100000110010101010110000011111111111111110000001110001110001110001110000]");
|
||||
assert(bitset_popcount(s1) == 40);
|
||||
}
|
||||
|
||||
M_LET(s1, bitset_t) {
|
||||
bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]");
|
||||
assert(bitset_ctz(s1) == 116);
|
||||
bitset_set_str(s1, "[10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]");
|
||||
assert(bitset_ctz(s1) == 0);
|
||||
bitset_set_str(s1, "[01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]");
|
||||
assert(bitset_ctz(s1) == 1);
|
||||
bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]");
|
||||
assert(bitset_ctz(s1) == 115);
|
||||
bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010]");
|
||||
assert(bitset_ctz(s1) == 114);
|
||||
bitset_set_str(s1, "[000001]");
|
||||
assert(bitset_ctz(s1) == 5);
|
||||
bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000001]");
|
||||
assert(bitset_ctz(s1) == 64);
|
||||
bitset_set_str(s1, "[000000000000000000000000000000000000000000000000000000000000000010000]");
|
||||
assert(bitset_ctz(s1) == 64);
|
||||
bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000001]");
|
||||
assert(bitset_ctz(s1) == 63);
|
||||
bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000001000]");
|
||||
assert(bitset_ctz(s1) == 63);
|
||||
bitset_set_str(s1, "[000000000000000000000000000000000000000000000000000000000000000001]");
|
||||
assert(bitset_ctz(s1) == 65);
|
||||
bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000000010000]");
|
||||
assert(bitset_ctz(s1) == 65);
|
||||
bitset_set_str(s1, "[00001000001110000011001010101011000001111111111111111000000111000111000111000111000]");
|
||||
assert(bitset_ctz(s1) == 4);
|
||||
bitset_set_str(s1, "[000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]");
|
||||
assert(bitset_ctz(s1) == 128);
|
||||
bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]");
|
||||
assert(bitset_ctz(s1) == 127);
|
||||
bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]");
|
||||
assert(bitset_ctz(s1) == 129);
|
||||
bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000100000000000000000001]");
|
||||
assert(bitset_ctz(s1) == 128);
|
||||
bitset_set_str(s1, "[000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000010000000000000000001000]");
|
||||
assert(bitset_ctz(s1) == 127);
|
||||
bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000011000000000000000000000000]");
|
||||
assert(bitset_ctz(s1) == 129);
|
||||
}
|
||||
}
|
||||
|
||||
// Detect bug on bitset_resize function in case of increase of size.
|
||||
// the first limb may not be cleared properly in some cases
|
||||
static void test_resize(void)
|
||||
{
|
||||
M_LET(set, bitset_t) {
|
||||
for(size_t i = 1; i < 257; i++) {
|
||||
bitset_resize(set, i);
|
||||
assert( bitset_get(set, i-1) == false);
|
||||
bitset_set_at(set, 0, true);
|
||||
bitset_set_at(set, i-1, true);
|
||||
bitset_reset(set);
|
||||
bitset_resize(set, i);
|
||||
assert( bitset_get(set, 0) == false);
|
||||
assert( bitset_get(set, i-1) == false);
|
||||
bitset_set_at(set, 0, true);
|
||||
bitset_set_at(set, i-1, true);
|
||||
bitset_resize(set, i-1);
|
||||
bitset_resize(set, i);
|
||||
assert( bitset_get(set, i-1) == false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
@@ -387,5 +451,6 @@ int main(void)
|
||||
test_logic();
|
||||
test_let();
|
||||
test_clz();
|
||||
test_resize();
|
||||
exit(0);
|
||||
}
|
||||
+59
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -28,27 +28,28 @@
|
||||
#include "coverage.h"
|
||||
|
||||
START_COVERAGE
|
||||
BPTREE_DEF2(btree, 3, int, M_DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
BPTREE_DEF2(btree, 3, int, M_BASIC_OPLIST, int, M_BASIC_OPLIST)
|
||||
END_COVERAGE
|
||||
|
||||
BPTREE_DEF2(btree_my, 3, testobj_t, TESTOBJ_CMP_OPLIST, testobj_t, TESTOBJ_CMP_OPLIST)
|
||||
BPTREE_DEF2(btree_string, 5, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
|
||||
BPTREE_DEF2(btree_int, 17, int, int)
|
||||
BPTREE_DEF2(btree_mpz, 9, string_t, STRING_OPLIST, testobj_t, TESTOBJ_CMP_OPLIST)
|
||||
|
||||
BPTREE_DEF(btree_intset, 13, int)
|
||||
BPTREE_DEF(btree_myset, 15, testobj_t, TESTOBJ_CMP_OPLIST)
|
||||
|
||||
BPTREE_MULTI_DEF2(multimap, 3, int, M_DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
BPTREE_MULTI_DEF(multiset, 6, int, M_DEFAULT_OPLIST)
|
||||
BPTREE_MULTI_DEF2(multimap, 3, int, M_BASIC_OPLIST, int, M_BASIC_OPLIST)
|
||||
BPTREE_MULTI_DEF(multiset, 6, int, M_BASIC_OPLIST)
|
||||
|
||||
BPTREE_DEF2_AS(MapDouble, MapDouble, MapDoubleIt, MapDoubleItRef, 4, double, double)
|
||||
#define M_OPL_MapDouble() BPTREE_OPLIST2(MapDouble, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_MapDouble() BPTREE_OPLIST2(MapDouble, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
BPTREE_DEF_AS(SetDouble, SetDouble, SetDoubleIt, 7, double)
|
||||
#define M_OPL_SetDouble() BPTREE_OPLIST(SetDouble, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_SetDouble() BPTREE_OPLIST(SetDouble, M_BASIC_OPLIST)
|
||||
BPTREE_MULTI_DEF2_AS(MultiMapDouble, MultiMapDouble, MultiMapDoubleIt, MultiMapDoubleItRef, 8, double, double)
|
||||
#define M_OPL_MultiMapDouble() BPTREE_OPLIST2(MultiMapDouble, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_MultiMapDouble() BPTREE_OPLIST2(MultiMapDouble, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
BPTREE_MULTI_DEF_AS(MultiSetDouble, MultiSetDouble, MultiSetDoubleIt, 9, double)
|
||||
#define M_OPL_MultiSetDouble() BPTREE_OPLIST(MultiSetDouble, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_MultiSetDouble() BPTREE_OPLIST(MultiSetDouble, M_BASIC_OPLIST)
|
||||
|
||||
static void test1(void)
|
||||
{
|
||||
@@ -641,6 +642,55 @@ static void test_double(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_emplace (void)
|
||||
{
|
||||
btree_mpz_t d;
|
||||
btree_mpz_init(d);
|
||||
string_t s;
|
||||
string_init(s);
|
||||
testobj_t o;
|
||||
testobj_init(o);
|
||||
|
||||
btree_mpz_emplace_key_val_str(d, "HELLO", "14");
|
||||
string_set_str(s, "HELLO");
|
||||
testobj_t *ptr = btree_mpz_get(d, s);
|
||||
assert(ptr != NULL);
|
||||
assert(testobj_cmp_ui(*ptr, 14) == 0);
|
||||
|
||||
btree_mpz_emplace_key_val_ui(d, "HE", 145);
|
||||
string_set_str(s, "HE");
|
||||
ptr = btree_mpz_get(d, s);
|
||||
assert(ptr != NULL);
|
||||
assert(testobj_cmp_ui(*ptr, 145) == 0);
|
||||
|
||||
testobj_set(o, *ptr);
|
||||
btree_mpz_emplace_key_val(d, "SHE", o);
|
||||
string_set_str(s, "SHE");
|
||||
ptr = btree_mpz_get(d, s);
|
||||
assert(ptr != NULL);
|
||||
assert(testobj_cmp_ui(*ptr, 145) == 0);
|
||||
|
||||
btree_mpz_emplace_key(d, "IT", o);
|
||||
string_set_str(s, "IT");
|
||||
ptr = btree_mpz_get(d, s);
|
||||
assert(ptr != NULL);
|
||||
assert(testobj_cmp_ui(*ptr, 145) == 0);
|
||||
|
||||
btree_mpz_emplace_val_ui(d, s, 19);
|
||||
ptr = btree_mpz_get(d, s);
|
||||
assert(ptr != NULL);
|
||||
assert(testobj_cmp_ui(*ptr, 19) == 0);
|
||||
|
||||
btree_mpz_emplace_val_str(d, s, "190");
|
||||
ptr = btree_mpz_get(d, s);
|
||||
assert(ptr != NULL);
|
||||
assert(testobj_cmp_ui(*ptr, 190) == 0);
|
||||
|
||||
testobj_clear(o);
|
||||
string_clear(s);
|
||||
btree_mpz_clear(d);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test1();
|
||||
@@ -654,5 +704,6 @@ int main(void)
|
||||
test_multimap();
|
||||
test_multiset();
|
||||
test_double();
|
||||
test_emplace();
|
||||
exit(0);
|
||||
}
|
||||
+22
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -49,9 +49,14 @@ QUEUE_SPSC_DEF(squeue_a, testobj_t, BUFFER_QUEUE, TESTOBJ_OPLIST)
|
||||
BUFFER_DEF_AS(BufferDouble1, BufferDouble1, double, 4, BUFFER_QUEUE)
|
||||
QUEUE_MPMC_DEF_AS(BufferDouble2, BufferDouble2, double, BUFFER_QUEUE)
|
||||
QUEUE_SPSC_DEF_AS(BufferDouble3, BufferDouble3, double, BUFFER_QUEUE)
|
||||
#define M_OPL_BufferDouble1() BUFFER_OPLIST(BufferDouble1, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_BufferDouble2() BUFFER_OPLIST(BufferDouble2, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_BufferDouble3() BUFFER_OPLIST(BufferDouble3, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_BufferDouble1() BUFFER_OPLIST(BufferDouble1, M_BASIC_OPLIST)
|
||||
#define M_OPL_BufferDouble2() BUFFER_OPLIST(BufferDouble2, M_BASIC_OPLIST)
|
||||
#define M_OPL_BufferDouble3() BUFFER_OPLIST(BufferDouble3, M_BASIC_OPLIST)
|
||||
|
||||
// Define buffer with ENUM oplist (with API_1 usage)
|
||||
typedef enum { OK, KO } state_t;
|
||||
#define M_OPL_state_t() M_ENUM_OPLIST(state_t, OK)
|
||||
BUFFER_DEF(array_state, state_t, 0, M_BUFFER_QUEUE)
|
||||
|
||||
buffer_uint_t g_buff;
|
||||
buffer_uint_t g_buffB;
|
||||
@@ -266,6 +271,18 @@ static void test_no_thread(void)
|
||||
buffer_llong_clear(buff);
|
||||
}
|
||||
|
||||
static void test_emplace(void)
|
||||
{
|
||||
buffer_mpz_t b;
|
||||
buffer_mpz_init(b, 32);
|
||||
buffer_mpz_emplace_str(b, "56");
|
||||
testobj_t o;
|
||||
testobj_init(o);
|
||||
buffer_mpz_pop(&o, b);
|
||||
assert( testobj_cmp_ui(o, 56) == 0 );
|
||||
testobj_clear(o);
|
||||
buffer_mpz_clear(b);
|
||||
}
|
||||
/********************************************************************************************/
|
||||
|
||||
/* Test intrusive shared pointer + buffer */
|
||||
@@ -637,6 +654,7 @@ int main(void)
|
||||
test_stack();
|
||||
test_stack2();
|
||||
test_no_thread();
|
||||
test_emplace();
|
||||
test_global_ishared();
|
||||
test_queue(1000000, 2, 2148371710223136ULL);
|
||||
test_spsc();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Test for Concurrent memory pool allocator
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -37,13 +37,13 @@
|
||||
#include "m-concurrent.h"
|
||||
|
||||
TUPLE_DEF2(point, (x, int), (y, int))
|
||||
#define M_OPL_point_t() TUPLE_OPLIST(point, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_point_t() TUPLE_OPLIST(point, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
START_COVERAGE
|
||||
CONCURRENT_DEF(ppoint, point_t)
|
||||
END_COVERAGE
|
||||
|
||||
VARIANT_DEF2(dimension, (x, int), (y, float))
|
||||
#define M_OPL_dimension_t() VARIANT_OPLIST(dimension, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_dimension_t() VARIANT_OPLIST(dimension, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
CONCURRENT_DEF(pdimension, dimension_t)
|
||||
|
||||
ARRAY_DEF(array1, int)
|
||||
@@ -68,7 +68,7 @@ PRIOQUEUE_DEF(prio1, int)
|
||||
CONCURRENT_DEF(pprio1, prio1_t, PRIOQUEUE_OPLIST(prio1))
|
||||
|
||||
BPTREE_DEF2(bptree1, 10, int, int)
|
||||
CONCURRENT_DEF(pbtree1, bptree1_t, BPTREE_OPLIST2(bptree1, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
CONCURRENT_DEF(pbtree1, bptree1_t, BPTREE_OPLIST2(bptree1, M_BASIC_OPLIST, M_BASIC_OPLIST))
|
||||
|
||||
BPTREE_DEF(bptree2, 10, int)
|
||||
CONCURRENT_DEF(pbtree2, bptree2_t, BPTREE_OPLIST(bptree2))
|
||||
@@ -110,8 +110,8 @@ static inline void int_oor_set(int *s, unsigned char n)
|
||||
*s = -n;
|
||||
}
|
||||
#define INT_OA_OPLIST \
|
||||
M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(int_oor_equal_p), OOR_SET(API_2(int_oor_set)))
|
||||
DICT_OA_DEF2(dict3, int, INT_OA_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(int_oor_equal_p), OOR_SET(API_2(int_oor_set)))
|
||||
DICT_OA_DEF2(dict3, int, INT_OA_OPLIST, int, M_BASIC_OPLIST)
|
||||
CONCURRENT_DEF(pdict3, dict3_t, DICT_OPLIST(dict3))
|
||||
|
||||
/********************************/
|
||||
@@ -226,6 +226,18 @@ static void test_double(void)
|
||||
ConcurrentRpDouble_clear(r);
|
||||
}
|
||||
|
||||
static void test_emplace(void)
|
||||
{
|
||||
key_list_ts_t ts;
|
||||
key_list_ts_init(ts);
|
||||
key_list_ts_emplace(ts, "HELLO");
|
||||
M_LET(s, string_t) {
|
||||
key_list_ts_pop(&s, ts);
|
||||
assert(string_equal_str_p(s, "HELLO"));
|
||||
}
|
||||
key_list_ts_clear(ts);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_basic();
|
||||
@@ -233,5 +245,6 @@ int main(void)
|
||||
test_thread();
|
||||
test_rp_thread();
|
||||
test_double();
|
||||
test_emplace();
|
||||
exit(0);
|
||||
}
|
||||
+155
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -34,6 +34,13 @@ static void test_cat(void)
|
||||
assert (M_C(A,andB));
|
||||
assert (M_C3(A,and,B));
|
||||
assert (M_C4(A,and,B,andC));
|
||||
|
||||
assert (M_C3_EMPTY(A,and,B));
|
||||
assert (M_C3_EMPTY(Aand,,B));
|
||||
assert (M_C3_EMPTY(AandB,,));
|
||||
|
||||
assert (M_C5_EMPTY(A,a,n,d,B));
|
||||
assert (M_C5_EMPTY(Aand,,,,B));
|
||||
}
|
||||
|
||||
static void test_power2(void)
|
||||
@@ -156,6 +163,37 @@ static void test_incdec(void)
|
||||
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)));
|
||||
// Test if the initial error is not lost in translation
|
||||
assert(M_KEYWORD_P(M_UNDERFLOW, M_INC(M_UNDERFLOW)));
|
||||
assert(M_KEYWORD_P(M_OVERFLOW, M_DEC(M_OVERFLOW)));
|
||||
|
||||
assert(M_AND(0, 0) == 0);
|
||||
assert(M_AND(0, 1) == 0);
|
||||
assert(M_AND(1, 0) == 0);
|
||||
assert(M_AND(1, 1) == 1);
|
||||
|
||||
assert(M_OR(0, 0) == 0);
|
||||
assert(M_OR(0, 1) == 1);
|
||||
assert(M_OR(1, 0) == 1);
|
||||
assert(M_OR(1, 1) == 1);
|
||||
|
||||
assert(M_AND3(0, 0, 0) == 0);
|
||||
assert(M_AND3(0, 0, 1) == 0);
|
||||
assert(M_AND3(0, 1, 0) == 0);
|
||||
assert(M_AND3(0, 1, 1) == 0);
|
||||
assert(M_AND3(1, 0, 0) == 0);
|
||||
assert(M_AND3(1, 0, 1) == 0);
|
||||
assert(M_AND3(1, 1, 0) == 0);
|
||||
assert(M_AND3(1, 1, 1) == 1);
|
||||
|
||||
assert(M_OR3(0, 0, 0) == 0);
|
||||
assert(M_OR3(0, 0, 1) == 1);
|
||||
assert(M_OR3(0, 1, 0) == 1);
|
||||
assert(M_OR3(0, 1, 1) == 1);
|
||||
assert(M_OR3(1, 0, 0) == 1);
|
||||
assert(M_OR3(1, 0, 1) == 1);
|
||||
assert(M_OR3(1, 1, 0) == 1);
|
||||
assert(M_OR3(1, 1, 1) == 1);
|
||||
}
|
||||
|
||||
static void test_return(void)
|
||||
@@ -230,6 +268,7 @@ static void test_map(void)
|
||||
assert (M_MAP (f, 1) 0 == 1);
|
||||
assert (M_MAP (f, 1, 2) 0 == 5);
|
||||
assert (M_MAP (f, 1, 2, 3) 0 == 14);
|
||||
assert (M_MAP (f, M_SEQ(1, 4)) 0 == 1+4+9+16);
|
||||
|
||||
assert (M_MAP2 (f2, 2, 1) 0 == 2);
|
||||
assert (M_MAP2 (f2, 3, 1, 2) 0 == 9);
|
||||
@@ -238,6 +277,19 @@ static void test_map(void)
|
||||
assert (M_MAP3 (f3, 2, 2) 0 == 4);
|
||||
assert (M_MAP3 (f3, 3, 2, 4) 0 == 30);
|
||||
assert (M_MAP3 (f3, 4, 2, 4, 6) 0 == 8+32+12*6);
|
||||
|
||||
assert (M_CROSS_MAP(f2, (1), (2)) 0 == 1*2);
|
||||
assert (M_CROSS_MAP(f2, (1), (2, 3)) 0 == 1*2+1*3);
|
||||
assert (M_CROSS_MAP(f2, (1, 3), (2)) 0 == 1*2+3*2);
|
||||
assert (M_CROSS_MAP(f2, (1, 3), (2,4)) 0 == 1*2 + 1*4 + 3*2 + 3*4);
|
||||
assert (M_CROSS_MAP(f2, (1, 3, 5), (2,4)) 0 == 1*2 + 1*4 + 3*2 + 3*4 + 5*2 + 5*4);
|
||||
|
||||
assert (M_CROSS_MAP2(f3, 2, (1), (2)) 0 == (1*2) * 2);
|
||||
assert (M_CROSS_MAP2(f3, 2, (1), (2, 3)) 0 == (1*2+1*3) * 2);
|
||||
assert (M_CROSS_MAP2(f3, 2, (1, 3), (2)) 0 == (1*2+3*2) * 2);
|
||||
assert (M_CROSS_MAP2(f3, 2, (1, 3), (2,4)) 0 == (1*2 + 1*4 + 3*2 + 3*4) * 2);
|
||||
assert (M_CROSS_MAP2(f3, 2, (1, 3, 5), (2,4)) 0 == (1*2 + 1*4 + 3*2 + 3*4 + 5*2 + 5*4)*2);
|
||||
|
||||
}
|
||||
|
||||
static void test_let(void)
|
||||
@@ -290,6 +342,7 @@ static void test_let(void)
|
||||
M_LET( (x, 4590) , OPL6)
|
||||
assert (x == 4590);
|
||||
|
||||
// Test of M_LET_IF
|
||||
int c = 0;
|
||||
M_LET_IF( assert(c++ == 0), (assert(c++ == 1), true), assert(c++ == 3)) {
|
||||
assert(c++ == 2);
|
||||
@@ -351,12 +404,14 @@ static void test_if(void)
|
||||
|
||||
static void test_test(void)
|
||||
{
|
||||
assert(M_COMMA_P(,));
|
||||
assert(M_COMMA_P(1,2));
|
||||
assert(M_COMMA_P(1,2,aa));
|
||||
assert(!M_COMMA_P(1));
|
||||
assert(!M_COMMA_P(()));
|
||||
assert(!M_COMMA_P("aa"));
|
||||
assert(!M_COMMA_P(""));
|
||||
assert(!M_COMMA_P((,)));
|
||||
|
||||
assert(M_PARENTHESIS_P(()));
|
||||
assert(M_PARENTHESIS_P((aa)));
|
||||
@@ -369,6 +424,26 @@ static void test_test(void)
|
||||
assert(!M_PARENTHESIS_P(,));
|
||||
assert(!M_PARENTHESIS_P((),));
|
||||
assert(!M_PARENTHESIS_P(()x));
|
||||
|
||||
assert(!M_KEYWORD_P(sum, sul));
|
||||
assert(M_KEYWORD_P(sum, sum));
|
||||
assert(M_KEYWORD_P(sum, add));
|
||||
assert(M_KEYWORD_P(product, product));
|
||||
assert(M_KEYWORD_P(product, mul));
|
||||
assert(!M_KEYWORD_P(product, mul2));
|
||||
assert(M_KEYWORD_P(_, _));
|
||||
assert(M_KEYWORD_P(_, _() ));
|
||||
|
||||
assert(M_KEYWORD_P(LIST, LIST));
|
||||
assert(M_KEYWORD_P(LIST, LIST(1,23,4) ));
|
||||
assert(!M_KEYWORD_P(LIST, SEQ(1,23,4) ));
|
||||
|
||||
assert(M_KEYWORD_TO_VA_ARGS(LIST, LIST(16)) == 16);
|
||||
assert(M_KEYWORD_TO_VA_ARGS(LIST, LIST(14)) == 14);
|
||||
assert(M_GET_AT( ( M_KEYWORD_TO_VA_ARGS(LIST, LIST(11, 22, 33)) ), 0) == 11);
|
||||
assert(M_GET_AT( ( M_KEYWORD_TO_VA_ARGS(LIST, LIST(11, 22, 33)) ), 1) == 22);
|
||||
assert(M_GET_AT( ( M_KEYWORD_TO_VA_ARGS(LIST, LIST(11, 22, 33)) ), 2) == 33);
|
||||
assert(M_KEYWORD_TO_VA_ARGS(_, _(10)) == 10);
|
||||
}
|
||||
|
||||
static void test_list(void)
|
||||
@@ -439,11 +514,11 @@ static void test_oplist(void)
|
||||
#define CHECK_OPLIST(op, oplist) \
|
||||
M_IF_METHOD(op, oplist) (true, false)
|
||||
|
||||
assert (CHECK_OPLIST (INIT, M_DEFAULT_OPLIST));
|
||||
assert (CHECK_OPLIST (INIT_SET, M_DEFAULT_OPLIST));
|
||||
assert (CHECK_OPLIST (SET, M_DEFAULT_OPLIST));
|
||||
assert (CHECK_OPLIST (CLEAR, M_DEFAULT_OPLIST));
|
||||
assert (!CHECK_OPLIST (CLEAR_TOOT, M_DEFAULT_OPLIST));
|
||||
assert (CHECK_OPLIST (INIT, M_BASIC_OPLIST));
|
||||
assert (CHECK_OPLIST (INIT_SET, M_BASIC_OPLIST));
|
||||
assert (CHECK_OPLIST (SET, M_BASIC_OPLIST));
|
||||
assert (CHECK_OPLIST (CLEAR, M_BASIC_OPLIST));
|
||||
assert (!CHECK_OPLIST (CLEAR_TOOT, M_BASIC_OPLIST));
|
||||
|
||||
assert (M_OPLIST_P(()));
|
||||
assert (M_OPLIST_P((INIT(init))));
|
||||
@@ -504,6 +579,9 @@ static void test_reduce(void)
|
||||
assert ( M_REDUCE2(id, add, d, M_SEQ(1, 5)) == 5 * 6 /2);
|
||||
assert ( M_REDUCE2(id, add, d, M_SEQ(1, 10)) == 10 * 11 /2);
|
||||
|
||||
assert ( M_REDUCE2(id, add, d, M_SEQ(1, 1)) == 1);
|
||||
assert ( M_REDUCE2(id, add, d, M_SEQ(1, 2)) == 1+2);
|
||||
|
||||
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)));
|
||||
@@ -694,6 +772,18 @@ static void test_builtin(void)
|
||||
assert(m_core_clz64((uint64_t) ((1ULL<<i) | 1)) == 63U - i);
|
||||
}
|
||||
|
||||
assert(m_core_ctz32(0) == 32);
|
||||
for(unsigned i = 0; i < 31; i++) {
|
||||
assert(m_core_ctz32((uint32_t) (1UL<<i)) == i);
|
||||
assert(m_core_ctz32((uint32_t) ((1UL<<i) | 1UL<<31)) == i);
|
||||
}
|
||||
|
||||
assert(m_core_ctz64(0) == 64);
|
||||
for(unsigned i = 0; i < 63; i++) {
|
||||
assert(m_core_ctz64((uint64_t) (1ULL<<i)) == i);
|
||||
assert(m_core_ctz64((uint64_t) ((1ULL<<i) | 1ULL<<63)) == i);
|
||||
}
|
||||
|
||||
assert ( m_core_roundpow2(0) == 0);
|
||||
for(unsigned i = 0; i < 62; i++) {
|
||||
assert ( m_core_roundpow2(1ULL<<i) == 1ULL<<i);
|
||||
@@ -758,6 +848,64 @@ static void test_properties(void)
|
||||
assert( M_GET_PROPERTY (OP_PROP(), IT_TYPE ) == 2);
|
||||
assert( M_KEYWORD_P( M_GET_PROPERTY (OP_PROP(), INIT_WITH ), priority));
|
||||
}
|
||||
|
||||
static int init3(int *p, int a, int b)
|
||||
{
|
||||
*p = b;
|
||||
return a;
|
||||
}
|
||||
|
||||
static int cmp1(int a, int b)
|
||||
{
|
||||
return a < b ? -1 : a > b;
|
||||
}
|
||||
|
||||
static int cmp2(int *a, int *b)
|
||||
{
|
||||
return *a < *b ? -1 : *a > *b;
|
||||
}
|
||||
|
||||
#define cmp3(a, b) \
|
||||
(a < b ? -1 : a > b)
|
||||
|
||||
static void test_generic_api(void)
|
||||
{
|
||||
assert( M_HEAD(17, 0) == 17);
|
||||
assert( M_TAIL(18, 19) == 19);
|
||||
assert( M_HEAD_2(18, 17, 0) == 17);
|
||||
assert( M_TAIL_2(18, 17, 8) == 8);
|
||||
|
||||
#define GO1 (INIT(API( init3, ARG1, ARGPTR2, 17, 43 )))
|
||||
#define GO2 (INIT(API( init3, NONE, ARGPTR2, 0, ARG1 )))
|
||||
#define GO3 (EQUAL(API( cmp2, EQ(0), ARGPTR1, ARGPTR2 )))
|
||||
#define GO4 (EQUAL(API( cmp1, EQ(0), ARG1, ARG2 )))
|
||||
#define GO5 (EQUAL(API( cmp3, EQ(0), ARG1, ARG2 )))
|
||||
|
||||
int x = 0, y = 0;
|
||||
M_CALL_INIT(GO1, x, y);
|
||||
assert(x == 17);
|
||||
assert(y == 43);
|
||||
|
||||
x = 89;
|
||||
M_CALL_INIT(GO2, x, y);
|
||||
assert( y == 89);
|
||||
assert( x == 89);
|
||||
|
||||
x = y = 78;
|
||||
bool b = M_CALL_EQUAL(GO3, x, y);
|
||||
assert(b);
|
||||
x = 77;
|
||||
b = M_CALL_EQUAL(GO4, x, y);
|
||||
assert(!b);
|
||||
|
||||
x = y = 78;
|
||||
b = M_CALL_EQUAL(GO5, x, y);
|
||||
assert(b);
|
||||
x = 77;
|
||||
b = M_CALL_EQUAL(GO5, x, y);
|
||||
assert(!b);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_cat();
|
||||
@@ -783,5 +931,6 @@ int main(void)
|
||||
test_str_hash();
|
||||
test_M_CSTR();
|
||||
test_properties();
|
||||
test_generic_api();
|
||||
exit(0);
|
||||
}
|
||||
+8
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -46,7 +46,7 @@ DEQUE_DEF(deque_retcode, ReturnCode_t, M_ENUM_OPLIST(ReturnCode_t, SUCCESS))
|
||||
#define OPL DEQUE_OPLIST(deque)
|
||||
|
||||
DEQUE_DEF_AS(DequeDouble, DequeDouble, DequeDoubleIt, double)
|
||||
#define M_OPL_DequeDouble() DEQUE_OPLIST(DequeDouble, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_DequeDouble() DEQUE_OPLIST(DequeDouble, M_BASIC_OPLIST)
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
|
||||
@@ -323,8 +323,13 @@ static void test_z(void)
|
||||
testobj_clear(z);
|
||||
deque_mpz_pop_front_move(&z, d);
|
||||
assert (testobj_cmp_ui (z, 4217) == 0);
|
||||
}
|
||||
|
||||
deque_mpz_emplace_back_ui(d, 45);
|
||||
assert(testobj_cmp_ui(*deque_mpz_back(d), 45) == 0);
|
||||
deque_mpz_emplace_front_str(d, "450");
|
||||
assert(testobj_cmp_ui(*deque_mpz_front(d), 450) == 0);
|
||||
assert(testobj_cmp_ui(*deque_mpz_back(d), 45) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_io(void)
|
||||
|
||||
Loaded 100 of 126 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user