Compare commits
138
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66d2aa26d3 | ||
|
|
1ae904dff2 | ||
|
|
4549f4ab91 | ||
|
|
75d5627378 | ||
|
|
8cbd27e629 | ||
|
|
333cc2ccf8 | ||
|
|
000dba1da5 | ||
|
|
11946f155d | ||
|
|
99713e873c | ||
|
|
ea5c993ff0 | ||
|
|
22d62f94bb | ||
|
|
8fd79f07d5 | ||
|
|
29fe80a6af | ||
|
|
e787b64978 | ||
|
|
4f9db5eba6 | ||
|
|
db5990de03 | ||
|
|
d4383ef854 | ||
|
|
d10c8c1b41 | ||
|
|
3c669548a2 | ||
|
|
ec11230b5e | ||
|
|
567473869b | ||
|
|
0b6733fdcb | ||
|
|
8e330862e1 | ||
|
|
b2adc77d76 | ||
|
|
82cbe9e282 | ||
|
|
93429c8bf3 | ||
|
|
150bef4d4d | ||
|
|
562fd875e9 | ||
|
|
5513a9df1b | ||
|
|
6fd2610eec | ||
|
|
11bf5e4691 | ||
|
|
cf0d82a706 | ||
|
|
b0cc17ea86 | ||
|
|
04d4bf6866 | ||
|
|
738123d4a7 | ||
|
|
a3ece09e66 | ||
|
|
8109c094db | ||
|
|
2c81582419 | ||
|
|
f8c79d9259 | ||
|
|
c7a894b34e | ||
|
|
5c36e045ff | ||
|
|
0f883d2ecf | ||
|
|
9dfcf41b64 | ||
|
|
1416f4e225 | ||
|
|
16c6a13fb1 | ||
|
|
9382cdc0f7 | ||
|
|
ced2719760 | ||
|
|
1798530284 | ||
|
|
68f890a015 | ||
|
|
5805038943 | ||
|
|
2395ceb3d2 | ||
|
|
2b455c5c6b | ||
|
|
d466e76702 | ||
|
|
9d33c85e13 | ||
|
|
4e24e7a533 | ||
|
|
0914c26b8d | ||
|
|
c245285123 | ||
|
|
be4ff6f94d | ||
|
|
aa055d0b00 | ||
|
|
e7d6e0d6ac | ||
|
|
8f97a194ae | ||
|
|
b191baec8b | ||
|
|
e4a85cdc61 | ||
|
|
12ee3213b0 | ||
|
|
6cba7ad8ba | ||
|
|
955c8bfb81 | ||
|
|
8602a259fd | ||
|
|
7404e63b53 | ||
|
|
c539eb57b7 | ||
|
|
3c4943015b | ||
|
|
c9fef6d80a | ||
|
|
5174781a7a | ||
|
|
7bf9f6a377 | ||
|
|
7575681e27 | ||
|
|
cfab3cf0cf | ||
|
|
a523a97a0e | ||
|
|
6f75bb938b | ||
|
|
a22046bc2a | ||
|
|
84ee15b2e7 | ||
|
|
fd6a8f1361 | ||
|
|
d22e75d7a0 | ||
|
|
ca25dfb537 | ||
|
|
e2159109b3 | ||
|
|
cc6bdbf06c | ||
|
|
cd37efc69d | ||
|
|
db08e62f1a | ||
|
|
3be653d55a | ||
|
|
e351730ad0 | ||
|
|
d7a232364f | ||
|
|
f7580e7ce9 | ||
|
|
26cec1591a | ||
|
|
52b58c5a51 | ||
|
|
8902a752f5 | ||
|
|
3445da13f3 | ||
|
|
127530abaa | ||
|
|
ed0f538fb7 | ||
|
|
76ef061dec | ||
|
|
c98786a3b3 | ||
|
|
422f3c2c04 | ||
|
|
5ceb34d980 | ||
|
|
73e3d1d1bd | ||
|
|
044a085fb6 | ||
|
|
5344423ad9 | ||
|
|
76ea989865 | ||
|
|
29c4ba3dcc | ||
|
|
42184f69db | ||
|
|
fb8bf65233 | ||
|
|
1d86e51f4a | ||
|
|
53c35a22d7 | ||
|
|
722737d60c | ||
|
|
f951a947ec | ||
|
|
d9401371a6 | ||
|
|
690fd72c8b | ||
|
|
d318493c6c | ||
|
|
fecece19cb | ||
|
|
ea640482a7 | ||
|
|
3e558af559 | ||
|
|
91a602f774 | ||
|
|
6a5c136c72 | ||
|
|
e50fdc82ef | ||
|
|
ec0a082701 | ||
|
|
7bf3ea3a87 | ||
|
|
15492394ad | ||
|
|
09f40b5695 | ||
|
|
eabfcd1d49 | ||
|
|
00aeafc616 | ||
|
|
f512051807 | ||
|
|
4e8b929da9 | ||
|
|
5841f936e6 | ||
|
|
2ee40339b0 | ||
|
|
0c8eca893d | ||
|
|
b16048a55b | ||
|
|
9dc582c6bc | ||
|
|
1df8bf84fb | ||
|
|
e017a90e5c | ||
|
|
58b317b759 | ||
|
|
3a057fc319 | ||
|
|
703ab6ff9c |
No files matched your search
+16
-13
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: CPU Information
|
||||
run: lscpu || sysctl -a|grep cpu || echo "CPU information not available"
|
||||
- name: make check C99
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: update package list
|
||||
run: sudo apt-get update
|
||||
- name: install multilib
|
||||
@@ -50,7 +50,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: CPU Information
|
||||
run: lscpu || echo "CPU information not available"
|
||||
- name: Clone TCC
|
||||
@@ -64,13 +64,13 @@ jobs:
|
||||
run: make depend
|
||||
- name: make check
|
||||
shell: bash
|
||||
run: make CC="/tmp/tcc/bin/tcc -std=c99" check
|
||||
run: make CC="/tmp/tcc/bin/tcc -std=c99" check -j4 || make CC="/tmp/tcc/bin/tcc -std=c99" check -j2 || make CC="/tmp/tcc/bin/tcc -std=c99" check
|
||||
|
||||
build_linux_sanitize:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: make sanitize
|
||||
working-directory: ./tests
|
||||
run: make sanitize -j 2
|
||||
@@ -79,7 +79,7 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: make check
|
||||
shell: bash
|
||||
run: mingw32-make -j 2 CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
@@ -90,7 +90,7 @@ jobs:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW64
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: make check
|
||||
shell: cmd
|
||||
working-directory: ./tests
|
||||
@@ -113,19 +113,21 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: make check
|
||||
shell: cmd
|
||||
working-directory: ./tests
|
||||
run: Make-check-cl.bat clang-cl
|
||||
|
||||
# The host should always be linux
|
||||
build_freebsd:
|
||||
runs-on: macos-12
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test in FreeBSD
|
||||
id: test
|
||||
uses: vmactions/freebsd-vm@v0
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
timeout-minutes: 60
|
||||
with:
|
||||
usesh: true
|
||||
run: |
|
||||
@@ -138,10 +140,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build on aarch64
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2.5.0
|
||||
name: Run commands on aarch64
|
||||
id: make
|
||||
timeout-minutes: 60
|
||||
with:
|
||||
arch: aarch64
|
||||
distro: bullseye
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ depend
|
||||
other/
|
||||
a*.dat
|
||||
config
|
||||
config.link
|
||||
config.*
|
||||
*.log
|
||||
.vscode
|
||||
.vs
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2023, Patrick Pelissier
|
||||
# Copyright (c) 2017-2024, 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.7.1
|
||||
VERSION=0.7.3
|
||||
|
||||
# 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-thread.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-try.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-generic.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-thread.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-try.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/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
|
||||
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 doc/bench-array-log.png doc/bench-array.png doc/bench-list-log.png doc/bench-list.png doc/bench-oset-log.png doc/bench-oset.png doc/bench-umap-log.png doc/bench-umap.png doc/cc.sh
|
||||
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 example/ex-curl.c example/ex-dict05.c example/ex-dict06.c example/exm-lib.c example/exm-main.c example/exn-lib.c example/exn-main.c example/exm-header.h example/exn-header.h example/ex-alloc1.c example/ex-alloc2.c example/ex-try01.c example/ex11-generic01.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 tests/test-mtry.c tests/tgen-mmap.c tests/tgen-try.c tests/tgen-tuple.c tests/test-mgeneric.c
|
||||
|
||||
.PHONY: all test check doc clean distclean depend install uninstall dist
|
||||
|
||||
@@ -66,7 +66,6 @@ doc: html doc/depend.png
|
||||
clean:
|
||||
cd tests && $(MAKE) 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'
|
||||
|
||||
-500
@@ -1,500 +0,0 @@
|
||||
# Copyright (c) 2017-2023, 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.
|
||||
|
||||
CC=cc -std=c11
|
||||
CXX=c++ -std=c++11
|
||||
CFLAGS=-O2 -march=native -Wall
|
||||
XCFLAGS=
|
||||
CPPFLAGS=-I..
|
||||
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-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
|
||||
|
||||
pgo:
|
||||
$(MAKE) all XCFLAGS="-fprofile-generate=pgo"
|
||||
$(MAKE) all XCFLAGS="-fprofile-use=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-emhash bench-hopscotchmap bench-uthash bench-qlibc bench-libsrt bench-nedtries bench-rigtorp-hashmap bench-ctl bench-stc bench-pottery bench-CC
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-rigtorp-mpmc-queue
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
mempool: bench-mempool
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
string: bench-string
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
plain: bench-plain
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
|
||||
|
||||
#########################################################################
|
||||
|
||||
|
||||
bench-mlib:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -pthread bench-mlib.c common.c -o bench-mlib.exe
|
||||
@./bench-mlib.exe 10
|
||||
@./bench-mlib.exe 11
|
||||
@./bench-mlib.exe 20
|
||||
@./bench-mlib.exe 30
|
||||
@./bench-mlib.exe 31
|
||||
@./bench-mlib.exe 40
|
||||
@./bench-mlib.exe 41
|
||||
@./bench-mlib.exe 42
|
||||
@./bench-mlib.exe 46
|
||||
@./bench-mlib.exe 47
|
||||
@./bench-mlib.exe 43
|
||||
@./bench-mlib.exe 50
|
||||
@./bench-mlib.exe 51
|
||||
|
||||
bench-mlib-mempool:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c common.c -DUSE_MEMPOOL -pthread -o bench-mlib-mempool.exe
|
||||
@./bench-mlib-mempool.exe 10
|
||||
@./bench-mlib-mempool.exe 11
|
||||
@./bench-mlib-mempool.exe 20
|
||||
@./bench-mlib-mempool.exe 30
|
||||
@./bench-mlib-mempool.exe 31
|
||||
@./bench-mlib-mempool.exe 40
|
||||
@./bench-mlib-mempool.exe 41
|
||||
@./bench-mlib-mempool.exe 42
|
||||
@./bench-mlib-mempool.exe 46
|
||||
@./bench-mlib-mempool.exe 47
|
||||
@./bench-mlib-mempool.exe 43
|
||||
@./bench-mlib-mempool.exe 50
|
||||
@./bench-mlib-mempool.exe 51
|
||||
|
||||
bench-mlib-thread:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c common.c -DMULTI_THREAD_MEASURE -pthread -o bench-mlib-thread.exe
|
||||
@./bench-mlib-thread.exe 60
|
||||
@./bench-mlib-thread.exe 61
|
||||
@./bench-mlib-thread.exe 62
|
||||
@./bench-mlib-thread.exe 63
|
||||
@./bench-mlib-thread.exe 64
|
||||
@./bench-mlib-thread.exe 65
|
||||
@./bench-mlib-thread.exe 66
|
||||
|
||||
bench-stl:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-stl.cpp common.c -o bench-stl.exe
|
||||
@./bench-stl.exe 10
|
||||
@./bench-stl.exe 20
|
||||
@./bench-stl.exe 30
|
||||
@./bench-stl.exe 40
|
||||
@./bench-stl.exe 41
|
||||
@./bench-stl.exe 42
|
||||
@./bench-stl.exe 46
|
||||
@./bench-stl.exe 43
|
||||
@./bench-stl.exe 50
|
||||
@./bench-stl.exe 51
|
||||
|
||||
# QT shall point to the the directory containing the file .pc are stored
|
||||
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 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
|
||||
@./bench-qt.exe 40
|
||||
@./bench-qt.exe 41
|
||||
@./bench-qt.exe 42
|
||||
@./bench-qt.exe 50
|
||||
|
||||
# GLIB shall point to the the directory containing the file .pc are stored
|
||||
bench-glib:
|
||||
@if test -n "$${GLIB}" ; then $(MAKE) bench-glib0 ; else echo "Nothing to be done for GLIB." ; fi
|
||||
bench-glib0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-glib.c common.c -o bench-glib.exe `PKG_CONFIG_PATH="$${GLIB}" pkg-config --libs --cflags glib-2.0`
|
||||
@./bench-glib.exe 10
|
||||
@./bench-glib.exe 20
|
||||
@./bench-glib.exe 30
|
||||
@./bench-glib.exe 40
|
||||
@./bench-glib.exe 41
|
||||
@./bench-glib.exe 50
|
||||
|
||||
# KLIB shall point to the directory where the headers are
|
||||
bench-klib:
|
||||
@if test -n "$${KLIB}" ; then $(MAKE) bench-klib0 ; else echo "Nothing to be done for KLIB." ; fi
|
||||
|
||||
bench-klib0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${KLIB} bench-klib.c common.c -o bench-klib.exe
|
||||
@./bench-klib.exe 10
|
||||
@./bench-klib.exe 20
|
||||
@./bench-klib.exe 30
|
||||
@./bench-klib.exe 40
|
||||
@./bench-klib.exe 41
|
||||
@./bench-klib.exe 50
|
||||
|
||||
# CMC shall point to the directory where the CMC main header is
|
||||
bench-cmc:
|
||||
@if test -n "$${CMC}" ; then $(MAKE) bench-cmc0 ; else echo "Nothing to be done for CMC." ; fi
|
||||
|
||||
bench-cmc0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${CMC} bench-cmc.c common.c -o bench-cmc.exe
|
||||
@./bench-cmc.exe 20
|
||||
@./bench-cmc.exe 30
|
||||
@./bench-cmc.exe 40
|
||||
|
||||
# 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 -I$${LIBDYNAMIC}/src $${LIBDYNAMIC}/.libs/libdynamic.a
|
||||
@./bench-libdynamic.exe 20
|
||||
@./bench-libdynamic.exe 40
|
||||
@./bench-libdynamic.exe 41
|
||||
|
||||
# SPARSEPP shall point to the directory where the headers are
|
||||
bench-sparsepp:
|
||||
@if test -n "$${SPARSEPP}" ; then $(MAKE) bench-sparsepp0 ; else echo "Nothing to be done for SPARSEPP." ; fi
|
||||
|
||||
bench-sparsepp0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${SPARSEPP}" -I "$${SPARSEPP}/.." bench-sparsepp.cpp common.c -o bench-sparsepp.exe
|
||||
@./bench-sparsepp.exe 41
|
||||
@./bench-sparsepp.exe 42
|
||||
@./bench-sparsepp.exe 43
|
||||
|
||||
# DENSEHASHMAP shall point to the directory where the src are
|
||||
bench-densehashmap:
|
||||
@if test -n "$${DENSEHASHMAP}" ; then $(MAKE) bench-densehashmap0 ; else echo "Nothing to be done Google DENSEHASHMAP." ; fi
|
||||
|
||||
bench-densehashmap0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${DENSEHASHMAP}" -I "$${DENSEHASHMAP}/.." bench-densehashmap.cpp common.c -o bench-densehashmap.exe
|
||||
@./bench-densehashmap.exe 41
|
||||
@./bench-densehashmap.exe 42
|
||||
@./bench-densehashmap.exe 43
|
||||
|
||||
# COLLECTIONC shall point to the directory where it is installed
|
||||
bench-collectionc:
|
||||
@if test -n "$${COLLECTIONC}" ; then $(MAKE) bench-collectionc0 ; else echo "Nothing to be done for COLLECTIONC." ; fi
|
||||
|
||||
bench-collectionc0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${COLLECTIONC}/include/collectc" bench-collectionc.c common.c "$${COLLECTIONC}/lib/libcollectc.a" -o bench-collectionc.exe
|
||||
@./bench-collectionc.exe 10
|
||||
@./bench-collectionc.exe 20
|
||||
@./bench-collectionc.exe 30
|
||||
@./bench-collectionc.exe 40
|
||||
@./bench-collectionc.exe 41
|
||||
@./bench-collectionc.exe 50
|
||||
|
||||
# TOMMYDS shall point to the source directory.
|
||||
bench-tommyds:
|
||||
@if test -n "$${TOMMYDS}" ; then $(MAKE) bench-tommyds0 ; else echo "Nothing to be done for TOMMYDS." ; fi
|
||||
|
||||
bench-tommyds0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${TOMMYDS}" bench-tommyds.c $${TOMMYDS}/tommyds/tommyarray.c $${TOMMYDS}/tommyds/tommylist.c $${TOMMYDS}/tommyds/tommytree.c $${TOMMYDS}/tommyds/tommyhashlin.c common.c -o bench-tommyds.exe
|
||||
@./bench-tommyds.exe 10
|
||||
@./bench-tommyds.exe 20
|
||||
@./bench-tommyds.exe 30
|
||||
@./bench-tommyds.exe 40
|
||||
@./bench-tommyds.exe 41
|
||||
|
||||
# FLATHASHMAP shall point to the directory where the headers are
|
||||
bench-flathashmap:
|
||||
@if test -n "$${FLATHASHMAP}" ; then $(MAKE) bench-flathashmap0 ; else echo "Nothing to be done for FLATHASHMAP." ; fi
|
||||
|
||||
bench-flathashmap0:
|
||||
$(CXX) -std=c++14 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${FLATHASHMAP}" bench-flathashmap.cpp common.c -o bench-flathashmap.exe
|
||||
@./bench-flathashmap.exe 41
|
||||
@./bench-flathashmap.exe 42
|
||||
@./bench-flathashmap.exe 46
|
||||
@./bench-flathashmap.exe 43
|
||||
|
||||
# EMILIB shall point to the directory where the headers are
|
||||
bench-emilib:
|
||||
@if test -n "$${EMILIB}" ; then $(MAKE) bench-emilib0 ; else echo "Nothing to be done for EMILIB." ; fi
|
||||
|
||||
bench-emilib0:
|
||||
$(CXX) -std=c++14 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${EMILIB}" bench-emilib.cpp common.c -o bench-emilib.exe
|
||||
@./bench-emilib.exe 41
|
||||
@./bench-emilib.exe 42
|
||||
@./bench-emilib.exe 46
|
||||
@./bench-emilib.exe 43
|
||||
|
||||
# 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
|
||||
|
||||
bench-hopscotchmap0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${HOPSCOTCHMAP}/include/tsl" bench-hopscotchmap.cpp common.c -o bench-hopscotchmap.exe
|
||||
@./bench-hopscotchmap.exe 41
|
||||
@./bench-hopscotchmap.exe 42
|
||||
@./bench-hopscotchmap.exe 43
|
||||
|
||||
# UTHASH shall point to the directory where the source are
|
||||
bench-uthash:
|
||||
@if test -n "$${UTHASH}" ; then $(MAKE) bench-uthash0 ; else echo "Nothing to be done for UTHASH." ; fi
|
||||
|
||||
bench-uthash0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${UTHASH}" bench-uthash.c common.c -o bench-uthash.exe
|
||||
@./bench-uthash.exe 10
|
||||
@./bench-uthash.exe 20
|
||||
@./bench-uthash.exe 40
|
||||
@./bench-uthash.exe 41
|
||||
@./bench-uthash.exe 50
|
||||
|
||||
# QLIBC shall point to the directory where the library is installed.
|
||||
bench-qlibc:
|
||||
@if test -n "$${QLIBC}" ; then $(MAKE) bench-qlibc0 ; else echo "Nothing to be done for QLIBC." ; fi
|
||||
|
||||
bench-qlibc0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${QLIBC}/include" -L "$${QLIBC}/lib" -lqlibc -pthread bench-qlibc.c common.c -o bench-qlibc.exe
|
||||
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 10
|
||||
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 20
|
||||
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 30
|
||||
|
||||
# LIBSRT shall point to the directory where it is installed
|
||||
bench-libsrt:
|
||||
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-libsrt0 ; else echo "Nothing to be done for LIBSRT." ; fi
|
||||
|
||||
bench-libsrt0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/src" bench-libsrt.c common.c -o bench-libsrt.exe $${LIBSRT}/src/.libs/libsrt.a
|
||||
@./bench-libsrt.exe 20
|
||||
@./bench-libsrt.exe 50
|
||||
|
||||
|
||||
# LIBLFDS shall point to the directory where the bin/build/inc/obj/src directories are
|
||||
# The library shall be built.
|
||||
bench-liblfds:
|
||||
@if test -n "$${LIBLFDS}" ; then $(MAKE) bench-liblfds0 ; else echo "Nothing to be done for LIBLFDS." ; fi
|
||||
bench-liblfds0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBLFDS}/inc" -Wno-unknown-pragmas bench-liblfds.c common.c -DMULTI_THREAD_MEASURE -o bench-liblfds.exe $${LIBLFDS}/bin/liblfds711.a -lpthread
|
||||
@LD_LIBRARY_PATH="$${LIBLFDS}/bin:$${LD_LIBRARY_PATH}" ./bench-liblfds.exe 60
|
||||
|
||||
|
||||
# CONCURRENTQUEUE shall point to the directory where the bin/build/inc/obj/src directories are
|
||||
# The library shall be built.
|
||||
bench-concurrentqueue:
|
||||
@if test -n "$${CONCURRENTQUEUE}" ; then $(MAKE) bench-concurrentqueue0 ; else echo "Nothing to be done for CONCURRENTQUEUE." ; fi
|
||||
bench-concurrentqueue0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${CONCURRENTQUEUE}/" bench-concurrentqueue.cpp common.c -DMULTI_THREAD_MEASURE -o bench-concurrentqueue.exe -lpthread
|
||||
@./bench-concurrentqueue.exe 60
|
||||
|
||||
|
||||
# XXHASH shall point to the source directory of xxhash
|
||||
# The library shall be built.
|
||||
bench-xxhash:
|
||||
@if test -n "$${XXHASH}" ; then $(MAKE) bench-xxhash0 ; else echo "Nothing to be done for XXHASH." ; fi
|
||||
bench-xxhash0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${XXHASH}/" bench-xxhash.c common.c "$${XXHASH}/libxxhash.a" -o bench-xxhash.exe
|
||||
@./bench-xxhash.exe 70
|
||||
|
||||
# BOOST shall point to the header location.
|
||||
bench-boost:
|
||||
@if test -n "$${BOOST}" ; then $(MAKE) bench-boost0 ; else echo "Nothing to be done for BOOST." ; fi
|
||||
bench-boost0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${BOOST}" bench-boost.cpp common.c -DMULTI_THREAD_MEASURE -o bench-boost.exe -lpthread
|
||||
@./bench-boost.exe 60
|
||||
|
||||
# NEDTRIES shall point to the header location.
|
||||
bench-nedtries:
|
||||
@if test -n "$${NEDTRIES}" ; then $(MAKE) bench-nedtries0 ; else echo "Nothing to be done for NEDTRIES." ; fi
|
||||
bench-nedtries0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${NEDTRIES}" bench-nedtries.c common.c -o bench-nedtries.exe
|
||||
@./bench-nedtries.exe 40
|
||||
@./bench-nedtries.exe 45
|
||||
|
||||
# RIGTORP_HASHMAP shall point to the directory where the headers are
|
||||
bench-rigtorp-hashmap:
|
||||
@if test -n "$${RIGTORP_HASHMAP}" ; then $(MAKE) bench-rigtorp-hashmap0 ; else echo "Nothing to be done for RIGTORP_HASHMAP." ; fi
|
||||
|
||||
bench-rigtorp-hashmap0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RIGTORP_HASHMAP}/include" bench-rigtorp-hashmap.cpp common.c -o bench-rigtorp-hashmap.exe
|
||||
@./bench-rigtorp-hashmap.exe 42
|
||||
@./bench-rigtorp-hashmap.exe 41
|
||||
@./bench-rigtorp-hashmap.exe 43
|
||||
|
||||
# RIGTORP_MPMC_QUEUE shall point to the directory where the headers are
|
||||
bench-rigtorp-mpmc-queue:
|
||||
@if test -n "$${RIGTORP_MPMC_QUEUE}" ; then $(MAKE) bench-rigtorp-mpmc-queue0 ; else echo "Nothing to be done for RIGTORP_MPMC_QUEUE." ; fi
|
||||
bench-rigtorp-mpmc-queue0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RIGTORP_MPMC_QUEUE}" bench-rigtorp-mpmcqueue.cpp common.c -DMULTI_THREAD_MEASURE -o bench-mpmcqueue.exe -lpthread
|
||||
@./bench-mpmcqueue.exe 60
|
||||
|
||||
# CTL shall point to the source directory (not where the headers are)
|
||||
bench-ctl:
|
||||
@if test -n "$${CTL}" ; then $(MAKE) bench-ctl0 ; else echo "Nothing to be done for CTL." ; fi
|
||||
|
||||
bench-ctl0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${CTL} bench-ctl.c common.c -o bench-ctl.exe
|
||||
@./bench-ctl.exe 10
|
||||
@./bench-ctl.exe 20
|
||||
@./bench-ctl.exe 30
|
||||
@./bench-ctl.exe 40
|
||||
@./bench-ctl.exe 50
|
||||
|
||||
# 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
|
||||
|
||||
# CCLIB shall point to the source directory of CC (where the headers are)
|
||||
bench-CC:
|
||||
@if test -n "$${CCLIB}" ; then $(MAKE) bench-CC0 ; else echo "Nothing to be done for CC." ; fi
|
||||
|
||||
bench-CC0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${CCLIB}/ bench-CC.c common.c -o bench-CC.exe
|
||||
@./bench-CC.exe 10
|
||||
@./bench-CC.exe 20
|
||||
@./bench-CC.exe 40
|
||||
@./bench-CC.exe 41
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-mlib-json: bench-mlib
|
||||
@./bench-mlib.exe 110
|
||||
@./bench-mlib.exe 111
|
||||
@./bench-mlib.exe 112
|
||||
|
||||
bench-rapidjson:
|
||||
@if test -n "$${RAPIDJSON}" ; then $(MAKE) bench-rapidjson0 ; else echo "Nothing to be done for RAPIDJSON." ; fi
|
||||
bench-rapidjson0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RAPIDJSON}/" bench-rapidjson.cpp common.c -o bench-rapidjson.exe
|
||||
@./bench-rapidjson.exe 110
|
||||
@./bench-rapidjson.exe 111
|
||||
@./bench-rapidjson.exe 112
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-plain:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-plain-c.c -o bench-plain-c.exe
|
||||
@./bench-plain-c.exe
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-mempool:
|
||||
@if test -n "$${BOOST}" ; then if test -n "$${GLIB}" ; then make bench-mempool0 BENCH_DEF="-DUSE_BOOST -DUSE_GLIB `pkg-config --libs --cflags glib-2.0` -lboost_system" ; else make bench-mempool0 BENCH_DEF="-DUSE_BOOST -lboost_system" ; fi ; else if test -n "$${GLIB}" ; then make bench-mempool0 BENCH_DEF="-DUSE_GLIB `pkg-config --libs --cflags glib-2.0`" ; else make bench-mempool0 ; fi ; fi
|
||||
bench-mempool0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) pool.cc $(BENCH_DEF) -o bench-mempool.exe
|
||||
@./bench-mempool.exe
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-maxdict:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) max-dict.c -o bench-max-dict.exe
|
||||
@./bench-max-dict.exe
|
||||
|
||||
############################################################################
|
||||
|
||||
# BSTRLIB shall point to the BSTRLIB sources
|
||||
# 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}/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:
|
||||
@if test -n "$${SDS}" ; then $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF) -fpermissive -DBENCH_CAN_USE_SDS -I$${SDS}/ $${SDS}/sds.o" ; else $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
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
|
||||
@./bench-string-2.exe 2000000 0
|
||||
@./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"
|
||||
$(MAKE) bench-string XCFLAGS="-fprofile-use=pgo"
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-find-sort:
|
||||
g++ bench-find-sort.cpp -O2 -march=native -std=c++11 -I.. -g common.c -o bench-find-sort.exe
|
||||
./bench-find-sort.exe 10000000
|
||||
|
||||
############################################################################
|
||||
|
||||
clean:
|
||||
$(RM) *.o bench-*.exe
|
||||
$(RM) bench-*.s *~ massif.out.*
|
||||
$(RM) plot-*.dat
|
||||
$(RM) pgo
|
||||
$(RM) tmp-serial.*
|
||||
cd nucleotide && $(MAKE) clean
|
||||
|
||||
############################################################################
|
||||
|
||||
massif-do: all
|
||||
@valgrind --tool=massif ./bench-mlib.exe $(N)
|
||||
@valgrind --tool=massif ./bench-mlib-mempool.exe $(N)
|
||||
@valgrind --tool=massif ./bench-stl.exe $(N)
|
||||
@valgrind --tool=massif ./bench-qt.exe $(N)
|
||||
@valgrind --tool=massif ./bench-glib.exe $(N)
|
||||
@test -f ./bench-klib.exe && valgrind --tool=massif ./bench-klib.exe $(N)
|
||||
@test -f ./bench-libdynamic.exe && valgrind --tool=massif ./bench-libdynamic.exe $(N)
|
||||
|
||||
massif-visu:
|
||||
test -f massif.out.* || $(MAKE) massif-do
|
||||
for i in massif.out.* ; do ms_print $$i|head -30 ; done
|
||||
@@ -1,140 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "cc.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
vec( unsigned int ) a1, a2;
|
||||
init(&a1);
|
||||
init(&a2);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
push(&a1, rand_get() );
|
||||
push(&a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *get(&a1, i ) * *get(&a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
cleanup(&a1);
|
||||
cleanup(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_list(size_t n)
|
||||
{
|
||||
list( unsigned int ) a1, a2;
|
||||
init(&a1);
|
||||
init(&a2);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
push(&a1, rand_get() );
|
||||
push(&a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned *it1 = first( &a1 ), *it2 = first( &a2 ); it1 != end( &a1 ); it1 = next( &a1, it1 ), it2 = next(&a2, it2) ) {
|
||||
s += *it1 * *it2;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
cleanup(&a1);
|
||||
cleanup(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
map( unsigned long, unsigned long ) dict;
|
||||
init(&dict);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long value = rand_get();
|
||||
unsigned long key = rand_get();
|
||||
insert(&dict, key, value);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long key = rand_get();
|
||||
const unsigned long *val = get(&dict, key);
|
||||
if (val != NULL)
|
||||
s += *val;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
cleanup(&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 bool char_cmp (const char_array_t *a, const char_array_t *b) { return strcmp(a->a,b->a); }
|
||||
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 CC_DTOR char_array_t, { char_clear(&val); }
|
||||
#define CC_CMPR char_array_t, { return char_cmp(&val_1, &val_2); }
|
||||
#define CC_HASH char_array_t, { return char_hash(&val); }
|
||||
#include "cc.h"
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
map( char_array_t, char_array_t) dict;
|
||||
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());
|
||||
insert(&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 char_array_t *val = get(&dict, s1);
|
||||
if (val != NULL)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
cleanup(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("CC", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <boost/lockfree/queue.hpp>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
boost::lockfree::queue<unsigned int, boost::lockfree::capacity<4*64>> g_buff;
|
||||
boost::lockfree::queue<unsigned long long, boost::lockfree::capacity<4*64>> g_final;
|
||||
|
||||
static void final(void *arg)
|
||||
{
|
||||
size_t *p_n = (size_t*) arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long j, s = 0;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
while (!g_final.pop(j));
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso(void *arg)
|
||||
{
|
||||
unsigned int j;
|
||||
size_t *p_n = (size_t*)arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long s = 0;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
while (!g_buff.pop(j));
|
||||
s += j;
|
||||
}
|
||||
while (!g_final.push(s));
|
||||
}
|
||||
|
||||
static void prod(void *arg)
|
||||
{
|
||||
size_t *p_n = (size_t*)arg;
|
||||
size_t n = *p_n;
|
||||
size_t r = n;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
while (!g_buff.push(r));
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_queue(size_t n)
|
||||
{
|
||||
const int cpu_count = get_cpu_count();
|
||||
const int prod_count = cpu_count/2;
|
||||
const int conso_count = cpu_count - prod_count;
|
||||
if (cpu_count < 2) {
|
||||
fprintf(stderr, "WARNING: Can not measure Buffer performance.\n");
|
||||
return;
|
||||
}
|
||||
rand_get();
|
||||
// Create thread
|
||||
m_thread_t idx_p[prod_count];
|
||||
m_thread_t idx_c[conso_count];
|
||||
m_thread_t idx_final;
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_create (idx_p[i], prod, &n);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_create (idx_c[i], conso, &n);
|
||||
}
|
||||
size_t n2 = conso_count;
|
||||
m_thread_create(idx_final, final, &n2);
|
||||
|
||||
// Wait for jobs to be done.
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_join(idx_p[i]);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_join(idx_c[i]);
|
||||
}
|
||||
m_thread_join(idx_final);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("BOOST-LOCKFREE", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "macro_collections.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
// CMC list are dynamic array
|
||||
#define MY_LIST_PARAMS (list_uint, list_uint_s, , , unsigned int)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, LIST, MY_LIST_PARAMS, (STR))
|
||||
|
||||
struct list_uint_s_fval list_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
struct list_uint_s *a1 = list_uint_new(1, &list_fval);
|
||||
struct list_uint_s *a2 = list_uint_new(1, &list_fval);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
list_uint_push_back(a1, rand_get() );
|
||||
list_uint_push_back(a2, rand_get() );
|
||||
}
|
||||
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += list_uint_get(a1, i ) * list_uint_get(a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
list_uint_free(a1);
|
||||
list_uint_free(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define my_cmp(a,b) ( (a) < (b) ? -1 : (a) > (b) )
|
||||
|
||||
#define MY_TMAP_PARAMS (tree_ulong, tree_ulong_s, , unsigned long, bool)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, TREEMAP, MY_TMAP_PARAMS, (STR))
|
||||
|
||||
int cmp_ulong(unsigned long a, unsigned long b) { return my_cmp(a,b); }
|
||||
|
||||
struct tree_ulong_s_fkey tree_fkey = { .cmp = cmp_ulong,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
struct tree_ulong_s_fval tree_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
struct tree_ulong_s *tree;
|
||||
tree = tree_ulong_new(&tree_fkey, &tree_fval);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
tree_ulong_insert(tree, j, true);
|
||||
}
|
||||
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
if (tree_ulong_get_ref(tree, j) != 0)
|
||||
s+= j;
|
||||
}
|
||||
g_result = s;
|
||||
tree_ulong_free(tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
#define hash_func(a) kh_int64_hash_func(a)
|
||||
size_t hash_ulong(unsigned long a)
|
||||
{
|
||||
return ( (a) >> 33 ) ^ (a) ^ ((a) << 11);
|
||||
}
|
||||
|
||||
#define MY_DICT_PARAMS (hmap, hmap_s, , unsigned long, unsigned long)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, HASHMAP, MY_DICT_PARAMS, (STR))
|
||||
|
||||
struct hmap_s_fkey hmap_fkey = { .cmp = cmp_ulong,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = hash_ulong,
|
||||
.pri = NULL };
|
||||
|
||||
struct hmap_s_fval hmap_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
struct hmap_s *dict = hmap_new(16, 0.7, &hmap_fkey, &hmap_fval);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
hmap_insert(dict, rand_get(), rand_get());
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long *val = hmap_get_ref(dict, rand_get());
|
||||
if (val != 0)
|
||||
s += *val;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
hmap_free(dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#if 0 // Not working issue in using not integer types
|
||||
|
||||
typedef struct {
|
||||
char a[256];
|
||||
} char_array_t;
|
||||
static inline int char_cmp (const char_array_t a, const char_array_t b) { return strcmp(a.a,b.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 MY_DICTB_PARAMS (bhmap, bhmap_s, , char_array_t, char_array_t)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, HASHMAP, MY_DICT_PARAMS, (STR))
|
||||
|
||||
struct bhmap_s_fkey bhmap_fkey = { .cmp = char_cmp,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = char_hash,
|
||||
.pri = NULL };
|
||||
|
||||
struct bhmap_s_fval bhmap_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
struct bhmap_s *dict = bhmap_new(16, 0.7, &bhmap_fkey, &bhmap_fval);
|
||||
|
||||
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());
|
||||
bhmap_insert(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() );
|
||||
char_array_t *val = bhmap_get_ref(dict, s1);
|
||||
if (val != 0)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
bhmap_free(dict);
|
||||
}
|
||||
#endif
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 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},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("CMC", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "array.h"
|
||||
#include "slist.h"
|
||||
#include "treetable.h"
|
||||
#include "hashtable.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
Array *a1, *a2;
|
||||
enum cc_stat stat;
|
||||
|
||||
stat = array_new(&a1);
|
||||
if (stat != CC_OK) abort();
|
||||
stat = array_new(&a2);
|
||||
if (stat != CC_OK) abort();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
stat = array_add(a1, (void*) (uintptr_t)rand_get() );
|
||||
if (stat != CC_OK) abort();
|
||||
stat = array_add(a2, (void*) (uintptr_t)rand_get() );
|
||||
if (stat != CC_OK) abort();
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
void *e, *f;
|
||||
stat = array_get_at(a1, i, &e);
|
||||
if (stat != CC_OK) abort();
|
||||
stat = array_get_at(a2, i, &f);
|
||||
if (stat != CC_OK) abort();
|
||||
s += ((unsigned int)(uintptr_t) e) * ((unsigned int)(uintptr_t) f);
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
array_destroy(a1);
|
||||
array_destroy(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_list(size_t n)
|
||||
{
|
||||
SList *a1, *a2;
|
||||
enum cc_stat stat;
|
||||
|
||||
stat = slist_new(&a1);
|
||||
if (stat != CC_OK) abort();
|
||||
stat = slist_new(&a2);
|
||||
if (stat != CC_OK) abort();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
stat = slist_add(a1, (void*) (uintptr_t)rand_get() );
|
||||
if (stat != CC_OK) abort();
|
||||
stat = slist_add(a2, (void*) (uintptr_t)rand_get() );
|
||||
if (stat != CC_OK) abort();
|
||||
}
|
||||
unsigned int s = 0;
|
||||
SListIter iter1, iter2;
|
||||
void *e, *f;
|
||||
slist_iter_init(&iter1, a1);
|
||||
slist_iter_init(&iter2, a2);
|
||||
while (slist_iter_next(&iter1, &e) == CC_OK && slist_iter_next(&iter2, &f) == CC_OK) {
|
||||
s += ((unsigned int)(uintptr_t) e) * ((unsigned int)(uintptr_t) f);
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
slist_destroy(a1);
|
||||
slist_destroy(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static int compare(const void *a, const void *b)
|
||||
{
|
||||
const uintptr_t pa = (uintptr_t) a;
|
||||
const uintptr_t pb = (uintptr_t) b;
|
||||
return (pa < pb) ? -1 : (pa > pb);
|
||||
}
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
TreeTable *tree;
|
||||
enum cc_stat stat;
|
||||
|
||||
stat = treetable_new(compare, &tree);
|
||||
if (stat != CC_OK) abort();
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
void *key = (void*)(uintptr_t) rand_get();
|
||||
stat = treetable_add(tree, key, key);
|
||||
if (stat != CC_OK) abort();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
void *e;
|
||||
void *key = (void*) (uintptr_t) rand_get();
|
||||
stat = treetable_get(tree, key, &e);
|
||||
if (stat == CC_OK)
|
||||
s += (uintptr_t)e;
|
||||
}
|
||||
g_result = s;
|
||||
treetable_destroy(tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static size_t hash_func (const void *key, int l, uint32_t seed)
|
||||
{
|
||||
const unsigned long pa = (uintptr_t) key;
|
||||
(void)l;
|
||||
return pa ^ seed;
|
||||
}
|
||||
|
||||
static int equal_func(const void *key1, const void *key2)
|
||||
{
|
||||
const unsigned long pa = (uintptr_t) key1;
|
||||
const unsigned long pb = (uintptr_t) key2;
|
||||
return (pa < pb) ? -1 : pa > pb;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
HashTable *dict;
|
||||
enum cc_stat stat;
|
||||
HashTableConf htc;
|
||||
hashtable_conf_init(&htc);
|
||||
htc.hash = hash_func;
|
||||
htc.key_compare = equal_func;
|
||||
stat = hashtable_new_conf(&htc, &dict);
|
||||
if (stat != CC_OK) abort();
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
void *value = (void*)(uintptr_t) rand_get();
|
||||
void *key = (void*)(uintptr_t) rand_get();
|
||||
stat = hashtable_add(dict, key, value );
|
||||
if (stat != CC_OK) abort();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
void *key = (void*)(uintptr_t) rand_get();
|
||||
void *r;
|
||||
stat = hashtable_get(dict, key, &r);
|
||||
if (stat == CC_OK)
|
||||
s += (uintptr_t) r;
|
||||
}
|
||||
g_result = s;
|
||||
hashtable_destroy(dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef char char_array_t[256];
|
||||
|
||||
static int char_equal (const void* a, const void * b)
|
||||
{
|
||||
const char_array_t *pa = (const char_array_t *)a;
|
||||
const char_array_t *pb = (const char_array_t *)b;
|
||||
return strcmp(*pa,*pb);
|
||||
}
|
||||
|
||||
static size_t char_hash(const void *a, int l, uint32_t seed)
|
||||
{
|
||||
const char_array_t *pa = (const char_array_t *)a;
|
||||
const char *s = *pa;
|
||||
(void)l ;
|
||||
size_t hash = seed;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
HashTable *dict;
|
||||
enum cc_stat stat;
|
||||
HashTableConf htc;
|
||||
hashtable_conf_init(&htc);
|
||||
htc.hash = char_hash;
|
||||
htc.key_compare = char_equal;
|
||||
stat = hashtable_new_conf(&htc, &dict);
|
||||
if (stat != CC_OK) abort();
|
||||
|
||||
char_array_t **tab = malloc (sizeof(char_array_t *)*2*n);
|
||||
if (!tab) abort();
|
||||
size_t cpt = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t *key = malloc (sizeof (char_array_t));
|
||||
char_array_t *value = malloc (sizeof (char_array_t));
|
||||
tab[cpt++] = key;
|
||||
tab[cpt++] = value;
|
||||
sprintf(*key, "%u", rand_get());
|
||||
sprintf(*value, "%u", rand_get());
|
||||
stat = hashtable_add(dict, key, value );
|
||||
if (stat != CC_OK) abort();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1;
|
||||
void *r;
|
||||
sprintf(s1, "%u", rand_get());
|
||||
stat = hashtable_get(dict, s1, &r);
|
||||
if (stat == CC_OK)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
hashtable_destroy(dict);
|
||||
if (cpt != 2*n) abort();
|
||||
for(size_t i = 0; i < 2*n;i++)
|
||||
free(tab[i]);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static int cmp_float(const void * a, const void *b)
|
||||
{
|
||||
const float *const*pa = a, *const*pb = b;
|
||||
return (**pa < **pb) ? -1 : (**pa > **pb);
|
||||
}
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
Array *a1;
|
||||
enum cc_stat stat;
|
||||
|
||||
stat = array_new(&a1);
|
||||
if (stat != CC_OK) abort();
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
float *v = malloc(sizeof(float));
|
||||
*v = rand_get();
|
||||
stat = array_add(a1, v );
|
||||
if (stat != CC_OK) abort();
|
||||
}
|
||||
array_sort(a1, cmp_float);
|
||||
void *e;
|
||||
stat = array_get_at(a1, 0, &e);
|
||||
if (stat != CC_OK) abort();
|
||||
g_result = *(float*)e;
|
||||
array_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("CollectionC", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "concurrentqueue.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
moodycamel::ConcurrentQueue<unsigned int> g_buff;
|
||||
moodycamel::ConcurrentQueue<unsigned long long> g_final;
|
||||
|
||||
static void final(void *arg)
|
||||
{
|
||||
size_t *p_n = (size_t*) arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long j, s = 0;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
while (!g_final.try_dequeue(j));
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso(void *arg)
|
||||
{
|
||||
unsigned int j;
|
||||
size_t *p_n = (size_t*)arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long s = 0;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
while (!g_buff.try_dequeue(j));
|
||||
s += j;
|
||||
}
|
||||
while (!g_final.try_enqueue(s));
|
||||
}
|
||||
|
||||
static void prod(void *arg)
|
||||
{
|
||||
size_t *p_n = (size_t*)arg;
|
||||
size_t n = *p_n;
|
||||
size_t r = n;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
while (!g_buff.try_enqueue(r));
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_queue(size_t n)
|
||||
{
|
||||
const int cpu_count = get_cpu_count();
|
||||
const int prod_count = cpu_count/2;
|
||||
const int conso_count = cpu_count - prod_count;
|
||||
if (cpu_count < 2) {
|
||||
fprintf(stderr, "WARNING: Can not measure Buffer performance.\n");
|
||||
return;
|
||||
}
|
||||
rand_get();
|
||||
// Create thread
|
||||
m_thread_t idx_p[prod_count];
|
||||
m_thread_t idx_c[conso_count];
|
||||
m_thread_t idx_final;
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_create (idx_p[i], prod, &n);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_create (idx_c[i], conso, &n);
|
||||
}
|
||||
size_t n2 = conso_count;
|
||||
m_thread_create(idx_final, final, &n2);
|
||||
|
||||
// Wait for jobs to be done.
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_join(idx_p[i]);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_join(idx_c[i]);
|
||||
}
|
||||
m_thread_join(idx_final);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("CONCURRENT-QUEUE", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "m-core.h"
|
||||
#include "common.h"
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
/********************************************************************************************/
|
||||
#define POD
|
||||
#define T uint
|
||||
#include "ctl/vector.h"
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
vec_uint a1 = vec_uint_init();
|
||||
vec_uint a2 = vec_uint_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
vec_uint_push_back(&a1, rand_get() );
|
||||
vec_uint_push_back(&a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *vec_uint_at(&a1, i ) * *vec_uint_at(&a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
vec_uint_free(&a1);
|
||||
vec_uint_free(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T uint
|
||||
#include "ctl/forward_list.h"
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
slist_uint a1 = slist_uint_init();
|
||||
slist_uint a2 = slist_uint_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
slist_uint_push_front(&a1, rand_get());
|
||||
slist_uint_push_front(&a2, rand_get());
|
||||
}
|
||||
unsigned int s = 0;
|
||||
slist_uint_it it1 = slist_uint_begin(&a1);
|
||||
slist_uint_it it2 = slist_uint_begin(&a2);
|
||||
for( ; !slist_uint_it_done(&it1) ;
|
||||
slist_uint_it_next(&it1), slist_uint_it_next(&it2)) {
|
||||
s += *slist_uint_it_ref(&it1) * *slist_uint_it_ref(&it2);
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
slist_uint_free(&a1);
|
||||
slist_uint_free(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T ulong
|
||||
#include "ctl/set.h"
|
||||
|
||||
static inline int
|
||||
int_cmp(ulong *a, ulong *b) {
|
||||
return *a < *b;
|
||||
}
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
set_ulong tree = set_ulong_init (int_cmp);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
set_ulong_insert (&tree, rand_get() );
|
||||
}
|
||||
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
if (set_ulong_find_node(&tree, j) != NULL)
|
||||
s+= j;
|
||||
}
|
||||
g_result = s;
|
||||
set_ulong_free(&tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
} pair_ulong;
|
||||
|
||||
// Use of M*LIB hash function
|
||||
static inline size_t
|
||||
pair_ulong_hash(pair_ulong *a)
|
||||
{
|
||||
return M_HASH_DEFAULT(a->key);
|
||||
}
|
||||
|
||||
static inline int
|
||||
pair_ulong_equal(pair_ulong *a, pair_ulong *b)
|
||||
{
|
||||
return a->key == b->key;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pair_ulong_free(pair_ulong *a) {
|
||||
(void) a;
|
||||
}
|
||||
|
||||
static inline pair_ulong
|
||||
pair_ulong_copy(pair_ulong *self) {
|
||||
return (pair_ulong) { .key = self->key, .value = self->value };
|
||||
}
|
||||
|
||||
#define T pair_ulong
|
||||
#include <ctl/unordered_map.h>
|
||||
|
||||
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++) {
|
||||
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;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
umap_pair_ulong_it it = umap_pair_ulong_find(&dict, (pair_ulong) { rand_get() , 0 } );
|
||||
if (!umap_pair_ulong_it_done(&it) )
|
||||
s += it.ref->value;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
umap_pair_ulong_free(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T float
|
||||
#include "ctl/vector.h"
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
vec_float a1 = vec_float_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
vec_float_push_back(&a1, rand_get());
|
||||
}
|
||||
vec_float_sort(&a1);
|
||||
g_result = *vec_float_at(&a1, 0);
|
||||
vec_float_free(&a1);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 50, "Sort", 10000000, 0, test_sort, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("CTL", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
#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 <google/dense_hash_map>
|
||||
|
||||
using google::dense_hash_map;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
dense_hash_map<unsigned long, unsigned long> dict;
|
||||
dict.set_empty_key(-1);
|
||||
dict.set_deleted_key(-2);
|
||||
|
||||
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++) {
|
||||
dense_hash_map<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
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;
|
||||
};
|
||||
};
|
||||
namespace tr1 {
|
||||
template <> struct hash<char_array_s> {
|
||||
std::size_t operator()(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)
|
||||
{
|
||||
dense_hash_map<char_array_s, char_array_s> dict;
|
||||
struct char_array_s empty, del;
|
||||
memset(&empty, 0, sizeof empty); empty.a[1] = 255;
|
||||
memset(&del, 0, sizeof del); del.a[1] = 255;
|
||||
dict.set_empty_key(empty);
|
||||
dict.set_deleted_key(del);
|
||||
|
||||
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());
|
||||
dense_hash_map<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)
|
||||
{
|
||||
dense_hash_map<string, string> dict;
|
||||
string empty, del;
|
||||
empty = "";
|
||||
del = "DEL";
|
||||
dict.set_empty_key(empty);
|
||||
dict.set_deleted_key(del);
|
||||
|
||||
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();
|
||||
dense_hash_map<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}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("DENSE-HASPMAP", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "emilib/hash_map.hpp"
|
||||
|
||||
using namespace emilib;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[rand_get()] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict2_linear(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[i] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long>::iterator it = dict.find(i);
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
struct char_array_s {
|
||||
char a[256];
|
||||
char_array_s () { a[0] = 0 ; }
|
||||
char_array_s ( const char_array_s & other) { strcpy(a, other.a); }
|
||||
bool operator==(const char_array_s &other) const { return strcmp(a, other.a) == 0; }
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <> struct hash<char_array_s> {
|
||||
std::size_t operator()(const char_array_s &k) const {
|
||||
size_t hash = 0;
|
||||
const char *s = k.a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
HashMap<char_array_s, char_array_s> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
HashMap<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
HashMap<string, string> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
HashMap<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict", 1000000, 0, test_dict2, 0},
|
||||
{ 43, "DictStr", 1000000, 0, test_dict_str, 0},
|
||||
{ 46, "DictLinear", 1000000, 0, test_dict2_linear, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("EMILIB", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
// program to find longest contiguous subsequence
|
||||
// based on https://www.geeksforgeeks.org/longest-consecutive-subsequence/
|
||||
#include <iostream>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Returns length of the longest contiguous subsequence
|
||||
int cpp_find_longest(int arr[], int n)
|
||||
{
|
||||
unordered_set<int> S;
|
||||
int ans = 0;
|
||||
|
||||
// Hash all the array elements
|
||||
for (int i = 0; i < n; i++)
|
||||
S.insert(arr[i]);
|
||||
|
||||
// check each possible sequence from
|
||||
// the start then update optimal length
|
||||
for (int i = 0; i < n; i++) {
|
||||
// if current element is the starting
|
||||
// element of a sequence
|
||||
if (S.find(arr[i] - 1) == S.end()) {
|
||||
// Then check for next elements
|
||||
// in the sequence
|
||||
int j = arr[i] + 1;
|
||||
while (S.find(j) != S.end())
|
||||
j++;
|
||||
|
||||
// update optimal length if
|
||||
// this length is more
|
||||
ans = max(ans, j - arr[i]);
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
static inline bool oor_equal_p(int a, unsigned char c) { return a == ((c == 0) ? INT_MIN : INT_MAX); }
|
||||
static inline void oor_set(int *a, unsigned char c) { *a = ((c == 0) ? INT_MIN : INT_MAX); }
|
||||
|
||||
DICT_OASET_DEF(dict_int, int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)))
|
||||
|
||||
// Returns length of the longest contiguous subsequence
|
||||
int mlib_find_longest(int arr[], int n)
|
||||
{
|
||||
dict_int_t S;
|
||||
int ans = 0;
|
||||
|
||||
dict_int_init(S);
|
||||
|
||||
// Hash all the array elements
|
||||
for (int i = 0; i < n; i++)
|
||||
dict_int_push(S, arr[i]);
|
||||
|
||||
// check each possible sequence from
|
||||
// the start then update optimal length
|
||||
for (int i = 0; i < n; i++) {
|
||||
// if current element is the starting
|
||||
// element of a sequence
|
||||
int *p = dict_int_get(S, arr[i]-1);
|
||||
if (p == NULL) {
|
||||
// Then check for next elements
|
||||
// in the sequence
|
||||
int j = arr[i] + 1;
|
||||
while (dict_int_get(S, j) != NULL)
|
||||
j++;
|
||||
|
||||
// update optimal length if
|
||||
// this length is more
|
||||
ans = M_MAX(ans, j - arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
dict_int_clear(S);
|
||||
return ans;
|
||||
}
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = argc == 1 ? 10000 : atoi(argv[1]);
|
||||
int *arr = (int*) malloc(n * sizeof(int));
|
||||
for(int i = 0; i < n; i++)
|
||||
arr[i] = rand_get();
|
||||
|
||||
unsigned long long t0 = cputime();
|
||||
cout << "Length of the Longest contiguous subsequence is "
|
||||
<< cpp_find_longest(arr, n) << endl;
|
||||
|
||||
unsigned long long t1 = cputime();
|
||||
|
||||
cout << "Length of the Longest contiguous subsequence is "
|
||||
<< mlib_find_longest(arr, n) << endl;
|
||||
unsigned long long t2 = cputime();
|
||||
|
||||
cout << "Time C++: " << (t1-t0) << " Time M*LIB: " << (t2-t1) << endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
// Need recent gcc
|
||||
#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 "flat_hash_map.hpp"
|
||||
|
||||
using namespace ska;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
flat_hash_map<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++) {
|
||||
flat_hash_map<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)
|
||||
{
|
||||
flat_hash_map<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++) {
|
||||
flat_hash_map<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)
|
||||
{
|
||||
flat_hash_map<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());
|
||||
flat_hash_map<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)
|
||||
{
|
||||
flat_hash_map<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();
|
||||
flat_hash_map<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("FLAT-HASPMAP", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
GArray *a1, *a2;
|
||||
a1 = g_array_new (FALSE, FALSE, sizeof (unsigned int));
|
||||
a2 = g_array_new (FALSE, FALSE, sizeof (unsigned int));
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int v = rand_get();
|
||||
g_array_append_val(a1, v );
|
||||
v = rand_get();
|
||||
g_array_append_val(a2, v );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += g_array_index(a1, unsigned int, i ) * g_array_index(a2, unsigned int, i );
|
||||
}
|
||||
g_result = s;
|
||||
g_array_free(a1, FALSE);
|
||||
g_array_free(a2, FALSE);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
GSList *a1 = NULL, *a2 = NULL;
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1 = g_slist_prepend (a1, GINT_TO_POINTER (rand_get() ));
|
||||
a2 = g_slist_prepend (a2, GINT_TO_POINTER (rand_get() ));
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(GSList *it1 = a1, *it2 = a2 ; it1 != NULL; it1 = g_slist_next(it1), it2 = g_slist_next(it2) ) {
|
||||
s += GPOINTER_TO_INT(it1->data) * GPOINTER_TO_INT(it2->data);
|
||||
n--;
|
||||
}
|
||||
g_result = s;
|
||||
g_slist_free(a1);
|
||||
g_slist_free(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static int compare(gconstpointer a, gconstpointer b, gpointer user_data)
|
||||
{
|
||||
const unsigned long *pa = a;
|
||||
const unsigned long *pb = b;
|
||||
(void) user_data;
|
||||
return (*pa < *pb) ? -1 : (*pa > *pb);
|
||||
}
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
GTree *tree = g_tree_new_full(compare, NULL, free, NULL);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
// NOTE: unsigned long are not designed to work with GPOINTER_TO_INT according to documentation.
|
||||
unsigned long *p = malloc(sizeof(unsigned long));
|
||||
*p = rand_get();
|
||||
g_tree_insert(tree, p, p);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long key = rand_get();
|
||||
unsigned long *p = g_tree_lookup(tree, &key);
|
||||
if (p)
|
||||
s += *p;
|
||||
}
|
||||
g_result = s;
|
||||
g_tree_destroy(tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static guint hash_func (gconstpointer a)
|
||||
{
|
||||
const unsigned long *pa = a;
|
||||
return *pa;
|
||||
}
|
||||
|
||||
static gboolean equal_func(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const unsigned long *pa = a;
|
||||
const unsigned long *pb = b;
|
||||
return *pa == *pb;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
GHashTable *dict = g_hash_table_new_full(hash_func, equal_func, free, free);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long *key = malloc(sizeof(unsigned long));
|
||||
unsigned long *value = malloc(sizeof(unsigned long));
|
||||
*key = rand_get();
|
||||
*value = rand_get();
|
||||
g_hash_table_insert(dict, key, value );
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long key = rand_get();
|
||||
unsigned long *p = g_hash_table_lookup(dict, &key);
|
||||
if (p)
|
||||
s += *p;
|
||||
}
|
||||
g_result = s;
|
||||
g_hash_table_destroy(dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef char char_array_t[256];
|
||||
|
||||
static gboolean char_equal (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const char_array_t *pa = (const char_array_t *)a;
|
||||
const char_array_t *pb = (const char_array_t *)b;
|
||||
return strcmp(*pa,*pb)==0;
|
||||
}
|
||||
|
||||
static guint char_hash(gconstpointer a)
|
||||
{
|
||||
const char_array_t *pa = (const char_array_t *)a;
|
||||
const char *s = *pa;
|
||||
guint hash = 0;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
GHashTable *dict = g_hash_table_new_full(char_hash, char_equal, free, free);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t *key = malloc (sizeof (char_array_t));
|
||||
char_array_t *value = malloc (sizeof (char_array_t));
|
||||
sprintf(*key, "%u", rand_get());
|
||||
sprintf(*value, "%u", rand_get());
|
||||
g_hash_table_insert(dict, key, value );
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1;
|
||||
sprintf(s1, "%u", rand_get());
|
||||
char_array_t *p = g_hash_table_lookup(dict, &s1);
|
||||
if (p)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
g_hash_table_destroy(dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static gint cmp_float(gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const float *pa = a, *pb = b;
|
||||
return (*pa < *pb) ? -1 : (*pa > *pb);
|
||||
}
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
GArray *a1 = g_array_new (FALSE, FALSE, sizeof (float));
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
float v = rand_get();
|
||||
g_array_append_val(a1, v );
|
||||
}
|
||||
g_array_sort(a1, cmp_float);
|
||||
g_result = g_array_index (a1, float, 0);
|
||||
g_array_free(a1, FALSE);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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("GLIB", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
#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 "hopscotch_map.h"
|
||||
|
||||
using namespace tsl;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
tsl::hopscotch_map<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++) {
|
||||
hopscotch_map<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
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)
|
||||
{
|
||||
hopscotch_map<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());
|
||||
hopscotch_map<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)
|
||||
{
|
||||
hopscotch_map<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();
|
||||
hopscotch_map<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}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("HOPSCOTCHMAP", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "kvec.h"
|
||||
#include "klist.h"
|
||||
#include "kbtree.h"
|
||||
#include "khash.h"
|
||||
#include "ksort.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
kvec_t(unsigned int) a1, a2;
|
||||
|
||||
kv_init(a1);
|
||||
kv_init(a2);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
kv_push(unsigned int, a1, rand_get() );
|
||||
kv_push(unsigned int, a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += kv_A(a1, i ) * kv_A(a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
kv_destroy(a1);
|
||||
kv_destroy(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define uint_free(x)
|
||||
KLIST_INIT(list_uint, unsigned int, uint_free)
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
klist_t(list_uint) *a1, *a2;
|
||||
a1 = kl_init(list_uint);
|
||||
a2 = kl_init(list_uint);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
*kl_pushp (list_uint, a1) = rand_get();
|
||||
*kl_pushp (list_uint, a2) = rand_get();
|
||||
}
|
||||
unsigned int s = 0;
|
||||
kliter_t(list_uint) *it1, *it2;
|
||||
for(it1 = kl_begin(a1), it2 = kl_begin(a2);
|
||||
it1 != kl_end(a1);
|
||||
it1 = kl_next(it1), it2 = kl_next(it2)) {
|
||||
s += kl_val(it1) * kl_val(it2);
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
kl_destroy(list_uint, a1);
|
||||
kl_destroy(list_uint, a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define my_cmp(a,b) ( (a) < (b) ? -1 : (a) > (b) )
|
||||
|
||||
KBTREE_INIT(kTree, unsigned long, my_cmp)
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
kbtree_t(kTree) *tree;
|
||||
tree = kb_init(kTree, KB_DEFAULT_SIZE/2);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
kb_putp(kTree, tree, &j);
|
||||
}
|
||||
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
if (kb_getp(kTree, tree, &j) != 0)
|
||||
s+= j;
|
||||
}
|
||||
g_result = s;
|
||||
kb_destroy(kTree, tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define hash_eq(a, b) ((a) == (b))
|
||||
#define hash_func(a) kh_int64_hash_func(a)
|
||||
|
||||
KHASH_INIT(iun, unsigned long, unsigned long, 1, hash_func, hash_eq)
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
khash_t(iun) *dict = kh_init(iun);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
int ret;
|
||||
khiter_t k = kh_put(iun, dict, rand_get(), &ret);
|
||||
kh_value(dict, k) = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
khiter_t k = kh_get(iun, dict, rand_get());
|
||||
if (kh_exist(dict, k))
|
||||
s += kh_value(dict, k);
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
kh_destroy(iun, 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 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;
|
||||
}
|
||||
|
||||
KHASH_INIT(iub, char_array_t, char_array_t, 1, char_hash, char_equal_p)
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
khash_t(iub) *dict = kh_init(iub);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
int ret;
|
||||
char_array_t s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
khiter_t k = kh_put(iub, dict, s1, &ret);
|
||||
char_set(&kh_value(dict, k), 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());
|
||||
khiter_t k = kh_get(iub, dict, s1);
|
||||
if (kh_exist(dict, k))
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
kh_destroy(iub, dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
// NOTE: Needed for compiling
|
||||
double drand48(void) { return rand_get(); }
|
||||
|
||||
KSORT_INIT_GENERIC(float)
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
kvec_t(float) a1;
|
||||
|
||||
kv_init(a1);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
kv_push(float, a1, rand_get() );
|
||||
}
|
||||
// NOTE: Is-it the right way to do? Seems very low level!
|
||||
ks_introsort_float(n, & kv_A(a1, 0));
|
||||
g_result = kv_A(a1, 0);
|
||||
kv_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("KLIB", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Needed due to compilation error in pool.h
|
||||
#include <pthread.h>
|
||||
|
||||
#include "dynamic.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
vector a1, a2;
|
||||
|
||||
vector_construct(&a1, sizeof(unsigned int));
|
||||
vector_construct(&a2, sizeof(unsigned int));
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int v = rand_get();
|
||||
vector_push_back(&a1, &v);
|
||||
v = rand_get();
|
||||
vector_push_back(&a2, &v);
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *(unsigned int*) vector_at(&a1, i) * *(unsigned int*) vector_at(&a2, i);
|
||||
}
|
||||
g_result = s;
|
||||
vector_destruct(&a1, NULL);
|
||||
vector_destruct(&a2, NULL);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static size_t hash_func (void *a)
|
||||
{
|
||||
return hash_data(a, sizeof (unsigned long));
|
||||
}
|
||||
|
||||
static int equal_func(void *a, void *b)
|
||||
{
|
||||
const unsigned long *pa = a;
|
||||
if (b == NULL) {
|
||||
return *pa == -1U;
|
||||
}
|
||||
const unsigned long *pb = b;
|
||||
return *pa == *pb;
|
||||
}
|
||||
|
||||
static void set_func(void *a, void *b)
|
||||
{
|
||||
unsigned long *pa = a;
|
||||
if (b == NULL) {
|
||||
*pa = -1U;
|
||||
} else {
|
||||
const unsigned long *pb = b;
|
||||
*pa = *pb;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct map_element map_element;
|
||||
struct map_element
|
||||
{
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
map dict;
|
||||
map_construct(&dict, sizeof(map_element), set_func);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
map_insert(&dict, (map_element[]) {{.key = rand_get(), .value = rand_get()}}, hash_func, set_func, equal_func, NULL);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
map_element *p = map_at(&dict, (map_element[]){{.key = rand_get()}}, hash_func, equal_func);
|
||||
if (p)
|
||||
s += p->value;
|
||||
}
|
||||
g_result = s;
|
||||
map_destruct(&dict, NULL, NULL);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef char char_array_t[256];
|
||||
|
||||
static int char_equal (void *a, void *b)
|
||||
{
|
||||
const char_array_t *pa = (const char_array_t *)a;
|
||||
if (b == NULL)
|
||||
return strcmp(*pa, "") == 0;
|
||||
const char_array_t *pb = (const char_array_t *)b;
|
||||
return strcmp(*pa,*pb)==0;
|
||||
}
|
||||
|
||||
static size_t char_hash(void *a)
|
||||
{
|
||||
char_array_t *pa = (char_array_t *)a;
|
||||
return hash_string(*pa);
|
||||
}
|
||||
|
||||
static void char_set(void *a, void *b)
|
||||
{
|
||||
char_array_t *pa = (char_array_t *)a;
|
||||
if (b == NULL) {
|
||||
strcpy(*pa, "");
|
||||
} else {
|
||||
const char_array_t *pb = (const char_array_t *)b;
|
||||
strcpy(*pa,*pb);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct big_map_element big_map_element;
|
||||
struct big_map_element
|
||||
{
|
||||
char_array_t key;
|
||||
char_array_t value;
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
map dict;
|
||||
map_construct(&dict, sizeof(big_map_element), char_set);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
big_map_element el;
|
||||
sprintf(el.key, "%u", rand_get());
|
||||
sprintf(el.value, "%u", rand_get());
|
||||
map_insert(&dict, &el, char_hash, char_set, char_equal, NULL);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
big_map_element el;
|
||||
sprintf(el.key, "%u", rand_get());
|
||||
big_map_element *p = map_at(&dict, &el, char_hash, char_equal);
|
||||
if (p)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
map_destruct(&dict, NULL, NULL);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("LIBDYNAMIC", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "liblfds711.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct lfds711_queue_bmm_state g_buff;
|
||||
struct lfds711_queue_bmm_state g_final;
|
||||
|
||||
static void final(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long j, s = 0;
|
||||
LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
|
||||
for(int i = 0; i < n;i++) {
|
||||
void *p;
|
||||
while (0 == lfds711_queue_bmm_dequeue(&g_final, &p, NULL)) { m_thread_yield(); }
|
||||
j = (uintptr_t)p;
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso(void *arg)
|
||||
{
|
||||
unsigned int j;
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long s = 0;
|
||||
LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
|
||||
for(int i = 0; i < n;i++) {
|
||||
void *p;
|
||||
while (0 == lfds711_queue_bmm_dequeue(&g_buff, &p, NULL)) { m_thread_yield(); }
|
||||
j = (uintptr_t) p;
|
||||
s += j;
|
||||
}
|
||||
while (0 == lfds711_queue_bmm_enqueue(&g_final, (void*)(uintptr_t)s, NULL)) { m_thread_yield(); }
|
||||
}
|
||||
|
||||
static void prod(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
size_t r = n;
|
||||
LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
while (0 == lfds711_queue_bmm_enqueue(&g_buff, (void*)(uintptr_t)r, NULL)) { m_thread_yield(); }
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_queue(size_t n)
|
||||
{
|
||||
const int cpu_count = get_cpu_count();
|
||||
const int prod_count = cpu_count/2;
|
||||
const int conso_count = cpu_count - prod_count;
|
||||
if (cpu_count < 2) {
|
||||
fprintf(stderr, "WARNING: Can not measure Buffer performance.\n");
|
||||
return;
|
||||
}
|
||||
rand_get();
|
||||
// Init
|
||||
const size_t size = m_core_roundpow2(64*cpu_count);
|
||||
struct lfds711_queue_bmm_element g_buff_elements[size];
|
||||
struct lfds711_queue_bmm_element g_final_elements[size];
|
||||
lfds711_queue_bmm_init_valid_on_current_logical_core(&g_buff, g_buff_elements,
|
||||
size, NULL);
|
||||
lfds711_queue_bmm_init_valid_on_current_logical_core(&g_final, g_final_elements,
|
||||
size, NULL);
|
||||
|
||||
// Create thread
|
||||
m_thread_t idx_p[prod_count];
|
||||
m_thread_t idx_c[conso_count];
|
||||
m_thread_t idx_final;
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_create (idx_p[i], prod, &n);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_create (idx_c[i], conso, &n);
|
||||
}
|
||||
size_t n2 = conso_count;
|
||||
m_thread_create(idx_final, final, &n2);
|
||||
|
||||
// Wait for jobs to be done.
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_join(idx_p[i]);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_join(idx_c[i]);
|
||||
}
|
||||
m_thread_join(idx_final);
|
||||
|
||||
// Clear & quit
|
||||
lfds711_queue_bmm_cleanup(&g_final, NULL);
|
||||
lfds711_queue_bmm_cleanup(&g_buff, NULL);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("LIBLFDS", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "svector.h"
|
||||
#include "smap.h"
|
||||
#include "smset.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
srt_vector *a1 = sv_alloc ( sizeof (unsigned int), 16, NULL);
|
||||
srt_vector *a2 = sv_alloc ( sizeof (unsigned int), 16, NULL);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int value = rand_get();
|
||||
sv_push(&a1, &value );
|
||||
value = rand_get();
|
||||
sv_push(&a2, &value );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *(unsigned int*)sv_at(a1, i ) * *(unsigned int *)sv_at(a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
sv_free(&a1);
|
||||
sv_free(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
/* There is no 'unsigned long' key in smset */
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static int cmp_float (const void *a, const void *b)
|
||||
{
|
||||
const float *pa=a;
|
||||
const float *pb = b;
|
||||
return (*pa < *pb) ? -1 : *pa > *pb;
|
||||
}
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
srt_vector *a1 = sv_alloc(sizeof(float), 16, cmp_float);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int value = rand_get();
|
||||
sv_push(&a1, &value );
|
||||
}
|
||||
sv_sort(a1);
|
||||
g_result = *(float*)sv_at(a1, 0);
|
||||
sv_free(&a1);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 50, "sort", 10000000, 0, test_sort, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("LIBSRT", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
-1086
File diff suppressed because it is too large.
Load diff
@@ -1,99 +0,0 @@
|
||||
#define NDEBUG
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "nedtrie.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct foo_s {
|
||||
NEDTRIE_ENTRY(foo_s) link;
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
} foo_t;
|
||||
typedef struct foo_tree_s foo_tree_t;
|
||||
NEDTRIE_HEAD(foo_tree_s, foo_s);
|
||||
|
||||
static inline size_t fookeyfunct(const foo_t *r)
|
||||
{
|
||||
return r->key;
|
||||
}
|
||||
|
||||
NEDTRIE_GENERATE(static, foo_tree_s, foo_s, link, fookeyfunct, NEDTRIE_NOBBLEZEROS(foo_tree_s))
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
foo_tree_t footree;
|
||||
NEDTRIE_INIT(&footree);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long key = rand_get();
|
||||
unsigned long val = rand_get();
|
||||
foo_t * p = malloc(sizeof(foo_t));
|
||||
if (p == NULL) abort();
|
||||
p->key = key;
|
||||
p->value = val;
|
||||
NEDTRIE_INSERT(foo_tree_s, &footree, p);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
foo_t key = { .key = rand_get() };
|
||||
foo_t *p = NEDTRIE_FIND(foo_tree_s, &footree, &key);
|
||||
if (p)
|
||||
s += p->value;
|
||||
}
|
||||
g_result = s;
|
||||
foo_t *r, *next;
|
||||
NEDTRIE_FOREACH_SAFE(r, foo_tree_s, &footree, next) {
|
||||
// Remove is needed, otherwise it segfault
|
||||
NEDTRIE_REMOVE(foo_tree_s, &footree, r);
|
||||
free(r);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_noalloc(size_t n)
|
||||
{
|
||||
foo_tree_t footree;
|
||||
NEDTRIE_INIT(&footree);
|
||||
|
||||
foo_t *tab = malloc(n*sizeof(foo_t));
|
||||
if (tab == NULL) abort();
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long key = rand_get();
|
||||
unsigned long val = rand_get();
|
||||
tab[i].key = key;
|
||||
tab[i].value = val;
|
||||
NEDTRIE_INSERT(foo_tree_s, &footree, &tab[i]);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
foo_t key = { .key = rand_get() };
|
||||
foo_t *p = NEDTRIE_FIND(foo_tree_s, &footree, &key);
|
||||
if (p)
|
||||
s += p->value;
|
||||
}
|
||||
g_result = s;
|
||||
free(tab);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 45, "dict(noalloc)", 1000000, 0, test_dict_noalloc, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("NEDTRIES", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
// Inspired by: http://stackoverflow.com/questions/3664272/is-stdvector-so-much-slower-than-plain-arrays/3664349#3664349
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-list.h"
|
||||
#include "m-rbtree.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-mempool.h"
|
||||
#include "m-string.h"
|
||||
|
||||
unsigned long g_result;
|
||||
|
||||
static unsigned long long
|
||||
cputime (void)
|
||||
{
|
||||
struct rusage rus;
|
||||
getrusage (0, &rus);
|
||||
return rus.ru_utime.tv_sec * 1000000ULL + rus.ru_utime.tv_usec;
|
||||
}
|
||||
|
||||
struct Pixel
|
||||
{
|
||||
unsigned char r, g, b;
|
||||
};
|
||||
|
||||
ARRAY_DEF(array_pixel, struct Pixel, (INIT(M_NOTHING_DEFAULT), INIT_SET(M_MEMCPY_DEFAULT) ))
|
||||
|
||||
void UseMlib(void)
|
||||
{
|
||||
unsigned long long t1 = cputime();
|
||||
|
||||
for(int i = 0; i < 1000; ++i)
|
||||
{
|
||||
int dimension = 999;
|
||||
|
||||
array_pixel_t pixels;
|
||||
array_pixel_init(pixels);
|
||||
array_pixel_reserve(pixels, dimension * dimension);
|
||||
|
||||
for(int i = 0; i < dimension * dimension; ++i)
|
||||
{
|
||||
const struct Pixel p = { 255, 0, 0};
|
||||
array_pixel_push_back (pixels, p);
|
||||
}
|
||||
|
||||
array_pixel_clear(pixels);
|
||||
}
|
||||
unsigned long long t2 = cputime();
|
||||
printf ("M*Lib Array: %Lu us\n", (t2-t1)/1000);
|
||||
}
|
||||
|
||||
void UseNative(void)
|
||||
{
|
||||
unsigned long long t1 = cputime();
|
||||
|
||||
for(int i = 0; i < 1000; ++i)
|
||||
{
|
||||
int dimension = 999;
|
||||
|
||||
struct Pixel * pixels = malloc(sizeof(struct Pixel) * dimension * dimension);
|
||||
|
||||
for(int i = 0 ; i < dimension * dimension; ++i)
|
||||
{
|
||||
pixels[i].r = 255;
|
||||
pixels[i].g = 0;
|
||||
pixels[i].b = 0;
|
||||
}
|
||||
|
||||
free(pixels);
|
||||
}
|
||||
unsigned long long t2 = cputime();
|
||||
printf ("Native Array: %Lu us\n", (t2-t1)/1000);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UseNative();
|
||||
UseMlib();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,269 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
#define NDEBUG
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "qlibc/qlibc.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
qvector_t *a1 = qvector(16, sizeof(unsigned int), QVECTOR_RESIZE_DOUBLE);
|
||||
if (!a1) abort();
|
||||
qvector_t *a2 = qvector(16, sizeof(unsigned int), QVECTOR_RESIZE_DOUBLE);
|
||||
if (!a2) abort();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int v = rand_get();
|
||||
bool success = a1->addlast(a1, &v);
|
||||
if (!success) abort();
|
||||
v = rand_get();
|
||||
success = a2->addlast(a2, &v);
|
||||
if (!success) abort();
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *(unsigned int*)a1->getat(a1, i, false) * *(unsigned int *) a2->getat(a2, i, false);
|
||||
}
|
||||
g_result = s;
|
||||
a1->free(a1);
|
||||
a2->free(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
qlist_t *a1 = qlist(0);
|
||||
qlist_t *a2 = qlist(0);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int u = rand_get(), v = rand_get();
|
||||
a1->addlast(a1, &u, sizeof(unsigned int));
|
||||
a2->addlast(a2, &v, sizeof(unsigned int));
|
||||
}
|
||||
unsigned int s = 0;
|
||||
qlist_obj_t it1, it2;
|
||||
memset(&it1, 0, sizeof (it1));
|
||||
memset(&it2, 0, sizeof (it2));
|
||||
while (a1->getnext(a1, &it1, false) == true
|
||||
&& a2->getnext(a2, &it2, false) == true) {
|
||||
s += *(unsigned int*)it1.data * *(unsigned int*)it2.data;
|
||||
}
|
||||
g_result = s;
|
||||
a1->free(a1);
|
||||
a2->free(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static int compare(const void *key1, size_t size1,
|
||||
const void *key2, size_t size2)
|
||||
{
|
||||
assert(size1 == sizeof(unsigned long));
|
||||
assert(size2 == sizeof(unsigned long));
|
||||
const unsigned long *pa = key1;
|
||||
const unsigned long *pb = key2;
|
||||
return (*pa < *pb) ? -1 : (*pa > *pb);
|
||||
}
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
qtreetbl_t *tree = qtreetbl(0);
|
||||
tree->set_compare(tree, compare);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long v = rand_get();
|
||||
tree->put_by_obj(tree,
|
||||
&v, sizeof(unsigned long), /* key */
|
||||
&v, sizeof(unsigned long) /* value */ );
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long v = rand_get();
|
||||
void *obj = tree->get_by_obj(tree, (const char*)&v, sizeof(unsigned long), NULL, 0);
|
||||
if (obj)
|
||||
s += *(unsigned long*)obj;
|
||||
}
|
||||
g_result = s;
|
||||
tree->free(tree);
|
||||
}
|
||||
|
||||
/* qlibc hash functions only accept a string as the key */
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("QLIBC", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <QLinkedList>
|
||||
#include <QVector>
|
||||
#include <QSet>
|
||||
#include <QMap>
|
||||
#include <QHash>
|
||||
#include <QtAlgorithms>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_list(size_t n)
|
||||
{
|
||||
QLinkedList<unsigned int> a1, a2;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
a2.push_back(rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for (QLinkedList<unsigned int>::const_iterator ci1 = a1.begin(), ci2 = a2.begin (); ci1 != a1.end(); ++ci1, ++ci2) {
|
||||
s += *ci1 * *ci2;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
QVector<unsigned int> a1, a2;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
a2.push_back(rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += a1[i] * a2[i];
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
/* NOTE: QSet doesn't perform full ordering. I can't find any container
|
||||
which is a set with total ordering within Qt. So we have to fake it. */
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
QMap<unsigned long, QHashDummyValue> tree;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
tree[rand_get()] = QHashDummyValue();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
QMap<unsigned long, QHashDummyValue>::iterator it = tree.find(rand_get());
|
||||
if (it != tree.end())
|
||||
s += it.key();
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict1(size_t n)
|
||||
{
|
||||
QMap<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++) {
|
||||
QMap<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it.value();
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
QHash<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++) {
|
||||
QHash<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it.value();
|
||||
}
|
||||
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; }
|
||||
};
|
||||
|
||||
uint qHash(const char_array_s &k)
|
||||
{
|
||||
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)
|
||||
{
|
||||
QHash<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());
|
||||
QHash<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
QVector<float> a1;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
}
|
||||
qSort(a1.begin(), a1.end());
|
||||
g_result = a1[0];
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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(m)", 1000000, 0, test_dict1, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict(u)", 1000000, 0, test_dict2, 0},
|
||||
{ 50, "Sort",10000000, 0, test_sort, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("QT", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
#define NDEBUG
|
||||
#define RAPIDJSON_HAS_STDSTRING 1
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
vector<string> vstring;
|
||||
vector<string> vstring2;
|
||||
|
||||
static void
|
||||
bench_vector_string_init(size_t n)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
char buff[100];
|
||||
snprintf(buff, sizeof(buff), "%zu", i);
|
||||
std::string s(buff);
|
||||
vstring.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_init_big(size_t n)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
char buff[100];
|
||||
snprintf(buff, sizeof(buff), "%zu%zu%zu%zu%zu%zu", i, i, i, i, i, i);
|
||||
std::string s(buff);
|
||||
vstring.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_json_run(size_t n)
|
||||
{
|
||||
if (vstring.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
if (!f) abort();
|
||||
{
|
||||
// Prepare writer and output stream.
|
||||
char writeBuffer[65536];
|
||||
typedef rapidjson::AutoUTFOutputStream<unsigned, rapidjson::FileWriteStream> OutputStream;
|
||||
rapidjson::FileWriteStream os(f, writeBuffer, sizeof(writeBuffer));
|
||||
OutputStream eos(os, rapidjson::kUTF8, false);
|
||||
rapidjson::PrettyWriter<OutputStream, rapidjson::UTF8<>, rapidjson::AutoUTF<unsigned> > writer(eos);
|
||||
|
||||
writer.StartArray();
|
||||
for(size_t i = 0; i < n; i++){
|
||||
writer.String(vstring[i]);
|
||||
}
|
||||
writer.EndArray();
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.json", "rt");
|
||||
if (!f) abort();
|
||||
{
|
||||
char readBuffer[65536];
|
||||
rapidjson::FileReadStream is(f, readBuffer, sizeof(readBuffer));
|
||||
rapidjson::Document d;
|
||||
d.ParseStream(is);
|
||||
for(size_t i = 0; i < d.Size(); i++) {
|
||||
rapidjson::Value& s = d[i];
|
||||
vstring2.push_back(s.GetString());
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vstring2.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_clear(void)
|
||||
{
|
||||
if (vstring != vstring2) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
vector<unsigned long> vulong;
|
||||
vector<unsigned long> vulong2;
|
||||
|
||||
static void
|
||||
bench_vector_ulong_init(size_t n)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
vulong.push_back(i*i);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_json_run(size_t n)
|
||||
{
|
||||
if (vulong.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
if (!f) abort();
|
||||
{
|
||||
// Prepare writer and output stream.
|
||||
char writeBuffer[65536];
|
||||
typedef rapidjson::AutoUTFOutputStream<unsigned, rapidjson::FileWriteStream> OutputStream;
|
||||
rapidjson::FileWriteStream os(f, writeBuffer, sizeof(writeBuffer));
|
||||
OutputStream eos(os, rapidjson::kUTF8, false);
|
||||
rapidjson::PrettyWriter<OutputStream, rapidjson::UTF8<>, rapidjson::AutoUTF<unsigned> > writer(eos);
|
||||
|
||||
writer.StartArray();
|
||||
for(size_t i = 0; i < n; i++){
|
||||
writer.Int64(vulong[i]);
|
||||
}
|
||||
writer.EndArray();
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.json", "rt");
|
||||
if (!f) abort();
|
||||
{
|
||||
char readBuffer[65536];
|
||||
rapidjson::FileReadStream is(f, readBuffer, sizeof(readBuffer));
|
||||
rapidjson::Document d;
|
||||
d.ParseStream(is);
|
||||
for(size_t i = 0; i < d.Size(); i++) {
|
||||
rapidjson::Value& s = d[i];
|
||||
vulong2.push_back(s.GetInt64());
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vulong2.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_clear(void)
|
||||
{
|
||||
if (vulong != vulong2) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{110, "serial-json STR", 10000000, bench_vector_string_init, bench_vector_string_json_run, bench_vector_string_clear},
|
||||
{111, "serial-json STR.big", 10000000, bench_vector_string_init_big, bench_vector_string_json_run, bench_vector_string_clear},
|
||||
{112, "serial-json INT", 10000000, bench_vector_ulong_init, bench_vector_ulong_json_run, bench_vector_ulong_clear}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("RAPIDJSON", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
#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 "rigtorp/HashMap.h"
|
||||
|
||||
using namespace rigtorp;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
// Hash for using unsigned long as lookup key
|
||||
struct UL_Hash {
|
||||
size_t operator()(const unsigned long v) { return v * 7; }
|
||||
};
|
||||
|
||||
// Equal comparison for using unsigned long as lookup key
|
||||
struct UL_Equal {
|
||||
bool operator()(const unsigned long lhs, const unsigned long rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long, UL_Hash, UL_Equal> dict(16, -1UL);
|
||||
|
||||
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, UL_Hash, UL_Equal>::iterator it = dict.find(rand_get());
|
||||
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;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
struct BIG_Hash {
|
||||
size_t operator()(const char_array_s v) { return hash<char_array_s>()(v); }
|
||||
};
|
||||
|
||||
struct BIG_Equal {
|
||||
bool operator()(const char_array_s lhs, const char_array_s rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
char_array_s empty;
|
||||
HashMap<char_array_s, char_array_s, BIG_Hash, BIG_Equal> dict(16, empty);
|
||||
|
||||
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, BIG_Hash, BIG_Equal>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct STR_Hash {
|
||||
size_t operator()(const string v) { return hash<string>()(v); }
|
||||
};
|
||||
|
||||
struct STR_Equal {
|
||||
bool operator()(const string lhs, const string rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
string empty;
|
||||
HashMap<string, string, STR_Hash, STR_Equal> dict(16, empty);
|
||||
|
||||
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, STR_Hash, STR_Equal>::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}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("RIGTORP-HASHMAP", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <rigtorp/MPMCQueue.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
rigtorp::MPMCQueue<unsigned int> g_buff(4*64);
|
||||
rigtorp::MPMCQueue<unsigned long long> g_final(4*64);
|
||||
|
||||
static void final(void *arg)
|
||||
{
|
||||
size_t *p_n = (size_t*) arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long j, s = 0;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
g_final.pop(j);
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso(void *arg)
|
||||
{
|
||||
unsigned int j;
|
||||
size_t *p_n = (size_t*)arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long s = 0;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
g_buff.pop(j);
|
||||
s += j;
|
||||
}
|
||||
g_final.push(s);
|
||||
}
|
||||
|
||||
static void prod(void *arg)
|
||||
{
|
||||
size_t *p_n = (size_t*)arg;
|
||||
size_t n = *p_n;
|
||||
size_t r = n;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
g_buff.push(r);
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_queue(size_t n)
|
||||
{
|
||||
const int cpu_count = get_cpu_count();
|
||||
const int prod_count = cpu_count/2;
|
||||
const int conso_count = cpu_count - prod_count;
|
||||
if (cpu_count < 2) {
|
||||
fprintf(stderr, "WARNING: Can not measure Buffer performance.\n");
|
||||
return;
|
||||
}
|
||||
rand_get();
|
||||
// Create thread
|
||||
m_thread_t idx_p[prod_count];
|
||||
m_thread_t idx_c[conso_count];
|
||||
m_thread_t idx_final;
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_create (idx_p[i], prod, &n);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_create (idx_c[i], conso, &n);
|
||||
}
|
||||
size_t n2 = conso_count;
|
||||
m_thread_create(idx_final, final, &n2);
|
||||
|
||||
// Wait for jobs to be done.
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_join(idx_p[i]);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_join(idx_c[i]);
|
||||
}
|
||||
m_thread_join(idx_final);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("RIGTORP-MPMC-QUEUE", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
#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 <sparsepp/spp.h>
|
||||
|
||||
using spp::sparse_hash_map;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
sparse_hash_map<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++) {
|
||||
sparse_hash_map<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
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)
|
||||
{
|
||||
sparse_hash_map<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());
|
||||
sparse_hash_map<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)
|
||||
{
|
||||
sparse_hash_map<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();
|
||||
sparse_hash_map<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}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("SPARSEPP", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#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>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_list(size_t n)
|
||||
{
|
||||
list<unsigned int> a1, a2;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
a2.push_back(rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for (list<unsigned int>::const_iterator ci1 = a1.begin(), ci2 = a2.begin (); ci1 != a1.end(); ++ci1, ++ci2) {
|
||||
s += *ci1 * *ci2;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
vector<unsigned int> a1, a2;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
a2.push_back(rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += a1[i] * a2[i];
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_deque(size_t n)
|
||||
{
|
||||
deque<unsigned int> a1, a2;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
a2.push_back(rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(auto it1 = a1.cbegin(), it2 = a2.cbegin();
|
||||
it1 != a1.cend() ;it1++, it2++) {
|
||||
s += *it1 * *it2;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
set<unsigned long> tree;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
tree.insert(rand_get());
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
set<unsigned long>::iterator it = tree.find(rand_get());
|
||||
if (it != tree.end())
|
||||
s += *it;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict1(size_t n)
|
||||
{
|
||||
map<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++) {
|
||||
map<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
unordered_map<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++) {
|
||||
unordered_map<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)
|
||||
{
|
||||
unordered_map<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++) {
|
||||
unordered_map<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)
|
||||
{
|
||||
unordered_map<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());
|
||||
unordered_map<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)
|
||||
{
|
||||
unordered_map<string, string> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = to_string(rand_get());
|
||||
string s2 = to_string(rand_get());
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = to_string (rand_get());
|
||||
unordered_map<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_str2(size_t n)
|
||||
{
|
||||
map<string, string> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = to_string(rand_get());
|
||||
string s2 = to_string(rand_get());
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = to_string(rand_get());
|
||||
map<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
vector<float> a1;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
}
|
||||
sort(a1.begin(), a1.end());
|
||||
g_result = a1[0];
|
||||
}
|
||||
|
||||
static void test_stable_sort(size_t n)
|
||||
{
|
||||
vector<float> a1;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
}
|
||||
stable_sort(a1.begin(), a1.end());
|
||||
g_result = a1[0];
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 21, "Deque", 100000000, 0, test_deque, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict(m)", 1000000, 0, test_dict1, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict(u)", 1000000, 0, test_dict2, 0},
|
||||
{ 43,"DictStr(u)", 1000000, 0, test_dict_str, 0},
|
||||
{ 44,"DictStr(m)", 1000000, 0, test_dict_str2, 0},
|
||||
{ 46, "dictLinear(u)", 1000000, 0, test_dict2_linear, 0},
|
||||
{ 50, "Sort",10000000, 0, test_sort, 0},
|
||||
{ 51, "Stable Sort",10000000, 0, test_stable_sort, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("STL", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,323 +0,0 @@
|
||||
/*
|
||||
* M*LIB - String Bench
|
||||
*
|
||||
* Copyright (c) 2017-2023, 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.
|
||||
*/
|
||||
#define NDEBUG
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define M_USE_SMALL_NAME 0
|
||||
#include "common.h"
|
||||
|
||||
#include "m-string.h"
|
||||
|
||||
#ifdef BENCH_CAN_USE_SDS
|
||||
extern "C" {
|
||||
#include "sds.h"
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
#include "bstrlib.h"
|
||||
#include "bstrwrap.h"
|
||||
#include "bstraux.h"
|
||||
#endif
|
||||
|
||||
#if defined(BENCH_CAN_USE_POTTERY)
|
||||
#include "pottery/string/string.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* BENCH
|
||||
* 2000000
|
||||
* 1. Generate N strings of random numbers 32 bits.
|
||||
* 2. Concat all strings in a string usigned a random permutation of N.
|
||||
* 3. Replace "1234" in the string into "WELL" until nothing remains.
|
||||
* 4. Replace "56789" in the string into "DONE" until nothing remains.
|
||||
* Return the final string length.
|
||||
*/
|
||||
|
||||
unsigned *permutation_tab = NULL;
|
||||
|
||||
void random_permutation(unsigned n)
|
||||
{
|
||||
if (permutation_tab) free(permutation_tab);
|
||||
permutation_tab = (unsigned *) malloc(n * sizeof(unsigned));
|
||||
if (permutation_tab == NULL) abort();
|
||||
for(unsigned i = 0; i < n; i++)
|
||||
permutation_tab[i] = i;
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
unsigned j = rand_get() % n;
|
||||
unsigned k = rand_get() % n;
|
||||
unsigned l = permutation_tab[j];
|
||||
permutation_tab[j] = permutation_tab[k];
|
||||
permutation_tab[k] = l;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
static void replace_all_stl(string &str, const char pattern[], const char replace[])
|
||||
{
|
||||
size_t pos = 0;
|
||||
do {
|
||||
pos = str.find(pattern, pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, strlen(pattern), replace);
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
}
|
||||
|
||||
size_t bench_stl(unsigned n)
|
||||
{
|
||||
vector<string> tab;
|
||||
tab.resize(n);
|
||||
for(unsigned i = 0; i < n; i++)
|
||||
tab[i] = to_string(rand_get());
|
||||
|
||||
string str;
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
str += tab[permutation_tab[i]];
|
||||
}
|
||||
|
||||
replace_all_stl(str, "1234", "WELL");
|
||||
replace_all_stl(str, "56789", "DONE");
|
||||
|
||||
return str.length();
|
||||
}
|
||||
|
||||
size_t bench_mlib(unsigned n)
|
||||
{
|
||||
m_string_t *tab = (m_string_t*) malloc (n * sizeof (m_string_t));
|
||||
assert (tab != 0);
|
||||
// P1
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
m_string_init(tab[i]);
|
||||
m_string_set_ui(tab[i], rand_get());
|
||||
}
|
||||
// P2
|
||||
m_string_t str;
|
||||
m_string_init(str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
m_string_cat(str, tab[permutation_tab[i]]);
|
||||
}
|
||||
// P3
|
||||
m_string_replace_all_cstr(str, "1234", "WELL");
|
||||
m_string_replace_all_cstr(str, "56789", "DONE");
|
||||
size_t length = m_string_size(str);
|
||||
|
||||
// Clean
|
||||
m_string_clear(str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
m_string_clear(tab[i]);
|
||||
}
|
||||
free(tab);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
|
||||
static void replace_all_bstrlib(CBString &str, const char pattern[], const char replace[])
|
||||
{
|
||||
size_t pos = 0;
|
||||
do {
|
||||
pos = str.find(pattern, pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, strlen(pattern), replace);
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
}
|
||||
|
||||
size_t bench_bstrlib(unsigned n)
|
||||
{
|
||||
vector<CBString> tab;
|
||||
tab.resize(n);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
char tmp[10];
|
||||
sprintf(tmp, "%u", rand_get());
|
||||
tab[i] = tmp;
|
||||
}
|
||||
|
||||
CBString str;
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
str += tab[permutation_tab[i]];
|
||||
}
|
||||
|
||||
replace_all_bstrlib(str, "1234", "WELL");
|
||||
replace_all_bstrlib(str, "56789", "DONE");
|
||||
|
||||
return str.length();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_SDS
|
||||
sds SDS_replace_at(sds str, size_t pos, size_t len, const char str2[])
|
||||
{
|
||||
// simple implementation as replace is not available
|
||||
sds a = sdsnewlen((const void*) str, pos);
|
||||
a = sdscat(a, str2);
|
||||
a = sdscat(a, &str[pos+len]);
|
||||
sdsfree(str);
|
||||
return a;
|
||||
}
|
||||
|
||||
sds replace_all_sds(sds str, const char pattern[], const char replace[])
|
||||
{
|
||||
size_t pos = 0;
|
||||
do {
|
||||
char *p = strstr(&str[pos], pattern);
|
||||
pos = p == NULL ? -1U : (p - str);
|
||||
if (pos != -1U) {
|
||||
str = SDS_replace_at(str, pos, strlen(pattern), replace);
|
||||
}
|
||||
} while (pos != -1U);
|
||||
return str;
|
||||
}
|
||||
|
||||
size_t bench_sds(unsigned n)
|
||||
{
|
||||
sds *tab = (sds*) malloc (n * sizeof (sds));
|
||||
assert (tab != 0);
|
||||
// P1
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
tab[i] = sdsfromlonglong(rand_get());
|
||||
}
|
||||
// P2
|
||||
sds str = sdsempty();
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
str = sdscat(str, tab[permutation_tab[i]]);
|
||||
}
|
||||
// P3
|
||||
str = replace_all_sds(str, "1234", "WELL");
|
||||
str = replace_all_sds(str, "56789", "DONE");
|
||||
// Clean
|
||||
size_t length = sdslen(str);
|
||||
sdsfree(str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
sdsfree(tab[i]);
|
||||
}
|
||||
free(tab);
|
||||
return length;
|
||||
}
|
||||
#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[])
|
||||
{
|
||||
unsigned length, n = atoi(argv[1]);
|
||||
unsigned select = atoi(argv[2]);
|
||||
const char *name;
|
||||
random_permutation(n);
|
||||
rand_init();
|
||||
unsigned long long t0 = cputime();
|
||||
|
||||
switch (select) {
|
||||
case 0:
|
||||
length = bench_mlib(n);
|
||||
name = "MLIB";
|
||||
break;
|
||||
case 1:
|
||||
length = bench_stl(n);
|
||||
name = "STL";
|
||||
break;
|
||||
#ifdef BENCH_CAN_USE_SDS
|
||||
case 2:
|
||||
length = bench_sds(n);
|
||||
name = "SDS";
|
||||
break;
|
||||
#endif
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
case 4:
|
||||
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);
|
||||
}
|
||||
unsigned long long t1 = cputime();
|
||||
printf("%5.5s LENGTH=%u T= %f s\n", name, length, (t1-t0) / 1000000.0 );
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,221 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tommyds/tommy.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
tommy_array a1, a2;
|
||||
|
||||
tommy_array_init(&a1);
|
||||
tommy_array_init(&a2);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int v = rand_get();
|
||||
tommy_array_insert(&a1, (void*)(uintptr_t) v);
|
||||
v = rand_get();
|
||||
tommy_array_insert(&a2, (void*)(uintptr_t) v);
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += (uintptr_t) *tommy_array_ref(&a1, i) * (uintptr_t) *tommy_array_ref(&a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
tommy_array_done(&a1);
|
||||
tommy_array_done(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct list_node_s {
|
||||
unsigned int value;
|
||||
tommy_node node;
|
||||
};
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
tommy_list a1, a2;
|
||||
|
||||
tommy_list_init(&a1);
|
||||
tommy_list_init(&a2);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
struct list_node_s *obj;
|
||||
obj = malloc(sizeof(struct list_node_s));
|
||||
if (obj == NULL) abort();
|
||||
obj->value = rand_get();
|
||||
tommy_list_insert_tail(&a1, &obj->node, obj);
|
||||
obj = malloc(sizeof(struct list_node_s));
|
||||
if (obj == NULL) abort();
|
||||
obj->value = rand_get();
|
||||
tommy_list_insert_tail(&a2, &obj->node, obj);
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(tommy_node *it1 = tommy_list_head(&a1), *it2 = tommy_list_head(&a2)
|
||||
; it1 != NULL; it1 = it1->next, it2 = it2->next ) {
|
||||
struct list_node_s *obj1 = it1->data, *obj2 = it2->data;
|
||||
s += obj1->value * obj2->value;
|
||||
}
|
||||
g_result = s;
|
||||
tommy_list_foreach(&a1, free);
|
||||
tommy_list_foreach(&a2, free);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct tree_node_s {
|
||||
unsigned long value;
|
||||
tommy_tree_node node;
|
||||
} ;
|
||||
|
||||
static int compare(const void *a, const void *b)
|
||||
{
|
||||
const struct tree_node_s *pa = a;
|
||||
const struct tree_node_s *pb = b;
|
||||
return (pa->value < pb->value) ? -1 : (pa->value > pb->value);
|
||||
}
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
tommy_tree tree;
|
||||
tommy_tree_init(&tree, compare);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
struct tree_node_s *obj = malloc(sizeof(struct tree_node_s));
|
||||
if (obj == NULL) abort();
|
||||
obj->value = rand_get();
|
||||
tommy_tree_insert(&tree, &obj->node, obj);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
struct tree_node_s key = { .value = rand_get() };
|
||||
struct tree_node_s *obj = tommy_tree_search (&tree, &key);
|
||||
if (obj)
|
||||
s += obj->value;
|
||||
}
|
||||
g_result = s;
|
||||
tommy_tree_foreach(&tree, free);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct hash_i_node_s {
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
tommy_node node;
|
||||
};
|
||||
|
||||
static inline size_t hash_func (const unsigned long key)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
static int equal_func(const void* arg, const void *obj_p)
|
||||
{
|
||||
const struct hash_i_node_s *obj = obj_p;
|
||||
const unsigned long *key = arg;
|
||||
return *key != obj->key;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
tommy_hashlin dict;
|
||||
tommy_hashlin_init(&dict);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
struct hash_i_node_s *obj = malloc(sizeof (struct hash_i_node_s));
|
||||
if(!obj) abort();
|
||||
obj->key = rand_get();
|
||||
obj->value = rand_get();
|
||||
tommy_hashlin_insert(&dict, &obj->node, obj, hash_func(obj->key));
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long key = rand_get();
|
||||
struct hash_i_node_s *obj = tommy_hashlin_search(&dict, &equal_func,
|
||||
&key,
|
||||
hash_func(key));
|
||||
if (obj)
|
||||
s += obj->value;
|
||||
}
|
||||
g_result = s;
|
||||
tommy_hashlin_done(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef char char_array_t[256];
|
||||
|
||||
struct hash_b_node_s {
|
||||
char_array_t key;
|
||||
char_array_t value;
|
||||
tommy_node node;
|
||||
};
|
||||
|
||||
static int char_equal (const void *arg, const void *obj_p)
|
||||
{
|
||||
const struct hash_b_node_s *obj = obj_p;
|
||||
const char_array_t *key = (const char_array_t *)arg;
|
||||
return strcmp(*key, (obj->key));
|
||||
}
|
||||
|
||||
static size_t char_hash(const char *s)
|
||||
{
|
||||
size_t hash = 0;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
tommy_hashlin dict;
|
||||
tommy_hashlin_init(&dict);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
struct hash_b_node_s *obj = malloc(sizeof (struct hash_b_node_s));
|
||||
if(!obj) abort();
|
||||
sprintf(obj->key, "%u", rand_get());
|
||||
sprintf(obj->value, "%u", rand_get());
|
||||
/* NOTE: this is not an insert_or_replace func...
|
||||
It will always insert a new node, even if the key already exists...
|
||||
Maybe searching then inserting will be a better representative?
|
||||
*/
|
||||
tommy_hashlin_insert(&dict, &obj->node, obj, char_hash(obj->key));
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1;
|
||||
sprintf(s1, "%u", rand_get());
|
||||
struct hash_b_node_s *obj = tommy_hashlin_search(&dict, &char_equal,
|
||||
&s1,
|
||||
char_hash(s1));
|
||||
if (obj)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
tommy_hashlin_done(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("TommyDS", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
#define NDEBUG
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "include/uthash.h"
|
||||
#include "include/utarray.h"
|
||||
#include "include/utlist.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static const UT_icd int_icd = {
|
||||
.sz = sizeof (unsigned int),
|
||||
.init = NULL,
|
||||
.dtor = NULL,
|
||||
.copy = NULL
|
||||
};
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
UT_array a1, a2;
|
||||
|
||||
utarray_init(&a1, &int_icd);
|
||||
utarray_init(&a2, &int_icd);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int v1 = rand_get(), v2 = rand_get();
|
||||
utarray_push_back(&a1, &v1);
|
||||
utarray_push_back(&a2, &v2);
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *(unsigned long *) utarray_eltptr(&a1, i ) * *(unsigned long *)utarray_eltptr(&a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
utarray_done(&a1);
|
||||
utarray_done(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct list_node_s {
|
||||
unsigned int value;
|
||||
struct list_node_s *next;
|
||||
};
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
struct list_node_s *a1 = NULL, *a2 = NULL;
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
struct list_node_s *p = malloc(sizeof(struct list_node_s));
|
||||
if (!p) abort();
|
||||
p->value = rand_get();
|
||||
LL_PREPEND(a1, p);
|
||||
p = malloc(sizeof(struct list_node_s));
|
||||
if (!p) abort();
|
||||
p->value = rand_get();
|
||||
LL_PREPEND(a2, p);
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(struct list_node_s *it1 = a1, *it2 = a2
|
||||
; it1 != NULL
|
||||
; it1 = it1->next, it2 = it2->next) {
|
||||
s += it1->value * it2->value;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
struct list_node_s *el;
|
||||
LL_FOREACH(a1, el) free(el);
|
||||
LL_FOREACH(a2, el) free(el);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct hash_i_node_s {
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
struct hash_i_node_s *dict = NULL;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long k = rand_get();
|
||||
struct hash_i_node_s *s;
|
||||
HASH_FIND(hh, dict, &k, sizeof (unsigned long), s);
|
||||
if (s == NULL) {
|
||||
s = malloc(sizeof(struct hash_i_node_s));
|
||||
if (!s) abort();
|
||||
s->key = k;
|
||||
s->value = rand_get();
|
||||
HASH_ADD(hh, dict, key, sizeof(unsigned long), s);
|
||||
}
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long k = rand_get();
|
||||
struct hash_i_node_s *sp;
|
||||
HASH_FIND(hh, dict, &k, sizeof (unsigned long), sp);
|
||||
if (sp != NULL)
|
||||
s += sp->value;
|
||||
}
|
||||
g_result = s;
|
||||
struct hash_i_node_s *current, *tmp;
|
||||
HASH_ITER(hh, dict, current, tmp) {
|
||||
HASH_DEL(dict,current); /* delete it (users advances to next) */
|
||||
free(current); /* free it */
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
char a[256];
|
||||
} char_array_t;
|
||||
|
||||
struct hash_b_node_s {
|
||||
char_array_t key;
|
||||
char_array_t value;
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
struct hash_b_node_s *dict = NULL;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t k;
|
||||
sprintf(k.a, "%u", rand_get());
|
||||
struct hash_b_node_s *s;
|
||||
HASH_FIND(hh, dict, &k, sizeof (char_array_t), s);
|
||||
if (s == NULL) {
|
||||
s = malloc(sizeof(struct hash_b_node_s));
|
||||
if (!s) abort();
|
||||
memcpy(s->key.a, k.a, sizeof(s->key));
|
||||
sprintf(s->value.a, "%u", rand_get());
|
||||
HASH_ADD(hh, dict, key, sizeof(char_array_t), s);
|
||||
}
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t k;
|
||||
sprintf(k.a, "%u", rand_get());
|
||||
struct hash_b_node_s *sp;
|
||||
HASH_FIND(hh, dict, &k, sizeof (char_array_t), sp);
|
||||
if (sp != NULL)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
struct hash_b_node_s *current, *tmp;
|
||||
HASH_ITER(hh, dict, current, tmp) {
|
||||
HASH_DEL(dict,current); /* delete it (users advances to next) */
|
||||
free(current); /* free it */
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static const UT_icd float_icd = {
|
||||
.sz = sizeof (float),
|
||||
.init = NULL,
|
||||
.dtor = NULL,
|
||||
.copy = NULL
|
||||
};
|
||||
|
||||
static int cmp(const void *a1, const void *a2)
|
||||
{
|
||||
const float *f1 = a1;
|
||||
const float *f2 = a2;
|
||||
return (*f1 < *f2) ? -1 : (*f1 > *f2);
|
||||
}
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
UT_array a1;
|
||||
|
||||
utarray_init(&a1, &float_icd);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
float v1 = rand_get();
|
||||
utarray_push_back(&a1, &v1);
|
||||
}
|
||||
utarray_sort(&a1, cmp);
|
||||
g_result = *(float *)utarray_eltptr(&a1, 0);
|
||||
utarray_done(&a1);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 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("UT-HASH", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "xxhash.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static unsigned long *g_p;
|
||||
|
||||
static void test_hash_prepare(size_t n)
|
||||
{
|
||||
g_p = malloc (n * sizeof(unsigned long));
|
||||
if (g_p == NULL) abort();
|
||||
for(size_t i = 0; i < n ; i++)
|
||||
g_p[i] = ((rand_get()*RAND_MAX + rand_get())*RAND_MAX+rand_get())*RAND_MAX + rand_get();
|
||||
}
|
||||
|
||||
|
||||
static void test_hash_final(void)
|
||||
{
|
||||
free(g_p);
|
||||
}
|
||||
|
||||
static void test_hash(size_t n)
|
||||
{
|
||||
g_result = XXH64(g_p, sizeof(unsigned long)*n, 0);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 70,"XXHASH64", 100000000, test_hash_prepare, test_hash, test_hash_final}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("XXHASH", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
-306
@@ -1,306 +0,0 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2023, 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 <string.h>
|
||||
#include "common.h"
|
||||
|
||||
// Maximum supported value for repeat argument
|
||||
#define MAX_REPEAT 10000
|
||||
|
||||
// The global result
|
||||
unsigned long g_result;
|
||||
|
||||
// The rand value
|
||||
#if defined(MULTI_THREAD_MEASURE)
|
||||
M_THREAD_ATTR
|
||||
#endif
|
||||
unsigned int randValue = 0;
|
||||
|
||||
void compiler_barrier(void *p)
|
||||
{
|
||||
// Do nothing, but let the compiler thinks that we did.
|
||||
(void) p;
|
||||
// Can be used for FLTO building
|
||||
// asm volatile("": "+r" (p) : :"memory");
|
||||
}
|
||||
|
||||
struct parse_opt_s {
|
||||
int test_function;
|
||||
double from, to, step, grow;
|
||||
double within;
|
||||
unsigned repeat;
|
||||
bool graph, best, best_within, average, quiet;
|
||||
};
|
||||
|
||||
static void
|
||||
parse_config(struct parse_opt_s *opt, int argc, const char *argv[])
|
||||
{
|
||||
char *end;
|
||||
|
||||
opt->test_function = 0;
|
||||
opt->from = 0.0;
|
||||
opt->to = 0.0;
|
||||
opt->step = 0.0;
|
||||
opt->grow = 1.1;
|
||||
opt->graph = false;
|
||||
opt->best = false;
|
||||
opt->best_within = false;
|
||||
opt->average = false;
|
||||
opt->quiet = false;
|
||||
opt->repeat = 1;
|
||||
opt->within = .05;
|
||||
|
||||
for(int i = 1; i < argc ; i++)
|
||||
{
|
||||
if (argv[i][0] == '-') {
|
||||
if (strcmp(argv[i], "--from") == 0){
|
||||
i++;
|
||||
opt->from = strtod(argv[i], &end);
|
||||
opt->to = opt->from;
|
||||
} else if (strcmp(argv[i], "--to") == 0) {
|
||||
i++;
|
||||
opt->to = strtod(argv[i], &end);
|
||||
opt->grow = 1.1;
|
||||
} else if (strcmp(argv[i], "--step") == 0) {
|
||||
i++;
|
||||
opt->step = strtod(argv[i], &end);
|
||||
opt->grow = 0;
|
||||
} else if (strcmp(argv[i], "--grow") == 0) {
|
||||
i++;
|
||||
opt->grow = strtod(argv[i], &end);
|
||||
opt->step = 0;
|
||||
} else if (strcmp(argv[i], "--repeat") == 0) {
|
||||
i++;
|
||||
opt->repeat = strtol(argv[i], &end, 10);
|
||||
opt->repeat = (opt->repeat > MAX_REPEAT) ? MAX_REPEAT : opt->repeat;
|
||||
} else if (strcmp(argv[i], "--graph") == 0) {
|
||||
opt->graph = true;
|
||||
} else if (strcmp(argv[i], "--best") == 0) {
|
||||
opt->best = true;
|
||||
opt->average = false;
|
||||
opt->best_within = false;
|
||||
} else if (strcmp(argv[i], "--best-within") == 0) {
|
||||
opt->best_within = true;
|
||||
opt->best = false;
|
||||
opt->average = false;
|
||||
i++;
|
||||
opt->within = strtod(argv[i], &end) / 100.0;
|
||||
} else if (strcmp(argv[i], "--average") == 0) {
|
||||
opt->average = true;
|
||||
opt->best = false;
|
||||
opt->best_within = false;
|
||||
} else if (strcmp(argv[i], "--quiet") == 0) {
|
||||
opt->quiet = true;
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: Option unkown: %s.\n",
|
||||
argv[i]);
|
||||
exit(-1);
|
||||
}
|
||||
if (*end != 0) {
|
||||
fprintf(stderr, "ERROR: Cannot parse %s. Expected float\n",
|
||||
argv[i]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
} else {
|
||||
opt->test_function = strtol (argv[i], &end, 10);
|
||||
if (*end != 0) {
|
||||
fprintf(stderr, "ERROR: Cannot parse %s. Expected function number\n",
|
||||
argv[i]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
select_config(int func, size_t n, const config_func_t functions[])
|
||||
{
|
||||
for(size_t i = 0; i < n;i++) {
|
||||
if (functions[i].num == func)
|
||||
return i;
|
||||
}
|
||||
fprintf(stderr, "ERROR: Function number %d not found. Available functions are:\n", func);
|
||||
for(size_t i = 0; i < n;i++) {
|
||||
fprintf(stderr, " %d: %s\n", functions[i].num, functions[i].funcname);
|
||||
}
|
||||
fprintf(stderr,
|
||||
"USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--graph]\n"
|
||||
"[--repeat number] [--best|--average|--best-within] [--quiet]\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Utility function for qsort
|
||||
static int cmp_double(const void *pa, const void *pb)
|
||||
{
|
||||
const double *a = (const double *) pa, *b = (const double *)pb;
|
||||
return (*a < *b) ? -1 : *a > *b;
|
||||
}
|
||||
|
||||
/* Get the longest sequence of values within 'f'% */
|
||||
static int
|
||||
get_sequence(int i, int n, double tab[], double f)
|
||||
{
|
||||
int j;
|
||||
for(j = i + 1; j < n; j++) {
|
||||
if (tab[j] > f * tab[i])
|
||||
break;
|
||||
}
|
||||
return j-i;
|
||||
}
|
||||
|
||||
/* Return the minimum of the longest sequence of values with 'f'% */
|
||||
static double
|
||||
get_best_within(int n, double tab[], double f)
|
||||
{
|
||||
qsort(tab, n, sizeof(double), cmp_double);
|
||||
int best_i = 0;
|
||||
int best_seq = get_sequence(0, n, tab, f);
|
||||
for(int i = 1; i < n && (n-i) > best_seq ; i++) {
|
||||
int seq = get_sequence(i, n, tab, f);
|
||||
if (seq > best_seq) {
|
||||
best_i = i;
|
||||
best_seq = seq;
|
||||
}
|
||||
}
|
||||
return tab[best_i];
|
||||
}
|
||||
|
||||
// Integer sqrt function (to avoid depending on libm)
|
||||
static unsigned integer_sqrt(unsigned n)
|
||||
{
|
||||
// Find greatest shift.
|
||||
int shift = 2;
|
||||
unsigned nShifted = n >> shift;
|
||||
// We check for nShifted being n, since some implementations
|
||||
// perform shift operations modulo the word size.
|
||||
while (nShifted != 0 && nShifted != n){
|
||||
shift += 2;
|
||||
nShifted = n >> shift;
|
||||
}
|
||||
shift -= 2;
|
||||
// Find digits of result.
|
||||
unsigned result = 0;
|
||||
while (shift >= 0) {
|
||||
result = result << 1;
|
||||
unsigned candidateResult = result + 1;
|
||||
if (candidateResult*candidateResult <= n >> shift) {
|
||||
result = candidateResult;
|
||||
}
|
||||
shift -= 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
test(const char library[], size_t n, const config_func_t functions[], int argc, const char *argv[])
|
||||
{
|
||||
// Init & parse arguments
|
||||
// NUMBER
|
||||
// --from NUMBER --to NUMBER --step NUMBER --grow NUMBER
|
||||
// --graph --best --average --quiet
|
||||
// --repeat N
|
||||
struct parse_opt_s arg;
|
||||
parse_config(&arg, argc, argv);
|
||||
int i = select_config(arg.test_function, n, functions);
|
||||
double from = (arg.from == 0) ? functions[i].default_n : arg.from;
|
||||
double to = (arg.to == 0) ? functions[i].default_n : arg.to;
|
||||
|
||||
// Open plot file if needed
|
||||
FILE *graph_file = NULL;
|
||||
if (arg.graph) {
|
||||
char filename[100];
|
||||
sprintf(filename, "plot-%s-%d.dat", library, arg.test_function);
|
||||
graph_file = fopen(filename, "wt");
|
||||
if (!graph_file) {
|
||||
fprintf(stderr, "ERROR: Cannot create the file '%s'\n", filename);
|
||||
exit(-2);
|
||||
}
|
||||
fprintf(graph_file, "# plotting %s-%d : %s\n# N T", library, arg.test_function, functions[i].funcname);
|
||||
}
|
||||
|
||||
// Do the bench
|
||||
for(double n = from; n <= to ; n = ((arg.grow == 0) ? n + arg.step : n * arg.grow))
|
||||
{
|
||||
double best = (1.0/0.0);
|
||||
double avg = 0.0;
|
||||
double variance = 0.0;
|
||||
static double measure[MAX_REPEAT];
|
||||
double ba = 0.0;
|
||||
|
||||
if (functions[i].init != NULL)
|
||||
functions[i].init(n);
|
||||
|
||||
// Measure the time of the test_function
|
||||
for(unsigned r = 0; r < arg.repeat; r++) {
|
||||
double t0 = test_function( (arg.graph|arg.best|arg.average|arg.quiet) ? NULL : functions[i].funcname, (size_t) n, functions[i].func);
|
||||
best = (t0 < best) ? t0 : best;
|
||||
avg += t0;
|
||||
variance += t0 * t0;
|
||||
measure[r] = t0;
|
||||
}
|
||||
|
||||
// Closure of the tests
|
||||
if (functions[i].clear != NULL)
|
||||
functions[i].clear();
|
||||
|
||||
// Finish computing the different times
|
||||
if (arg.repeat > 1) {
|
||||
avg /= arg.repeat;
|
||||
variance = (variance - arg.repeat * avg * avg) / (arg.repeat - 1);
|
||||
ba = get_best_within(arg.repeat, measure, 1. + arg.within);
|
||||
} else {
|
||||
ba = avg;
|
||||
}
|
||||
|
||||
// The average value shall be around best_within (and greater)
|
||||
// otherwise the result doesn't seem reliable.
|
||||
bool reliable = (ba <= avg && ba * (1.0+arg.within/2) + 0.5 > avg);
|
||||
|
||||
// Print the result
|
||||
if (arg.graph) {
|
||||
fprintf(graph_file, "%f %f\n", n, arg.average ? avg : arg.best ? best : ba);
|
||||
} else if (arg.quiet) {
|
||||
printf("%ld\n", (long)(arg.average ? avg : arg.best ? best : reliable ? ba : -1));
|
||||
} else if (arg.repeat > 1) {
|
||||
if (arg.average == false && arg.best_within == false)
|
||||
printf ("%20.20s time %lu ms for n = %lu *** BEST ***\n", functions[i].funcname, (unsigned long) best, (unsigned long) n);
|
||||
if (arg.best == false && arg.best_within == false)
|
||||
printf ("%20.20s time %lu ms +/- %u ms for n = %lu *** AVERAGE ***\n", functions[i].funcname, (unsigned long) avg, 2*integer_sqrt(variance), (unsigned long) n);
|
||||
if (arg.best == false && arg.average == false)
|
||||
printf ("%20.20s time %lu ms for n = %lu *** BEST within %d%% *** %s\n", functions[i].funcname, (unsigned long) ba, (unsigned long) n, (int)(100*arg.within), reliable ? "" : "(unreliable result)");
|
||||
}
|
||||
}
|
||||
|
||||
// Close the FILE if needed
|
||||
if (arg.graph) {
|
||||
fclose(graph_file);
|
||||
printf("File plot-%s-%d.dat generated.\n"
|
||||
"Run in gnuplot the following command:\n"
|
||||
"\tplot 'plot-%s-%d.dat' with linespoints linestyle 1\n",
|
||||
library, arg.test_function, library, arg.test_function);
|
||||
}
|
||||
return;
|
||||
}
|
||||
-171
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __COMMON_BENCH__H
|
||||
#define __COMMON_BENCH__H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Needed for M_THREAD_ATTR
|
||||
#if defined(MULTI_THREAD_MEASURE)
|
||||
#include "m-thread.h"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
#elif (defined(__APPLE__) && defined(__MACH__)) \
|
||||
|| defined(__DragonFly__) || defined(__FreeBSD__) \
|
||||
|| defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# include <sys/types.h>
|
||||
# include <sys/resource.h>
|
||||
# include <sys/time.h>
|
||||
# include <sys/param.h>
|
||||
# include <sys/sysctl.h>
|
||||
# define USE_SYSCTL
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <sys/resource.h>
|
||||
# include <sys/time.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
// Number of elements of a table
|
||||
#define numberof(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
/* Get the current CPU time in microsecond. */
|
||||
#if defined(_WIN32)
|
||||
/* WINDOWS variant */
|
||||
static inline unsigned long long
|
||||
cputime (void)
|
||||
{
|
||||
LARGE_INTEGER freq, val;
|
||||
QueryPerformanceFrequency(&freq);
|
||||
QueryPerformanceCounter(&val);
|
||||
return (unsigned long long) (1000000. * (double) val.QuadPart / (double) freq.QuadPart);
|
||||
}
|
||||
#else
|
||||
/* UNIX variant */
|
||||
static inline unsigned long long
|
||||
cputime (void)
|
||||
{
|
||||
#if defined(MULTI_THREAD_MEASURE)
|
||||
// Multi thread: Uses real time
|
||||
struct timeval tv;
|
||||
gettimeofday (&tv, NULL);
|
||||
return tv.tv_sec * 1000000ULL + tv.tv_usec;
|
||||
#else
|
||||
// Single thread: Uses process usage time
|
||||
struct rusage rus;
|
||||
getrusage (0, &rus);
|
||||
return rus.ru_utime.tv_sec * 1000000ULL + rus.ru_utime.tv_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// The result of the bench
|
||||
extern unsigned long g_result;
|
||||
|
||||
// The rand value
|
||||
extern
|
||||
#if defined(MULTI_THREAD_MEASURE)
|
||||
M_THREAD_ATTR
|
||||
#endif
|
||||
unsigned int randValue;
|
||||
|
||||
// Pseudo rand value generator.
|
||||
// Not very random but sufficient and fast enough for the bench
|
||||
static inline void rand_init(void)
|
||||
{
|
||||
randValue = 0;
|
||||
}
|
||||
static inline unsigned int rand_get(void)
|
||||
{
|
||||
randValue = randValue * 31421U + 6927U;
|
||||
return randValue;
|
||||
}
|
||||
|
||||
// The function that performs the bench
|
||||
static inline double
|
||||
test_function(const char *str, size_t n, void (*func)(size_t))
|
||||
{
|
||||
double result;
|
||||
unsigned long long start, end;
|
||||
rand_init();
|
||||
start = cputime();
|
||||
(*func)(n);
|
||||
end = cputime();
|
||||
result = (double)(end-start) / 1000.0;
|
||||
if (str != NULL) {
|
||||
printf ("%20.20s time %.2f ms for n = %lu [r=%lu]\n", str, result, (unsigned long) n, g_result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Configuration table
|
||||
typedef struct {
|
||||
int num;
|
||||
const char *funcname;
|
||||
size_t default_n;
|
||||
void (*init)(size_t);
|
||||
void (*func)(size_t);
|
||||
void (*clear)(void);
|
||||
} config_func_t;
|
||||
|
||||
// Perform a parsing of the given arguments and do the bench according to the table
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
void test(const char library[], size_t n, const config_func_t functions[], int argc, const char *argv[]);
|
||||
|
||||
/* Return the number of CPU of the system */
|
||||
static inline int get_cpu_count(void)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
SYSTEM_INFO sysinfo;
|
||||
GetSystemInfo(&sysinfo);
|
||||
return sysinfo.dwNumberOfProcessors;
|
||||
#elif defined(USE_SYSCTL)
|
||||
int nm[2];
|
||||
int count = 0;
|
||||
size_t len = sizeof (count);
|
||||
nm[0] = CTL_HW;
|
||||
nm[1] = HW_NCPU;
|
||||
sysctl(nm, 2, &count, &len, NULL, 0);
|
||||
return MAX(1, count);
|
||||
#elif defined (_SC_NPROCESSORS_ONLN)
|
||||
return sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
void compiler_barrier(void *p);
|
||||
|
||||
#endif
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* MLIB - TEST module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include "m-dict.h"
|
||||
|
||||
static inline bool oor_equal_p(int64_t k, unsigned char n)
|
||||
{
|
||||
return k == (int)-n-1;
|
||||
}
|
||||
static inline void oor_set(int64_t *k, unsigned char n)
|
||||
{
|
||||
*k = (int)-n-1;
|
||||
}
|
||||
|
||||
DICT_OA_DEF2(dict_int64, int64_t, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)), int64_t, M_DEFAULT_OPLIST)
|
||||
|
||||
static int64_t get_rand(void)
|
||||
{
|
||||
int64_t n;
|
||||
do {
|
||||
n = (rand() * RAND_MAX + rand()) * RAND_MAX + rand();
|
||||
} while (n == -1 || n == -2);
|
||||
return n;
|
||||
}
|
||||
|
||||
// Let's push value into the dict until the system abandons!
|
||||
static void find_max(void)
|
||||
{
|
||||
dict_int64_t dict;
|
||||
dict_int64_init(dict);
|
||||
size_t n = 0;
|
||||
while (true) {
|
||||
dict_int64_set_at (dict, get_rand(), get_rand());
|
||||
n++;
|
||||
if ((n & ((1<<20)-1)) == 0) {
|
||||
printf ("n=%zu\n", n);
|
||||
}
|
||||
}
|
||||
dict_int64_clear(dict);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
find_max();
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
CC=cc -std=c11
|
||||
CXX=c++ -std=c++11
|
||||
CFLAGS=-O2 -march=native -Wall
|
||||
CPPFLAGS=-I../..
|
||||
|
||||
all: k-nucleotide
|
||||
|
||||
k-nucleotide: k-nucleotide.exe data.txt
|
||||
./k-nucleotide.exe < data.txt
|
||||
|
||||
k-nucleotide.exe: nucleotide.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) nucleotide.c -o k-nucleotide.exe -lpthread
|
||||
|
||||
data.txt: fasta.exe
|
||||
./fasta.exe 25000000 > data.txt
|
||||
|
||||
fasta.exe: fasta.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -fopenmp fasta.c -o fasta.exe
|
||||
|
||||
clean:
|
||||
rm -f *.exe *~ *.o data.txt
|
||||
|
||||
@@ -1,344 +0,0 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// contributed by Jeremy Zerfas
|
||||
// rewritten by Аноним Легионов, inspired by fasta Rust #2 program
|
||||
// use two OpenMP locks instead of one critical section
|
||||
// decouples IO activity from random number generation
|
||||
//
|
||||
// modified by Josh Goldfoot, adding use of a buffer for fasta_repeat
|
||||
|
||||
|
||||
// This controls the width of lines that are output by this program.
|
||||
#define MAXIMUM_LINE_WIDTH 60
|
||||
|
||||
// This program will generate the random nucleotide sequences in parallel which
|
||||
// are worked on in blocks of lines. The number of lines in those blocks is
|
||||
// controlled by this setting.
|
||||
#define LINES_PER_BLOCK 1024
|
||||
|
||||
#define CHARACTERS_PER_BLOCK (MAXIMUM_LINE_WIDTH*LINES_PER_BLOCK)
|
||||
|
||||
#define THREADS_TO_USE 4
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
// intptr_t should be the native integer type on most sane systems.
|
||||
typedef intptr_t intnative_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char letter;
|
||||
float probability;
|
||||
} nucleotide_info;
|
||||
|
||||
|
||||
// Repeatedly print string_To_Repeat until it has printed
|
||||
// number_Of_Characters_To_Create. The output is also wrapped to
|
||||
// MAXIMUM_LINE_WIDTH columns.
|
||||
static char* make_Sequence_Buffer(const char string_To_Repeat[])
|
||||
{
|
||||
const intnative_t string_To_Repeat_Length = strlen(string_To_Repeat);
|
||||
|
||||
// JG: Changed to that this writes a sequence to a buffer, which is used
|
||||
intnative_t number_Of_Characters_To_Create = string_To_Repeat_Length * MAXIMUM_LINE_WIDTH;
|
||||
char* buffer = (char*) malloc(number_Of_Characters_To_Create +
|
||||
number_Of_Characters_To_Create / MAXIMUM_LINE_WIDTH + 1);
|
||||
if (buffer == NULL)
|
||||
exit(-1);
|
||||
char* bufferOffset = buffer;
|
||||
|
||||
// Create an extended_String_To_Repeat which is a copy of string_To_Repeat
|
||||
// but extended with another copy of the first MAXIMUM_LINE_WIDTH characters
|
||||
// of string_To_Repeat appended to the end. Later on this allows us to
|
||||
// generate a line of output just by doing simple memory copies using an
|
||||
// appropriate offset into extended_String_To_Repeat.
|
||||
char extended_String_To_Repeat[string_To_Repeat_Length + MAXIMUM_LINE_WIDTH];
|
||||
for (intnative_t column = 0; column<string_To_Repeat_Length + MAXIMUM_LINE_WIDTH;
|
||||
column++)
|
||||
extended_String_To_Repeat[column] =
|
||||
string_To_Repeat[column%string_To_Repeat_Length];
|
||||
intnative_t offset = 0;
|
||||
|
||||
char line[MAXIMUM_LINE_WIDTH + 1];
|
||||
line[MAXIMUM_LINE_WIDTH] = '\n';
|
||||
|
||||
for (intnative_t current_Number_Of_Characters_To_Create =
|
||||
number_Of_Characters_To_Create;
|
||||
current_Number_Of_Characters_To_Create>0;)
|
||||
{
|
||||
// Figure out the length of the line we need to write. If it's less than
|
||||
// MAXIMUM_LINE_WIDTH then we also need to add a line feed in the right
|
||||
// spot too.
|
||||
intnative_t line_Length = MAXIMUM_LINE_WIDTH;
|
||||
if (current_Number_Of_Characters_To_Create<MAXIMUM_LINE_WIDTH)
|
||||
{
|
||||
line_Length = current_Number_Of_Characters_To_Create;
|
||||
line[line_Length] = '\n';
|
||||
}
|
||||
|
||||
memcpy(line, extended_String_To_Repeat + offset, line_Length);
|
||||
|
||||
// Update the offset, reducing it by string_To_Repeat_Length if
|
||||
// necessary.
|
||||
offset += line_Length;
|
||||
if (offset>string_To_Repeat_Length)
|
||||
offset -= string_To_Repeat_Length;
|
||||
|
||||
// "Output" that line to our buffer and update the
|
||||
// current_Number_Of_Characters_To_Create.
|
||||
memcpy(bufferOffset, line, line_Length + 1); // JG: used to be fwrite(line, line_Length + 1, 1, stdout);
|
||||
bufferOffset += line_Length + 1;
|
||||
current_Number_Of_Characters_To_Create -= line_Length;
|
||||
}
|
||||
*bufferOffset = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void repeat_And_Wrap_String(const char string_To_Repeat[], intnative_t number_Of_Characters_To_Create)
|
||||
{
|
||||
/* JG: fasta_repeat repeats every len(alu) * line-length = 287 * 61 = 17507 characters.
|
||||
So, calculate this once, then just print that buffer over and over. */
|
||||
char* sequence = make_Sequence_Buffer(string_To_Repeat);
|
||||
intnative_t sequenceLen = (intnative_t) strlen(sequence);
|
||||
intnative_t outputBytes = number_Of_Characters_To_Create + number_Of_Characters_To_Create / 60;
|
||||
while (outputBytes >= sequenceLen) {
|
||||
fwrite(sequence, sequenceLen, 1, stdout);
|
||||
outputBytes -= sequenceLen;
|
||||
}
|
||||
if (outputBytes > 0) {
|
||||
fwrite(sequence, outputBytes, 1, stdout);
|
||||
printf("\n");
|
||||
}
|
||||
free(sequence);
|
||||
}
|
||||
|
||||
|
||||
// Generate a pseudorandom number from 0 to max using a linear
|
||||
// congruential generator.
|
||||
#define IM 139968
|
||||
#define IA 3877
|
||||
#define IC 29573
|
||||
uint32_t seed = 42;
|
||||
|
||||
int rng_tid; //Thread ID
|
||||
int rng_tnum = 1; //Thread number
|
||||
intnative_t rng_cnt = 0;
|
||||
|
||||
#ifdef _OPENMP
|
||||
omp_lock_t rng_lock;
|
||||
#define RNG_LOCK_INIT() omp_init_lock(&rng_lock)
|
||||
#define RNG_LOCK() omp_set_lock(&rng_lock)
|
||||
#define RNG_FREE() omp_unset_lock(&rng_lock)
|
||||
#else
|
||||
#define RNG_LOCK_INIT() do{}while(0)
|
||||
#define RNG_LOCK() do{}while(0)
|
||||
#define RNG_FREE() do{}while(0)
|
||||
#endif
|
||||
|
||||
static void rng_init(void)
|
||||
{
|
||||
RNG_LOCK_INIT();
|
||||
rng_tid = 0;
|
||||
}
|
||||
|
||||
static intnative_t rng_gen_blk(uint32_t * buf, intnative_t len, int curr_tid)
|
||||
{
|
||||
intnative_t gen_cnt = -1;//Error by default
|
||||
RNG_LOCK();
|
||||
|
||||
if (rng_tid == curr_tid)
|
||||
{
|
||||
if (++rng_tid >= rng_tnum)
|
||||
{
|
||||
rng_tid = 0;
|
||||
}
|
||||
|
||||
gen_cnt = (len<rng_cnt) ? len : rng_cnt;
|
||||
rng_cnt -= gen_cnt;
|
||||
|
||||
len = gen_cnt;
|
||||
|
||||
while (0 != len--)
|
||||
{
|
||||
seed = (seed*IA + IC) % IM;
|
||||
*(buf++) = seed;//This is stupid actually!
|
||||
}
|
||||
}
|
||||
|
||||
RNG_FREE();
|
||||
return gen_cnt;
|
||||
}
|
||||
|
||||
int out_tid; //Thread ID
|
||||
int out_tnum = 1; //Thread number
|
||||
#ifdef _OPENMP
|
||||
omp_lock_t out_lock;
|
||||
#define OUT_LOCK_INIT() omp_init_lock(&out_lock)
|
||||
#define OUT_LOCK() omp_set_lock(&out_lock)
|
||||
#define OUT_FREE() omp_unset_lock(&out_lock)
|
||||
#else
|
||||
#define OUT_LOCK_INIT() do{}while(0)
|
||||
#define OUT_LOCK() do{}while(0)
|
||||
#define OUT_FREE() do{}while(0)
|
||||
#endif
|
||||
|
||||
static void out_init(void)
|
||||
{
|
||||
OUT_LOCK_INIT();
|
||||
rng_tid = 0;
|
||||
}
|
||||
|
||||
static intnative_t out_write(char * buf, intnative_t len, int curr_tid)
|
||||
{
|
||||
intnative_t wr_cnt = -1;//Error by default
|
||||
OUT_LOCK();
|
||||
|
||||
if (out_tid == curr_tid)
|
||||
{
|
||||
if (++out_tid >= out_tnum)
|
||||
{
|
||||
out_tid = 0;
|
||||
}
|
||||
wr_cnt = fwrite(buf, len, 1, stdout);
|
||||
}
|
||||
|
||||
OUT_FREE();
|
||||
return wr_cnt; //-1 - thread error, 0 - IO error, 1 - ОК
|
||||
}
|
||||
|
||||
static void generate_And_Wrap_Pseudorandom_DNA_Sequence(
|
||||
const nucleotide_info nucl_info[],
|
||||
const intnative_t nucl_num,
|
||||
const intnative_t char_num)
|
||||
{
|
||||
uint32_t cumul_p[nucl_num];
|
||||
float cumul_acc = 0.0;
|
||||
|
||||
for (intnative_t i = 0; i<nucl_num; i++)
|
||||
{
|
||||
cumul_acc += nucl_info[i].probability;
|
||||
cumul_p[i] = 1ul + (uint32_t)(cumul_acc*(float)IM); //Compensate rounding errors on test file
|
||||
}
|
||||
|
||||
#ifdef _OPENMP
|
||||
intnative_t tnum = omp_get_num_procs();
|
||||
if (tnum>THREADS_TO_USE) tnum = THREADS_TO_USE;
|
||||
omp_set_num_threads(tnum);
|
||||
rng_tnum = tnum;
|
||||
out_tnum = tnum;
|
||||
#endif
|
||||
rng_tid = 0;
|
||||
out_tid = 0;
|
||||
rng_cnt = char_num;
|
||||
|
||||
#pragma omp parallel
|
||||
{
|
||||
char block[CHARACTERS_PER_BLOCK + LINES_PER_BLOCK];
|
||||
char * line;
|
||||
uint32_t rnd[CHARACTERS_PER_BLOCK], r;
|
||||
intnative_t cnt, col, prid, nid, ncnt;
|
||||
int cur_tid;
|
||||
#ifdef _OPENMP
|
||||
cur_tid = omp_get_thread_num();
|
||||
#else
|
||||
cur_tid = 0;
|
||||
#endif
|
||||
while (1)
|
||||
{
|
||||
do
|
||||
{
|
||||
cnt = rng_gen_blk(rnd, CHARACTERS_PER_BLOCK, cur_tid);
|
||||
} while (-1 == cnt);
|
||||
|
||||
if (0 == cnt)
|
||||
{
|
||||
break;//Work finished!
|
||||
}
|
||||
|
||||
line = block;
|
||||
|
||||
for (col = 0, prid = 0; prid < cnt; prid++)
|
||||
{
|
||||
r = rnd[prid];
|
||||
|
||||
ncnt = 0;
|
||||
for (nid = 0; nid < nucl_num; nid++)
|
||||
{
|
||||
if (cumul_p[nid] <= r)
|
||||
{
|
||||
ncnt++;
|
||||
}
|
||||
}
|
||||
|
||||
*line++ = nucl_info[ncnt].letter;
|
||||
if (++col >= MAXIMUM_LINE_WIDTH)
|
||||
{
|
||||
col = 0;
|
||||
*line++ = '\n';
|
||||
}
|
||||
}
|
||||
//Check if we need to end the line
|
||||
if (0 != col)
|
||||
{
|
||||
//Last iteration didn't end the line, so finish the job.
|
||||
*line++ = '\n';
|
||||
}
|
||||
//Print results
|
||||
do
|
||||
{
|
||||
cnt = out_write(block, line - block, cur_tid);
|
||||
} while (-1 == cnt);
|
||||
//Check fot IO error
|
||||
if (0 == cnt)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
const intnative_t n = atoi(argv[1]);
|
||||
|
||||
fputs(">ONE Homo sapiens alu\n", stdout);
|
||||
const char homo_Sapiens_Alu[] =
|
||||
"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTC"
|
||||
"AGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCG"
|
||||
"TGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGG"
|
||||
"AGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
|
||||
repeat_And_Wrap_String(homo_Sapiens_Alu, 2 * n);
|
||||
|
||||
rng_init();
|
||||
out_init();
|
||||
|
||||
fputs(">TWO IUB ambiguity codes\n", stdout);
|
||||
nucleotide_info iub_Nucleotides_Information[] =
|
||||
{
|
||||
{ 'a', 0.27 },{ 'c', 0.12 },{ 'g', 0.12 },{ 't', 0.27 },{ 'B', 0.02 },
|
||||
{ 'D', 0.02 },{ 'H', 0.02 },{ 'K', 0.02 },{ 'M', 0.02 },{ 'N', 0.02 },
|
||||
{ 'R', 0.02 },{ 'S', 0.02 },{ 'V', 0.02 },{ 'W', 0.02 },{ 'Y', 0.02 }
|
||||
};
|
||||
generate_And_Wrap_Pseudorandom_DNA_Sequence(iub_Nucleotides_Information,
|
||||
sizeof(iub_Nucleotides_Information) / sizeof(nucleotide_info), 3 * n);
|
||||
|
||||
fputs(">THREE Homo sapiens frequency\n", stdout);
|
||||
nucleotide_info homo_Sapien_Nucleotides_Information[] =
|
||||
{
|
||||
{ 'a', 0.3029549426680 },{ 'c', 0.1979883004921 },
|
||||
{ 'g', 0.1975473066391 },{ 't', 0.3015094502008 }
|
||||
};
|
||||
generate_And_Wrap_Pseudorandom_DNA_Sequence(homo_Sapien_Nucleotides_Information,
|
||||
sizeof(homo_Sapien_Nucleotides_Information) / sizeof(nucleotide_info), 5 * n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// Original version Contributed by Jeremy Zerfas
|
||||
// M*LIB port contributed by Patrick Pélissier
|
||||
#define NDEBUG
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "m-worker.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-bptree.h"
|
||||
|
||||
// This controls the maximum length for each set of oligonucleotide frequencies
|
||||
// and each oligonucleotide count output by this program.
|
||||
#define MAXIMUM_OUTPUT_LENGTH 4096
|
||||
|
||||
// Number of outputs to display
|
||||
#define MAXMUM_NUMBER_OUTPUT 7
|
||||
|
||||
/* Define the needed containers */
|
||||
/* Define Open Addressing dictionary of uint64_t --> uint32_t. Need to define how to handle out of bound data. */
|
||||
static inline bool my_oor_equal_p(uint64_t k, unsigned char n)
|
||||
{
|
||||
return k == ~(uint64_t) n;
|
||||
}
|
||||
static inline void my_oor_set(uint64_t *k, unsigned char n)
|
||||
{
|
||||
*k = ~(uint64_t)n;
|
||||
}
|
||||
static inline size_t my_hash(uint64_t key)
|
||||
{
|
||||
return ((key) ^ (key)>>7);
|
||||
}
|
||||
DICT_OA_DEF2(dict_oligonucleotide,
|
||||
uint64_t, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(my_oor_equal_p), OOR_SET(my_oor_set M_IPTR)),
|
||||
uint32_t, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_dict_oligonucleotide_t() DICT_OPLIST(dict_oligonucleotide, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(my_oor_equal_p), OOR_SET(my_oor_set M_IPTR)), M_DEFAULT_OPLIST)
|
||||
|
||||
// Define a B*TREE-21 of uint32_t --> uint64_t and register its oplist
|
||||
#define TREE_CMP(a,b) ((a) > (b) ? -1 : (a) < (b)) /* reverse natural order */
|
||||
BPTREE_DEF2(tree_dict_oligonucleotide, 21, uint32_t, M_OPEXTEND(M_DEFAULT_OPLIST, CMP(TREE_CMP)), uint64_t, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_tree_dict_oligonucleotide_t() BPTREE_OPLIST2(tree_dict_oligonucleotide, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
/* Define the data to analyse (a plain array) */
|
||||
ARRAY_DEF(polynucleotide, unsigned char)
|
||||
|
||||
// Macro to convert a nucleotide character to a code. Note that upper and lower
|
||||
// case ASCII letters only differ in the fifth bit from the right and we only
|
||||
// need the three least significant bits to differentiate the letters 'A', 'C',
|
||||
// 'G', and 'T'. Spaces in this array/string will never be used as long as
|
||||
// characters other than 'A', 'C', 'G', and 'T' aren't used.
|
||||
#define CODE_FOR_NUCLEOTIDE(nucleotide) (" \0 \1\3 \2"[nucleotide & 0x7])
|
||||
|
||||
// And one more macro to convert the codes back to nucleotide characters.
|
||||
#define NUCLEOTIDE_FOR_CODE(code) ("ACGT"[code & 0x3])
|
||||
|
||||
static worker_t worker;
|
||||
|
||||
// Read from the given stream the data and fill in the array with the converted one.
|
||||
static void polynucleotide_init_stream(polynucleotide_t p, FILE *stream)
|
||||
{
|
||||
char buffer[MAXIMUM_OUTPUT_LENGTH], c;
|
||||
|
||||
polynucleotide_init(p);
|
||||
polynucleotide_reserve(p, MAXIMUM_OUTPUT_LENGTH);
|
||||
// Find the start of the third polynucleotide.
|
||||
while(fgets(buffer, sizeof(buffer), stream) && memcmp(">THREE", buffer, 6));
|
||||
// Start reading and encoding the third polynucleotide.
|
||||
while(fgets(buffer, sizeof(buffer), stream) && buffer[0]!='>'){
|
||||
for(size_t i = 0; (c = buffer[i]) !='\0'; i++) {
|
||||
if (c != '\n') {
|
||||
polynucleotide_push_back(p, CODE_FOR_NUCLEOTIDE(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is the function which does 95% of the work.
|
||||
/* NOTE: paralelisation is not done by cutting the input set in two.
|
||||
This is not efficient as the size of the output table will be the same
|
||||
as for the whole table. */
|
||||
static void init_hash(dict_oligonucleotide_t hash_Table, const size_t size, const unsigned char tab[size], const size_t desiredLength, const size_t offset, const size_t skip)
|
||||
{
|
||||
uint64_t key = 0;
|
||||
const uint64_t mask = (1ULL<<(2*desiredLength))-1;
|
||||
assert (2*desiredLength < 64 && desiredLength < size);
|
||||
assert ((1 == skip || 4 == skip) && offset < size);
|
||||
|
||||
// For the first several nucleotides we only need to append them to key in
|
||||
// preparation for the insertion of complete oligonucleotides to hash.
|
||||
for(size_t i = 0; i < desiredLength - 1 + offset; i++)
|
||||
key = (key<<2) | tab[i];
|
||||
key &= mask;
|
||||
|
||||
dict_oligonucleotide_t hash;
|
||||
dict_oligonucleotide_init(hash);
|
||||
|
||||
// Add all the complete oligonucleotides of
|
||||
// desiredLength to hash, updating their count
|
||||
if (skip == 1) {
|
||||
for(size_t i = desiredLength-1+offset ; i < size; i++) {
|
||||
key = (key<<2) | tab[i+0];
|
||||
key &= mask;
|
||||
uint32_t *p = dict_oligonucleotide_get(hash, key);
|
||||
if (p != NULL) {
|
||||
(*p) ++;
|
||||
} else {
|
||||
dict_oligonucleotide_set_at(hash, key, 1);
|
||||
}
|
||||
}
|
||||
} else { // skip = 4
|
||||
for(size_t i = desiredLength-1+offset ; i < size; i+=4) {
|
||||
for (size_t j = 0; j < 4; j++)
|
||||
key = (key<<2) | tab[i+j];
|
||||
key &= mask;
|
||||
uint32_t *p = dict_oligonucleotide_get(hash, key);
|
||||
if (p != NULL) {
|
||||
(*p) ++;
|
||||
} else {
|
||||
dict_oligonucleotide_set_at(hash, key, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
dict_oligonucleotide_init_move(hash_Table, hash);
|
||||
}
|
||||
|
||||
static void compute_hash(dict_oligonucleotide_t hash_Table, const polynucleotide_t p, const size_t desiredLength)
|
||||
{
|
||||
size_t size = polynucleotide_size(p);
|
||||
unsigned char *tab = polynucleotide_get(p, 0);
|
||||
if (desiredLength < 8) {
|
||||
init_hash(hash_Table, size, tab, desiredLength, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
worker_sync_t block; // Define a synchronization block
|
||||
worker_start(block, worker);
|
||||
dict_oligonucleotide_t hash_Table3, *p_hash_Table3 = &hash_Table3;
|
||||
dict_oligonucleotide_t hash_Table2, *p_hash_Table2 = &hash_Table2;
|
||||
dict_oligonucleotide_t hash_Table1, *p_hash_Table1 = &hash_Table1;
|
||||
WORKER_SPAWN(block, (p_hash_Table1, size, tab, desiredLength), {
|
||||
init_hash(*p_hash_Table1, size, tab, desiredLength, 3, 4);
|
||||
}, (/*no output*/));
|
||||
WORKER_SPAWN(block, (p_hash_Table2, size, tab, desiredLength), {
|
||||
init_hash(*p_hash_Table2, size, tab, desiredLength, 2, 4);
|
||||
}, (/*no output*/));
|
||||
WORKER_SPAWN(block, (p_hash_Table3, size, tab, desiredLength), {
|
||||
init_hash(*p_hash_Table3, size, tab, desiredLength, 1, 4);
|
||||
}, (/*no output*/));
|
||||
init_hash(hash_Table, size, tab, desiredLength, 0, 4);
|
||||
worker_sync(block);
|
||||
|
||||
// Merge all hashtables
|
||||
dict_oligonucleotide_splice(hash_Table, hash_Table1);
|
||||
dict_oligonucleotide_splice(hash_Table, hash_Table2);
|
||||
dict_oligonucleotide_splice(hash_Table, hash_Table3);
|
||||
// Clear extra hashtables
|
||||
dict_oligonucleotide_clear(hash_Table3);
|
||||
dict_oligonucleotide_clear(hash_Table2);
|
||||
dict_oligonucleotide_clear(hash_Table1);
|
||||
}
|
||||
|
||||
// Generate frequencies for all oligonucleotides in polynucleotide that are of
|
||||
// desiredLength and then save it to output.
|
||||
static void compute_freq(const polynucleotide_t p, const size_t desiredLength, char output[])
|
||||
{
|
||||
dict_oligonucleotide_t hash_Table;
|
||||
compute_hash(hash_Table, p, desiredLength);
|
||||
|
||||
// Order key is the count frequency (inverse value & key)
|
||||
tree_dict_oligonucleotide_t tree;
|
||||
tree_dict_oligonucleotide_init(tree);
|
||||
for M_EACH(item, hash_Table, dict_oligonucleotide_t) {
|
||||
tree_dict_oligonucleotide_set_at (tree, item->value, item->key);
|
||||
}
|
||||
|
||||
// Create Output
|
||||
char oligonucleotide[64];
|
||||
const double invSum = 100.0 / (double) (polynucleotide_size(p) - desiredLength + 1);
|
||||
int output_Position = 0;
|
||||
for M_EACH(item, tree, tree_dict_oligonucleotide_t) {
|
||||
// Convert the key for the oligonucleotide to a string.
|
||||
uint64_t freq = *item->value_ptr;
|
||||
uint32_t count = *item->key_ptr;
|
||||
for(size_t j = desiredLength-1; j < desiredLength; j--){
|
||||
oligonucleotide[j]=NUCLEOTIDE_FOR_CODE(freq);
|
||||
freq>>=2;
|
||||
}
|
||||
oligonucleotide[desiredLength]='\0';
|
||||
// Output the frequency for oligonucleotide to output.
|
||||
output_Position+=snprintf(output+output_Position, MAXIMUM_OUTPUT_LENGTH-output_Position,
|
||||
"%s %.3f\n", oligonucleotide, invSum * count);
|
||||
}
|
||||
|
||||
dict_oligonucleotide_clear(hash_Table);
|
||||
tree_dict_oligonucleotide_clear(tree);
|
||||
}
|
||||
|
||||
// Generate a count for the number of times oligonucleotide appears in
|
||||
// polynucleotide and then save it to output.
|
||||
static void compute_count(polynucleotide_t p, const char oligonucleotide[], char output[])
|
||||
{
|
||||
const size_t oligonucleotide_Length = strlen(oligonucleotide);
|
||||
dict_oligonucleotide_t hash_Table;
|
||||
compute_hash(hash_Table, p, oligonucleotide_Length);
|
||||
|
||||
// Generate the key for oligonucleotide.
|
||||
uint64_t key=0;
|
||||
for(size_t i=0; i<oligonucleotide_Length; i++)
|
||||
key = (key<<2) | CODE_FOR_NUCLEOTIDE(oligonucleotide[i]);
|
||||
|
||||
// Output the count for oligonucleotide to output.
|
||||
uint32_t *val = dict_oligonucleotide_get(hash_Table, key);
|
||||
uintmax_t count= val== NULL ? 0 : *val;
|
||||
snprintf(output, MAXIMUM_OUTPUT_LENGTH, "%ju\t%s", count, oligonucleotide);
|
||||
|
||||
dict_oligonucleotide_clear(hash_Table);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Initialize the different worker threads by auto-detecting the number of cores of the system
|
||||
worker_init(worker, -1, 0, NULL);
|
||||
|
||||
// Read the input
|
||||
polynucleotide_t p, *ptr = &p;
|
||||
polynucleotide_init_stream(p, stdin);
|
||||
|
||||
// Prepare outputs
|
||||
char outputBuffer[MAXMUM_NUMBER_OUTPUT][MAXIMUM_OUTPUT_LENGTH];
|
||||
char (*output)[MAXIMUM_OUTPUT_LENGTH] = outputBuffer;
|
||||
|
||||
// Do the following functions in parallel.
|
||||
worker_sync_t block; // Define a synchronization block
|
||||
worker_start(block, worker);
|
||||
|
||||
WORKER_SPAWN(block, (ptr, output), {
|
||||
compute_count(*ptr, "GGTATTTTAATTTATAGT", output[6]);
|
||||
}, (/*no output*/));
|
||||
WORKER_SPAWN(block, (ptr, output), {
|
||||
compute_count(*ptr, "GGTATTTTAATT", output[5]);
|
||||
}, (/*no output*/));
|
||||
WORKER_SPAWN(block, (ptr, output), {
|
||||
compute_count(*ptr, "GGTATT", output[4]);
|
||||
}, (/*no output*/));
|
||||
WORKER_SPAWN(block, (ptr, output), {
|
||||
compute_count(*ptr, "GGTA", output[3]);
|
||||
}, (/*no output*/));
|
||||
compute_count(*ptr, "GGT", output[2]);
|
||||
compute_freq(*ptr, 2, output[1]);
|
||||
compute_freq(p, 1, output[0]);
|
||||
worker_sync(block);
|
||||
|
||||
// Output the results to stdout.
|
||||
for(int i=0; i<MAXMUM_NUMBER_OUTPUT; i++)
|
||||
printf("%s\n", outputBuffer[i]);
|
||||
|
||||
polynucleotide_clear(p);
|
||||
worker_clear(worker);
|
||||
|
||||
return 0;
|
||||
}
|
||||
-940
@@ -1,940 +0,0 @@
|
||||
/**
|
||||
* Memory pool benchmark.
|
||||
*
|
||||
* Results (the better values for each measure from at least 3 runs)for
|
||||
* Intel Core i7-4650U CPU 1.70GHz, 8GB RAM:
|
||||
*
|
||||
* small object size: 24
|
||||
* big object size: 240
|
||||
* huge object size: 8305
|
||||
*
|
||||
* boost::pool (Small): 258ms
|
||||
* boost::pool w/ free (Small): 165ms
|
||||
* boost::pool (Big): 174ms
|
||||
* boost::pool w/ free (Big): 154ms
|
||||
* boost::pool cr. & destr.: 133ms
|
||||
*
|
||||
* ngx_pool (Small): 305ms
|
||||
* ngx_pool (Big): 132ms
|
||||
* ngx_pool w/ free (Mix): 542ms
|
||||
* ngx_pool cr. & destr.: 98ms
|
||||
*
|
||||
* tfw_pool (Small): 279ms
|
||||
* tfw_pool w/ free (Small): 101ms
|
||||
* tfw_pool (Big): 106ms
|
||||
* tfw_pool w/ free (Big): 50ms
|
||||
* tfw_pool w/ free (Mix): 107ms
|
||||
* tfw_pool cr. & destr.: 53ms
|
||||
*
|
||||
* Copyright (C) 2015 Alexander Krizhanovsky (ak@natsys-lab.com).
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* See http://www.gnu.org/licenses/lgpl.html .
|
||||
*
|
||||
* From https://github.com/natsys/blog/tree/master/mempool
|
||||
*/
|
||||
#define NDEBUG
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#ifdef USE_BOOST
|
||||
#include <boost/pool/object_pool.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef USE_GLIB
|
||||
#include <glib.h>
|
||||
#endif
|
||||
|
||||
static const size_t PAGE_SIZE = 4096;
|
||||
|
||||
// sizeof(TfwStr)
|
||||
struct Small {
|
||||
long l[3];
|
||||
|
||||
std::string
|
||||
operator+(const char *str)
|
||||
{ return std::string(str) + " (Small)"; }
|
||||
};
|
||||
|
||||
// size of common HTTP headers table
|
||||
struct Big {
|
||||
Small s[10];
|
||||
|
||||
std::string
|
||||
operator+(const char *str)
|
||||
{ return std::string(str) + " (Big)"; }
|
||||
};
|
||||
|
||||
// very big allocation
|
||||
struct Huge {
|
||||
char c[PAGE_SIZE * 2 + 113];
|
||||
|
||||
std::string
|
||||
operator+(const char *str)
|
||||
{ return std::string(str) + " (Huge)"; }
|
||||
};
|
||||
|
||||
static const size_t N = 20 * 1000 * 1000;
|
||||
|
||||
void
|
||||
benchmark(std::string &&desc, std::function<void ()> cb)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
// steady_clock has the same resolution as high_resolution_clock
|
||||
auto t(steady_clock::now());
|
||||
|
||||
cb();
|
||||
|
||||
auto dt = steady_clock::now() - t;
|
||||
std::cout << std::setw(30) << std::right << desc << ": "
|
||||
<< duration_cast<milliseconds>(dt).count()
|
||||
<< "ms" << std::endl;
|
||||
}
|
||||
|
||||
#define touch_obj(o) \
|
||||
if (__builtin_expect(!o, 0)) { \
|
||||
std::cerr << "failed alloc" << std::endl; \
|
||||
break; \
|
||||
} else { \
|
||||
*(long *)o = 1; \
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
* Boost::pool
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
#ifdef USE_BOOST
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_boost_pool()
|
||||
{
|
||||
boost::object_pool<T> p;
|
||||
|
||||
benchmark(std::move(T() + "boost::pool"), [&]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = p.malloc();
|
||||
touch_obj(o);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_boost_pool_free()
|
||||
{
|
||||
boost::object_pool<T> p;
|
||||
|
||||
benchmark(std::move(T() + "boost::pool w/ free"), [&]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = p.malloc();
|
||||
touch_obj(o);
|
||||
if (__builtin_expect(!(i & 3), 0))
|
||||
p.free(o);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
benchmark_boost_pool_create_and_destroy()
|
||||
{
|
||||
benchmark(std::move(std::string("boost::pool cr. & destr.")), []() {
|
||||
for (size_t i = 0; i < N / 100; ++i) {
|
||||
if (__builtin_expect(!(i & 3), 0)) {
|
||||
boost::object_pool<Big> p;
|
||||
for (size_t j = 0; j < 100; ++j) {
|
||||
Big *o = p.malloc();
|
||||
touch_obj(o);
|
||||
}
|
||||
} else {
|
||||
boost::object_pool<Small> p;
|
||||
for (size_t j = 0; j < 100; ++j) {
|
||||
Small *o = p.malloc();
|
||||
touch_obj(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
* malloc/free
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
template<class T>
|
||||
void
|
||||
benchmark_mallocfree()
|
||||
{
|
||||
benchmark(std::move(T() + "mallocfree"), [&]() {
|
||||
static __thread T *ptrs[N * sizeof(Small) / sizeof(T)];
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = (T*)malloc(sizeof(T));
|
||||
ptrs[i] = o;
|
||||
touch_obj(o);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
free(ptrs[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_mallocfree_free()
|
||||
{
|
||||
benchmark(std::move(T() + "mallocfree w/ free"), [&]() {
|
||||
static __thread T *ptrs[N * sizeof(Small) / sizeof(T)];
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = (T*)malloc(sizeof(T));
|
||||
ptrs[i] = o;
|
||||
touch_obj(o);
|
||||
|
||||
if (__builtin_expect(!(i & 3), 0)) {
|
||||
free(o);
|
||||
ptrs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
free(ptrs[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
* GLib slices
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
#ifdef USE_GLIB
|
||||
template<class T>
|
||||
void
|
||||
benchmark_glib_slices()
|
||||
{
|
||||
benchmark(std::move(T() + "GLib slices"), [&]() {
|
||||
static __thread T *ptrs[N * sizeof(Small) / sizeof(T)];
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = (T*)g_slice_alloc(sizeof(T));
|
||||
ptrs[i] = o;
|
||||
touch_obj(o);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
g_slice_free1(sizeof(T), ptrs[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_glib_slices_free()
|
||||
{
|
||||
benchmark(std::move(T() + "GLib slices w/ free"), [&]() {
|
||||
static __thread T *ptrs[N * sizeof(Small) / sizeof(T)];
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = (T*)g_slice_alloc(sizeof(T));
|
||||
ptrs[i] = o;
|
||||
touch_obj(o);
|
||||
|
||||
if (__builtin_expect(!(i & 3), 0)) {
|
||||
g_slice_free1(sizeof(T), o);
|
||||
ptrs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
g_slice_free1(sizeof(T), ptrs[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
* Nginx pool
|
||||
* Simplified version of src/core/ngx_palloc.c from nginx-1.9.5 with
|
||||
* some code adjustments to be built in this benchmark.
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
struct ngx_pool_t;
|
||||
typedef uintptr_t ngx_uint_t;
|
||||
|
||||
#define NGX_POOL_ALIGNMENT 16
|
||||
#define NGX_ALIGNMENT sizeof(unsigned long)
|
||||
#define ngx_align_ptr(p, a) \
|
||||
(u_char *)(((uintptr_t)(p) + ((uintptr_t)a - 1)) & ~((uintptr_t)a - 1))
|
||||
#define NGX_MAX_ALLOC_FROM_POOL ((size_t)PAGE_SIZE - 1)
|
||||
|
||||
struct ngx_pool_data_t {
|
||||
unsigned char *last;
|
||||
unsigned char *end;
|
||||
ngx_pool_t *next;
|
||||
unsigned int failed;
|
||||
};
|
||||
|
||||
struct ngx_pool_large_t {
|
||||
ngx_pool_large_t *next;
|
||||
void *alloc;
|
||||
};
|
||||
|
||||
struct ngx_pool_t {
|
||||
ngx_pool_data_t d;
|
||||
size_t max;
|
||||
ngx_pool_t *current;
|
||||
ngx_pool_large_t *large;
|
||||
};
|
||||
|
||||
ngx_pool_t *
|
||||
ngx_create_pool(size_t size)
|
||||
{
|
||||
ngx_pool_t *p;
|
||||
|
||||
if (posix_memalign((void **)&p, NGX_POOL_ALIGNMENT, size))
|
||||
return NULL;
|
||||
|
||||
p->d.last = (unsigned char *)p + sizeof(ngx_pool_t);
|
||||
p->d.end = (unsigned char *)p + size;
|
||||
p->d.next = NULL;
|
||||
p->d.failed = 0;
|
||||
|
||||
size = size - sizeof(ngx_pool_t);
|
||||
p->max = (size < NGX_MAX_ALLOC_FROM_POOL)
|
||||
? size : NGX_MAX_ALLOC_FROM_POOL;
|
||||
|
||||
p->current = p;
|
||||
p->large = NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
ngx_destroy_pool(ngx_pool_t *pool)
|
||||
{
|
||||
ngx_pool_t *p, *n;
|
||||
ngx_pool_large_t *l;
|
||||
|
||||
for (l = pool->large; l; l = l->next) {
|
||||
if (l->alloc)
|
||||
free(l->alloc);
|
||||
}
|
||||
|
||||
for (p = pool, n = pool->d.next; ; p = n, n = n->d.next) {
|
||||
free(p);
|
||||
if (n == NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
ngx_palloc_block(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
unsigned char *m;
|
||||
size_t psize = (size_t)(pool->d.end - (unsigned char *)pool);
|
||||
ngx_pool_t *p, *p_new;
|
||||
|
||||
if (posix_memalign((void **)&m, NGX_POOL_ALIGNMENT, psize))
|
||||
return NULL;
|
||||
p_new = (ngx_pool_t *)m;
|
||||
|
||||
p_new->d.end = m + psize;
|
||||
p_new->d.next = NULL;
|
||||
p_new->d.failed = 0;
|
||||
|
||||
m += sizeof(ngx_pool_data_t);
|
||||
m = ngx_align_ptr(m, NGX_ALIGNMENT);
|
||||
p_new->d.last = m + size;
|
||||
|
||||
for (p = pool->current; p->d.next; p = p->d.next) {
|
||||
if (p->d.failed++ > 4)
|
||||
pool->current = p->d.next;
|
||||
}
|
||||
p->d.next = p_new;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void *ngx_palloc(ngx_pool_t *pool, size_t size);
|
||||
|
||||
static void *
|
||||
ngx_palloc_large(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
void *p;
|
||||
unsigned int n = 0;
|
||||
ngx_pool_large_t *large;
|
||||
|
||||
p = malloc(size);
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
for (large = pool->large; large; large = large->next) {
|
||||
if (large->alloc == NULL) {
|
||||
large->alloc = p;
|
||||
return p;
|
||||
}
|
||||
if (n++ > 3)
|
||||
break;
|
||||
}
|
||||
|
||||
large = (ngx_pool_large_t *)ngx_palloc(pool, sizeof(ngx_pool_large_t));
|
||||
if (large == NULL) {
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
large->alloc = p;
|
||||
large->next = pool->large;
|
||||
pool->large = large;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void *
|
||||
ngx_palloc(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
unsigned char *m;
|
||||
ngx_pool_t *p;
|
||||
|
||||
if (size <= pool->max) {
|
||||
p = pool->current;
|
||||
do {
|
||||
m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);
|
||||
if ((size_t)(p->d.end - m) >= size) {
|
||||
p->d.last = m + size;
|
||||
return m;
|
||||
}
|
||||
p = p->d.next;
|
||||
} while (p);
|
||||
|
||||
return ngx_palloc_block(pool, size);
|
||||
}
|
||||
|
||||
return ngx_palloc_large(pool, size);
|
||||
}
|
||||
|
||||
void
|
||||
ngx_pfree(ngx_pool_t *pool, void *p)
|
||||
{
|
||||
ngx_pool_large_t *l;
|
||||
|
||||
for (l = pool->large; l; l = l->next) {
|
||||
if (p == l->alloc) {
|
||||
free(l->alloc);
|
||||
l->alloc = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_ngx_pool()
|
||||
{
|
||||
ngx_pool_t *p = ngx_create_pool(PAGE_SIZE);
|
||||
assert(p);
|
||||
|
||||
benchmark(std::move(T() + "ngx_pool"), [=]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = (T *)ngx_palloc(p, sizeof(T));
|
||||
touch_obj(o);
|
||||
}
|
||||
});
|
||||
|
||||
ngx_destroy_pool(p);
|
||||
}
|
||||
|
||||
void
|
||||
benchmark_ngx_pool_mix_free()
|
||||
{
|
||||
ngx_pool_t *p = ngx_create_pool(PAGE_SIZE);
|
||||
assert(p);
|
||||
|
||||
benchmark(std::move(std::string("ngx_pool w/ free (Mix)")), [=]() {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (__builtin_expect(!(i & 0xfff), 0)) {
|
||||
Huge *o;
|
||||
o = (Huge *)ngx_palloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
ngx_pfree(p, o);
|
||||
}
|
||||
else if (__builtin_expect(!(i & 3), 0)) {
|
||||
Big *o = (Big *)ngx_palloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
ngx_pfree(p, o);
|
||||
}
|
||||
else {
|
||||
Small *o = (Small *)ngx_palloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
ngx_pfree(p, o);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ngx_destroy_pool(p);
|
||||
}
|
||||
|
||||
void
|
||||
benchmark_ngx_pool_create_and_destroy()
|
||||
{
|
||||
benchmark(std::move(std::string("ngx_pool cr. & destr.")), []() {
|
||||
for (size_t i = 0; i < N / 100; ++i) {
|
||||
ngx_pool_t *p = ngx_create_pool(PAGE_SIZE);
|
||||
for (size_t j = 0; j < 100; ++j) {
|
||||
if (__builtin_expect(!(i & 3), 0)) {
|
||||
Big *o;
|
||||
o = (Big *)ngx_palloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
} else {
|
||||
Small *o;
|
||||
o = (Small *)ngx_palloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
}
|
||||
}
|
||||
ngx_destroy_pool(p);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
* Tempesta FW pool
|
||||
* Simplified and ported to user-space from
|
||||
* https://github.com/natsys/tempesta/blob/master/tempesta_fw/pool.c
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* Emulation of Linux buddy allocator.
|
||||
*/
|
||||
#define GFP_ATOMIC 0
|
||||
#define PAGE_MASK (~(PAGE_SIZE - 1))
|
||||
#define likely(x) __builtin_expect(x, 1)
|
||||
#define unlikely(x) __builtin_expect(x, 0)
|
||||
#define free_pages(p, o) free((void *)(p))
|
||||
#define get_order(n) (assert((n) < PAGE_SIZE * 128), \
|
||||
(n) < PAGE_SIZE ? 0 \
|
||||
: (n) < PAGE_SIZE * 2 ? 1 \
|
||||
: (n) < PAGE_SIZE * 4 ? 2 \
|
||||
: (n) < PAGE_SIZE * 8 ? 3 \
|
||||
: (n) < PAGE_SIZE * 16 ? 4 \
|
||||
: (n) < PAGE_SIZE * 32 ? 5 \
|
||||
: (n) < PAGE_SIZE * 64 ? 6 \
|
||||
: 7)
|
||||
|
||||
static inline unsigned long
|
||||
__get_free_pages(int flags __attribute__((unused)), int order)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (posix_memalign((void **)&p, PAGE_SIZE, PAGE_SIZE << order))
|
||||
return 0;
|
||||
|
||||
return (unsigned long)p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Memory pool chunk descriptor.
|
||||
*
|
||||
* @next - pointer to next memory chunk;
|
||||
* @order - order of number of pages in the chunk;
|
||||
* @off - current chunk offset;
|
||||
*/
|
||||
struct TfwPoolChunk {
|
||||
TfwPoolChunk *next;
|
||||
unsigned int order;
|
||||
unsigned int off;
|
||||
};
|
||||
|
||||
/**
|
||||
* Memory pool descriptor.
|
||||
*
|
||||
* @curr - current chunk to allocate memory from;
|
||||
* @order,@off - cached members of @curr;
|
||||
*/
|
||||
typedef struct {
|
||||
TfwPoolChunk *curr;
|
||||
unsigned int order;
|
||||
unsigned int off;
|
||||
} TfwPool;
|
||||
|
||||
#define TFW_POOL_CHUNK_SZ(p) (PAGE_SIZE << (p)->order)
|
||||
#define TFW_POOL_CHUNK_BASE(c) ((unsigned long)(c) & PAGE_MASK)
|
||||
#define TFW_POOL_CHUNK_END(p) (TFW_POOL_CHUNK_BASE((p)->curr) + (p)->off)
|
||||
#define TFW_POOL_ALIGN_SZ(n) (((n) + 7) & ~7UL)
|
||||
#define TFW_POOL_HEAD_OFF (TFW_POOL_ALIGN_SZ(sizeof(TfwPool)) \
|
||||
+ TFW_POOL_ALIGN_SZ(sizeof(TfwPoolChunk)))
|
||||
#define TFW_POOL_PGCACHE_SZ 256
|
||||
|
||||
static unsigned int pg_next;
|
||||
static unsigned long pg_cache[TFW_POOL_PGCACHE_SZ];
|
||||
|
||||
static unsigned long
|
||||
tfw_pool_alloc_pages(unsigned int order)
|
||||
{
|
||||
if (likely(pg_next && !order))
|
||||
return pg_cache[--pg_next];
|
||||
return __get_free_pages(GFP_ATOMIC, order);
|
||||
}
|
||||
|
||||
static void
|
||||
tfw_pool_free_pages(unsigned long addr, unsigned int order)
|
||||
{
|
||||
if (likely(pg_next < TFW_POOL_PGCACHE_SZ && !order)) {
|
||||
pg_cache[pg_next++] = addr;
|
||||
} else {
|
||||
free_pages(addr, order);
|
||||
}
|
||||
}
|
||||
|
||||
TfwPool *
|
||||
__tfw_pool_new(size_t n)
|
||||
{
|
||||
TfwPool *p;
|
||||
TfwPoolChunk *c;
|
||||
unsigned int order;
|
||||
|
||||
order = get_order(TFW_POOL_ALIGN_SZ(n) + TFW_POOL_HEAD_OFF);
|
||||
|
||||
c = (TfwPoolChunk *)tfw_pool_alloc_pages(order);
|
||||
if (unlikely(!c))
|
||||
return NULL;
|
||||
|
||||
p = (TfwPool *)((char *)c + TFW_POOL_ALIGN_SZ(sizeof(*c)));
|
||||
c->next = NULL;
|
||||
|
||||
p->order = order;
|
||||
p->off = TFW_POOL_HEAD_OFF;
|
||||
p->curr = c;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void *
|
||||
tfw_pool_alloc(TfwPool *p, size_t n)
|
||||
{
|
||||
void *a;
|
||||
|
||||
n = TFW_POOL_ALIGN_SZ(n);
|
||||
|
||||
if (unlikely(p->off + n > TFW_POOL_CHUNK_SZ(p))) {
|
||||
TfwPoolChunk *c, *curr = p->curr;
|
||||
unsigned int off = TFW_POOL_ALIGN_SZ(sizeof(TfwPoolChunk)) + n;
|
||||
unsigned int order = get_order(off);
|
||||
|
||||
c = (TfwPoolChunk *)tfw_pool_alloc_pages(order);
|
||||
if (!c)
|
||||
return NULL;
|
||||
c->next = curr;
|
||||
|
||||
curr->order = p->order;
|
||||
curr->off = p->off;
|
||||
|
||||
p->order = order;
|
||||
p->off = off;
|
||||
p->curr = c;
|
||||
|
||||
return (void *)TFW_POOL_ALIGN_SZ((unsigned long)(c + 1));
|
||||
}
|
||||
|
||||
a = (char *)TFW_POOL_CHUNK_END(p);
|
||||
p->off += n;
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
void
|
||||
tfw_pool_free(TfwPool *p, void *ptr, size_t n)
|
||||
{
|
||||
n = TFW_POOL_ALIGN_SZ(n);
|
||||
|
||||
/* Stack-like usage is expected. */
|
||||
if (unlikely((char *)ptr + n != (char *)TFW_POOL_CHUNK_END(p)))
|
||||
return;
|
||||
|
||||
p->off -= n;
|
||||
|
||||
/* Free empty chunk which doesn't contain the pool header. */
|
||||
if (unlikely(p->off == TFW_POOL_ALIGN_SZ(sizeof(TfwPoolChunk)))) {
|
||||
TfwPoolChunk *next = p->curr->next;
|
||||
tfw_pool_free_pages(TFW_POOL_CHUNK_BASE(p->curr), p->order);
|
||||
p->curr = next;
|
||||
p->order = next->order;
|
||||
p->off = next->off;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tfw_pool_destroy(TfwPool *p)
|
||||
{
|
||||
TfwPoolChunk *c, *next;
|
||||
|
||||
for (c = p->curr; c; c = next) {
|
||||
next = c->next;
|
||||
tfw_pool_free_pages(TFW_POOL_CHUNK_BASE(c), c->order);
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_tfw_pool()
|
||||
{
|
||||
TfwPool *p = __tfw_pool_new(0);
|
||||
assert(p);
|
||||
|
||||
benchmark(std::move(T() + "tfw_pool"), [=]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = (T *)tfw_pool_alloc(p, sizeof(T));
|
||||
touch_obj(o);
|
||||
}
|
||||
});
|
||||
|
||||
tfw_pool_destroy(p);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_tfw_pool_free()
|
||||
{
|
||||
TfwPool *p = __tfw_pool_new(0);
|
||||
assert(p);
|
||||
|
||||
benchmark(std::move(T() + "tfw_pool w/ free"), [&]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = (T *)tfw_pool_alloc(p, sizeof(T));
|
||||
touch_obj(o);
|
||||
if (__builtin_expect(!(i & 3), 0))
|
||||
tfw_pool_free(p, o, sizeof(T));
|
||||
}
|
||||
});
|
||||
|
||||
tfw_pool_destroy(p);
|
||||
}
|
||||
|
||||
void
|
||||
benchmark_tfw_pool_mix_free()
|
||||
{
|
||||
TfwPool *p = __tfw_pool_new(0);
|
||||
assert(p);
|
||||
|
||||
benchmark(std::move(std::string("tfw_pool w/ free (Mix)")), [=]() {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (__builtin_expect(!(i & 0xfff), 0)) {
|
||||
Huge *o;
|
||||
o = (Huge *)tfw_pool_alloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
tfw_pool_free(p, o, sizeof(*o));
|
||||
}
|
||||
else if (__builtin_expect(!(i & 3), 0)) {
|
||||
Big *o = (Big *)tfw_pool_alloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
tfw_pool_free(p, o, sizeof(*o));
|
||||
}
|
||||
else {
|
||||
Small *o;
|
||||
o = (Small *)tfw_pool_alloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tfw_pool_destroy(p);
|
||||
}
|
||||
|
||||
void
|
||||
benchmark_tfw_pool_create_and_destroy()
|
||||
{
|
||||
benchmark(std::move(std::string("tfw_pool cr. & destr.")), []() {
|
||||
for (size_t i = 0; i < N / 100; ++i) {
|
||||
TfwPool *p = __tfw_pool_new(0);
|
||||
for (size_t j = 0; j < 100; ++j) {
|
||||
if (__builtin_expect(!(i & 3), 0)) {
|
||||
Big *o;
|
||||
o = (Big *)tfw_pool_alloc(p,
|
||||
sizeof(*o));
|
||||
touch_obj(o);
|
||||
} else {
|
||||
Small *o;
|
||||
o = (Small *)tfw_pool_alloc(p,
|
||||
sizeof(*o));
|
||||
touch_obj(o);
|
||||
}
|
||||
}
|
||||
tfw_pool_destroy(p);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/* Adding M*LIB mempool */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "m-mempool.h"
|
||||
|
||||
MEMPOOL_DEF(mempool_small, Small)
|
||||
MEMPOOL_DEF(mempool_big, Big)
|
||||
MEMPOOL_DEF(mempool_huge, Huge)
|
||||
|
||||
void
|
||||
benchmark_mempool_small()
|
||||
{
|
||||
mempool_small_t p;
|
||||
mempool_small_init (p);
|
||||
mempool_small_t *ptr = &p; // C++ lambda !
|
||||
|
||||
benchmark(std::move(Small() + "M*LIB mempool"), [=]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(Small); ++i) {
|
||||
Small *o = mempool_small_alloc(*ptr);
|
||||
touch_obj(o);
|
||||
}
|
||||
});
|
||||
|
||||
mempool_small_clear(p);
|
||||
}
|
||||
|
||||
void
|
||||
benchmark_mempool_big()
|
||||
{
|
||||
mempool_big_t p;
|
||||
mempool_big_init (p);
|
||||
mempool_big_t *ptr = &p; // C++ lambda !
|
||||
|
||||
benchmark(std::move(Big() + "M*LIB mempool"), [=]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(Big); ++i) {
|
||||
Big *o = mempool_big_alloc(*ptr);
|
||||
touch_obj(o);
|
||||
}
|
||||
});
|
||||
|
||||
mempool_big_clear(p);
|
||||
}
|
||||
|
||||
void
|
||||
benchmark_mempool_mix_free()
|
||||
{
|
||||
mempool_small_t s, *ptr_s = &s;
|
||||
mempool_big_t b, *ptr_b = &b;
|
||||
mempool_huge_t h, *ptr_h = &h;
|
||||
|
||||
mempool_small_init (s);
|
||||
mempool_big_init (b);
|
||||
mempool_huge_init (h);
|
||||
|
||||
benchmark(std::move(std::string("M*LIB mempool w/ free (Mix)")), [=]() {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (__builtin_expect(!(i & 0xfff), 0)) {
|
||||
Huge *o = mempool_huge_alloc (*ptr_h);
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
mempool_huge_free (*ptr_h, o);
|
||||
}
|
||||
else if (__builtin_expect(!(i & 3), 0)) {
|
||||
Big *o = mempool_big_alloc(*ptr_b);
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
mempool_big_free (*ptr_b, o);
|
||||
}
|
||||
else {
|
||||
Small *o = mempool_small_alloc (*ptr_s);
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
mempool_small_free (*ptr_s, o);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mempool_small_clear (s);
|
||||
mempool_big_clear (b);
|
||||
mempool_huge_clear (h);
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
* Main part of the benchmark
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
int
|
||||
main()
|
||||
{
|
||||
std::cout << std::setw(35) << std::right << "small object size: "
|
||||
<< sizeof(Small) << std::endl;
|
||||
std::cout << std::setw(35) << std::right << "big object size: "
|
||||
<< sizeof(Big) << std::endl;
|
||||
std::cout << std::setw(35) << std::right << "huge object size: "
|
||||
<< sizeof(Huge) << "\n" << std::endl;
|
||||
|
||||
// Warm up malloc().
|
||||
static const size_t n = N * sizeof(Big);
|
||||
void *p = malloc(n);
|
||||
assert(p);
|
||||
memset(p, 0, n);
|
||||
free(p);
|
||||
|
||||
benchmark_mallocfree<Small>();
|
||||
benchmark_mallocfree_free<Small>();
|
||||
benchmark_mallocfree<Big>();
|
||||
benchmark_mallocfree_free<Big>();
|
||||
std::cout << std::endl;
|
||||
|
||||
#ifdef USE_GLIB
|
||||
benchmark_glib_slices<Small>();
|
||||
benchmark_glib_slices_free<Small>();
|
||||
benchmark_glib_slices<Big>();
|
||||
benchmark_glib_slices_free<Big>();
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
|
||||
#ifdef USE_BOOST
|
||||
benchmark_boost_pool<Small>();
|
||||
benchmark_boost_pool_free<Small>();
|
||||
benchmark_boost_pool<Big>();
|
||||
benchmark_boost_pool_free<Big>();
|
||||
benchmark_boost_pool_create_and_destroy();
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
|
||||
benchmark_ngx_pool<Small>();
|
||||
benchmark_ngx_pool<Big>();
|
||||
benchmark_ngx_pool_mix_free();
|
||||
benchmark_ngx_pool_create_and_destroy();
|
||||
std::cout << std::endl;
|
||||
|
||||
benchmark_mempool_small();
|
||||
benchmark_mempool_big();
|
||||
benchmark_mempool_mix_free();
|
||||
std::cout << std::endl;
|
||||
|
||||
benchmark_tfw_pool<Small>();
|
||||
benchmark_tfw_pool_free<Small>();
|
||||
benchmark_tfw_pool<Big>();
|
||||
benchmark_tfw_pool_free<Big>();
|
||||
benchmark_tfw_pool_mix_free();
|
||||
benchmark_tfw_pool_create_and_destroy();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
CC= gcc
|
||||
CXX= g++
|
||||
CFLAGS= -g -Wall -O2 -fomit-frame-pointer -march=native -lm -include stddef.h
|
||||
CXXFLAGS= $(CFLAGS)
|
||||
LDFLAGS=
|
||||
OBJS=
|
||||
LIBS= -lm
|
||||
|
||||
all: run
|
||||
|
||||
benchmarks:
|
||||
git clone https://github.com/attractivechaos/benchmarks.git
|
||||
|
||||
build: benchmarks
|
||||
mkdir -p benchmarks/udb/mlib
|
||||
cp test-mlib.c benchmarks/udb/mlib/test.c
|
||||
cp Makefile-mlib benchmarks/udb/mlib/Makefile
|
||||
mkdir -p benchmarks/udb/mlib-oa
|
||||
cp test-mlib-oa.c benchmarks/udb/mlib-oa/test.c
|
||||
cp Makefile-mlib benchmarks/udb/mlib-oa/Makefile
|
||||
touch build
|
||||
|
||||
all-recur: build
|
||||
cd benchmarks/udb; \
|
||||
wdir=`pwd`; \
|
||||
list_c=`find . -name 'test.c'`; \
|
||||
list_cc=`find . -name 'test.cc'`; \
|
||||
for t in $$list_c $$list_cc ; do \
|
||||
subdir=`dirname $$t`; \
|
||||
cd $$subdir; \
|
||||
$(MAKE) CC="$(CC)" CXX="$(CXX)" DFLAGS="$(DFLAGS)" CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" || exit 1; \
|
||||
cd $$wdir; \
|
||||
done;
|
||||
|
||||
run: all-recur
|
||||
@cd benchmarks/udb; \
|
||||
echo ; echo "LIBRARY | INT TIME | STR TIME" ; \
|
||||
for i in `find . -name 'test'` ; do \
|
||||
printf "%s|" `dirname $$i|sed -e 's+./++g'`; \
|
||||
$$i -is | awk ' \
|
||||
/\[int data\] # element/ { nbInt= $$5 } \
|
||||
/\[int data\] CPU time/ {timeInt= $$5 } \
|
||||
/\[str data\] # element/ { nbStr= $$5 } \
|
||||
/\[str data\] CPU time/ {timeStr= $$5 } \
|
||||
END { \
|
||||
if (nbInt != 624444) timeInt="BRK" ; \
|
||||
if (nbStr != 624444) timeStr="BRK" ; \
|
||||
print timeInt,"|" ,timeStr \
|
||||
}' ; \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm -rf benchmarks build
|
||||
@@ -1,22 +0,0 @@
|
||||
CC= gcc
|
||||
CFLAGS= -g -Wall -O2 -march=native
|
||||
OBJS= ../benchmark/benchmark.o ../runit/runlib.o test.o
|
||||
DFLAGS=
|
||||
INCLUDES= -I../benchmark -I../runit -I../../../../..
|
||||
LIBS=
|
||||
|
||||
.SUFFIXES:.c .o
|
||||
|
||||
.c.o:
|
||||
$(CC) -std=gnu11 -DNDEBUG -c $(INCLUDES) $(CFLAGS) $(DFLAGS) $< -o $@
|
||||
|
||||
all:test
|
||||
|
||||
test:$(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
||||
cleanlocal:
|
||||
rm -f *.o a.out *~ test
|
||||
|
||||
clean:cleanlocal
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "benchmark.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-mempool.h"
|
||||
|
||||
static inline bool oor_equal_p(int k, unsigned char n)
|
||||
{
|
||||
return k == (int)-n - 1;
|
||||
}
|
||||
|
||||
static inline void oor_set(int *k, unsigned char n)
|
||||
{
|
||||
*k = (int)-n - 1;
|
||||
}
|
||||
|
||||
DICT_OA_DEF2(dict_int,
|
||||
int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
|
||||
int, M_DEFAULT_OPLIST)
|
||||
|
||||
static const char *const oor[2] = { "EMPTY", "DELETED" };
|
||||
|
||||
static inline bool str_oor_equal_p(const char *k, unsigned char n)
|
||||
{
|
||||
return k == oor[n];
|
||||
}
|
||||
|
||||
static inline void str_oor_set(const char * *k, unsigned char n)
|
||||
{
|
||||
*k = oor[n];
|
||||
}
|
||||
|
||||
DICT_OA_DEF2(dict_str, const char *,
|
||||
M_OPEXTEND (M_CSTR_OPLIST, OOR_EQUAL(str_oor_equal_p), OOR_SET(str_oor_set M_IPTR)),
|
||||
int, M_DEFAULT_OPLIST)
|
||||
|
||||
|
||||
int test_int(int N, const unsigned *data)
|
||||
{
|
||||
int ret;
|
||||
M_LET(h, DICT_OPLIST(dict_int)) {
|
||||
for (int i = 0; i < N; ++i) {
|
||||
if (dict_int_get (h, data[i]) == NULL) {
|
||||
dict_int_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_int_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_int_size(h);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int test_str(int N, char * const *data)
|
||||
{
|
||||
int ret;
|
||||
M_LET(h, DICT_OPLIST(dict_str)) {
|
||||
for (int i = 0; i < N; ++i) {
|
||||
if (dict_str_get (h, data[i]) == NULL) {
|
||||
dict_str_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_str_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_str_size(h);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return udb_benchmark(argc, argv, test_int, test_str);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "benchmark.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-mempool.h"
|
||||
|
||||
DICT_STOREHASH_DEF2(dict_int,
|
||||
int, M_OPEXTEND(M_DEFAULT_OPLIST, MEMPOOL(mpool_int), MEMPOOL_LINKAGE(static)),
|
||||
int, M_DEFAULT_OPLIST)
|
||||
DICT_STOREHASH_DEF2(dict_str,
|
||||
const char *, M_OPEXTEND (M_CSTR_OPLIST, MEMPOOL(mpool_str), MEMPOOL_LINKAGE(static)),
|
||||
int, M_DEFAULT_OPLIST)
|
||||
|
||||
int test_int(int N, const unsigned *data)
|
||||
{
|
||||
int ret;
|
||||
dict_int_list_pair_mempool_init(mpool_int);
|
||||
M_LET(h, DICT_OPLIST(dict_int)) {
|
||||
for (int i = 0; i < N; ++i) {
|
||||
if (dict_int_get (h, data[i]) == NULL) {
|
||||
dict_int_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_int_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_int_size(h);
|
||||
}
|
||||
dict_int_list_pair_mempool_clear(mpool_int);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int test_str(int N, char * const *data)
|
||||
{
|
||||
int ret;
|
||||
dict_str_list_pair_mempool_init(mpool_str);
|
||||
M_LET(h, DICT_OPLIST(dict_str)) {
|
||||
for (int i = 0; i < N; ++i) {
|
||||
if (dict_str_get (h, data[i]) == NULL) {
|
||||
dict_str_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_str_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_str_size(h);
|
||||
}
|
||||
dict_str_list_pair_mempool_clear(mpool_str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return udb_benchmark(argc, argv, test_int, test_str);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
CC= gcc
|
||||
CXX= g++
|
||||
CFLAGS= -g -Wall -O2 -fomit-frame-pointer -march=native -lm -include stddef.h
|
||||
CXXFLAGS= $(CFLAGS)
|
||||
LDFLAGS=
|
||||
OBJS=
|
||||
LIBS=
|
||||
|
||||
all: run
|
||||
|
||||
udb2:
|
||||
git clone https://github.com/attractivechaos/udb2.git
|
||||
|
||||
build: udb2
|
||||
mkdir -p udb2/mlib
|
||||
cp test-mlib.c udb2/mlib/test.c
|
||||
cp Makefile-mlib udb2/mlib/Makefile
|
||||
touch build
|
||||
|
||||
all-recur: build
|
||||
cd udb2/stb && make CC="gcc -lm"
|
||||
cd udb2 && for dir in `ls | egrep -v '^(Makefile|common.c|_)'`; do cd $$dir && make && cd -; done
|
||||
|
||||
run: all-recur
|
||||
@cd udb2; \
|
||||
echo ; echo RUNNING BENCH ; echo ; \
|
||||
for i in `find . -name 'run-test'` ; do \
|
||||
echo ; echo `dirname $$i|sed -e 's+./++g'`; \
|
||||
$$i ; \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm -rf udb2 build *~
|
||||
@@ -1,8 +0,0 @@
|
||||
all:run-test
|
||||
|
||||
run-test:test.c ../common.c
|
||||
$(CC) -std=gnu99 -O2 -Wall -I../../../.. $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f run-test* *~
|
||||
rm -rf mlib
|
||||
@@ -1,34 +0,0 @@
|
||||
#include "../common.c"
|
||||
#define M_USE_DICT_OA_PROBING(s) 1
|
||||
#include "m-dict.h"
|
||||
|
||||
static inline bool oor_equal_p(unsigned int k, unsigned char n)
|
||||
{
|
||||
return k == (unsigned int)n;
|
||||
}
|
||||
static inline void oor_set(unsigned int *k, unsigned char n)
|
||||
{
|
||||
*k = (unsigned int)n;
|
||||
}
|
||||
|
||||
DICT_OA_DEF2(dict_oa_uint,
|
||||
unsigned int, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(hash_fn), OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
|
||||
unsigned int, M_DEFAULT_OPLIST)
|
||||
|
||||
uint32_t test_int(uint32_t n, uint32_t x0)
|
||||
{
|
||||
uint32_t i, x, z = 0;
|
||||
dict_oa_uint_t h;
|
||||
dict_oa_uint_init(h);
|
||||
for (i = 0, x = x0; i < n; ++i) {
|
||||
x = hash32(x);
|
||||
unsigned int key = get_key(n, x);
|
||||
unsigned int *ptr = dict_oa_uint_get_at(h, key);
|
||||
(*ptr)++;
|
||||
z += *ptr;
|
||||
}
|
||||
fprintf(stderr, "# unique keys: %d; checksum: %u\n", (int) dict_oa_uint_size(h), z);
|
||||
z = dict_oa_uint_size(h);
|
||||
dict_oa_uint_clear(h);
|
||||
return z;
|
||||
}
|
||||
+5
-1
@@ -81,4 +81,8 @@ V0.6.*: * Rename M_DEFAULT_OPLIST in M_BASIC_OPLIST
|
||||
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.
|
||||
|
||||
V0.7.*: * Rename m-mutex.h header in m-thread.h
|
||||
V0.7.2: * Rename m-mutex.h header in m-thread.h
|
||||
|
||||
V0.7.3 : * DICT_STOREHASH_DEF2 / DICT_STOREHASH_DEF2_AS are deprecated.
|
||||
Use DICT_DEF2 / DICT_DEF2_AS
|
||||
|
||||
+141
-27
@@ -1,18 +1,52 @@
|
||||
*Long term issues*
|
||||
==========================================================
|
||||
|
||||
* TODO #33 : Handling of partially constructed object :ANOMALY:
|
||||
* TODO #34 : Pass old size arguments to memory allocator :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
|
||||
Some custom allocators don't store the old size of an object to maximize memory usage
|
||||
used by the allocated objects. On realloc, they need the old size argument.
|
||||
This is inline with the GMP allocator which provides the old size argument.
|
||||
There is no difficulty in the data structure to compute the old size of the object
|
||||
(it is quite easily available).
|
||||
It is needed for REALLOC operator (and FREE)
|
||||
|
||||
** Solution #1
|
||||
|
||||
Add the oldsize argument to the REALLOC and FREE operators.
|
||||
|
||||
** Solution #2
|
||||
|
||||
Create a local variable m_local_old_size before calling the REALLOC or FREE operators
|
||||
Modify GAIA interface to link OLDSIZE patttern to m_local_old_size
|
||||
Need to handle the warnings correctly.
|
||||
|
||||
** Tradeof analysis
|
||||
|
||||
Solution #1 is simpler but breaks API. However custom allocators are not common.
|
||||
Solution #2 keeps API as it is but increases code complexity by adding more hacks into the codebase.
|
||||
|
||||
* TODO #33 : Handling of partially constructed object :ANOMALY:
|
||||
** State
|
||||
|
||||
Support of partially constructed object needs special code to handle it
|
||||
correctly (register a correct cleanup function in case of exception).
|
||||
|
||||
Current containers don't support such features.
|
||||
|
||||
> NOTE:
|
||||
An exception for init_set supposes that the object is *not* initialized.
|
||||
An exception for set supposes that the object *remains* initialized.
|
||||
Some containers perform an init_set using init+set
|
||||
others perform a set using a clear+init_set
|
||||
The property of init_set (resp. set) is broken if an exception is raised in the set (resp. init_set):
|
||||
the object is not let in the expected uninitialized (resp. initialized) state.
|
||||
|
||||
** Actions
|
||||
|
||||
Add such support in M*LIB containers.
|
||||
Need to analyse each function for execption safety.
|
||||
|
||||
It can be difficult. For example, for array _init_set
|
||||
function due to the copy of the object one per one. Each copied sub object
|
||||
@@ -20,7 +54,6 @@ may throw an exception, so we always need to have the container in a correct
|
||||
state so that it can be cleanup.
|
||||
|
||||
* TODO #32 : User specialization fields in the container :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
|
||||
Some methods of a contained object may need to have some options that
|
||||
@@ -41,10 +74,57 @@ of the GAIA by adding support for identification of specialization like this:
|
||||
|
||||
** Open points:
|
||||
|
||||
- How to get access to the specialization field of the container? ==> Define the "self" name as the name of the container for all methods? What to do when there are several containers for a method?
|
||||
- How to initialize the specialization field of the container? provide custom initialization functions? It seems to be the hard point.
|
||||
- How to get access to the specialization field of the container?
|
||||
==> Define the "self" name as the name of the container for all methods?
|
||||
- What to do when there are several containers for a method?
|
||||
==> self shall be the destination?
|
||||
|
||||
* TODO #31 : Uniformize parametrisation options of containers :ENHANCEMENT:
|
||||
- How to initialize the specialization field of the container? provide custom initialization functions? It seems to be the hard point.
|
||||
Use GAIA interface and a local variable with force naming : m_local_context for example.
|
||||
|
||||
** Proposed Solution:
|
||||
|
||||
New operator USER_CONTEXT created. If operator USER_CONTEXT exist:
|
||||
+ add a USER_CONTEXT user_data in the data structure.
|
||||
+ for INIT & INIT_WITH, add a new parameter to the function to pass the context to initialize
|
||||
+ for INIT_SET & INIT_MOVE & MOVE, initialize it with the source object (FIXME: This may not be what we want for INIT_SET if we want to copy an object from an allocator to another)
|
||||
+ for each functions that use an operator that may use the USER_CONTEXT, add a local variable m_local_context and initialize to the user context
|
||||
==> Limit user context to pointer or integer (Good enough)
|
||||
+ Expand GAIA interface to handle specially the term USER_CONTEXT: if it exists, expands it to m_local_context. The user will therefore be able to expand its operator with the user provided local context.
|
||||
+ Update OPLIST of data structure to change the call to INIT & INIT_WITH to use GAIA/USER_CONTEXT if the basic type has a USER_CONTEXT
|
||||
+ To be checked: EMPLACE_TYPE ?
|
||||
+ Create M_USING_CONTEXT to initialize a local variable m_local_context and initalize it with the user context to be used y the M_LET macro:
|
||||
M_USING_CONTEXT(int *, &y)
|
||||
M_LET(x, object_t) {
|
||||
|
||||
}
|
||||
|
||||
Done in branch feature/user-data-v2 with a full working implementation for array
|
||||
|
||||
** Solution limitation:
|
||||
|
||||
INIT & INIT_WITH interface change for the user. This however is an acceptable limitation.
|
||||
|
||||
Adding a user context to each data structure will increase a lot the size of the data structure in case of recursive data structures: For example, an array of string_t. Each string_t will need a user data context for it to work properly, so we'll need N*sizeof(user data context) memory just to make it work. This becomes even more problematic if we chain more data structures.
|
||||
And in general, we use custom allocators to be faster and use less memory: this will defeat the purpose of custom allocators a lot.
|
||||
|
||||
Another limitation is that string_t / bitset_t are not supported correctly. We can make this change globally but it will prevent mixing different codebase that uses the string_t together (one expects a user context, the other not).
|
||||
|
||||
** Alternative #1
|
||||
|
||||
Passing user context arguments to each function call seems to be a little bit better.
|
||||
It might however reduces code optimization as one more register will be user everywhere in the calling chain, which may huge.
|
||||
|
||||
** Alternative #2
|
||||
|
||||
The custom allocator could have a thread default allocator as a global variable (thread attribute). It seems to be a better solution, more scalable.
|
||||
The custom allocator will need to be able to switch quickly between scrach arena and permanent arena. This seems to be easy.
|
||||
|
||||
However switching allocators puts a burden to the user:
|
||||
the user needs to properly be sure to call the destructor with the custom allocator set to be the same as when it was created.
|
||||
This might not even be possible in case of exceptions.
|
||||
|
||||
* TODO #31 : Uniformize parametrization options of containers :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
|
||||
@@ -121,31 +201,33 @@ Currently, each container supports 3 serialization methods:
|
||||
|
||||
Generic serialiation connect the container format to the serialization object constraints.
|
||||
It is done through a vtable. As such there is a performance penality and it avoids proper inlining.
|
||||
It is however quite flexible and decouple the data structure from the serialization format.
|
||||
|
||||
** Evolution
|
||||
|
||||
Old format should be deprecated and shall use the generic serialization interface.
|
||||
Old format should be deprecated and the functions implemented it shall use the generic serialization interface.
|
||||
|
||||
Serialization object shall provide an OPLIST of serialization.
|
||||
For example CORE will provide OLD Format oplist and serial-json will provide JSON format oplist.
|
||||
Serialization object shall provide a special OPLIST of serialization.
|
||||
For example M-CORE will provide OLD Format oplist and M-SERIAL-JSON will provide JSON format oplist.
|
||||
Each oplist will provide the suffix needed for the serialization, and the interface
|
||||
(see already existing interface).
|
||||
|
||||
Then a container will generate specialized serialization methods for each provided oplist.
|
||||
|
||||
Pros:
|
||||
** Pros:
|
||||
|
||||
- Faster
|
||||
- In the M*LIB philosphy: much like other oplist usage.
|
||||
|
||||
Cons:
|
||||
** Cons:
|
||||
|
||||
- compatibility breakage.
|
||||
- increase code complexity.
|
||||
|
||||
Open point:
|
||||
** Open point:
|
||||
|
||||
- how can a user add a new serialization object?
|
||||
- Can we make a generic serialization object to support migration path?
|
||||
- how can a user add a new serialization object? ==> See solution implemented by M-GENERIC.
|
||||
- Can we make a generic serialization object to support migration path? Seems possible.
|
||||
|
||||
** Example
|
||||
|
||||
@@ -204,9 +286,11 @@ of the M_CHAIN_INIT are called.
|
||||
|
||||
* TODO #28 : Separate generation of interface to implementation :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
Enable support for generating an interface only for the headers
|
||||
and an implementation only for the source code.
|
||||
|
||||
** Analysis
|
||||
Try to keep API compatibility
|
||||
==> Only modify renamed macro with M_ prefix by giving a new mandatory
|
||||
argument for such generation.
|
||||
@@ -248,7 +332,7 @@ a fixed size will be good to have too for such interface.
|
||||
- Uniformization of the interface (See #31)
|
||||
- Provide static size for all QUEUE.
|
||||
|
||||
* TODO #26 : Hash-Map for huge objects :ENHANCEMENT:
|
||||
* DONE #26 : Hash-Map for huge objects :ENHANCEMENT:
|
||||
|
||||
Specialize Hashmap for huge objects on supported hardware:
|
||||
|
||||
@@ -281,18 +365,27 @@ unsigned get_small_hash(int64_t x) {
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
Can also (should?) use SIMD to test for several hash entries at the same times
|
||||
In which case a complete new implementation will be needed
|
||||
Note: SIMD doesn't seem to be a win if not handled properly.
|
||||
Since the first guess of a good hashtable shall give the right entry > 90% of the time.
|
||||
So 90% of the times SIMD will pay the cost of reading not needed memory.
|
||||
It might still be a win, but proper tuning needs to be done.
|
||||
|
||||
* TODO #25 : Support of error return model for error handling. :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
Find a way to support error return code for the API in case of allocation
|
||||
failure.
|
||||
|
||||
** Analysis
|
||||
Any service that returns void shall return a "int" (or another type).
|
||||
In case of allocation failure, it shall return an error.
|
||||
M_CALL macro shall stop its execution if the service returns an error code
|
||||
and the error code represents an error (avoid rewritting everything)
|
||||
and throw back the error code (stopping the execution flow).
|
||||
|
||||
Services returning already something shall not be modified.
|
||||
Services returning already something shall not be modified but returns the error code embedded (like a NULL pointer).
|
||||
|
||||
This model should be applied at the container level only and not globally.
|
||||
Different containers may need different levels of error handling.
|
||||
@@ -344,17 +437,20 @@ RETCODE/RETCODE
|
||||
|
||||
If really needed, the macro can be avoided and code can be hand written.
|
||||
|
||||
Open points:
|
||||
** Open points:
|
||||
|
||||
- How to handle warnings on unused labels?
|
||||
- What about M_LET / M_EACH? Maybe only supports those.
|
||||
|
||||
* TODO #24 : New MIN-MAX-HEAP container :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
See https://en.wikipedia.org/wiki/Min-max_heap
|
||||
as DPRIORITY_QUEUE_DEF ?
|
||||
|
||||
** Analysis
|
||||
NOTE: Needs for such container?
|
||||
On hold until a user needs it.
|
||||
|
||||
* TODO #23 : Strict MOVE semantic to clarify :ENHANCEMENT:
|
||||
|
||||
@@ -364,7 +460,7 @@ Some type may need to have a force MOVE semantic (for example, they can store
|
||||
pointer to themselves). Currently the INIT_MOVE & MOVE operators are more
|
||||
a help for performance than a strict semantic usage.
|
||||
|
||||
** ARRAY container
|
||||
** ARRAY container constraint
|
||||
|
||||
The ARRAY container doesn't support strict MOVE semantic for example.
|
||||
It is not a simple matter as it performs a realloc of the table, thus
|
||||
@@ -387,9 +483,9 @@ For example for tuple, it shall
|
||||
|
||||
** DO_INIT_MOVE operator
|
||||
|
||||
DO_INIT_MOVE macro is not also fully working for structure
|
||||
DO_INIT_MOVE macro is also fully working for structure
|
||||
defined with [1] tricks but without an explicit INIT_MOVE / MOVE
|
||||
operators as it uses MOVE_DEFAULT which is not (fully compatible).
|
||||
operators as it uses MOVE_DEFAULT which is not compatible.
|
||||
==> Analyse limitation and possible constraint usages.
|
||||
|
||||
Being able to define a correct default for INIT_MOVE will be really good
|
||||
@@ -403,12 +499,13 @@ will transform the argument to T*, and the type of the argument doesn't match
|
||||
what is expecting resulting in a move of the pointers, not a move of the design data.
|
||||
|
||||
Defining this type seems possible with C11 _Generic and a TYPE in the oplist,
|
||||
but without C11 _Generic I don't see any way to define such macro.
|
||||
but without C11 _Generic I don't see any way to define such macro
|
||||
and we still need to target C99 for such basic feature.
|
||||
|
||||
Without a way to write such a macro, the ticket seems pretty much a dead end.
|
||||
|
||||
* TODO #20 : New: Bucket priority queue :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
Add a new kind of priority queue.
|
||||
See https://en.wikipedia.org/wiki/Bucket_queue
|
||||
|
||||
@@ -423,19 +520,33 @@ except that we can scan 64 entries at a time).
|
||||
Check if we can use BITSET, or introduce fixed size BITSET or use ad-hock
|
||||
implementation.
|
||||
|
||||
* TODO #19 : New: Intrusive Red Black Tree :ENHANCEMENT:
|
||||
** Analysis
|
||||
NOTE: Needs for such container?
|
||||
On hold until a user needs it.
|
||||
|
||||
* CANC #19 : New: Intrusive Red Black Tree :ENHANCEMENT:
|
||||
** State
|
||||
Add intrusive red black tree.
|
||||
Look also for AVL tree (NOTE: Is there a performance difference between the two?)
|
||||
|
||||
* TODO #18 : Missing methods :ENHANCEMENT:
|
||||
** Analysis
|
||||
Only needed for unmovable objects for which B+Tree cannot do the job.
|
||||
But standard Read/Black Tree will do the job just fine.
|
||||
There is really no need for it.
|
||||
==> Cancelled
|
||||
|
||||
* TODO #18 : Missing methods :ENHANCEMENT:
|
||||
** State
|
||||
Some containers don't have all the methods they should.
|
||||
See the cells in yellow here:
|
||||
http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Container.html
|
||||
|
||||
** Analysis
|
||||
Analyzed each missing methods and fill in the gap
|
||||
|
||||
* TODO #17 : New: Ressource handler :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
A global 'ressouce handler' which shall associated a unique handle to a ressource.
|
||||
The handle shall be unique for the ressource and shall not be reused.
|
||||
It is typically a 64 bits integers always incremented (even if the program
|
||||
@@ -461,8 +572,9 @@ http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Co
|
||||
|
||||
How to handle multiple resource ?
|
||||
|
||||
* variant: Pro : easy. Con: Memory usage can be (much) higher than needed if there is a lot of dissimilarity between the size of the objects.
|
||||
* embedded the type in the ressource handler: Con: more work, API more complex. Pro: Memory usage seems better.
|
||||
** Analysis
|
||||
- use of variant: Pro : easy. Con: Memory usage can be (much) higher than needed if there is a lot of dissimilarity between the size of the objects.
|
||||
- embedded the type in the ressource handler: Con: more work, API more complex. Pro: Memory usage seems better.
|
||||
|
||||
* TODO #16 : New: Lock Free List :ENHANCEMENT:
|
||||
|
||||
@@ -487,6 +599,8 @@ http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Co
|
||||
- needs to be logically deleted : needs a previous field
|
||||
(NULL if not logically deleted) ? TBC
|
||||
|
||||
NOTE: m-c-mempool doesn't seem to be fully robust. random failure of the test cases appear (more notably with Visual C++, but it is still quite rare).
|
||||
|
||||
* DONE #14 : Memory allocation enhancement :ENHANCEMENT:
|
||||
|
||||
Enhancement of the memory allocation scheme to find way to deal properly with advanced allocators:
|
||||
@@ -524,7 +638,7 @@ It is a kind of object inheritance where the container inherits some extra data
|
||||
Duplicate with #32 which is more generic ==> Closed
|
||||
|
||||
* TODO #12 : New: Atomic shared pointer :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
Add an extension to the SHARED_PTR API:
|
||||
|
||||
- New type atomic_shared_ptr
|
||||
@@ -598,7 +712,7 @@ Other alternative solution is to use the bit 0 to mark the pointer as being upda
|
||||
Other implementation seems to have it hard to be lock-free: cf. https://github.com/llvm-mirror/libcxx/commit/5fec82dc0db3623546038e4a86baa44f749e554f
|
||||
|
||||
* TODO #5 : New: Concurrent dictionary Container :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
Implement a more efficient dictionary than lock + std dictionary for all operations when dealing with threads.
|
||||
See https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ param2=""
|
||||
while test $# -gt 0 ; do
|
||||
case $1 in
|
||||
-c) param2="$param2 -c" ;;
|
||||
-o) param2="$param2 -o $2" ; shift ;;
|
||||
*\.c) param1="$param1 $1" ;;
|
||||
*) param1="$param1 $1" ; param2="$param2 $1" ;;
|
||||
esac
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 128 KiB |
+4
-4
@@ -31,7 +31,7 @@ RM=rm -f
|
||||
.SUFFIXES: .c .exe
|
||||
|
||||
.c.exe:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ `cat config` $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ `cat config` `cat config.curl` $(LDFLAGS)
|
||||
|
||||
.c.o:
|
||||
@$(MAKE) config
|
||||
@@ -53,11 +53,11 @@ config:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib config-test.c -lgmp -o config-test.exe $(LDFLAGS) 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=0 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0 -DHAVE_MPFR=0 " > config
|
||||
printf "#include <mpfr.h>\nint main(void){mpfr_t z; mpfr_init(z); return 0;}\n" > config-test.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I$(GMP_DIR)/include -I$(MPFR_DIR)/include -L$(GMP_DIR)/lib -L$(MPFR_DIR)/lib config-test.c -lmpfr -lgmp -o config-test.exe $(LDFLAGS) 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -I$(MPFR_DIR)/include -L$(MPFR_DIR)/lib -lmpfr -lgmp" > config || echo "MPFR not available"
|
||||
printf "#include <curl/curl.h>\nint main(void){curl_global_init(CURL_GLOBAL_DEFAULT);}" > config-test.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) config-test.c `curl-config --cflags --libs` -o config-test.exe 2> /dev/null && echo "-DHAVE_CURL=1 `curl-config --cflags --libs`" > config.curl || echo "-DHAVE_CURL=0 " > config.curl
|
||||
printf "#include <stdio.h>\nint main(void){printf(\"Ok\"); return 0;}\n" > config-test.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) config-test.c -ffunction-sections -fdata-sections -Wl,--gc-sections 2> /dev/null && echo "-ffunction-sections -fdata-sections -Wl,--gc-sections" > config.link || echo "" > config.link
|
||||
$(RM) config-test.c config-test.exe
|
||||
|
||||
clean:
|
||||
$(RM) *.exe *.s *~ *.o ./a.dat config config.link
|
||||
|
||||
|
||||
$(RM) *.exe *.s *~ *.o ./a.dat config config.link config.curl
|
||||
@@ -0,0 +1,109 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static size_t allocated_size = 0;
|
||||
|
||||
static void* my_alloc(size_t s)
|
||||
{
|
||||
printf("Alloc called s=%lu!\n", s);
|
||||
allocated_size += s;
|
||||
return malloc(s);
|
||||
}
|
||||
|
||||
static void my_free(void *ptr, size_t s)
|
||||
{
|
||||
printf("Free called s=%lu!\n", s);
|
||||
allocated_size -= s;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static void *last_alloc;
|
||||
|
||||
static void* my_array_alloc(size_t s, void *org, size_t n)
|
||||
{
|
||||
printf("Array Alloc called org=%p of n=%zu elements of size s=%lu!\n", org, n, s);
|
||||
last_alloc = realloc(org, s*n);
|
||||
return last_alloc;
|
||||
}
|
||||
|
||||
static void my_array_free(void *ptr)
|
||||
{
|
||||
printf("Array Free called ptr=%p last_alloc=%p!\n", ptr, last_alloc);
|
||||
if (ptr != last_alloc) {
|
||||
printf("Somthing went wrong.\n");
|
||||
exit(4);
|
||||
}
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// Allocate for single object
|
||||
# define M_MEMORY_ALLOC(type) my_alloc (sizeof (type))
|
||||
# define M_MEMORY_DEL(ptr) my_free(ptr, sizeof *ptr)
|
||||
|
||||
// Allocate for array of objects
|
||||
# define M_MEMORY_REALLOC(type, ptr, n) my_array_alloc (sizeof (type), ptr, n)
|
||||
# define M_MEMORY_FREE(ptr) my_array_free(ptr)
|
||||
|
||||
#include "m-list.h"
|
||||
#include "m-array.h"
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
LIST_DEF(list_int, int)
|
||||
|
||||
static void test_list(void)
|
||||
{
|
||||
printf("List demo\n");
|
||||
|
||||
list_int_t list;
|
||||
list_int_init(list);
|
||||
|
||||
list_int_push_back(list, 34);
|
||||
list_int_push_back(list, 34);
|
||||
|
||||
if (allocated_size == 0) {
|
||||
printf("Nothing was allocated... Very strange...\n");
|
||||
exit(1);
|
||||
}
|
||||
list_int_clear(list);
|
||||
|
||||
if (allocated_size != 0) {
|
||||
printf("Nothing was freed (%lu)... Very strange...\n", allocated_size);
|
||||
exit(2);
|
||||
}
|
||||
printf("Global custom allocator for list works!\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
ARRAY_DEF(array_int, int)
|
||||
|
||||
static void test_array(void)
|
||||
{
|
||||
printf("Array demo\n");
|
||||
|
||||
array_int_t array;
|
||||
array_int_init(array);
|
||||
|
||||
array_int_push_back(array, 34);
|
||||
array_int_push_back(array, 34);
|
||||
|
||||
array_int_clear(array);
|
||||
|
||||
printf("Global custom allocator for array works!\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_list();
|
||||
test_array();
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "m-list.h"
|
||||
#include "m-array.h"
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static size_t allocated_size = 0;
|
||||
|
||||
static void* my_alloc(size_t s)
|
||||
{
|
||||
printf("Alloc called s=%lu!\n", s);
|
||||
allocated_size += s;
|
||||
return malloc(s);
|
||||
}
|
||||
|
||||
static void my_free(void *ptr, size_t s)
|
||||
{
|
||||
printf("Free called s=%lu!\n", s);
|
||||
allocated_size -= s;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
// Allocate for single object
|
||||
# define MY_MEMORY_ALLOC(type) my_alloc (sizeof (type))
|
||||
# define MY_MEMORY_DEL(ptr) my_free(ptr, sizeof *ptr)
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// Override only for this container the memory allocation function
|
||||
LIST_DEF(list_int, int, M_OPEXTEND(M_BASIC_OPLIST, NEW(MY_MEMORY_ALLOC), DEL(MY_MEMORY_DEL)))
|
||||
|
||||
static void test_list(void)
|
||||
{
|
||||
printf("List demo\n");
|
||||
|
||||
list_int_t list;
|
||||
list_int_init(list);
|
||||
|
||||
list_int_push_back(list, 34);
|
||||
list_int_push_back(list, 34);
|
||||
|
||||
if (allocated_size == 0) {
|
||||
printf("Nothing was allocated... Very strange...\n");
|
||||
exit(1);
|
||||
}
|
||||
list_int_clear(list);
|
||||
|
||||
if (allocated_size != 0) {
|
||||
printf("Nothing was freed (%lu)... Very strange...\n", allocated_size);
|
||||
exit(2);
|
||||
}
|
||||
printf("Global custom allocator for list works!\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static void *last_alloc;
|
||||
|
||||
static void* my_array_alloc(size_t s, void *org, size_t n)
|
||||
{
|
||||
printf("Array Alloc called org=%p of n=%zu elements of size s=%lu!\n", org, n, s);
|
||||
last_alloc = realloc(org, s*n);
|
||||
return last_alloc;
|
||||
}
|
||||
|
||||
static void my_array_free(void *ptr)
|
||||
{
|
||||
printf("Array Free called ptr=%p last_alloc=%p!\n", ptr, last_alloc);
|
||||
if (ptr != last_alloc) {
|
||||
printf("Somthing went wrong.\n");
|
||||
exit(4);
|
||||
}
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
// Allocate for array of objects
|
||||
# define MY_MEMORY_REALLOC(type, ptr, n) my_array_alloc (sizeof (type), ptr, n)
|
||||
# define MY_MEMORY_FREE(ptr) my_array_free(ptr)
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// Override only for this container the memory allocation function
|
||||
ARRAY_DEF(array_int, int, M_OPEXTEND(M_BASIC_OPLIST, REALLOC(MY_MEMORY_REALLOC), FREE(MY_MEMORY_FREE)))
|
||||
|
||||
static void test_array(void)
|
||||
{
|
||||
printf("Array demo\n");
|
||||
|
||||
array_int_t array;
|
||||
array_int_init(array);
|
||||
|
||||
array_int_push_back(array, 34);
|
||||
array_int_push_back(array, 34);
|
||||
|
||||
array_int_clear(array);
|
||||
|
||||
printf("Global custom allocator for array works!\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_list();
|
||||
test_array();
|
||||
exit(0);
|
||||
}
|
||||
@@ -59,10 +59,12 @@ int main(void)
|
||||
}
|
||||
|
||||
// Print
|
||||
printf("\nElisabeth has id = %d\n", *map_employee_name_get(Employees_r, STRING_CTE("Elisabeth")));
|
||||
printf("\nElisabeth has id = %d\n", *map_employee_name_get(Employees_r, STRING_CTE("Elisabeth")));
|
||||
// Print using emplace (we give a const char [] isntead of a const string_t, avoiding macro STRING_CTE)
|
||||
printf("\nElisabeth has id = %d\n", *map_employee_name_get_emplace(Employees_r, "Elisabeth"));
|
||||
} /* Employees_r is cleared beyond this point */
|
||||
|
||||
// But employee is not
|
||||
// But employee is not since we don't use M_LET
|
||||
map_employee_id_clear(Employees);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_MULTI_DEF2(multimap, 5, int, M_BASIC_OPLIST, int, M_BASIC_OPLIST)
|
||||
#define M_OPL_map_multimap_t() BPTREE_OPLIST2(multimap, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
// Fill in with multiple value
|
||||
static void
|
||||
fill_in(multimap_t map)
|
||||
{
|
||||
for(int i = 1 ; i < 100; i++)
|
||||
multimap_set_at(map, i, i);
|
||||
for(int i = 1 ; i < 100; i+=2)
|
||||
multimap_set_at(map, i, i*i);
|
||||
for(int i = 1 ; i < 100; i+=3)
|
||||
multimap_set_at(map, i, i*i*i);
|
||||
}
|
||||
|
||||
// Count the number of occurence of a key
|
||||
static int
|
||||
count(multimap_t map, int key)
|
||||
{
|
||||
int n = 0;
|
||||
multimap_it_t it;
|
||||
// it_from is O(n*ln n) complexity
|
||||
// it_while_p and next are O(1) complexity
|
||||
for(multimap_it_from(it, map, key); multimap_it_while_p(it, key); multimap_next(it))
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
// Print the map in details
|
||||
static void
|
||||
print(multimap_t map)
|
||||
{
|
||||
for(int i = 0; i < 101;i++) {
|
||||
printf("Key=%d Count=%d ", i, count(map, i));
|
||||
multimap_it_t it;
|
||||
for(multimap_it_from(it, map, i); multimap_it_while_p(it, i); multimap_next(it)) {
|
||||
printf("Value=%d ", *multimap_ref(it)->value_ptr );
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
multimap_t map;
|
||||
multimap_init(map);
|
||||
fill_in(map);
|
||||
print(map);
|
||||
multimap_clear(map);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
#if HAVE_CURL
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include "m-dict.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-string.h"
|
||||
#include "m-list.h"
|
||||
#include "m-serial-json.h"
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
// Define container types
|
||||
// First a generic map string to string
|
||||
DICT_DEF2(map_str, string_t, string_t)
|
||||
#define M_OPL_map_str_t() DICT_OPLIST(map_str, STRING_OPLIST, STRING_OPLIST)
|
||||
|
||||
// This structure matches the JSON structure returns by the used WEB server
|
||||
// for the GET command.
|
||||
// It can be whatever you want provided it matches what is expected by the WEB server
|
||||
TUPLE_DEF2(web_data,
|
||||
(args, map_str_t),
|
||||
(headers, map_str_t),
|
||||
(origin, string_t),
|
||||
(url, string_t))
|
||||
#define M_OPL_web_data_t() TUPLE_OPLIST(web_data, M_OPL_map_str_t(), M_OPL_map_str_t(), STRING_T, STRING_T)
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
|
||||
static size_t
|
||||
write_data(void *buffer, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
(void) size; // Parameter not used
|
||||
char *src = buffer;
|
||||
string_ptr str = userp;
|
||||
for(size_t i = 0; i < nmemb; i++) {
|
||||
string_push_back(str, src[i]);
|
||||
}
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
static bool get_data(web_data_t data, const char url[])
|
||||
{
|
||||
m_serial_return_code_t r = M_SERIAL_FAIL;
|
||||
CURLcode res;
|
||||
string_t str;
|
||||
CURL *handle = curl_easy_init();
|
||||
if (handle) {
|
||||
string_init(str);
|
||||
// Perform an http GET request and fill in str with the JSON answer
|
||||
curl_easy_setopt(handle, CURLOPT_URL, url);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEDATA, str);
|
||||
res = curl_easy_perform(handle);
|
||||
curl_easy_cleanup(handle);
|
||||
if (res == CURLE_OK) {
|
||||
// Parse the string and fill in the object
|
||||
m_serial_str_json_read_t serial;
|
||||
m_serial_str_json_read_init(serial, string_get_cstr(str));
|
||||
r = web_data_in_serial(data, serial);
|
||||
m_serial_str_json_read_clear(serial);
|
||||
}
|
||||
string_clear(str);
|
||||
}
|
||||
return r == M_SERIAL_OK_DONE;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
static size_t
|
||||
ignore_data(void *buffer, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
(void) buffer; // Parameter not used
|
||||
(void) size; // Parameter not used
|
||||
(void) userp; // Parameter not used
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
static bool post_data(web_data_t data, const char url[], bool display_answer)
|
||||
{
|
||||
m_serial_return_code_t r = M_SERIAL_FAIL;
|
||||
CURLcode res = 0;
|
||||
string_t str;
|
||||
CURL *handle = curl_easy_init();
|
||||
if (handle) {
|
||||
string_init(str);
|
||||
// Get a JSON string
|
||||
m_serial_str_json_write_t serial;
|
||||
m_serial_str_json_write_init(serial, str);
|
||||
r = web_data_out_serial(serial, data);
|
||||
m_serial_str_json_write_clear(serial);
|
||||
if (r == M_SERIAL_OK_DONE) {
|
||||
// Post JSON string
|
||||
struct curl_slist *headers=NULL;
|
||||
headers = curl_slist_append(headers, "Content-Type: text/json");
|
||||
if (headers != NULL) {
|
||||
curl_easy_setopt(handle, CURLOPT_POSTFIELDS, string_get_cstr(str));
|
||||
curl_easy_setopt(handle, CURLOPT_URL, url);
|
||||
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
|
||||
if (display_answer == false) {
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ignore_data);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL);
|
||||
}
|
||||
res = curl_easy_perform(handle);
|
||||
curl_slist_free_all(headers);
|
||||
}
|
||||
}
|
||||
curl_easy_cleanup(handle);
|
||||
string_clear(str);
|
||||
}
|
||||
return (r == M_SERIAL_OK_DONE) && (res == CURLE_OK);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
// Remote server URL
|
||||
#define URL_GET "https://httpbin.org/get"
|
||||
#define URL_POST "https://httpbin.org/post"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
CURLcode ret = curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
if (ret != CURLE_OK) abort();
|
||||
|
||||
web_data_t data;
|
||||
web_data_init(data);
|
||||
|
||||
// Test http GET
|
||||
bool b = get_data(data, URL_GET);
|
||||
if (b) {
|
||||
// We success receiving the JSON object and fill in the C object web_data with it.
|
||||
// Let's display the object content:
|
||||
printf("SUCCESS. Receive data =\n");
|
||||
web_data_out_str(stdout, data);
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("ERROR: Cannot GET data or get data are not in expected format\n");
|
||||
}
|
||||
|
||||
// Test http POST
|
||||
web_data_emplace_origin(data, "This is the origin");
|
||||
web_data_emplace_url(data, "This is the URL");
|
||||
//web_data_set_origin(data, STRING_CTE("This is the origin"));
|
||||
//web_data_set_url(data, STRING_CTE("This is the URL"));
|
||||
b = post_data(data, URL_POST, false);
|
||||
if (b) {
|
||||
printf("SUCCESS: Post\n");
|
||||
} else {
|
||||
printf("ERROR post\n");
|
||||
}
|
||||
|
||||
web_data_clear(data);
|
||||
|
||||
curl_global_cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void) { return 0; }
|
||||
#endif
|
||||
+11
-10
@@ -4,44 +4,45 @@
|
||||
#include "m-dict.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Define a dictionnary of string --> int
|
||||
// Define a dictionary of string --> int
|
||||
// named 'dict_str'
|
||||
DICT_DEF2(dict_str, string_t, STRING_OPLIST, int, M_BASIC_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Declare the dictionnary 'h'
|
||||
// Declare the dictionary 'h'
|
||||
dict_str_t h;
|
||||
int max = 1;
|
||||
// Declare the string 'key'
|
||||
string_t key;
|
||||
|
||||
// Initialize the dictionnary & the string
|
||||
// Initialize the dictionary & the string
|
||||
dict_str_init(h);
|
||||
string_init (key);
|
||||
|
||||
// While there is some data in the stream
|
||||
while (!feof(stdin))
|
||||
while (true)
|
||||
{
|
||||
// Read a complete line from the stream and fill in the string 'key'
|
||||
string_fgets (key, stdin, STRING_READ_PURE_LINE);
|
||||
// If the 'key' exists in the dictionnary
|
||||
if (feof(stdin)) break;
|
||||
// If the 'key' exists in the dictionary
|
||||
int *v = dict_str_get (h, key);
|
||||
if (v != NULL) {
|
||||
// Increment the counter in the dictionnary
|
||||
// Increment the counter in the dictionary
|
||||
(*v)++;
|
||||
max = M_MAX(*v, max);
|
||||
} else {
|
||||
// Update the dictionnary with h[key] = 1
|
||||
// Update the dictionary with h[key] = 1
|
||||
dict_str_set_at(h, key, 1);
|
||||
}
|
||||
}
|
||||
printf ("Max occurence = %d\n", max);
|
||||
printf ("Max occurrence = %d\n", max);
|
||||
|
||||
// Iterate on the dictionnary
|
||||
// Iterate on the dictionary
|
||||
dict_str_it_t it;
|
||||
for(dict_str_it(it, h); !dict_str_end_p(it); dict_str_next(it)) {
|
||||
// Get a constant reference on the pair stored in the dictionnary
|
||||
// Get a constant reference on the pair stored in the dictionary
|
||||
const struct dict_str_pair_s *pair = dict_str_cref(it);
|
||||
printf ("Key=%s Value=%d\n",
|
||||
string_get_cstr(pair->key), pair->value);
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
static const char empty_str[] = "EMPTY";
|
||||
static const char deleted_str[] = "DELETED";
|
||||
static const char *oor_table[] = { empty_str, deleted_str };
|
||||
static const char *const oor_table[] = { empty_str, deleted_str };
|
||||
|
||||
static inline bool oor_equal_p(const char *k, int n)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#include "m-try.h"
|
||||
#include "m-array.h"
|
||||
|
||||
// Define & register an array of int
|
||||
ARRAY_DEF(array, int)
|
||||
#define M_OPL_array_t() ARRAY_OPLIST(array, M_BASIC_OPLIST)
|
||||
|
||||
// This shall be defined once per program to define the global variables needed
|
||||
// to handle the exceptions.
|
||||
M_TRY_DEF_ONCE()
|
||||
|
||||
static void f(void)
|
||||
{
|
||||
M_TRY(f_exception) {
|
||||
// Let's define a variable and do stuff:
|
||||
// Using M_LET allows the register of destructors for the exception handler.
|
||||
M_LET(a, array_t) {
|
||||
array_push_back(a, 5);
|
||||
array_push_back(a, 4);
|
||||
array_push_back(a, 3);
|
||||
array_push_back(a, 2);
|
||||
array_push_back(a, 1);
|
||||
// Throw a M_ERROR_MEMORY exception
|
||||
M_THROW(M_ERROR_MEMORY);
|
||||
printf("This should never be printed!\n");
|
||||
}
|
||||
} M_CATCH(f_exception, M_ERROR_MEMORY) {
|
||||
// Exception handler than catches the M_ERROR_MEMORY errors.
|
||||
// Here the destructor of variable a has been called to free memory
|
||||
printf("Memory exception %d received in f function, thrown by %s:%d\n",
|
||||
f_exception->error_code, f_exception->filename, f_exception->line);
|
||||
}
|
||||
}
|
||||
|
||||
static void g(void)
|
||||
{
|
||||
M_TRY(f_exception) {
|
||||
// Let's define a variable and do stuff:
|
||||
// Using M_LET allows the register of destructors for the exception handler.
|
||||
M_LET(a, array_t) {
|
||||
array_push_back(a, 5);
|
||||
array_push_back(a, 4);
|
||||
array_push_back(a, 3);
|
||||
array_push_back(a, 2);
|
||||
array_push_back(a, 1);
|
||||
// Throw an unkown exception
|
||||
M_THROW(42);
|
||||
printf("This should never be printed!\n");
|
||||
}
|
||||
} M_CATCH(f_exception, M_ERROR_MEMORY) {
|
||||
printf("Memory exception %d received in f function, thrown by %s:%d\n",
|
||||
f_exception->error_code, f_exception->filename, f_exception->line);
|
||||
printf("This should never be printed!\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Let's do a global exception handler
|
||||
M_TRY(main_exception) {
|
||||
f();
|
||||
g();
|
||||
} M_CATCH(main_exception, 0) {
|
||||
// Exception handler than catches all errors.
|
||||
// Here the destructor of variable a has been called to free memory
|
||||
printf("Exception %d received in main function, thrown by %s:%d\n",
|
||||
main_exception->error_code, main_exception->filename, main_exception->line);
|
||||
}
|
||||
printf("You should run it under valgrind to check that all memory allocations are freed.\n");
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "m-list.h"
|
||||
#include "m-generic.h"
|
||||
|
||||
LIST_DEF(list_uint, unsigned int)
|
||||
// Register for M_LET & M_EACH
|
||||
#define M_OPL_list_uint_t() LIST_OPLIST(list_uint, M_BASIC_OPLIST)
|
||||
// Register for Generic:
|
||||
#define M_GENERIC_ORG_1() (USER)
|
||||
#define M_GENERIC_ORG_USER_COMP_1() (CORE)
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_1() M_OPL_list_uint_t()
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET(list, list_uint_t) {
|
||||
// We can push in the list. It will call the registered method.
|
||||
push(list, 42);
|
||||
push(list, 17);
|
||||
// We can iterate over the list
|
||||
for each(item, list) {
|
||||
M_PRINT("ITEM=", *item, "\n");
|
||||
}
|
||||
// We can print directly the list. It will use the registered method
|
||||
M_PRINT("List = ", list, "\n");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
#if HAVE_GMP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gmp.h>
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-list.h"
|
||||
#include "m-generic.h"
|
||||
|
||||
// Register an organization for generic: USER
|
||||
// Each index (here '1') shall be unique for the whole program
|
||||
#define M_GENERIC_ORG_1() (USER)
|
||||
// Register a component for the organization USER: CORE
|
||||
// Each index (here '1') shall be unique for the whole organization
|
||||
#define M_GENERIC_ORG_USER_COMP_1() (CORE)
|
||||
|
||||
// Register the oplist of a mpz_t. It is a classic oplist.
|
||||
// Adding support for emplace and initialization
|
||||
// Adding the ability to output its value for serialization/printing
|
||||
// Adding type information for handling correctly the generic association
|
||||
#define M_OPL_mpz_t() M_OPEXTEND(M_CLASSIC_OPLIST(mpz), \
|
||||
INIT_WITH(mpz_init_set_ui), EMPLACE_TYPE(unsigned int), \
|
||||
OUT_STR( API( mpz_out_str, VOID, ARG1, 10, ARG2)), \
|
||||
GENTYPE(__mpz_struct *), TYPE(mpz_t) )
|
||||
// Register the oplist as a generic type of the component CORE of the organization USER
|
||||
// Each index (here '1') shall be unique for the whole component
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_1() M_OPL_mpz_t()
|
||||
|
||||
// Define an instance of an array of mpz_t (both type and function)
|
||||
ARRAY_DEF(array_mpz, mpz_t)
|
||||
// Register the oplist of the created instance of array of mpz_t
|
||||
#define M_OPL_array_mpz_t() ARRAY_OPLIST(array_mpz, M_OPL_mpz_t())
|
||||
// Register the oplist as a generic type of the component CORE of the organization USER
|
||||
// Each index (here '10') shall be unique for the whole component
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_10() M_OPL_array_mpz_t()
|
||||
|
||||
// Define an instance of a list of mpz_t (both type and function)
|
||||
LIST_DEF(list_mpz, mpz_t)
|
||||
// Register the oplist of the created instance of array of mpz_t
|
||||
#define M_OPL_list_mpz_t() LIST_OPLIST(list_mpz, M_OPL_mpz_t())
|
||||
// Register the oplist as a generic type of the component CORE of the organization USER
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_11() M_OPL_list_mpz_t()
|
||||
|
||||
// Define an instance of a list of unsigned int (both type and function)
|
||||
LIST_DEF(list_uint, unsigned)
|
||||
// Register the oplist of the created instance of list of unsigned
|
||||
#define M_OPL_list_uint_t() LIST_OPLIST(list_uint, M_BASIC_OPLIST)
|
||||
// Register the oplist as a generic type of the component CORE of the organization USER
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_12() M_OPL_list_uint_t()
|
||||
|
||||
// Define an instance of a array of unsigned int (both type and function)
|
||||
ARRAY_DEF(array_uint, unsigned)
|
||||
// Register the oplist of the created instance of list of unsigned
|
||||
#define M_OPL_array_uint_t() ARRAY_OPLIST(array_uint, M_BASIC_OPLIST)
|
||||
// Register the oplist as a generic type of the component CORE of the organization USER
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_13() M_OPL_array_uint_t()
|
||||
|
||||
int main(void) {
|
||||
|
||||
print("LIST UINT = ");
|
||||
// Initialize list as list_uint_t and push 17 & 42 in it.
|
||||
let( (list, 17, 42), list_uint_t) {
|
||||
push(list, 1742);
|
||||
// Iterate over all elements of the list of unsigned int
|
||||
for each (item, list) {
|
||||
// Print the element
|
||||
print(*item, " ");
|
||||
}
|
||||
// Print the full list too
|
||||
print("\n","List=", list, "\n");
|
||||
}
|
||||
// Now list has been cleared.
|
||||
|
||||
print("Array UINT = ");
|
||||
// Initialize list as array_uint_t and push 17 & 42 in it.
|
||||
let( (list, 17, 42), array_uint_t) {
|
||||
push(list, 1742);
|
||||
// Iterate over all elements of the array of unsigned int
|
||||
for each (item, list) {
|
||||
// Print the element
|
||||
print(*item, " ");
|
||||
}
|
||||
// Print the full array too
|
||||
print("\n","List=", list, "\n");
|
||||
}
|
||||
// Now array has been cleared.
|
||||
|
||||
print("LIST MPZ = ");
|
||||
// Initialize list as array_mpz_t and push_emplace mpz_t from 17 & 42 in it.
|
||||
// The parenthesis around 17 in (17) means to emplace
|
||||
let( (list, (17), (42)), list_mpz_t) {
|
||||
list_mpz_emplace_back(list, 1742); // Generic emplace is not supported yet
|
||||
// Iterate over all elements of the array of mpz_t
|
||||
for each (item, list) {
|
||||
// Print the element
|
||||
// Since we registered the out_str of a mpz_t, we can display it directly
|
||||
print(*item, " ");
|
||||
}
|
||||
// Print the full list too
|
||||
print("\n","List=", list, "\n");
|
||||
}
|
||||
|
||||
print("ARRAY MPZ = ");
|
||||
// Same as before but for array
|
||||
let( (list, (17), (42)), array_mpz_t) {
|
||||
array_mpz_emplace_back(list, 1742);
|
||||
for each (item, list) {
|
||||
print(*item, " ");
|
||||
}
|
||||
print("\n","List=", list, "\n");
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void) {}
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - ALGO module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - dynamic ARRAY module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -89,7 +89,7 @@
|
||||
,INIT_MOVE(M_F(name, _init_move)) \
|
||||
,MOVE(M_F(name, _move)) \
|
||||
,SWAP(M_F(name, _swap)) \
|
||||
,TYPE(M_F(name,_ct)) \
|
||||
,TYPE(M_F(name,_ct)) , GENTYPE(struct M_F(name,_s)*) \
|
||||
,NAME(name) \
|
||||
,SUBTYPE(M_F(name, _subtype_ct)) \
|
||||
,EMPTY_P(M_F(name,_empty_p)) \
|
||||
@@ -254,10 +254,12 @@
|
||||
size_t step1 = M_MIN(s->size, d->size); \
|
||||
for(i = 0; i < step1; i++) \
|
||||
M_CALL_SET(oplist, d->ptr[i], s->ptr[i]); \
|
||||
for( ; i < s->size; i++) \
|
||||
M_CALL_INIT_SET(oplist, d->ptr[i], s->ptr[i]); \
|
||||
for( ; i < d->size; i++) \
|
||||
M_CALL_CLEAR(oplist, d->ptr[i]); \
|
||||
for( ; i < s->size; i++) { \
|
||||
M_CALL_INIT_SET(oplist, d->ptr[i], s->ptr[i]); \
|
||||
M_IF_EXCEPTION( d->size = i + 1 ); \
|
||||
} \
|
||||
d->size = s->size; \
|
||||
M_ARRA4_CONTRACT(d); \
|
||||
} \
|
||||
@@ -266,8 +268,10 @@
|
||||
M_F(name, _init_set)(array_t d, const array_t s) \
|
||||
{ \
|
||||
M_ASSERT (d != s); \
|
||||
M_F(name, _init)(d); \
|
||||
M_F(name, _set)(d, s); \
|
||||
M_ON_EXCEPTION(M_F(name, _clear)(d) ) { \
|
||||
M_F(name, _init)(d); \
|
||||
M_F(name, _set)(d, s); \
|
||||
} \
|
||||
} \
|
||||
, /* No SET & INIT_SET */) \
|
||||
\
|
||||
@@ -348,7 +352,9 @@
|
||||
type *data = M_F(name, _push_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_CALL_INIT_SET(oplist, *data, x); \
|
||||
M_IF_EXCEPTION( v->size --); \
|
||||
M_CALL_INIT_SET(oplist, *data, x); \
|
||||
M_IF_EXCEPTION( v->size ++); \
|
||||
} \
|
||||
, /* No INIT_SET */ ) \
|
||||
\
|
||||
@@ -359,7 +365,9 @@
|
||||
type *data = M_F(name, _push_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return NULL; \
|
||||
M_IF_EXCEPTION( v->size --); \
|
||||
M_CALL_INIT(oplist, *data); \
|
||||
M_IF_EXCEPTION( v->size ++); \
|
||||
return data; \
|
||||
} \
|
||||
, /* No INIT */ ) \
|
||||
@@ -400,8 +408,10 @@
|
||||
} \
|
||||
M_ASSERT(v->ptr != NULL); \
|
||||
memmove(&v->ptr[key+1], &v->ptr[key], (v->size-key)*sizeof(type)); \
|
||||
M_ON_EXCEPTION( memmove(&v->ptr[key], &v->ptr[v->size], sizeof(type))) { \
|
||||
M_CALL_INIT_SET(oplist, v->ptr[key], x); \
|
||||
} \
|
||||
v->size++; \
|
||||
M_CALL_INIT_SET(oplist, v->ptr[key], x); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
, /* No INIT_SET */ ) \
|
||||
@@ -428,8 +438,10 @@
|
||||
v->ptr = ptr; \
|
||||
v->alloc = alloc; \
|
||||
} \
|
||||
for(size_t i = v->size ; i < size; i++) \
|
||||
for(size_t i = v->size ; i < size; i++) { \
|
||||
M_CALL_INIT(oplist, v->ptr[i]); \
|
||||
M_IF_EXCEPTION( v->size = i+1); \
|
||||
} \
|
||||
v->size = size; \
|
||||
} \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
@@ -484,8 +496,10 @@
|
||||
v->ptr = ptr; \
|
||||
v->alloc = alloc; \
|
||||
} \
|
||||
for(size_t i = v->size ; i < size; i++) \
|
||||
for(size_t i = v->size ; i < size; i++) { \
|
||||
M_CALL_INIT(oplist, v->ptr[i]); \
|
||||
M_IF_EXCEPTION( v->size = i+1); \
|
||||
} \
|
||||
v->size = size; \
|
||||
} \
|
||||
M_ASSERT (idx < v->size); \
|
||||
@@ -613,8 +627,11 @@
|
||||
v->alloc = alloc; \
|
||||
} \
|
||||
memmove(&v->ptr[i+num], &v->ptr[i], sizeof(type)*(v->size - i) ); \
|
||||
for(size_t k = i ; k < i+num; k++) \
|
||||
M_CALL_INIT(oplist, v->ptr[k]); \
|
||||
m_volatile size_t k; \
|
||||
M_ON_EXCEPTION(memmove(&v->ptr[k], &v->ptr[i+num], sizeof(type)*(v->size - i) ), v->size += (k-i) ) { \
|
||||
for(k = i ; k < i+num; k++) \
|
||||
M_CALL_INIT(oplist, v->ptr[k]); \
|
||||
} \
|
||||
v->size = size; \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
@@ -796,7 +813,7 @@
|
||||
{ \
|
||||
M_ASSERT (it != NULL && a == it->array); \
|
||||
M_F(name, _pop_at)(NULL, a, it->index); \
|
||||
/* NOTE: it->index will naturaly point to the next element */ \
|
||||
/* NOTE: it->index will naturally point to the next element */ \
|
||||
} \
|
||||
, /* End of SET | INIT_SET */ ) \
|
||||
\
|
||||
@@ -918,7 +935,7 @@
|
||||
bool b = M_CALL_EQUAL(oplist, *item1, *item2); \
|
||||
if (!b) return false; \
|
||||
} \
|
||||
return i == array1->size; \
|
||||
return true; \
|
||||
} \
|
||||
, /* no EQUAL */ ) \
|
||||
\
|
||||
@@ -946,7 +963,7 @@
|
||||
/* To overflow newSize, we need to a1 and a2 a little bit above \
|
||||
SIZE_MAX/2, which is not possible in the classic memory model as we \
|
||||
should have exhausted all memory before reaching such sizes. */ \
|
||||
M_ASSERT(newSize > a1->size); \
|
||||
M_ASSERT_INDEX(a1->size, newSize); \
|
||||
if (newSize > a1->alloc) { \
|
||||
type *ptr = M_CALL_REALLOC(oplist, type, a1->ptr, newSize); \
|
||||
if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \
|
||||
@@ -1018,7 +1035,7 @@
|
||||
if (M_UNLIKELY (c == ']')) { goto exit; } \
|
||||
if (M_UNLIKELY (c == 0)) { goto exit; } \
|
||||
str--; \
|
||||
M_QLET(item, type, oplist) { \
|
||||
M_QLET(1, item, type, oplist) { \
|
||||
do { \
|
||||
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
|
||||
c = m_core_str_nospace(&str); \
|
||||
@@ -1046,7 +1063,7 @@
|
||||
if (M_UNLIKELY (c == ']')) return true; \
|
||||
if (M_UNLIKELY (c == EOF)) return false; \
|
||||
ungetc(c, file); \
|
||||
M_QLET(item, type, oplist) { \
|
||||
M_QLET(1, item, type, oplist) { \
|
||||
do { \
|
||||
bool b = M_CALL_IN_STR(oplist, item, file); \
|
||||
c = m_core_fgetc_nospace(file); \
|
||||
@@ -1095,7 +1112,7 @@
|
||||
return ret; \
|
||||
} \
|
||||
M_F(name, _reserve)(array, estimated_size); \
|
||||
M_QLET(item, type, oplist) { \
|
||||
M_QLET(1, item, type, oplist) { \
|
||||
do { \
|
||||
ret = M_CALL_IN_SERIAL(oplist, item, f); \
|
||||
if (ret != M_SERIAL_OK_DONE) { break; } \
|
||||
@@ -1117,7 +1134,9 @@
|
||||
M_F(name, _subtype_ct) *data = M_F(name, _push_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_IF_EXCEPTION( v->size --); \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
M_IF_EXCEPTION( v->size ++); \
|
||||
} \
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
+9
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin stdatomic wrapper for C++ compatibility
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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,7 +25,7 @@
|
||||
#ifndef MSTARLIB_ATOMIC_H
|
||||
#define MSTARLIB_ATOMIC_H
|
||||
|
||||
/* NOTE: Due to the C++ not having recognized stdatomic.h officialy,
|
||||
/* NOTE: Due to the C++ not having recognized stdatomic.h officially,
|
||||
it is hard to use this header directly with a C++ compiler.
|
||||
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932
|
||||
clang++ has no issue with this header but if someone includes
|
||||
@@ -332,4 +332,11 @@ M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
|
||||
// C17 deprecated ATOMIC_VAR_INIT
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201710L
|
||||
# define M_ATOMIC_VAR_INIT(x) (x)
|
||||
#else
|
||||
# define M_ATOMIC_VAR_INIT(x) ATOMIC_VAR_INIT(x)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+7
-4
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - BITSET module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -145,6 +145,9 @@ M_INLINE void
|
||||
m_bitset_init_set(m_bitset_t d, const m_bitset_t s)
|
||||
{
|
||||
M_ASSERT (d != s);
|
||||
// In case of exception, d remains initialized,
|
||||
// but without any allocation done.
|
||||
// Therefore it is safe, not to clear d on exception.
|
||||
m_bitset_init(d);
|
||||
m_bitset_set(d, s);
|
||||
}
|
||||
@@ -286,7 +289,7 @@ m_bitset_resize (m_bitset_t v, size_t size)
|
||||
M_B1TSET_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Reserve allocation in the bitset to accomodate at least 'size' bits without reallocation */
|
||||
/* Reserve allocation in the bitset to accommodate at least 'size' bits without reallocation */
|
||||
M_INLINE void
|
||||
m_bitset_reserve (m_bitset_t v, size_t alloc)
|
||||
{
|
||||
@@ -750,7 +753,7 @@ m_bitset_not(m_bitset_t dest)
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
}
|
||||
|
||||
/* Copute a hash of the bitset */
|
||||
/* Compute a hash of the bitset */
|
||||
M_INLINE size_t
|
||||
m_bitset_hash(const m_bitset_t set)
|
||||
{
|
||||
@@ -961,7 +964,7 @@ M_END_PROTECTED_CODE
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Output to a m_string_t 'str' the formatted text representation of the bitset 'set'
|
||||
or append it to the strinf (append=true) */
|
||||
or append it to the string (append=true) */
|
||||
M_INLINE void
|
||||
m_bitset_get_str(m_string_t str, const m_bitset_t set, bool append)
|
||||
{
|
||||
|
||||
+58
-73
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - B+TREE module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_BPTR33_KEY_OPLIST_P1(arg) M_BPTR33_KEY_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplists */
|
||||
/* Validation of the given oplist */
|
||||
#define M_BPTR33_KEY_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_BPTR33_KEY_OPLIST_P3, M_BPTR33_KEY_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
MOVE(M_F(name, _move)), \
|
||||
SWAP(M_F(name, _swap)), \
|
||||
NAME(name), \
|
||||
TYPE(M_F(name,_ct)), \
|
||||
TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
SUBTYPE(M_F(name, _subtype_ct)), \
|
||||
IT_TYPE(M_F(name, _it_ct)), \
|
||||
IT_FIRST(M_F(name,_it)), \
|
||||
@@ -215,7 +215,7 @@
|
||||
MOVE(M_F(name, _move)), \
|
||||
SWAP(M_F(name, _swap)), \
|
||||
NAME(name), \
|
||||
TYPE(M_F(name,_ct)), \
|
||||
TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
SUBTYPE(M_F(name, _subtype_ct)), \
|
||||
EMPTY_P(M_F(name,_empty_p)), \
|
||||
IT_TYPE(M_F(name, _it_ct)), \
|
||||
@@ -950,7 +950,7 @@
|
||||
node_t parent = pit->parent[--pit->num]; \
|
||||
M_ASSERT (parent != NULL); \
|
||||
k = M_F(name, _search_for_node)(parent, leaf); \
|
||||
/* Look for the neighboor of the removed key. */ \
|
||||
/* Look for the neighbour of the removed key. */ \
|
||||
/* if we can steal one key from them to keep our node balanced */ \
|
||||
if (k > 0 && M_F(name, _get_num)(parent->kind.node[k-1]) > N/2) { \
|
||||
M_F(name, _left_shift)(parent, k-1); \
|
||||
@@ -1042,6 +1042,7 @@
|
||||
b->size = ref->size; \
|
||||
b->root = ref->root; \
|
||||
ref->root = NULL; \
|
||||
ref->size = 1; \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
@@ -1209,7 +1210,7 @@
|
||||
it_t it1; \
|
||||
it_t it2; \
|
||||
/* NOTE: We can't compare two trees directly as they can be \
|
||||
structuraly different but functionnaly equal (you get this by \
|
||||
structurally different but functionally equal (you get this by \
|
||||
constructing the tree in a different way). We have to \
|
||||
compare the ordered value within the tree. */ \
|
||||
M_F(name, _it)(it1, t1); \
|
||||
@@ -1263,7 +1264,6 @@
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT(str != NULL); \
|
||||
(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; \
|
||||
for (M_F(name, _it)(it, t1) ; \
|
||||
@@ -1320,38 +1320,31 @@
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT (str != NULL); \
|
||||
M_F(name,_reset)(t1); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
if (M_UNLIKELY (c != '[')) { c = 0; goto exit; } \
|
||||
c = *str++; \
|
||||
if (M_UNLIKELY (c == ']')) { success = true; goto exit;} \
|
||||
if (M_UNLIKELY (c == 0)) goto exit; \
|
||||
if (M_UNLIKELY (c == ']' || c == 0)) goto exit; \
|
||||
str--; \
|
||||
key_t key; \
|
||||
M_CALL_INIT(key_oplist, key); \
|
||||
M_IF(isMap)(value_t value; \
|
||||
M_CALL_INIT(value_oplist, value); \
|
||||
, /* No isMap */) \
|
||||
do { \
|
||||
bool b = M_CALL_PARSE_STR(key_oplist, key, str, &str); \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
if (b == false) goto exit_clear; \
|
||||
M_IF(isMap)(if (c != ':') goto exit_clear; \
|
||||
b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
if (b == false || c == 0) goto exit_clear; \
|
||||
M_F(name, _set_at)(t1, key, value); \
|
||||
, \
|
||||
M_F(name, _push)(t1, key); \
|
||||
) \
|
||||
} while (c == M_GET_SEPARATOR key_oplist); \
|
||||
success = (c == ']'); \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(key_oplist, key); \
|
||||
M_IF(isMap)(M_CALL_CLEAR(value_oplist, value); , /* No isMap */ ) \
|
||||
M_QLET(1, key, key_t, key_oplist) \
|
||||
M_IF(isMap)(M_QLET(2, value, value_t, value_oplist), /* No isMap */) { \
|
||||
do { \
|
||||
bool b = M_CALL_PARSE_STR(key_oplist, key, str, &str); \
|
||||
c = m_core_str_nospace(&str); \
|
||||
if (b == false) { c = 0; break; } \
|
||||
M_IF(isMap)(if (c != ':') { c = 0; break; } \
|
||||
b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \
|
||||
c = m_core_str_nospace(&str); \
|
||||
if (b == false || c == 0) { c = 0; break; } \
|
||||
M_F(name, _set_at)(t1, key, value); \
|
||||
, \
|
||||
M_F(name, _push)(t1, key); \
|
||||
) \
|
||||
} while (c == M_GET_SEPARATOR key_oplist); \
|
||||
} \
|
||||
exit: \
|
||||
if (endp) *endp = str; \
|
||||
return success; \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
return (c == ']'); \
|
||||
} \
|
||||
, /* no parse_str */ ) \
|
||||
\
|
||||
@@ -1368,27 +1361,23 @@
|
||||
if (M_UNLIKELY (c == ']')) return true; \
|
||||
if (M_UNLIKELY (c == EOF)) return false; \
|
||||
ungetc(c, file); \
|
||||
key_t key; \
|
||||
M_CALL_INIT (key_oplist, key); \
|
||||
M_IF(isMap)(value_t value; \
|
||||
M_CALL_INIT (value_oplist, value); \
|
||||
,) \
|
||||
do { \
|
||||
bool b = M_CALL_IN_STR(key_oplist, key, file); \
|
||||
do { c = fgetc(file); } while (isspace(c)); \
|
||||
if (b == false) break; \
|
||||
M_IF(isMap)(if (c!=':') break; \
|
||||
b = M_CALL_IN_STR(value_oplist,value, file); \
|
||||
do { c = fgetc(file); } while (isspace(c)); \
|
||||
if (b == false || c == EOF) break; \
|
||||
M_F(name, _set_at)(t1, key, value) \
|
||||
, \
|
||||
M_F(name, _push)(t1, key) \
|
||||
); \
|
||||
} while (c == M_GET_SEPARATOR key_oplist); \
|
||||
M_CALL_CLEAR(key_oplist, key); \
|
||||
M_IF(isMap)(M_CALL_CLEAR(value_oplist, value); \
|
||||
,) \
|
||||
M_QLET(1, key, key_t, key_oplist) \
|
||||
M_IF(isMap)(M_QLET(2, value, value_t, value_oplist) , /*nothing*/) { \
|
||||
do { \
|
||||
bool b = M_CALL_IN_STR(key_oplist, key, file); \
|
||||
c = m_core_fgetc_nospace(file); \
|
||||
if (b == false) { c = 0; break; } \
|
||||
M_IF(isMap)(if (c!=':') { c = 0; break; } \
|
||||
b = M_CALL_IN_STR(value_oplist,value, file); \
|
||||
c = m_core_fgetc_nospace(file); \
|
||||
if (b == false || c == EOF) { c = 0; break; } \
|
||||
M_F(name, _set_at)(t1, key, value) \
|
||||
, \
|
||||
M_F(name, _push)(t1, key) \
|
||||
); \
|
||||
} while (c == M_GET_SEPARATOR key_oplist); \
|
||||
} \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
return c == ']'; \
|
||||
} \
|
||||
, /* no in_str */ ) \
|
||||
@@ -1446,37 +1435,33 @@
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
size_t estimated_size = 0; \
|
||||
key_t key; \
|
||||
M_F(name,_reset)(t1); \
|
||||
M_IF(isMap)( \
|
||||
value_t value; \
|
||||
M_QLET(1, key, key_t, key_oplist) \
|
||||
M_IF(isMap)(M_QLET(2, value, value_t, value_oplist) , /*nothing*/) { \
|
||||
M_IF(isMap)( \
|
||||
ret = f->m_interface->read_map_start(local, f, &estimated_size); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
|
||||
M_CALL_INIT(key_oplist, key); \
|
||||
M_CALL_INIT (value_oplist, value); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) break; \
|
||||
do { \
|
||||
ret = M_CALL_IN_SERIAL(key_oplist, key, f); \
|
||||
if (ret != M_SERIAL_OK_DONE) return M_SERIAL_FAIL; \
|
||||
if (ret != M_SERIAL_OK_DONE) break; \
|
||||
ret = f->m_interface->read_map_value(local, f); \
|
||||
if (ret != M_SERIAL_OK_CONTINUE) return M_SERIAL_FAIL; \
|
||||
if (ret != M_SERIAL_OK_CONTINUE) break; \
|
||||
ret = M_CALL_IN_SERIAL(value_oplist, value, f); \
|
||||
if (ret != M_SERIAL_OK_DONE) return M_SERIAL_FAIL; \
|
||||
if (ret != M_SERIAL_OK_DONE) break; \
|
||||
M_F(name, _set_at)(t1, key, value); \
|
||||
} while ((ret = f->m_interface->read_map_next(local, f)) == M_SERIAL_OK_CONTINUE); \
|
||||
M_CALL_CLEAR(key_oplist, key); \
|
||||
M_CALL_CLEAR(value_oplist, value); \
|
||||
, \
|
||||
, /* queue style */ \
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
|
||||
M_CALL_INIT(key_oplist, key); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) break; \
|
||||
do { \
|
||||
ret = M_CALL_IN_SERIAL(key_oplist, key, f); \
|
||||
if (ret != M_SERIAL_OK_DONE) { break; } \
|
||||
if (ret != M_SERIAL_OK_DONE) break; \
|
||||
M_F(name, _push)(t1, key); \
|
||||
} while ((ret = f->m_interface->read_array_next(local, f)) == M_SERIAL_OK_CONTINUE); \
|
||||
M_CALL_CLEAR(key_oplist, key); \
|
||||
) /* End of IF isMap */ \
|
||||
return ret; \
|
||||
) /* End of IF isMap */ \
|
||||
} \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
return ret; \
|
||||
} \
|
||||
, /* no in_serial */ ) \
|
||||
|
||||
|
||||
+29
-29
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Fixed size (Bounded) QUEUE & STACK interface
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -78,7 +78,7 @@ typedef enum {
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define a nearly lock-free queue for Many Producer Many Consummer.
|
||||
/* Define a nearly lock-free queue for Many Producers Many Consumers.
|
||||
Much faster than queue of BUFFER_DEF in heavy communication scenario
|
||||
but without any blocking features (this is let to the user).
|
||||
Size of created queue shall be a power of 2 and is defined at run-time.
|
||||
@@ -88,7 +88,7 @@ typedef enum {
|
||||
M_QUEUE_MPMC_DEF_AS(name, M_F(name,_t), type, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a nearly lock-free queue for Many Producer Many Consummer
|
||||
/* Define a nearly lock-free queue for Many Producers Many Consumers
|
||||
as the provided type name_t.
|
||||
Much faster than queue of BUFFER_DEF in heavy communication scenario
|
||||
but without any blocking features (this is let to the user).
|
||||
@@ -103,7 +103,7 @@ typedef enum {
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define a wait-free queue for Single Producer Single Consummer
|
||||
/* Define a wait-free queue for Single Producer Single Consumer
|
||||
Much faster than queue of BUFFER_DEF or QUEUE_MPMC in heavy communication scenario
|
||||
but without any blocking features (this is let to the user).
|
||||
Size of created queue shall be a power of 2 and is defined at run-time.
|
||||
@@ -113,7 +113,7 @@ typedef enum {
|
||||
M_QUEUE_SPSC_DEF_AS(name, M_F(name, _t), type, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a wait-free queue for Single Producer Single Consummer
|
||||
/* Define a wait-free queue for Single Producer Single Consumer
|
||||
as the provided type name_t.
|
||||
Much faster than queue of BUFFER_DEF in heavy communication scenario
|
||||
but without any blocking features (this is let to the user).
|
||||
@@ -278,7 +278,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
|
||||
m_cond_t there_is_data; /* condition raised when there is data */ \
|
||||
/* Read only Data */ \
|
||||
M_BUFF3R_IF_CTE_SIZE(m_size)( ,size_t capacity;) /* Capacity of the buffer */ \
|
||||
/* Data for a consummer */ \
|
||||
/* Data for a consumer */ \
|
||||
m_cond_t there_is_room_for_data; /* Cond. raised when there is room */ \
|
||||
m_mutex_t mutexPop; /* MUTEX used for popping elements */ \
|
||||
size_t idx_cons; /* Index of the consumption threads */ \
|
||||
@@ -291,13 +291,13 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
|
||||
\
|
||||
typedef struct M_F(name, _s) *M_F(name, _ptr); \
|
||||
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
|
||||
/* Internal type used to unconst the buffer */ \
|
||||
/* Internal type used to un-const the buffer */ \
|
||||
typedef union { M_F(name, _srcptr) cptr; M_F(name, _ptr) ptr; } M_F(name, _uptr_ct); \
|
||||
/* Internal types used by the oplist */ \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
typedef buffer_t M_F(name, _ct); \
|
||||
|
||||
/* Define the core functionnalities of a buffer */
|
||||
/* Define the core functionalities of a buffer */
|
||||
#define M_BUFF3R_DEF_CORE(name, type, m_size, policy, oplist, buffer_t) \
|
||||
\
|
||||
M_INLINE void \
|
||||
@@ -415,7 +415,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_set)(buffer_t dest, const buffer_t src) \
|
||||
{ \
|
||||
/* unconst 'src', so that we can lock it (semantically it is const) */ \
|
||||
/* un-const 'src', so that we can lock it (semantically it is const) */ \
|
||||
M_F(name, _uptr_ct) vu; \
|
||||
vu.cptr = src; \
|
||||
M_F(name, _ptr) v = vu.ptr; \
|
||||
@@ -459,7 +459,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
M_INLINE void \
|
||||
M_F(name, _set)(buffer_t dest, const buffer_t src) \
|
||||
{ \
|
||||
/* unconst 'src', so that we can lock it (semantically it is const) */ \
|
||||
/* un-const 'src', so that we can lock it (semantically it is const) */ \
|
||||
M_F(name, _uptr_ct) vu; \
|
||||
vu.cptr = src; \
|
||||
M_F(name, _ptr) v = vu.ptr; \
|
||||
@@ -607,7 +607,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
v->idx_prod = idx; \
|
||||
\
|
||||
/* number[] is the only variable which can be modified by both \
|
||||
the consummer thread which has the pop lock and the producer \
|
||||
the consumer thread which has the pop lock and the producer \
|
||||
thread which has the push lock. As such, it is an atomic variable \
|
||||
that performs a release memory barrier. */ \
|
||||
/* Increment number of elements of the buffer */ \
|
||||
@@ -615,14 +615,14 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
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 */ \
|
||||
/* From this point, consumer may read the data in the table */ \
|
||||
} \
|
||||
\
|
||||
/* Producer unlock (mutex unlock performs a release memory barrier) */ \
|
||||
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 \
|
||||
/* If the number of items in the buffer was 0, some consumer \
|
||||
may be waiting. Signal to them the availability of the data \
|
||||
We cannot only signal one thread. */ \
|
||||
if (previousSize == 0) { \
|
||||
m_mutex_lock(v->mutexPop); \
|
||||
@@ -641,7 +641,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
M_BUFF3R_CONTRACT(v,m_size); \
|
||||
M_ASSERT (data != NULL); \
|
||||
\
|
||||
/* Consummer lock (mutex lock performs an acquire memory barrier) */ \
|
||||
/* consumer lock (mutex lock performs an acquire memory barrier) */ \
|
||||
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_lock(v->mutexPop); \
|
||||
while (M_F(name, _empty_p)(v)) { \
|
||||
@@ -675,7 +675,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
} \
|
||||
\
|
||||
/* number[] is the only variable which can be modified by both \
|
||||
the consummer thread which has the pop lock and the producer \
|
||||
the consumer thread which has the pop lock and the producer \
|
||||
thread which has the push lock. As such, it is an atomic variable \
|
||||
that performs a release memory barrier. */ \
|
||||
/* Decrement number of elements in the buffer */ \
|
||||
@@ -687,11 +687,11 @@ M_F(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) */ \
|
||||
/* consumer unlock (mutex unlock performs a release memory barrier) */ \
|
||||
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 \
|
||||
may be waiting. Signal to them the availability of the free room \
|
||||
We cannot only signal one thread. */ \
|
||||
if ((!M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) \
|
||||
&& previousSize == M_BUFF3R_SIZE(m_size)) { \
|
||||
@@ -750,7 +750,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
/* Definition of a a QUEUE for Many Produccer / Many Consummer
|
||||
/* Definition of a a QUEUE for Many Producers / Many consumers
|
||||
for high bandwidth scenario:
|
||||
* nearly lock-free,
|
||||
* quite fast
|
||||
@@ -805,7 +805,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
\
|
||||
/* The sequence number of an element will be equal to either \
|
||||
- 2* the index of the production which creates it, \
|
||||
- 1 + 2* the index of the consumption which consummes it \
|
||||
- 1 + 2* the index of the consumption which consumes it \
|
||||
In case of wrapping, as there is no order comparison but only \
|
||||
equal comparison, there is no special issue. \
|
||||
Each element is put in a separate cache line to avoid false \
|
||||
@@ -817,7 +817,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
M_CACHELINE_ALIGN(align, atomic_uint, type); \
|
||||
} M_F(name, _el_ct); \
|
||||
\
|
||||
/* If there is only one producer and one consummer, then they won't \
|
||||
/* If there is only one producer and one consumer, then they won't \
|
||||
typically use the same cache line, increasing performance. */ \
|
||||
typedef struct M_F(name, _s) { \
|
||||
atomic_uint ProdIdx; /* Can only increase until wrapping */ \
|
||||
@@ -831,7 +831,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
typedef buffer_t M_F(name, _ct); \
|
||||
|
||||
/* Define the core functionnalities of a MPMC queue */
|
||||
/* Define the core functionalities of a MPMC queue */
|
||||
#define M_QU3UE_MPMC_DEF_CORE(name, type, policy, oplist, buffer_t) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _push)(buffer_t table, type const x) \
|
||||
@@ -952,7 +952,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
const unsigned int iC = atomic_load_explicit(&table->ConsoIdx, memory_order_relaxed); \
|
||||
const unsigned int iP = atomic_load_explicit(&table->ProdIdx, memory_order_acquire); \
|
||||
/* We return an approximation as we can't read both iC & iP atomically \
|
||||
As we read producer index after consummer index, \
|
||||
As we read producer index after consumer index, \
|
||||
and they are atomic variables without reordering \
|
||||
producer index is always greater or equal than consumer index \
|
||||
(or on overflow occurs, in which case as we compute with modulo \
|
||||
@@ -986,7 +986,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
/* Definition of a a QUEUE for Single Producer / Single Consummer
|
||||
/* Definition of a a QUEUE for Single Producer / Single consumer
|
||||
for high bandwidth scenario:
|
||||
* wait-free,
|
||||
* quite fast
|
||||
@@ -1038,7 +1038,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
/* Define the type of a SPSC queue */
|
||||
#define M_QU3UE_SPSC_DEF_TYPE(name, type, policy, oplist, buffer_t) \
|
||||
\
|
||||
/* Single producer / Single consummer \
|
||||
/* Single producer / Single consumer \
|
||||
So, only one thread will write in this table. The other thread \
|
||||
will only read. As such, there is no concurrent write, and no \
|
||||
need to align the structure for best performance. */ \
|
||||
@@ -1057,7 +1057,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
typedef buffer_t M_F(name, _ct); \
|
||||
|
||||
/* Define the core functionnalities of a SPSC queue */
|
||||
/* Define the core functionalities of a SPSC queue */
|
||||
#define M_QU3UE_SPSC_DEF_CORE(name, type, policy, oplist, buffer_t) \
|
||||
\
|
||||
M_INLINE bool \
|
||||
@@ -1208,14 +1208,14 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
unsigned int w = atomic_load_explicit(&table->prodIdx, \
|
||||
memory_order_acquire); \
|
||||
/* We return an approximation as we can't read both r & w atomically \
|
||||
As we read producer index after consummer index, \
|
||||
As we read producer index after consumer index, \
|
||||
and they are atomic variables without reordering \
|
||||
producer index is always greater or equal than consumer index \
|
||||
(or on overflow occurs, in which case as we compute with modulo \
|
||||
arithmetic, the right result is computed). \
|
||||
We may return a result which is greater than the size of the queue \
|
||||
if the function is interrupted a long time between reading the \
|
||||
indexs. The function is not protected against it. \
|
||||
index. The function is not protected against it. \
|
||||
*/ \
|
||||
return w-r; \
|
||||
} \
|
||||
@@ -1308,7 +1308,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
,SET(M_F(name, _set)) \
|
||||
,CLEAR(M_F(name, _clear)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_F(name,_ct)) \
|
||||
,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \
|
||||
,SUBTYPE(M_F(name, _subtype_ct)) \
|
||||
,RESET(M_F(name,_reset)) \
|
||||
,PUSH(M_F(name,_push)) \
|
||||
|
||||
+11
-11
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Concurrent memory pool allocator
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -114,14 +114,14 @@ M_BEGIN_PROTECTED_CODE
|
||||
- Thread 1 performs a PUSH of N in Q1 with Q1 empty (only node is NA)
|
||||
NA.next is NIL.
|
||||
- Thread 1 is interrupted just before the CAS on NA.next
|
||||
- Thread 2 performs a sucessfull push of NB in Q1. NA.next is set to NB.
|
||||
- Thread 2 performs a sucessfull pop of NA in Q1
|
||||
- Thread 2 performs a sucessfull push of NA in Q2. NA.next is set to NIL.
|
||||
- Thread 2 performs a successful push of NB in Q1. NA.next is set to NB.
|
||||
- Thread 2 performs a successful pop of NA in Q1
|
||||
- Thread 2 performs a successful push of NA in Q2. NA.next is set to NIL.
|
||||
- Thread 1 is restored and will succeed as NA.next is once again NIL.
|
||||
In order to prevent the last CAS to succeed, each queue uses its own NIL pointer.
|
||||
It is a derived problem of the ABA problem.
|
||||
*/
|
||||
/* TODO: Optimize alignement to reduce memory consumption. NIL object can use []
|
||||
/* TODO: Optimize alignment to reduce memory consumption. NIL object can use []
|
||||
to reduce memory consumption too (non compatible with C++ ...) */
|
||||
#define M_CMEMP00L_DEF_LF_QUEUE(name, type_t) \
|
||||
\
|
||||
@@ -232,7 +232,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
/* dequeue returns an element that becomes the new dummy element (the new head), \
|
||||
and the former dummy element (the former head) is removed: \
|
||||
Since we want a link of free list, and we don't care about the content itsef, \
|
||||
Since we want a link of free list, and we don't care about the content itself, \
|
||||
provided that the node we return is older than the one we should return, \
|
||||
Therefore, we return the previous dummy head. \
|
||||
As such, it is not the original MSqueue algorithm. */ \
|
||||
@@ -263,7 +263,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
memory_order_release, \
|
||||
memory_order_relaxed); \
|
||||
} else { \
|
||||
/* Test if the node is old enought to be popped */ \
|
||||
/* Test if the node is old enough to be popped */ \
|
||||
if (atomic_load_explicit(&next->cpt, memory_order_relaxed) >= age) \
|
||||
return NULL; \
|
||||
/* Try to swing Head to the next node */ \
|
||||
@@ -338,15 +338,15 @@ M_BEGIN_PROTECTED_CODE
|
||||
nodes). If it fails, it requests a new pool to the system allocator
|
||||
(and from there it is no longer lock free).
|
||||
This memory pool can only be lock free if the initial state is
|
||||
sufficiently dimensionned to avoid calling the system allocator during
|
||||
sufficiently dimensioned to avoid calling the system allocator during
|
||||
the normal processing.
|
||||
Then each thread pushs its deleted node into another pool of nodes,
|
||||
Then each thread pushes its deleted node into another pool of nodes,
|
||||
where the node is logically deleted (no contain of the node is destroyed
|
||||
at this point and the node can be freely accessed by other threads).
|
||||
Once the thread mempool is put to sleep, the age of the pool of logical
|
||||
deleted nodes is computed and this pool is move to the Lock Free Queue
|
||||
List of pools to be reclaimed. Then A Garbage Collector is performed
|
||||
on this Lock Free Queue list to reclaim all pools thare are sufficiently
|
||||
on this Lock Free Queue list to reclaim all pools that are sufficiently
|
||||
aged (taking into account the grace period of the pool) to be moved back
|
||||
to the Lock Free Queue of the free pools.
|
||||
|
||||
@@ -822,7 +822,7 @@ m_vlapool_del(m_vlapool_t mem, void *d, m_gc_tid_t id)
|
||||
// Get back the pointer to a struct m_vlapool_slist_node_s.
|
||||
d = M_ASSIGN_CAST(void *, M_ASSIGN_CAST(char *, d) - offsetof(struct m_vlapool_slist_node_s, data));
|
||||
m_vlapool_slist_node_ct *snode = M_ASSIGN_CAST(m_vlapool_slist_node_ct *, d);
|
||||
// Push the logicaly free memory into the list of the nodes to be reclaimed.
|
||||
// Push the logically free memory into the list of the nodes to be reclaimed.
|
||||
m_vlapool_slist_push(mem->thread_data[id].to_be_reclaimed, snode);
|
||||
}
|
||||
|
||||
|
||||
+38
-56
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Basic Protected Concurrent module over container.
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -106,7 +106,7 @@
|
||||
,M_IF_METHOD(MOVE, oplist)(MOVE(M_F(name, _move)),) \
|
||||
,M_IF_METHOD(SWAP,oplist)(SWAP(M_F(name, _swap)),) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_F(name,_ct)) \
|
||||
,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \
|
||||
,SUBTYPE(M_F(name, _subtype_ct)) \
|
||||
,OPLIST(oplist) \
|
||||
,M_IF_METHOD(EMPTY_P, oplist)(EMPTY_P(M_F(name,_empty_p)),) \
|
||||
@@ -329,7 +329,7 @@
|
||||
T1: A := B \
|
||||
T2: B := A \
|
||||
If we lock first the mutex of out, then the src, it could be possible \
|
||||
in the previous scenario that both mutexs are locked: T1 has locked A \
|
||||
in the previous scenario that both mutexes are locked: T1 has locked A \
|
||||
and T2 has locked B, and T1 is waiting for locking B, and T2 is waiting \
|
||||
for locking A, resulting in a deadlock. \
|
||||
To avoid this problem, we **always** lock the mutex which address is \
|
||||
@@ -641,7 +641,7 @@
|
||||
M_C0NCURRENT_CONTRACT(out1); \
|
||||
M_C0NCURRENT_CONTRACT(out2); \
|
||||
if (M_UNLIKELY (out1 == out2)) return true; \
|
||||
/* See comment above on mutal mutexs */ \
|
||||
/* See comment above on mutual mutexes */ \
|
||||
if (out1 < out2) { \
|
||||
M_F(name, _read_lock)(out1); \
|
||||
M_F(name, _read_lock)(out2); \
|
||||
@@ -777,9 +777,8 @@
|
||||
typedef struct M_F(name, _s) { \
|
||||
struct M_F(name, _s) *self; \
|
||||
m_mutex_t lock; \
|
||||
m_cond_t rw_done; \
|
||||
size_t read_count; \
|
||||
bool writer_waiting; \
|
||||
atomic_uint num_reader; /* number of reader threads */ \
|
||||
atomic_uint num_waiting_writer; /* number of waiting writer threads */ \
|
||||
m_cond_t there_is_data; /* condition raised when there is data */ \
|
||||
type data; \
|
||||
} concurrent_t[1]; \
|
||||
@@ -796,11 +795,10 @@
|
||||
M_F(name, _internal_init)(concurrent_t out) \
|
||||
{ \
|
||||
m_mutex_init(out->lock); \
|
||||
m_cond_init(out->rw_done); \
|
||||
atomic_init(&out->num_reader, 0); \
|
||||
atomic_init(&out->num_waiting_writer, 0); \
|
||||
m_cond_init(out->there_is_data); \
|
||||
out->self = out; \
|
||||
out->read_count = 0; \
|
||||
out->writer_waiting = false; \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
\
|
||||
@@ -809,7 +807,6 @@
|
||||
{ \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_clear(out->lock); \
|
||||
m_cond_clear(out->rw_done); \
|
||||
m_cond_clear(out->there_is_data); \
|
||||
out->self = NULL; \
|
||||
} \
|
||||
@@ -819,12 +816,28 @@
|
||||
{ \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
struct M_F(name, _s) *self = out->self; \
|
||||
m_mutex_lock (self->lock); \
|
||||
while (self->writer_waiting == true) { \
|
||||
m_cond_wait(self->rw_done, self->lock); \
|
||||
m_core_backoff_ct backoff; \
|
||||
m_core_backoff_init(backoff); \
|
||||
while (true) { \
|
||||
unsigned int num = atomic_load(&self->num_reader); \
|
||||
/* To avoid reader threads that starve writer threads \
|
||||
Disable sharing of lock for reader threads if some writer thread \
|
||||
waits */ \
|
||||
/* Otherwise try to reuse the lock opened by another reader thread */ \
|
||||
if (num != 0 \
|
||||
&& atomic_load(&self->num_waiting_writer) == 0 \
|
||||
&& atomic_compare_exchange_strong(&self->num_reader, &num, num+1)) { \
|
||||
break; \
|
||||
} \
|
||||
/* Otherwise try to get the lock ourself */ \
|
||||
if (m_mutex_trylock(self->lock)) { \
|
||||
atomic_store(&self->num_reader, 1); \
|
||||
break; \
|
||||
} \
|
||||
/* Perform exponential backoff to avoid monopolizing the memory bus */ \
|
||||
m_core_backoff_wait(backoff); \
|
||||
} \
|
||||
self->read_count ++; \
|
||||
m_mutex_unlock (self->lock); \
|
||||
m_core_backoff_clear(backoff); \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
@@ -832,36 +845,28 @@
|
||||
{ \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
struct M_F(name, _s) *self = out->self; \
|
||||
m_mutex_lock (self->lock); \
|
||||
self->read_count --; \
|
||||
if (self->read_count == 0) { \
|
||||
m_cond_broadcast (self->rw_done); \
|
||||
unsigned int num = atomic_fetch_sub(&self->num_reader, 1); \
|
||||
if (num == 1) { \
|
||||
/* We are the last reader thread: release the lock */ \
|
||||
m_mutex_unlock(self->lock); \
|
||||
} \
|
||||
m_mutex_unlock (self->lock); \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
M_F(name, _write_lock)(concurrent_t out) \
|
||||
{ \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
atomic_fetch_add(&out->num_waiting_writer, 1); \
|
||||
m_mutex_lock (out->lock); \
|
||||
while (out->writer_waiting == true) { \
|
||||
m_cond_wait(out->rw_done, out->lock); \
|
||||
} \
|
||||
out->writer_waiting = true; \
|
||||
while (out->read_count > 0) { \
|
||||
m_cond_wait(out->rw_done, out->lock); \
|
||||
} \
|
||||
m_mutex_unlock (out->lock); \
|
||||
atomic_fetch_sub(&out->num_waiting_writer, 1); \
|
||||
M_ASSERT(atomic_load(&out->num_reader) == 0); \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
M_F(name, _write_unlock)(concurrent_t out) \
|
||||
{ \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->lock); \
|
||||
out->writer_waiting = false; \
|
||||
m_cond_broadcast (out->rw_done); \
|
||||
M_ASSERT(atomic_load(&out->num_reader) == 0); \
|
||||
m_mutex_unlock (out->lock); \
|
||||
} \
|
||||
\
|
||||
@@ -870,45 +875,22 @@
|
||||
{ \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
struct M_F(name, _s) *self = out->self; \
|
||||
M_ASSERT (self == out); \
|
||||
m_mutex_lock (out->self->lock); \
|
||||
self->read_count --; \
|
||||
if (self->read_count == 0) { \
|
||||
m_cond_broadcast (self->rw_done); \
|
||||
} \
|
||||
m_cond_wait(self->there_is_data, self->lock); \
|
||||
while (self->writer_waiting == true) { \
|
||||
m_cond_wait(self->rw_done, self->lock); \
|
||||
} \
|
||||
self->read_count ++; \
|
||||
m_mutex_unlock (out->self->lock); \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
M_F(name, _write_wait)(concurrent_t out) \
|
||||
{ \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->lock); \
|
||||
out->writer_waiting = false; \
|
||||
m_cond_broadcast (out->rw_done); \
|
||||
m_cond_wait(out->there_is_data, out->lock); \
|
||||
while (out->writer_waiting == true) { \
|
||||
m_cond_wait(out->rw_done, out->lock); \
|
||||
} \
|
||||
out->writer_waiting = true; \
|
||||
while (out->read_count > 0) { \
|
||||
m_cond_wait(out->rw_done, out->lock); \
|
||||
} \
|
||||
m_mutex_unlock (out->lock); \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
M_F(name, _write_signal)(concurrent_t out) \
|
||||
{ \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->lock); \
|
||||
M_ASSERT(atomic_load(&out->num_reader) == 0); \
|
||||
m_cond_broadcast(out->there_is_data); \
|
||||
m_mutex_unlock (out->lock); \
|
||||
} \
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Extended Pre-processing macros module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -71,7 +71,7 @@
|
||||
/* Define M*LIB version */
|
||||
#define M_CORE_VERSION_MAJOR 0
|
||||
#define M_CORE_VERSION_MINOR 7
|
||||
#define M_CORE_VERSION_PATCHLEVEL 1
|
||||
#define M_CORE_VERSION_PATCHLEVEL 3
|
||||
|
||||
/* M_ASSUME is equivalent to M_ASSERT, but gives hints to compiler
|
||||
about how to optimize the code if NDEBUG is defined.
|
||||
@@ -88,7 +88,7 @@
|
||||
# define M_ASSUME(x) M_ASSERT(x)
|
||||
#endif
|
||||
|
||||
/* M_LIKELY / M_UNLIKELY gives hints on the compiler of the likehood
|
||||
/* M_LIKELY / M_UNLIKELY gives hints on the compiler of the likelihood
|
||||
of the given condition */
|
||||
#ifdef __GNUC__
|
||||
# define M_LIKELY(cond) __builtin_expect(!!(cond), 1)
|
||||
@@ -132,15 +132,27 @@
|
||||
# define M_ATTR_NO_RETURN
|
||||
#endif
|
||||
|
||||
/* The cold attribute on functions is used to inform the compiler
|
||||
that the function is unlikely to be executed. */
|
||||
/* The hot/cold attribute on functions is used to inform the compiler
|
||||
that the function is likely/unlikely to be executed. */
|
||||
#if defined(__GNUC__)
|
||||
# define M_ATTR_HOT_FUNCTION __attribute__ ((hot))
|
||||
# define M_ATTR_COLD_FUNCTION __attribute__ ((cold))
|
||||
#else
|
||||
# define M_ATTR_HOT_FUNCTION
|
||||
# define M_ATTR_COLD_FUNCTION
|
||||
#endif
|
||||
|
||||
|
||||
/* Prefetch . */
|
||||
#if defined(__GNUC__)
|
||||
# define M_PREFETCH(p) __builtin_prefetch((p), 0, 0)
|
||||
#else
|
||||
# define M_PREFETCH(p) do { \
|
||||
volatile char m_c = *(volatile char *) (p); \
|
||||
(void) m_c; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* Ignore some warnings detected by some compilers in the library.
|
||||
* Whatever we do, there is some warnings that cannot be fixed.
|
||||
* So they are ignored in order to avoid polluting the user with
|
||||
@@ -153,7 +165,7 @@
|
||||
* and CLANG failed to realize it.
|
||||
* See https://bugs.llvm.org//show_bug.cgi?id=22712
|
||||
*
|
||||
* * A manualy created buffer is given to fscanf. It is needed
|
||||
* * A manually created buffer is given to fscanf. It is needed
|
||||
* to give the size of the array of char to fscanf (this is the safe way).
|
||||
*/
|
||||
#if defined(__clang__) && defined(__cplusplus)
|
||||
@@ -229,6 +241,24 @@
|
||||
|
||||
#endif
|
||||
|
||||
/* Warnings disabled for CLANG in C mode:
|
||||
Due to the genericity of the _Generic generation,
|
||||
we cannot avoid generating both T and const T in the generic association. */
|
||||
#if defined(__clang__) && __clang_major__ >= 15
|
||||
#define M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wunreachable-code-generic-assoc\"")
|
||||
|
||||
#define M_G3N_END_PROTECTED_CODE \
|
||||
_Pragma("clang diagnostic pop")
|
||||
|
||||
#else
|
||||
|
||||
#define M_G3N_BEGIN_PROTECTED_CODE
|
||||
#define M_G3N_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Autodetect if Address sanitizer is run */
|
||||
#if defined(__has_feature)
|
||||
@@ -396,7 +426,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the default assertion macro used by M*LIB.
|
||||
* By default, it is an encapsulation of CLIB assert.
|
||||
* NOTE: Can be overiden by user if it needs to keep finer access
|
||||
* NOTE: Can be overriden by user if it needs to keep finer access
|
||||
* on the assertions.
|
||||
*/
|
||||
#ifndef M_ASSERT
|
||||
@@ -404,9 +434,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
#endif
|
||||
|
||||
|
||||
/* If within the M*LIB tests, perform additional (potentialy slow) checks
|
||||
/* If within the M*LIB tests, perform additional (potentially slow) checks
|
||||
* By default, it is an encapsulation of CLIB assert for M*LIB own tests.
|
||||
* NOTE: Can be overiden by user if it needs to keep finer access
|
||||
* NOTE: Can be overriden by user if it needs to keep finer access
|
||||
* on the assertions.
|
||||
*/
|
||||
#ifndef M_ASSERT_SLOW
|
||||
@@ -419,7 +449,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Always perform a runtime check of the given condition
|
||||
* NOTE: Can be overiden by user if it needs to keep finer access
|
||||
* NOTE: Can be overriden by user if it needs to keep finer access
|
||||
* on the assertions or display message on another device.
|
||||
*/
|
||||
#ifndef M_ASSERT_INIT
|
||||
@@ -434,7 +464,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define an assertion check on an index, compared to its maximum.
|
||||
* The index is supposed to be unsigned.
|
||||
* It is only used to valid user input, not an intermediary calculus.
|
||||
* NOTE: Can be overiden by user if it needs to keep access under control
|
||||
* NOTE: Can be overriden by user if it needs to keep access under control
|
||||
* even on release mode
|
||||
* NOTE: (index)-(index) is used to represent 0, but to avoid spurious
|
||||
* warning by the compiler on "comparaison is always true" for unsigned
|
||||
@@ -449,15 +479,14 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Terminate the compilation of the current unit with an error message.
|
||||
The error parameter is a C token which classifies the error
|
||||
with an optional message detailling the error.
|
||||
Either use C11 to get a proper message, or at least a good hint in C99.
|
||||
error shall be a C name, msg a string.
|
||||
Quite usefull to terminate with a proper error message rather than
|
||||
with an optional message detailing the error.
|
||||
It is not an expression and shall not be used in an expression.
|
||||
It shall be used outside of a function, therefore it is not an expression.
|
||||
In C99, it uses a bitfield to be compatible with most compilers
|
||||
(so that it properly displays 'error' on the command line
|
||||
Quite useful to terminate with a proper error message rather than
|
||||
a garbage of error due to incorrect code generation in the methods
|
||||
expansion.
|
||||
NOTE: Some implementation claims to be C11 (default mode) but fails
|
||||
to deliver a working assert.h with static_assert so we test for the
|
||||
explicity precense of the macro static_assert.
|
||||
*/
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && defined(static_assert)) || defined(__cplusplus)
|
||||
# define M_STATIC_FAILURE(error, msg) static_assert(false, #error ": " msg);
|
||||
@@ -468,20 +497,23 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Test at compile time if the given condition is true.
|
||||
The error parameter is a C token which classifies the error
|
||||
with an optional message detailling the error.
|
||||
NOTE: Use bitfield to be compatible with most compilers
|
||||
with an optional message detailing the error.
|
||||
In C99, it uses a bitfield to be compatible with most compilers
|
||||
(so that it properly displays 'error' on the command line
|
||||
It cannot use C11 Static Assert as is not usable in expression.
|
||||
NOTE: In C++, use of lambda to encapsulate static_assert in
|
||||
an expression.
|
||||
NOTE: For GNU compatible compilers, uses of a GNU extension.
|
||||
C11 static Assert is not usable in expression,
|
||||
but is usable in struct declaration. Therefore we create
|
||||
a dummy struct, define the static assert within it
|
||||
compute its size and cast it to void.
|
||||
NOTE: Some implementation claims to be C11 (default mode) but fails
|
||||
to deliver a working assert.h with static_assert so we test for the
|
||||
explicitly presence of the macro static_assert.
|
||||
*/
|
||||
#if defined(__cplusplus)
|
||||
#ifdef __cplusplus
|
||||
# define M_STATIC_ASSERT(cond, error, msg) \
|
||||
([] { static_assert(cond, #error ": " msg); } ())
|
||||
#elif defined(__GNUC__) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && defined(static_assert)
|
||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && defined(static_assert)
|
||||
# define M_STATIC_ASSERT(cond, error, msg) \
|
||||
M_ATTR_EXTENSION ({ static_assert(cond, #error ": " msg); })
|
||||
((void) sizeof(struct { int error; static_assert(cond, #error ": " msg);}))
|
||||
#else
|
||||
# define M_STATIC_ASSERT(cond, error, msg) \
|
||||
((void) sizeof(struct { int error : !!(cond);}))
|
||||
@@ -516,13 +548,13 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Generation of function name by concatenation
|
||||
Can be ovverrided by user
|
||||
Can be overriden by user
|
||||
*/
|
||||
#ifndef M_F
|
||||
#define M_F(a, b) M_C2I(a, b)
|
||||
#endif
|
||||
|
||||
/* Concatenation of function name that enable developer to use customizaton
|
||||
/* Concatenation of function name that enable developer to use customization
|
||||
developer shall provide its own name customization by forcing M_F to it
|
||||
then provide its own suffix in the namespace M_OVERRIDE_ ## suffix ():
|
||||
Each generated suffix shall start with a comma.
|
||||
@@ -758,7 +790,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define M_ADDI_52(n) M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(n))))))))))))))))))))))))))))))))))))))))))))))))))))
|
||||
|
||||
|
||||
/* Substract two integers with both integers from [0 to M_MAX_NB_ARGUMENT[
|
||||
/* Subtract two integers with both integers from [0 to M_MAX_NB_ARGUMENT[
|
||||
Generated by:
|
||||
for i in $(seq 0 52) ; do printf "#define M_SUBI_%d(n) " $i ; for j in $(seq 1 $i) ; do printf "M_DEC(";done ; printf "n" ; for j in $(seq 1 $i) ; do printf ")" ;done ; printf "\n" ; done */
|
||||
#define M_SUB(x,y) M_C(M_SUBI_, y)(x)
|
||||
@@ -901,7 +933,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Return the nth argument of a VA_ARGS.
|
||||
- M_RET_ARG<n> lets the VA_ARGS been evaluated, and returns the <n> argument.
|
||||
- M_RETI_ARG<n> returns the <n> argument.
|
||||
- M_RET_ARG takes n as argument, evaluate the arguments, and returns the 'n' argument.
|
||||
- M_RET_ARG takes 'n' as argument, evaluate the arguments, and returns the 'n' argument.
|
||||
NOTE: A comma is added at the end in M_RET_ARG<n> in order to avoid error if the number of
|
||||
argument is exactly <n> (in which case, otherwise the __VA_ARGS__ will be non existent).
|
||||
Generated by:
|
||||
@@ -1156,6 +1188,12 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define M_TRIPLE_2(a,b,c) b
|
||||
#define M_TRIPLE_3(a,b,c) c
|
||||
|
||||
/* Same for quad */
|
||||
#define M_QUAD_1(a,b,c,d) a
|
||||
#define M_QUAD_2(a,b,c,d) b
|
||||
#define M_QUAD_3(a,b,c,d) c
|
||||
#define M_QUAD_4(a,b,c,d) d
|
||||
|
||||
/* Skip the Nth first arguments of a VA_ARGS
|
||||
Generated by:
|
||||
for i in $(seq 0 52) ; do printf "#define M_SKIPI_%d(" $i ; for j in $(seq 1 $i) ; do printf "_%d, " $j ; done ; printf "...) __VA_ARGS__\n"; done
|
||||
@@ -1390,7 +1428,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define M_IF_EMPTY(...) M_IF(M_EMPTY_P(__VA_ARGS__))
|
||||
|
||||
|
||||
/* Concatene the two preprocessing token.
|
||||
/* Concatenate the two preprocessing token.
|
||||
* Handle the case where the second argument is empty, in which case
|
||||
* it returns the first token without concatenation.
|
||||
*/
|
||||
@@ -1450,7 +1488,10 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define M_PATTERN_type_type ,
|
||||
#define M_PATTERN_TYPE_TYPE ,
|
||||
#define M_PATTERN_SUBTYPE_SUBTYPE ,
|
||||
#define M_PATTERN_SUBTYPE_PTR_SUBTYPE_PTR ,
|
||||
#define M_PATTERN_IT_TYPE_IT_TYPE ,
|
||||
#define M_PATTERN_KEY_TYPE_KEY_TYPE ,
|
||||
#define M_PATTERN_VALUE_TYPE_VALUE_TYPE ,
|
||||
#define M_PATTERN_M_UNDERFLOW_M_UNDERFLOW ,
|
||||
#define M_PATTERN_M_OVERFLOW_M_OVERFLOW ,
|
||||
#define M_PATTERN_M_OVERFLOW_M_OVERFLOW ,
|
||||
@@ -1486,7 +1527,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define M_EAT_KEYWORD____(...) __VA_ARGS__
|
||||
|
||||
|
||||
/* Necessary macros to handle recursivity,
|
||||
/* Necessary macros to handle recursion,
|
||||
delaying the evaluation by one (or more) level of macro expansion.
|
||||
The argument is a macro-function which has to be deferred */
|
||||
#define M_DELAY0()
|
||||
@@ -1504,7 +1545,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
forcing the pre-processor to expand the given macro a lot of times.
|
||||
NOTE: There can be only one EVAL macro per complete macro-evaluation pass.
|
||||
As such the given macro cannot contain M_EVAL itself,
|
||||
NOTE: Using recursivity impacts compilation time performance.
|
||||
NOTE: Using recursion impacts compilation time performance.
|
||||
*/
|
||||
#define M_EVAL(...) M_EVAL1(M_EVAL1(M_EVAL1(__VA_ARGS__)))
|
||||
#define M_EVAL1(...) M_EVAL2(M_EVAL2(M_EVAL2(__VA_ARGS__)))
|
||||
@@ -1523,7 +1564,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
|
||||
/* MAP: apply the given macro to all arguments.
|
||||
NOTE: Perform a first step evalution so that the given VA_ARGS is fullu evaluated
|
||||
NOTE: Perform a first step evaluation so that the given VA_ARGS is fully evaluated
|
||||
and expanded before further preprocessing. This helps if the argument given to M_MAP
|
||||
perform a construction of the VA_ARGS as its argument.
|
||||
NOTE: It is a non recursive version that is much faster than the recursive one.
|
||||
@@ -1730,6 +1771,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define M_MAP2B_74(f, d, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74) f(d, _1) f(d, _2) f(d, _3) f(d, _4) f(d, _5) f(d, _6) f(d, _7) f(d, _8) f(d, _9) f(d, _10) f(d, _11) f(d, _12) f(d, _13) f(d, _14) f(d, _15) f(d, _16) f(d, _17) f(d, _18) f(d, _19) f(d, _20) f(d, _21) f(d, _22) f(d, _23) f(d, _24) f(d, _25) f(d, _26) f(d, _27) f(d, _28) f(d, _29) f(d, _30) f(d, _31) f(d, _32) f(d, _33) f(d, _34) f(d, _35) f(d, _36) f(d, _37) f(d, _38) f(d, _39) f(d, _40) f(d, _41) f(d, _42) f(d, _43) f(d, _44) f(d, _45) f(d, _46) f(d, _47) f(d, _48) f(d, _49) f(d, _50) f(d, _51) f(d, _52) f(d, _53) f(d, _54) f(d, _55) f(d, _56) f(d, _57) f(d, _58) f(d, _59) f(d, _60) f(d, _61) f(d, _62) f(d, _63) f(d, _64) f(d, _65) f(d, _66) f(d, _67) f(d, _68) f(d, _69) f(d, _70) f(d, _71) f(d, _72) f(d, _73) f(d, _74)
|
||||
#define M_MAP2B_75(f, d, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75) f(d, _1) f(d, _2) f(d, _3) f(d, _4) f(d, _5) f(d, _6) f(d, _7) f(d, _8) f(d, _9) f(d, _10) f(d, _11) f(d, _12) f(d, _13) f(d, _14) f(d, _15) f(d, _16) f(d, _17) f(d, _18) f(d, _19) f(d, _20) f(d, _21) f(d, _22) f(d, _23) f(d, _24) f(d, _25) f(d, _26) f(d, _27) f(d, _28) f(d, _29) f(d, _30) f(d, _31) f(d, _32) f(d, _33) f(d, _34) f(d, _35) f(d, _36) f(d, _37) f(d, _38) f(d, _39) f(d, _40) f(d, _41) f(d, _42) f(d, _43) f(d, _44) f(d, _45) f(d, _46) f(d, _47) f(d, _48) f(d, _49) f(d, _50) f(d, _51) f(d, _52) f(d, _53) f(d, _54) f(d, _55) f(d, _56) f(d, _57) f(d, _58) f(d, _59) f(d, _60) f(d, _61) f(d, _62) f(d, _63) f(d, _64) f(d, _65) f(d, _66) f(d, _67) f(d, _68) f(d, _69) f(d, _70) f(d, _71) f(d, _72) f(d, _73) f(d, _74) f(d, _75)
|
||||
|
||||
|
||||
/* Map a macro to all given arguments with two additional fixed data (non recursive version):
|
||||
one of the parameter is given and one numerical which is the argument number.
|
||||
Example:
|
||||
@@ -1793,15 +1835,6 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define M_MAP3I_52(f, d, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52) f(d, 1, _1) f(d, 2, _2) f(d, 3, _3) f(d, 4, _4) f(d, 5, _5) f(d, 6, _6) f(d, 7, _7) f(d, 8, _8) f(d, 9, _9) f(d, 10, _10) f(d, 11, _11) f(d, 12, _12) f(d, 13, _13) f(d, 14, _14) f(d, 15, _15) f(d, 16, _16) f(d, 17, _17) f(d, 18, _18) f(d, 19, _19) f(d, 20, _20) f(d, 21, _21) f(d, 22, _22) f(d, 23, _23) f(d, 24, _24) f(d, 25, _25) f(d, 26, _26) f(d, 27, _27) f(d, 28, _28) f(d, 29, _29) f(d, 30, _30) f(d, 31, _31) f(d, 32, _32) f(d, 33, _33) f(d, 34, _34) f(d, 35, _35) f(d, 36, _36) f(d, 37, _37) f(d, 38, _38) f(d, 39, _39) f(d, 40, _40) f(d, 41, _41) f(d, 42, _42) f(d, 43, _43) f(d, 44, _44) f(d, 45, _45) f(d, 46, _46) f(d, 47, _47) f(d, 48, _48) f(d, 49, _49) f(d, 50, _50) f(d, 51, _51) f(d, 52, _52)
|
||||
|
||||
|
||||
|
||||
/* Map a macro to all given pair of arguments (Using recursivity) (OBSOLETE) */
|
||||
/* Example: M_MAP_PAIR(f, a, b, c, d) ==> f(a,b) f(c,d) */
|
||||
#define M_MAP_PAIR_L0_INDIRECT() M_MAP_PAIR_L0
|
||||
#define M_MAP_PAIR_L0(f, ...) M_IF_NARGS_EQ2(__VA_ARGS__)( f(__VA_ARGS__) , M_MAP_PAIR_L1(f, __VA_ARGS__))
|
||||
#define M_MAP_PAIR_L1(f, a, b, ...) f(a,b) M_DELAY3(M_MAP_PAIR_L0_INDIRECT) () (f, __VA_ARGS__)
|
||||
#define M_MAP_PAIR(f, ...) M_IF_EMPTY(__VA_ARGS__)( /* end */, M_EVAL(M_MAP_PAIR_L0(f, __VA_ARGS__)))
|
||||
|
||||
|
||||
/* Map a macro to all given arguments and reduce all theses computation
|
||||
with another reduce macro.
|
||||
Example:
|
||||
@@ -2303,13 +2336,14 @@ done
|
||||
#define M_CROSSI_MAP2_51b(f, d, blist, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, a51) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a1), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a2), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a3), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a4), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a5), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a6), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a7), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a8), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a9), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a10), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a11), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a12), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a13), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a14), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a15), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a16), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a17), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a18), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a19), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a20), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a21), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a22), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a23), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a24), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a25), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a26), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a27), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a28), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a29), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a30), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a31), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a32), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a33), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a34), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a35), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a36), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a37), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a38), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a39), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a40), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a41), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a42), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a43), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a44), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a45), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a46), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a47), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a48), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a49), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a50), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a51), M_ID blist)
|
||||
#define M_CROSSI_MAP2_52(...) M_CROSSI_MAP2_52b(__VA_ARGS__)
|
||||
#define M_CROSSI_MAP2_52b(f, d, blist, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a1), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a2), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a3), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a4), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a5), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a6), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a7), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a8), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a9), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a10), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a11), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a12), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a13), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a14), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a15), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a16), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a17), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a18), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a19), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a20), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a21), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a22), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a23), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a24), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a25), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a26), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a27), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a28), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a29), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a30), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a31), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a32), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a33), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a34), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a35), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a36), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a37), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a38), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a39), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a40), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a41), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a42), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a43), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a44), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a45), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a46), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a47), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a48), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a49), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a50), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a51), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a52), M_ID blist)
|
||||
|
||||
/* Wrapper function that unpacks the argument to call the real macro with the right arguments */
|
||||
#define M_CROSSI_MAP2_F_A(d, b) M_CROSSI_MAP2_F_B(M_ID d, b)
|
||||
#define M_CROSSI_MAP2_F_B(...) M_CROSSI_MAP2_F_C(__VA_ARGS__)
|
||||
#define M_CROSSI_MAP2_F_C(f, d, a1, b1) f(d, a1, b1)
|
||||
|
||||
|
||||
/* Sequence of numerical
|
||||
/* Sequence of numbers
|
||||
Example:
|
||||
M_SEQ(init,end)==>init, init+1, ...end
|
||||
M_MAP(f, M_SEQ(init, end)) ==> f(init) f(init+1) .... f(end)
|
||||
@@ -2357,10 +2391,11 @@ done
|
||||
/* Return the tail sublist of the sublist of the VA_ARGS (removing the 3 first elements) */
|
||||
#define M_TAIL_3(x, y, z, ...) __VA_ARGS__
|
||||
|
||||
/* Concatene two arglists 'a' and 'b',
|
||||
|
||||
/* Concatenate two arglists 'a' and 'b',
|
||||
handling the case of empty arglist
|
||||
handling the cases where the arguments are not arglist.
|
||||
and returning an arglist within parenthesis if it concats.
|
||||
Always return an arglist within parenthesis if it concatenates
|
||||
(internal macro)
|
||||
*/
|
||||
#define M_CAT_ARGLIST(a, b) \
|
||||
@@ -2445,7 +2480,7 @@ done
|
||||
#define M_ID(...) __VA_ARGS__
|
||||
|
||||
|
||||
/* Globber the input */
|
||||
/* Remove the input from preprocessing evaluation */
|
||||
#define M_EAT(...)
|
||||
|
||||
|
||||
@@ -2466,9 +2501,9 @@ done
|
||||
#define M_IF_NARGS_EQ2(...) M_IF(M_EQUAL(M_NARGS(__VA_ARGS__), 2))
|
||||
|
||||
|
||||
/* If NDEBUG macro is defined
|
||||
M_IF_DEBUG(code if NDEBUG is not defined)
|
||||
Note: not 100% robust */
|
||||
/* If NDEBUG macro is not defined, expand code
|
||||
USAGE: M_IF_DEBUG(code if NDEBUG is not defined)
|
||||
Note: not 100% robust but sufficient for its usage */
|
||||
#define M_TEST_NDEBUG_P() M_C3(M_, NDEBUG, _TEST)
|
||||
#define M_NDEBUG_TEST 0
|
||||
#define M_IF_DEBUG(a) M_IF(M_TEST_NDEBUG_P())(,a)
|
||||
@@ -2477,7 +2512,7 @@ done
|
||||
/* If the Function Object is included, expands the code,
|
||||
otherwise do nothing.
|
||||
M_FUNC0BJ_IS_NOT_DEFINED is defined to 0.
|
||||
NOTE: M_IF is the variable is not defined assummes yes.
|
||||
NOTE: M_IF is the variable is not defined assumes yes.
|
||||
*/
|
||||
#define M_IF_FUNCOBJ(a) M_IF(M_FUNC0BJ_IS_NOT_DEFINED)( ,a)
|
||||
|
||||
@@ -2513,6 +2548,14 @@ done
|
||||
#define M_AS_STR(x) M_AS_STRI(x)
|
||||
#define M_AS_STRI(x) #x
|
||||
|
||||
/* Convert an oplist into a string. It may generate a very long string,
|
||||
which generates warning (string length greater than 4095).
|
||||
So the conversion is optional */
|
||||
#ifdef M_USE_PRINT_OPLIST
|
||||
# define M_OPL_AS_STR(x) M_AS_STR(x)
|
||||
#else
|
||||
# define M_OPL_AS_STR(x)
|
||||
#endif
|
||||
|
||||
/* C11 MACROS */
|
||||
|
||||
@@ -2619,15 +2662,6 @@ m_core_fopen(const char filename[], const char opt[])
|
||||
/* Can be overloaded by m-string to support string output too */
|
||||
#define M_CORE_PRINTF_ARG(x) x
|
||||
|
||||
/* Print a C variable if it is a standard type (or extension) to stdout
|
||||
If a variable is extended (i.e. like (x, type) ) it will use the
|
||||
method associated to the OUT_STR operator.
|
||||
*/
|
||||
#define M_PRINT_ARG(x) \
|
||||
M_IF(M_PARENTHESIS_P(x)) \
|
||||
( M_FPRINT_ARG_OUT_STR(stdout, M_PAIR_2 x, M_PAIR_1 x), \
|
||||
printf(M_PRINTF_FORMAT(x), M_CORE_PRINTF_ARG(x) ) )
|
||||
|
||||
/* Print a C variable if it is a standard type to the given file 'f'.
|
||||
If a variable is extended (i.e. like (x, type) ) it will use the
|
||||
method associated to the OUT_STR operator.
|
||||
@@ -2670,7 +2704,7 @@ m_core_fscan_bool (bool *ptr, FILE *f)
|
||||
{
|
||||
int c = fgetc(f);
|
||||
*ptr = (c == '1');
|
||||
return (c == '0' || c == '1');
|
||||
return (c == '0') || (c == '1');
|
||||
}
|
||||
|
||||
M_INLINE bool
|
||||
@@ -2802,7 +2836,7 @@ M_PARSE_DEFAULT_TYPE_DEF(m_core_parse_ldouble, long double, strtold, )
|
||||
|
||||
/* Generic PRINT macro: print all its inputs regardless of the type
|
||||
provided it is a generic "non-struct" type. */
|
||||
#define M_PRINT(...) do { M_REDUCE(M_PRINT_ARG, M_SEPARATE_PER_SEMICOLON, __VA_ARGS__); } while (0)
|
||||
#define M_PRINT(...) do { M_REDUCE2(M_FPRINT_ARG, M_SEPARATE_PER_SEMICOLON, stdout, __VA_ARGS__); } while (0)
|
||||
|
||||
/* Generic FPRINT macro: print all its inputs regardless of the type
|
||||
provided it is a generic "non-struct" type into the file 'f'. */
|
||||
@@ -2818,20 +2852,6 @@ M_PARSE_DEFAULT_TYPE_DEF(m_core_parse_ldouble, long double, strtold, )
|
||||
*/
|
||||
#define M_AS_TYPE(type, x) _Generic(((void)0,(x)), type: (x), default: (type) {0})
|
||||
|
||||
/* Perform a C conditional operator with the following restriction:
|
||||
* - cond shall be a compile time constant.
|
||||
* However, true_expr and false_expr can be objects of different types.
|
||||
* The type of the returned expression will be the same as the
|
||||
* returned object without any promotion.
|
||||
* NOTE: The classic conditional operator can return different types
|
||||
* if and only both objects are pointers. If the selected pointer is
|
||||
* a null pointer constant, the returned type depends if the **other**
|
||||
* expression is itself a null pointer constant or not.
|
||||
* NOTE: Not compatible with C++.
|
||||
*/
|
||||
#define M_CONDITIONAL(cond, true_expr, false_expr) \
|
||||
_Generic(1 ? (float *) 0 : (void *)(intptr_t) (cond), float *: false_expr, void *: true_expr)
|
||||
|
||||
/* Return the minimum between x and y (computed in compile time) */
|
||||
#define M_MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
@@ -2874,7 +2894,7 @@ M_PARSE_DEFAULT_TYPE_DEF(m_core_parse_ldouble, long double, strtold, )
|
||||
*/
|
||||
#ifndef __cplusplus
|
||||
# define M_CONST_CAST(type, n) \
|
||||
(((union { type *ptr; type const *cptr; }){n}).cptr)
|
||||
(((union { type *ptr; type const *cptr; }){ .ptr = n}).cptr)
|
||||
#else
|
||||
# define M_CONST_CAST(type, n) const_cast<type*>(n)
|
||||
#endif
|
||||
@@ -2903,11 +2923,15 @@ M_PARSE_DEFAULT_TYPE_DEF(m_core_parse_ldouble, long double, strtold, )
|
||||
|
||||
|
||||
/* C++ doesn't support flexible array within a structure.
|
||||
Let's define at least one element for an array. */
|
||||
Let's define at least one element for an array.
|
||||
It doesn't also support VLA usage in function prototype.
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
# define M_MIN_FLEX_ARRAY_SIZE 1
|
||||
# define M_VLA(n)
|
||||
#else
|
||||
# define M_MIN_FLEX_ARRAY_SIZE
|
||||
# define M_VLA(n) n
|
||||
#endif
|
||||
|
||||
#if M_USE_STDARG && M_USE_STDIO
|
||||
@@ -3360,6 +3384,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
#define M_TYPE_TYPE(a) ,a,
|
||||
#define M_SUBTYPE_SUBTYPE(a) ,a,
|
||||
#define M_GENTYPE_GENTYPE(a) ,a,
|
||||
#define M_SUBTYPE_PTR_SUBTYPE_PTR(a) ,a,
|
||||
#define M_NAME_NAME(a) ,a,
|
||||
#define M_OPLIST_OPLIST(a) ,a,
|
||||
#define M_SORT_SORT(a) ,a,
|
||||
@@ -3438,77 +3463,77 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
/* Get the given method */
|
||||
#define M_GET_INIT(...) M_GET_METHOD(INIT, M_INIT_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_INIT_SET(...) M_GET_METHOD(INIT_SET, M_SET_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_INIT_MOVE(...) M_GET_METHOD(INIT_MOVE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_INIT_WITH(...) M_GET_METHOD(INIT_WITH, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_INIT_MOVE(...) M_GET_METHOD(INIT_MOVE, M_NO_DEF_INIT_MOVE, __VA_ARGS__)
|
||||
#define M_GET_INIT_WITH(...) M_GET_METHOD(INIT_WITH, M_NO_DEF_INIT_WITH, __VA_ARGS__)
|
||||
#define M_GET_SET(...) M_GET_METHOD(SET, M_SET_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_MOVE(...) M_GET_METHOD(MOVE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SWAP(...) M_GET_METHOD(SWAP, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_MOVE(...) M_GET_METHOD(MOVE, M_NO_DEF_MOVE, __VA_ARGS__)
|
||||
#define M_GET_SWAP(...) M_GET_METHOD(SWAP, M_NO_DEF_SWAP, __VA_ARGS__)
|
||||
#define M_GET_CLEAR(...) M_GET_METHOD(CLEAR, M_NOTHING_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_HASH(...) M_GET_METHOD(HASH, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_HASH(...) M_GET_METHOD(HASH, M_NO_DEF_HASH, __VA_ARGS__)
|
||||
#define M_GET_EQUAL(...) M_GET_METHOD(EQUAL, M_EQUAL_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_CMP(...) M_GET_METHOD(CMP, M_CMP_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_TYPE(...) M_GET_METHOD(TYPE, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_SUBTYPE(...) M_GET_METHOD(SUBTYPE, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_GENTYPE(...) M_GET_METHOD(GENTYPE, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_NAME(...) M_GET_METHOD(NAME, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_SUBTYPE(...) M_GET_METHOD(SUBTYPE, M_NO_DEF_SUBTYPE, __VA_ARGS__)
|
||||
#define M_GET_SUBTYPE_PTR(...) M_GET_METHOD(SUBTYPE_PTR, M_NO_DEF_SUBTYPE_PTR, __VA_ARGS__)
|
||||
#define M_GET_GENTYPE(...) M_GET_METHOD(GENTYPE, M_NO_DEF_GENTYPE, __VA_ARGS__)
|
||||
#define M_GET_NAME(...) M_GET_METHOD(NAME, M_NO_DEF_NAME, __VA_ARGS__)
|
||||
#define M_GET_OPLIST(...) M_GET_METHOD(OPLIST, (), __VA_ARGS__)
|
||||
#define M_GET_SORT(...) M_GET_METHOD(SORT, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SPLICE_BACK(...) M_GET_METHOD(SPLICE_BACK, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SPLICE_AT(...) M_GET_METHOD(SPLICE_AT, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_TYPE(...) M_GET_METHOD(IT_TYPE, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_IT_FIRST(...) M_GET_METHOD(IT_FIRST, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_LAST(...) M_GET_METHOD(IT_LAST, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_END(...) M_GET_METHOD(IT_END, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_SET(...) M_GET_METHOD(IT_SET, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_END_P(...) M_GET_METHOD(IT_END_P, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_LAST_P(...) M_GET_METHOD(IT_LAST_P, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_EQUAL_P(...) M_GET_METHOD(IT_EQUAL_P, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_NEXT(...) M_GET_METHOD(IT_NEXT, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_PREVIOUS(...) M_GET_METHOD(IT_PREVIOUS, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_REF(...) M_GET_METHOD(IT_REF, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_CREF(...) M_GET_METHOD(IT_CREF, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_REMOVE(...) M_GET_METHOD(IT_REMOVE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_INSERT(...) M_GET_METHOD(IT_INSERT, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_EMPTY_P(...) M_GET_METHOD(EMPTY_P, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SORT(...) M_GET_METHOD(SORT, M_NO_DEF_SORT, __VA_ARGS__)
|
||||
#define M_GET_SPLICE_BACK(...) M_GET_METHOD(SPLICE_BACK, M_NO_DEF_SPLICE_BACK, __VA_ARGS__)
|
||||
#define M_GET_SPLICE_AT(...) M_GET_METHOD(SPLICE_AT, M_NO_DEF_SPLICE_AT, __VA_ARGS__)
|
||||
#define M_GET_IT_TYPE(...) M_GET_METHOD(IT_TYPE, M_NO_DEF_IT_TYPE, __VA_ARGS__)
|
||||
#define M_GET_IT_FIRST(...) M_GET_METHOD(IT_FIRST, M_NO_DEF_IT_FIRST, __VA_ARGS__)
|
||||
#define M_GET_IT_LAST(...) M_GET_METHOD(IT_LAST, M_NO_DEF_IT_LAST, __VA_ARGS__)
|
||||
#define M_GET_IT_END(...) M_GET_METHOD(IT_END, M_NO_DEF_IT_END, __VA_ARGS__)
|
||||
#define M_GET_IT_SET(...) M_GET_METHOD(IT_SET, M_NO_DEF_IT_SET, __VA_ARGS__)
|
||||
#define M_GET_IT_END_P(...) M_GET_METHOD(IT_END_P, M_NO_DEF_IT_END_P, __VA_ARGS__)
|
||||
#define M_GET_IT_LAST_P(...) M_GET_METHOD(IT_LAST_P, M_NO_DEF_IT_LAST_P, __VA_ARGS__)
|
||||
#define M_GET_IT_EQUAL_P(...) M_GET_METHOD(IT_EQUAL_P, M_NO_DEF_IT_EQUAL_P,__VA_ARGS__)
|
||||
#define M_GET_IT_NEXT(...) M_GET_METHOD(IT_NEXT, M_NO_DEF_IT_NEXT, __VA_ARGS__)
|
||||
#define M_GET_IT_PREVIOUS(...) M_GET_METHOD(IT_PREVIOUS, M_NO_DEF_IT_PREVIOUS,__VA_ARGS__)
|
||||
#define M_GET_IT_REF(...) M_GET_METHOD(IT_REF, M_NO_DEF_IT_REF, __VA_ARGS__)
|
||||
#define M_GET_IT_CREF(...) M_GET_METHOD(IT_CREF, M_NO_DEF_IT_CREFT, __VA_ARGS__)
|
||||
#define M_GET_IT_REMOVE(...) M_GET_METHOD(IT_REMOVE, M_NO_DEF_IT_REMOVE, __VA_ARGS__)
|
||||
#define M_GET_IT_INSERT(...) M_GET_METHOD(IT_INSERT, M_NO_DEF_IT_INSERT, __VA_ARGS__)
|
||||
#define M_GET_EMPTY_P(...) M_GET_METHOD(EMPTY_P, M_NO_DEF_EMPTY_P, __VA_ARGS__)
|
||||
#define M_GET_ADD(...) M_GET_METHOD(ADD, M_ADD_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SUB(...) M_GET_METHOD(SUB, M_SUB_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_MUL(...) M_GET_METHOD(MUL, M_MUL_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_DIV(...) M_GET_METHOD(DIV, M_DIV_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_RESET(...) M_GET_METHOD(RESET, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_KEY_TYPE(...) M_GET_METHOD(KEY_TYPE, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_VALUE_TYPE(...) M_GET_METHOD(VALUE_TYPE, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_KEY_OPLIST(...) M_GET_METHOD(KEY_OPLIST, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_VALUE_OPLIST(...) M_GET_METHOD(VALUE_OPLIST, M_NO_DEF_TYPE, __VA_ARGS__)
|
||||
#define M_GET_GET_KEY(...) M_GET_METHOD(GET_KEY, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SET_KEY(...) M_GET_METHOD(SET_KEY, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SAFE_GET_KEY(...) M_GET_METHOD(SAFE_GET_KEY, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_ERASE_KEY(...) M_GET_METHOD(ERASE_KEY, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_GET_SIZE(...) M_GET_METHOD(GET_SIZE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_PUSH(...) M_GET_METHOD(PUSH, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_POP(...) M_GET_METHOD(POP, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_PUSH_MOVE(...) M_GET_METHOD(PUSH_MOVE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_POP_MOVE(...) M_GET_METHOD(POP_MOVE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_REVERSE(...) M_GET_METHOD(REVERSE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_GET_STR(...) M_GET_METHOD(GET_STR, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_PARSE_STR(...) M_GET_METHOD(PARSE_STR, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_OUT_STR(...) M_GET_METHOD(OUT_STR, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IN_STR(...) M_GET_METHOD(IN_STR, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_OUT_SERIAL(...) M_GET_METHOD(OUT_SERIAL, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IN_SERIAL(...) M_GET_METHOD(IN_SERIAL, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_RESET(...) M_GET_METHOD(RESET, M_NO_DEF_RESET, __VA_ARGS__)
|
||||
#define M_GET_KEY_TYPE(...) M_GET_METHOD(KEY_TYPE, M_NO_DEF_KEY_TYPE, __VA_ARGS__)
|
||||
#define M_GET_VALUE_TYPE(...) M_GET_METHOD(VALUE_TYPE, M_NO_DEF_VALUE_TYPE,__VA_ARGS__)
|
||||
#define M_GET_KEY_OPLIST(...) M_GET_METHOD(KEY_OPLIST, (), __VA_ARGS__)
|
||||
#define M_GET_VALUE_OPLIST(...) M_GET_METHOD(VALUE_OPLIST, (), __VA_ARGS__)
|
||||
#define M_GET_GET_KEY(...) M_GET_METHOD(GET_KEY, M_NO_DEF_GET_KEY, __VA_ARGS__)
|
||||
#define M_GET_SET_KEY(...) M_GET_METHOD(SET_KEY, M_NO_DEF_SET_KEY, __VA_ARGS__)
|
||||
#define M_GET_SAFE_GET_KEY(...) M_GET_METHOD(SAFE_GET_KEY, M_NO_DEF_SAFE_GET_KEY, __VA_ARGS__)
|
||||
#define M_GET_ERASE_KEY(...) M_GET_METHOD(ERASE_KEY, M_NO_DEF_ERASE_KEY, __VA_ARGS__)
|
||||
#define M_GET_GET_SIZE(...) M_GET_METHOD(GET_SIZE, M_NO_DEF_GET_SIZE, __VA_ARGS__)
|
||||
#define M_GET_PUSH(...) M_GET_METHOD(PUSH, M_NO_DEF_PUSH, __VA_ARGS__)
|
||||
#define M_GET_POP(...) M_GET_METHOD(POP, M_NO_DEF_POP, __VA_ARGS__)
|
||||
#define M_GET_PUSH_MOVE(...) M_GET_METHOD(PUSH_MOVE, M_NO_DEF_PUSH_MOVE, __VA_ARGS__)
|
||||
#define M_GET_POP_MOVE(...) M_GET_METHOD(POP_MOVE, M_NO_DEF_POP_MOVE, __VA_ARGS__)
|
||||
#define M_GET_REVERSE(...) M_GET_METHOD(REVERSE, M_NO_DEF_REVERSE, __VA_ARGS__)
|
||||
#define M_GET_GET_STR(...) M_GET_METHOD(GET_STR, M_NO_DEF_GET_STR, __VA_ARGS__)
|
||||
#define M_GET_PARSE_STR(...) M_GET_METHOD(PARSE_STR, M_NO_DEF_PARSE_STR, __VA_ARGS__)
|
||||
#define M_GET_OUT_STR(...) M_GET_METHOD(OUT_STR, M_NO_DEF_OUT_STR, __VA_ARGS__)
|
||||
#define M_GET_IN_STR(...) M_GET_METHOD(IN_STR, M_NO_DEF_IN_STR, __VA_ARGS__)
|
||||
#define M_GET_OUT_SERIAL(...) M_GET_METHOD(OUT_SERIAL, M_NO_DEF_OUT_SERIAL,__VA_ARGS__)
|
||||
#define M_GET_IN_SERIAL(...) M_GET_METHOD(IN_SERIAL, M_NO_DEF_IN_SERIAL, __VA_ARGS__)
|
||||
#define M_GET_SEPARATOR(...) M_GET_METHOD(SEPARATOR, ',', __VA_ARGS__)
|
||||
#define M_GET_EXT_ALGO(...) M_GET_METHOD(EXT_ALGO, M_NO_EXT_ALGO, __VA_ARGS__)
|
||||
#define M_GET_INC_ALLOC(...) M_GET_METHOD(INC_ALLOC, M_INC_ALLOC_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_OOR_SET(...) M_GET_METHOD(OOR_SET, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_OOR_EQUAL(...) M_GET_METHOD(OOR_EQUAL, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_LIMITS(...) M_GET_METHOD(LIMITS, M_LIMITS_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_OOR_SET(...) M_GET_METHOD(OOR_SET, M_NO_DEF_OOR_SET, __VA_ARGS__)
|
||||
#define M_GET_OOR_EQUAL(...) M_GET_METHOD(OOR_EQUAL, M_NO_DEF_OOR_EQUAL, __VA_ARGS__)
|
||||
#define M_GET_PROPERTIES(...) M_GET_METHOD(PROPERTIES, (), __VA_ARGS__)
|
||||
#define M_GET_EMPLACE_TYPE(...) M_GET_METHOD(EMPLACE_TYPE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
// As sttribute customization
|
||||
#define M_GET_EMPLACE_TYPE(...) M_GET_METHOD(EMPLACE_TYPE, , __VA_ARGS__)
|
||||
// As attribute customization
|
||||
#define M_GET_NEW(...) M_GET_METHOD(NEW, M_NEW_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_DEL(...) M_GET_METHOD(DEL, M_DEL_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_REALLOC(...) M_GET_METHOD(REALLOC, M_REALLOC_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_FREE(...) M_GET_METHOD(FREE, M_FREE_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_MEMPOOL(...) M_GET_METHOD(MEMPOOL, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_MEMPOOL(...) M_GET_METHOD(MEMPOOL, M_NO_DEF_MEMPOOL, __VA_ARGS__)
|
||||
#define M_GET_MEMPOOL_LINKAGE(...) M_GET_METHOD(MEMPOOL_LINKAGE, , __VA_ARGS__)
|
||||
#define M_GET_SIZE(...) M_GET_METHOD(SIZE, 0, __VA_ARGS__)
|
||||
#define M_GET_CONTEXT(...) M_GET_METHOD(CONTEXT, 0, __VA_ARGS__)
|
||||
@@ -3530,6 +3555,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
#define M_CALL_CMP(oplist, ...) M_APPLY_API(M_GET_CMP oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_TYPE(oplist, ...) M_APPLY_API(M_GET_TYPE oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_SUBTYPE(oplist, ...) M_APPLY_API(M_GET_SUBTYPE oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_SUBTYPE_PTR(oplist, ...) M_APPLY_API(M_GET_SUBTYPE_PTR oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_GENTYPE(oplist, ...) M_APPLY_API(M_GET_GENTYPE oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_NAME(oplist, ...) M_APPLY_API(M_GET_NAME oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_OPLIST(oplist, ...) M_APPLY_API(M_GET_OPLIST oplist, oplist, __VA_ARGS__)
|
||||
@@ -3577,7 +3603,6 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
#define M_CALL_INC_ALLOC(oplist, ...) M_APPLY_API(M_GET_INC_ALLOC oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_OOR_SET(oplist, ...) M_APPLY_API(M_GET_OOR_SET oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_OOR_EQUAL(oplist, ...) M_APPLY_API(M_GET_OOR_EQUAL oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_LIMITS(oplist, ...) M_APPLY_API(M_GET_LIMITS oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_PROPERTIES(oplist, ...) M_APPLY_API(M_GET_PROPERTIES oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_EMPLACE_TYPE(oplist, ...) M_APPLY_API(M_GET_EMPLACE_TYPE oplist, oplist, __VA_ARGS__)
|
||||
// As attribute customization
|
||||
@@ -3610,7 +3635,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
|
||||
NOTE: It starts by a comma, to ack the success of the transformation.
|
||||
*/
|
||||
#define M_OPLAPI_ERROR(method, oplist, ...) , M_STATIC_FAILURE(M_LIB_DISABLED_METHOD, "The method has been explictly disabled for the requested operator, yet it has been called by the container")
|
||||
#define M_OPLAPI_ERROR(method, oplist, ...) , M_STATIC_ASSERT(false, M_LIB_DISABLED_METHOD, "The method has been explictly disabled for the requested operator, yet it has been called by the container")
|
||||
#define M_OPLAPI_0(method, oplist, ...) , M_DELAY3(method)(__VA_ARGS__)
|
||||
#define M_OPLAPI_1(method, oplist, ...) , M_DELAY3(method)(oplist, __VA_ARGS__)
|
||||
#define M_OPLAPI_2(method, oplist, ...) , M_DELAY3(method)(& __VA_ARGS__)
|
||||
@@ -3726,16 +3751,76 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
#define M_OPLAPI_EXTRACT_API(...) ( __VA_ARGS__ )
|
||||
|
||||
|
||||
/* Define the no default function that generates a compiler error
|
||||
if the method is expanded.
|
||||
/* Define the no default function that generates
|
||||
* a proper compiler error if the method is expanded.
|
||||
*/
|
||||
#define M_NO_DEFAULT(...) \
|
||||
M_STATIC_FAILURE(M_LIB_MISSING_METHOD, \
|
||||
"The requested operator has no method registered in the given OPLIST. ")
|
||||
#define M_NO_DEFAULT(operator, return_type) \
|
||||
(M_STATIC_ASSERT(false, M_LIB_MISSING_METHOD, \
|
||||
"The " #operator " operator has no method associated in the given OPLIST."),\
|
||||
(return_type) 0)
|
||||
|
||||
#define M_NO_DEF_TYPE \
|
||||
M_STATIC_FAILURE(M_LIB_MISSING_METHOD, \
|
||||
"The requested operator has no type/subtype/suboplist registered in the given OPLIST. ")
|
||||
#define M_NO_DEF_INIT_MOVE(...) M_NO_DEFAULT(INIT_MOVE, void)
|
||||
#define M_NO_DEF_INIT_WITH(...) M_NO_DEFAULT(INIT_WITH, void)
|
||||
#define M_NO_DEF_MOVE(...) M_NO_DEFAULT(MOVE, void)
|
||||
#define M_NO_DEF_SWAP(...) M_NO_DEFAULT(SWAP, void)
|
||||
#define M_NO_DEF_HASH(...) M_NO_DEFAULT(HASH, size_t)
|
||||
#define M_NO_DEF_SORT(...) M_NO_DEFAULT(SORT, void)
|
||||
#define M_NO_DEF_SPLICE_BACK(...) M_NO_DEFAULT(SPLICE_BACK, void)
|
||||
#define M_NO_DEF_SPLICE_AT(...) M_NO_DEFAULT(SPLICE_AT, void)
|
||||
#define M_NO_DEF_IT_FIRST(...) M_NO_DEFAULT(IT_FIRST, void)
|
||||
#define M_NO_DEF_IT_LAST(...) M_NO_DEFAULT(IT_LAST, void)
|
||||
#define M_NO_DEF_IT_END(...) M_NO_DEFAULT(IT_END, void)
|
||||
#define M_NO_DEF_IT_SET(...) M_NO_DEFAULT(IT_SET, void)
|
||||
#define M_NO_DEF_IT_END_P(...) M_NO_DEFAULT(IT_END_P, bool)
|
||||
#define M_NO_DEF_IT_LAST_P(...) M_NO_DEFAULT(IT_LAST_P, bool)
|
||||
#define M_NO_DEF_IT_EQUAL_P(...) M_NO_DEFAULT(IT_EQUAL_P, bool)
|
||||
#define M_NO_DEF_IT_NEXT(...) M_NO_DEFAULT(IT_NEXT, void)
|
||||
#define M_NO_DEF_IT_PREVIOUS(...) M_NO_DEFAULT(IT_PREVIOUS, void)
|
||||
#define M_NO_DEF_IT_REF(...) M_NO_DEFAULT(IT_REF, void)
|
||||
#define M_NO_DEF_IT_CREF(...) M_NO_DEFAULT(IT_CREF, void)
|
||||
#define M_NO_DEF_IT_REMOVE(...) M_NO_DEFAULT(IT_REMOVE, void)
|
||||
#define M_NO_DEF_IT_INSERT(...) M_NO_DEFAULT(IT_INSET, void)
|
||||
#define M_NO_DEF_EMPTY_P(...) M_NO_DEFAULT(EMPTY_P, bool)
|
||||
#define M_NO_DEF_RESET(...) M_NO_DEFAULT(RESET, void)
|
||||
#define M_NO_DEF_GET_KEY(...) M_NO_DEFAULT(GET_KEY, void*)
|
||||
#define M_NO_DEF_SET_KEY(...) M_NO_DEFAULT(SET_KEY, void)
|
||||
#define M_NO_DEF_SAFE_GET_KEY(...) M_NO_DEFAULT(SAFE_GET_KEY, void*)
|
||||
#define M_NO_DEF_ERASE_KEY(...) M_NO_DEFAULT(ERASE_KEY, void)
|
||||
#define M_NO_DEF_GET_SIZE(...) M_NO_DEFAULT(GET_SIZE, size_t)
|
||||
#define M_NO_DEF_PUSH(...) M_NO_DEFAULT(PUSH, void)
|
||||
#define M_NO_DEF_POP(...) M_NO_DEFAULT(POP, void)
|
||||
#define M_NO_DEF_PUSH_MOVE(...) M_NO_DEFAULT(PUSH_MOVE, void)
|
||||
#define M_NO_DEF_POP_MOVE(...) M_NO_DEFAULT(POP_MOVE, void)
|
||||
#define M_NO_DEF_REVERSE(...) M_NO_DEFAULT(REVERSE, void)
|
||||
#define M_NO_DEF_GET_STR(...) M_NO_DEFAULT(GET_STR, void)
|
||||
#define M_NO_DEF_PARSE_STR(...) M_NO_DEFAULT(PARSE_STR, bool)
|
||||
#define M_NO_DEF_OUT_STR(...) M_NO_DEFAULT(OUT_STR, void)
|
||||
#define M_NO_DEF_IN_STR(...) M_NO_DEFAULT(IN_STR, bool)
|
||||
#define M_NO_DEF_OUT_SERIAL(...) M_NO_DEFAULT(OUT_SERIAL, m_serial_return_code_t)
|
||||
#define M_NO_DEF_IN_SERIAL(...) M_NO_DEFAULT(IN_SERIAL, m_serial_return_code_t)
|
||||
#define M_NO_DEF_OOR_SET(...) M_NO_DEFAULT(OOR_SET, void)
|
||||
#define M_NO_DEF_OOR_EQUAL(...) M_NO_DEFAULT(OOR_EQUAL, bool)
|
||||
#define M_NO_DEF_MEMPOOL(...) M_NO_DEFAULT(MEMPOOL, void)
|
||||
|
||||
/* Create a type with an invalid static assertion.
|
||||
Creating a type allowed the macro into something not too bad
|
||||
from a syntaxic point of view, reducing the amount of errors reported
|
||||
so that the user can concentrate to the real error.
|
||||
*/
|
||||
#define M_NO_DEFAULT_TYPE(op) \
|
||||
struct { int m_x[ \
|
||||
(M_STATIC_ASSERT(false, M_LIB_MISSING_METHOD, \
|
||||
"The " #op " operator is not registered in the given OPLIST. ") \
|
||||
, 1)]; }
|
||||
|
||||
#define M_NO_DEF_TYPE M_NO_DEFAULT_TYPE(TYPE)
|
||||
#define M_NO_DEF_IT_TYPE M_NO_DEFAULT_TYPE(IT_TYPE)
|
||||
#define M_NO_DEF_SUBTYPE M_NO_DEFAULT_TYPE(SUBTYPE)
|
||||
#define M_NO_DEF_SUBTYPE_PTR M_NO_DEFAULT_TYPE(SUBTYPE_PTR)
|
||||
#define M_NO_DEF_GENTYPE M_NO_DEFAULT_TYPE(GENTYPE)
|
||||
#define M_NO_DEF_KEY_TYPE M_NO_DEFAULT_TYPE(KEY_TYPE)
|
||||
#define M_NO_DEF_VALUE_TYPE M_NO_DEFAULT_TYPE(VALUE_TYPE)
|
||||
#define M_NO_DEF_NAME M_NO_DEFAULT_TYPE(NAME) m_no_name
|
||||
|
||||
/* Test if the given variable is a basic C variable:
|
||||
int, float, enum, bool or compatible.
|
||||
@@ -3770,11 +3855,19 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
/* Check if both variables are of the same type.
|
||||
The test compare their size.
|
||||
NOTE: Not perfect but catch some errors */
|
||||
#if defined(__GNUC__) && !defined(__cplusplus)
|
||||
#define M_CHECK_SAME(a, b) \
|
||||
M_STATIC_ASSERT(__builtin_types_compatible_p(__typeof__(a), __typeof__(b)), \
|
||||
M_LIB_NOT_SAME_TYPE, \
|
||||
"The variable " M_AS_STR(a) " and " M_AS_STR(b) \
|
||||
" are not of same type.")
|
||||
#else
|
||||
#define M_CHECK_SAME(a, b) \
|
||||
M_STATIC_ASSERT(sizeof(a) == sizeof(b), \
|
||||
M_LIB_NOT_SAME_TYPE, \
|
||||
"The variable " M_AS_STR(a) " and " M_AS_STR(b) \
|
||||
" are not of same type.")
|
||||
#endif
|
||||
|
||||
/* Check if the oplist is compatible with the type.
|
||||
The oplist should define a TYPE method, in which case it is tested.
|
||||
@@ -3800,7 +3893,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
M_LIB_TYPE_MISTMACH, \
|
||||
"The given type " M_AS_STR(type) \
|
||||
" and the type of the oplist does not match: " \
|
||||
M_AS_STR(oplist) ); \
|
||||
M_OPL_AS_STR(oplist) ); \
|
||||
} \
|
||||
, /* End of TYPE */)
|
||||
#else
|
||||
@@ -3814,7 +3907,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
M_LIB_TYPE_MISTMACH, \
|
||||
"The given type " M_AS_STR(type) \
|
||||
" and the type of the oplist does not match: " \
|
||||
M_AS_STR(oplist) ); \
|
||||
M_OPL_AS_STR(oplist) ); \
|
||||
} \
|
||||
, /* End of TYPE */)
|
||||
#endif
|
||||
@@ -4239,6 +4332,7 @@ m_core_parse2_enum (const char str[], const char **endptr)
|
||||
#define M_OPL_bool() M_BOOL_OPLIST
|
||||
#define M_OPL__Bool() M_BOOL_OPLIST
|
||||
|
||||
|
||||
/************************************************************/
|
||||
/******************** Syntax Enhancing **********************/
|
||||
/************************************************************/
|
||||
@@ -4310,7 +4404,7 @@ m_core_parse2_enum (const char str[], const char **endptr)
|
||||
M_IF_OPLIST(oplist)(M_LETI3, M_LETI2_FAILURE)(cont, oplist, __VA_ARGS__)
|
||||
// Stop with a failure (invalid oplist)
|
||||
#define M_LETI2_FAILURE(cont, oplist, ...) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(M_LET): the given argument is not a valid oplist: " M_AS_STR(oplist))
|
||||
M_STATIC_ASSERT(false, M_LIB_NOT_AN_OPLIST, "(M_LET): the given argument is not a valid oplist: " M_AS_STR(oplist))
|
||||
// 4. Map all variables to their own LET
|
||||
#define M_LETI3(cont, oplist, ...) \
|
||||
for(bool cont = true; cont ; /* unused */) \
|
||||
@@ -4349,10 +4443,15 @@ m_core_parse2_enum (const char str[], const char **endptr)
|
||||
#define M_LET_TRY_INJECT_POST(cont, oplist, name)
|
||||
|
||||
/*
|
||||
Internal M_LET for use for withing container.
|
||||
* Internal M_LET for use within container.
|
||||
* Declare the given variable of the given type and
|
||||
* initialize / clear it using the given oplist .
|
||||
*
|
||||
* index shall be a number within the function (from 1)
|
||||
* identifying the M_QLET in the service.
|
||||
*/
|
||||
#define M_QLET(x, type, oplist) \
|
||||
M_LET(x, M_OPEXTEND(oplist, TYPE(type)))
|
||||
#define M_QLET(index, var, type, oplist) \
|
||||
M_LET(var, M_OPEXTEND(oplist, TYPE(type)))
|
||||
|
||||
/* Transform the va list by adding their number as the first argument of
|
||||
the list.
|
||||
@@ -4469,25 +4568,24 @@ m_core_parse2_enum (const char str[], const char **endptr)
|
||||
|
||||
/* If exceptions are activated, M_ON_EXCEPTION enables support for fixing
|
||||
the data structure when an exception is throw,
|
||||
so that the data structure is proper for the CLEAR method.
|
||||
so that the data structure integrity is ready for the CLEAR method.
|
||||
The fix code is *only* executed on exception.
|
||||
USAGE:
|
||||
void init_function(struct_t s) {
|
||||
M_ON_EXCEPTION(name, OPLIST, s->size = i ) {
|
||||
M_ON_EXCEPTION(s->size = i ) {
|
||||
// Rest of initialization code
|
||||
}
|
||||
}
|
||||
Do nothing if exceptions are not enabled.
|
||||
*/
|
||||
#define M_ON_EXCEPTION(name, oplist, fix) \
|
||||
M_IF(M_GET_PROPERTY(oplist, NOCLEAR))(M_EAT, M_ON_EXCEPTION_B) \
|
||||
(M_C(m_var_, name), fix)
|
||||
#define M_ON_EXCEPTION(...) for(bool cont = true; cont; cont = false) \
|
||||
|
||||
#define M_ON_EXCEPTION_B(cont, fix) \
|
||||
for(bool cont = true; cont; cont = false) \
|
||||
M_DEFER_TRY_INJECT_PRE(cont, clear) \
|
||||
for( ; cont ; cont = false) \
|
||||
M_DEFER_TRY_INJECT_POST(cont, clear) \
|
||||
for( ; cont; cont = false)
|
||||
/* If exceptions are activated, M_IF_EXCEPTION will expand the code.
|
||||
Do nothing if exceptions are not enabled. */
|
||||
#define M_IF_EXCEPTION(...) (void) 0
|
||||
|
||||
/* Declare a variable as volatile if exceptions are enabled */
|
||||
#define m_volatile /* nothing */
|
||||
|
||||
|
||||
/* Declare a variable, initialize it, continue if the initialization succeeds,
|
||||
@@ -4977,7 +5075,7 @@ m_core_parse2_enum (const char str[], const char **endptr)
|
||||
/* Can be increased / decreased by user code if needed
|
||||
to increase / decrease backoff of code */
|
||||
#ifndef M_USE_BACKOFF_MAX_COUNT
|
||||
#define M_USE_BACKOFF_MAX_COUNT 6
|
||||
#define M_USE_BACKOFF_MAX_COUNT 8
|
||||
#endif
|
||||
|
||||
/* Exponential backoff object.
|
||||
@@ -4991,14 +5089,12 @@ typedef struct m_core_backoff_s {
|
||||
unsigned int seed; // Initial seed
|
||||
} m_core_backoff_ct[1];
|
||||
|
||||
/* Initialize a backoff object.
|
||||
* Use the C function rand to initialize its internal seed.
|
||||
* It should be good enough for the purpose of the backoff */
|
||||
/* Initialize a backoff object. */
|
||||
M_INLINE void
|
||||
m_core_backoff_init(m_core_backoff_ct backoff)
|
||||
{
|
||||
backoff->count = 0;
|
||||
backoff->seed = (unsigned int) rand();
|
||||
backoff->seed = 0;
|
||||
}
|
||||
|
||||
/* Reset the count of the backoff object */
|
||||
@@ -5014,6 +5110,16 @@ m_core_backoff_reset(m_core_backoff_ct backoff)
|
||||
M_INLINE void
|
||||
m_core_backoff_wait(m_core_backoff_ct backoff)
|
||||
{
|
||||
if (backoff->count <= 2) {
|
||||
backoff->count++;
|
||||
if (backoff->count < 3)
|
||||
return;
|
||||
// Use the C function rand to initialize its internal seed.
|
||||
// It should be good enough for the purpose of the backoff.
|
||||
// We only do it once if we already have performed several loops
|
||||
// to avoid paying the cost of 'rand' for the small start.
|
||||
backoff->seed = (unsigned int) rand();
|
||||
}
|
||||
/* x is qualified as volatile to avoid being optimized away
|
||||
by the compiler in the active sleep loop */
|
||||
volatile int x = 0;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - DEQUE module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -177,6 +177,7 @@
|
||||
/* Test for overflow of the size computation */ \
|
||||
if (M_UNLIKELY_NOMEM (def > SIZE_MAX / sizeof (type) - sizeof(node_t))) { \
|
||||
M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \
|
||||
abort(); \
|
||||
return NULL; \
|
||||
} \
|
||||
/* Alloc a new node with dynamic size */ \
|
||||
@@ -185,6 +186,7 @@
|
||||
sizeof(node_t) + def * sizeof(type) ); \
|
||||
if (M_UNLIKELY_NOMEM (n==NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \
|
||||
abort(); \
|
||||
return NULL; \
|
||||
} \
|
||||
/* Initialize the node */ \
|
||||
@@ -205,7 +207,6 @@
|
||||
d->default_size = M_USE_DEQUE_DEFAULT_SIZE; \
|
||||
d->count = 0; \
|
||||
node_t *n = M_C3(m_d3qu3_,name,_new_node)(d); \
|
||||
if (n == NULL) return; \
|
||||
M_F(name, _node_list_push_back)(d->list, n); \
|
||||
d->front->node = n; \
|
||||
d->front->index = M_USE_DEQUE_DEFAULT_SIZE/2; \
|
||||
@@ -264,7 +265,6 @@
|
||||
if (n == NULL) { \
|
||||
/* No node exists, allocate a new one */ \
|
||||
n = M_C3(m_d3qu3_,name,_new_node)(d); \
|
||||
if (M_UNLIKELY (n == NULL)) return NULL; \
|
||||
M_F(name, _node_list_push_back)(d->list, n); \
|
||||
} \
|
||||
d->back->node = n; \
|
||||
@@ -289,7 +289,7 @@
|
||||
M_F(name, _push_back)(deque_t d, type const x) \
|
||||
{ \
|
||||
type *p = M_F(name, _push_back_raw)(d); \
|
||||
if (M_LIKELY(p != NULL)) { \
|
||||
M_ON_EXCEPTION(d->back->index --, d->count--) { \
|
||||
M_CALL_INIT_SET(oplist, *p, x); \
|
||||
} \
|
||||
} \
|
||||
@@ -299,7 +299,7 @@
|
||||
M_F(name, _push_back_new)(deque_t d) \
|
||||
{ \
|
||||
type *p = M_F(name, _push_back_raw)(d); \
|
||||
if (M_LIKELY(p != NULL)) { \
|
||||
M_ON_EXCEPTION(d->back->index --, d->count--) { \
|
||||
M_CALL_INIT(oplist, *p); \
|
||||
} \
|
||||
return p; \
|
||||
@@ -311,8 +311,6 @@
|
||||
{ \
|
||||
M_ASSERT (x != NULL); \
|
||||
type *p = M_F(name, _push_back_raw)(d); \
|
||||
if (M_UNLIKELY(p == NULL)) \
|
||||
return; \
|
||||
M_DO_INIT_MOVE (oplist, *p, *x); \
|
||||
} \
|
||||
\
|
||||
@@ -328,7 +326,6 @@
|
||||
n = M_F(name, _node_list_previous_obj)(d->list, n); \
|
||||
if (n == NULL) { \
|
||||
n = M_C3(m_d3qu3_,name,_new_node)(d); \
|
||||
if (M_UNLIKELY (n == NULL)) return NULL; \
|
||||
M_F(name, _node_list_push_front)(d->list, n); \
|
||||
} \
|
||||
d->front->node = n; \
|
||||
@@ -345,7 +342,7 @@
|
||||
M_F(name, _push_front)(deque_t d, type const x) \
|
||||
{ \
|
||||
type *p = M_F(name, _push_front_raw)(d); \
|
||||
if (M_LIKELY(p != NULL)) { \
|
||||
M_ON_EXCEPTION(d->front->index ++, d->count--) { \
|
||||
M_CALL_INIT_SET(oplist, *p, x); \
|
||||
} \
|
||||
} \
|
||||
@@ -355,7 +352,7 @@
|
||||
M_F(name, _push_front_new)(deque_t d) \
|
||||
{ \
|
||||
type *p = M_F(name, _push_front_raw)(d); \
|
||||
if (M_LIKELY(p != NULL)) { \
|
||||
M_ON_EXCEPTION(d->front->index ++, d->count--) { \
|
||||
M_CALL_INIT(oplist, *p); \
|
||||
} \
|
||||
return p; \
|
||||
@@ -367,8 +364,6 @@
|
||||
{ \
|
||||
M_ASSERT (x != NULL); \
|
||||
type *p = M_F(name, _push_front_raw)(d); \
|
||||
if (M_UNLIKELY(p == NULL)) \
|
||||
return; \
|
||||
M_DO_INIT_MOVE (oplist, *p, *x); \
|
||||
} \
|
||||
\
|
||||
@@ -396,11 +391,7 @@
|
||||
index = n->size-1; \
|
||||
} \
|
||||
if (ptr != NULL) \
|
||||
M_IF_METHOD(MOVE, oplist) ( \
|
||||
M_CALL_MOVE(oplist, *ptr, n->data[index]); else \
|
||||
, \
|
||||
M_CALL_SET(oplist, *ptr, n->data[index]); \
|
||||
) \
|
||||
M_DO_MOVE(oplist, *ptr, n->data[index]); else \
|
||||
M_CALL_CLEAR(oplist, n->data[index]); \
|
||||
d->count --; \
|
||||
d->back->index = index; \
|
||||
@@ -426,11 +417,7 @@
|
||||
node_t *n = d->front->node; \
|
||||
size_t index = d->front->index; \
|
||||
if (ptr != NULL) \
|
||||
M_IF_METHOD(MOVE, oplist) ( \
|
||||
M_CALL_MOVE(oplist, *ptr, n->data[index]); else \
|
||||
, \
|
||||
M_CALL_SET(oplist, *ptr, n->data[index]); \
|
||||
) \
|
||||
M_DO_MOVE(oplist, *ptr, n->data[index]); else \
|
||||
M_CALL_CLEAR(oplist, n->data[index]); \
|
||||
index++; \
|
||||
if (M_UNLIKELY (n->size <= index)) { \
|
||||
@@ -449,7 +436,7 @@
|
||||
/* No next obj. \
|
||||
It is only possible if there was only 1 element */ \
|
||||
M_ASSERT(d->count == 1); \
|
||||
/* Reset the deque to the midle of the current node */ \
|
||||
/* Reset the deque to the middle of the current node */ \
|
||||
d->back->node = d->front->node; \
|
||||
index = d->front->node->size/2; \
|
||||
d->back->index = d->front->node->size/2; \
|
||||
@@ -746,9 +733,8 @@
|
||||
M_ASSERT (d != NULL); \
|
||||
M_F(name, _node_list_init)(d->list); \
|
||||
d->default_size = M_USE_DEQUE_DEFAULT_SIZE + src->count; \
|
||||
d->count = src->count; \
|
||||
node_t *n = M_C3(m_d3qu3_,name,_new_node)(d); \
|
||||
if (n == NULL) return; \
|
||||
d->count = src->count; \
|
||||
d->default_size /= 2; \
|
||||
M_F(name, _node_list_push_back)(d->list, n); \
|
||||
d->front->node = n; \
|
||||
@@ -756,7 +742,8 @@
|
||||
d->back->node = n; \
|
||||
d->back->index = M_USE_DEQUE_DEFAULT_SIZE/2 + src->count; \
|
||||
it_t it; \
|
||||
size_t i = M_USE_DEQUE_DEFAULT_SIZE/2; \
|
||||
size_t m_volatile i = M_USE_DEQUE_DEFAULT_SIZE/2; \
|
||||
M_ON_EXCEPTION(d->count = i - M_USE_DEQUE_DEFAULT_SIZE/2, d->back->index = i, M_F(name, _clear)(d) ) \
|
||||
for(M_F(name, _it)(it, src); !M_F(name, _end_p)(it) ; M_F(name, _next)(it)) { \
|
||||
type const *obj = M_F(name, _cref)(it); \
|
||||
M_CALL_INIT_SET(oplist, n->data[i], *obj); \
|
||||
@@ -772,8 +759,10 @@
|
||||
if (M_UNLIKELY (src == d)) \
|
||||
return; \
|
||||
/* TODO: Reuse memory of d! */ \
|
||||
M_F(name, _clear)(d); \
|
||||
M_F(name, _init_set)(d, src); \
|
||||
M_ON_EXCEPTION( M_F(name, _init)(d) ) { \
|
||||
M_F(name, _clear)(d); \
|
||||
M_F(name, _init_set)(d, src); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
@@ -951,28 +940,23 @@
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
M_ASSERT (str != NULL); \
|
||||
M_F(name,_reset)(deque); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
if (M_UNLIKELY (c != '[')) { c = 0; goto exit; } \
|
||||
c = *str++; \
|
||||
if (M_UNLIKELY (c == ']')) {success = true; goto exit;} \
|
||||
if (M_UNLIKELY (c == 0)) goto exit; \
|
||||
if (M_UNLIKELY (c == ']' || c == 0)) goto exit; \
|
||||
str--; \
|
||||
type item; \
|
||||
M_CALL_INIT(oplist, item); \
|
||||
do { \
|
||||
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
if (b == false || c == 0) { goto exit_clear; } \
|
||||
M_F(name, _push_back)(deque, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
success = (c == ']'); \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
M_QLET(1, item, type, oplist) { \
|
||||
do { \
|
||||
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
|
||||
c = m_core_str_nospace(&str); \
|
||||
if (b == false || c == 0) { c = 0; break; } \
|
||||
M_F(name, _push_back)(deque, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
exit: \
|
||||
if (endp) *endp = str; \
|
||||
return success; \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
return c == ']'; \
|
||||
} \
|
||||
, /* no PARSE_STR */ ) \
|
||||
\
|
||||
@@ -989,15 +973,14 @@
|
||||
if (M_UNLIKELY (c == ']')) return true; \
|
||||
if (M_UNLIKELY (c == EOF)) return false; \
|
||||
ungetc(c, file); \
|
||||
type item; \
|
||||
M_CALL_INIT(oplist, item); \
|
||||
do { \
|
||||
bool b = M_CALL_IN_STR(oplist, item, file); \
|
||||
do { c = fgetc(file); } while (isspace(c)); \
|
||||
if (b == false || c == EOF) { break; } \
|
||||
M_F(name, _push_back)(deque, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
M_QLET(1, item, type, oplist) { \
|
||||
do { \
|
||||
bool b = M_CALL_IN_STR(oplist, item, file); \
|
||||
c = m_core_fgetc_nospace(file); \
|
||||
if (b == false || c == EOF) { c = 0; break; } \
|
||||
M_F(name, _push_back)(deque, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
return c == ']'; \
|
||||
} \
|
||||
@@ -1040,15 +1023,14 @@
|
||||
M_F(name,_reset)(deque); \
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
|
||||
type item; \
|
||||
M_CALL_INIT(oplist, item); \
|
||||
do { \
|
||||
ret = M_CALL_IN_SERIAL(oplist, item, f); \
|
||||
if (ret != M_SERIAL_OK_DONE) { break; } \
|
||||
M_F(name, _push_back)(deque, item); \
|
||||
ret = f->m_interface->read_array_next(local, f); \
|
||||
} while (ret == M_SERIAL_OK_CONTINUE); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
M_QLET(1, item, type, oplist) { \
|
||||
do { \
|
||||
ret = M_CALL_IN_SERIAL(oplist, item, f); \
|
||||
if (ret != M_SERIAL_OK_DONE) { break; } \
|
||||
M_F(name, _push_back)(deque, item); \
|
||||
ret = f->m_interface->read_array_next(local, f); \
|
||||
} while (ret == M_SERIAL_OK_CONTINUE); \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
, /* no IN_SERIAL & INIT */ ) \
|
||||
@@ -1060,9 +1042,9 @@
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_F(name, _subtype_ct) *data = M_F(name, _push_back_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
M_ON_EXCEPTION(v->back->index --, v->count--) { \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
@@ -1073,9 +1055,9 @@
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_F(name, _subtype_ct) *data = M_F(name, _push_front_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
M_ON_EXCEPTION(v->front->index ++, v->count--) { \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
@@ -1104,7 +1086,7 @@
|
||||
,MOVE(M_F(name, _move)) \
|
||||
,SWAP(M_F(name, _swap)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_F(name,_ct)) \
|
||||
,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \
|
||||
,SUBTYPE(M_F(name, _subtype_ct)) \
|
||||
,EMPTY_P(M_F(name,_empty_p)) \
|
||||
,IT_TYPE(M_F(name,_it_ct)) \
|
||||
|
||||
+7
-7
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Function Object module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -96,7 +96,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.
|
||||
NOTE: It is reversed (0 instead of 1) so that it can be used in M_IF reliably.
|
||||
*/
|
||||
#define M_FUNC0BJ_IS_NOT_DEFINED 0
|
||||
|
||||
@@ -105,13 +105,13 @@
|
||||
*
|
||||
* Structure definitions are specialized in function of the presence or not
|
||||
* of parameters and/or attributes
|
||||
* FIXME: How to factorize reasonnably well between the definitions?
|
||||
* FIXME: How to factorize reasonably well between the definitions?
|
||||
*/
|
||||
|
||||
/* Specialization of the OPLIST in function if there is at least one member or not */
|
||||
#define M_FUNC0BJ_INS_NO_ATTR_OPLIST(name) ( \
|
||||
NAME(name), \
|
||||
TYPE(M_F(name, _ct)), \
|
||||
TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
CLEAR(M_F(name, _clear)), \
|
||||
INIT(M_F(name,_init)) \
|
||||
)
|
||||
@@ -127,7 +127,7 @@
|
||||
/* Define the oplist of the instance */
|
||||
#define M_FUNC0BJ_INS_ATTR_OPLIST_P3(name, ...) ( \
|
||||
NAME(name), \
|
||||
TYPE(M_F(name, _ct)), \
|
||||
TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
INIT_WITH(M_F(name, _init_with)), \
|
||||
CLEAR(M_F(name, _clear)), \
|
||||
M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_F(name,_init)),), \
|
||||
@@ -156,7 +156,7 @@
|
||||
\
|
||||
typedef struct M_F(name, _s) { \
|
||||
M_F(name, _callback_ct) callback; \
|
||||
} interface_t[1]; \
|
||||
} *interface_t; \
|
||||
\
|
||||
/* Internal type for oplist & instance */ \
|
||||
typedef interface_t M_F(name, _ct); \
|
||||
@@ -192,7 +192,7 @@
|
||||
\
|
||||
typedef struct M_F(name, _s) { \
|
||||
M_F(name, _callback_ct) callback; \
|
||||
} interface_t[1]; \
|
||||
} *interface_t; \
|
||||
\
|
||||
/* Internal type for oplist & instance */ \
|
||||
typedef interface_t M_F(name, _ct); \
|
||||
|
||||
+328
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* M*LIB - Generic module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef MSTARLIB_GENERIC_H
|
||||
#define MSTARLIB_GENERIC_H
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define the generic macro-functions */
|
||||
// TODO: m_ prefix?
|
||||
#define init(x) M_G3N_CALL_1(INIT, x)
|
||||
#define init_set(x, y) M_G3N_CALL_2(INIT_SET, x, TYPE, x, TYPE, y)
|
||||
#define init_move(x, y) M_G3N_CALL_2(INIT_MOVE, x, TYPE, x, TYPE, y)
|
||||
#define move(x, y) M_G3N_CALL_2(MOVE, x, TYPE, x, TYPE, y)
|
||||
#define set(x, y) M_G3N_CALL_2(SET, x, TYPE, x , TYPE, y)
|
||||
#define clear(x) M_G3N_CALL_1(CLEAR, x)
|
||||
#define swap(x, y) M_G3N_CALL_2(SWAP, x, TYPE, x , TYPE, y)
|
||||
#define hash(x) M_G3N_CALL_1(HASH, x)
|
||||
#define equal(x, y) M_G3N_CALL_2(EQUAL, x, TYPE, x , TYPE, y)
|
||||
#define cmp(x, y) M_G3N_CALL_2(CMP, x, TYPE, x , TYPE, y)
|
||||
#define sort(x) M_G3N_CALL_1(SORT, x)
|
||||
#define splice_back(d, s, i) M_G3N_CALL_3(SPLICE_BACK, d, TYPE, d, TYPE, s, IT_TYPE, i)
|
||||
#define splice_at(d, id, s, is) M_G3N_CALL_4(SPLICE_BACK, d, TYPE, d, IT_TYPE, id, TYPE, s, IT_TYPE, is)
|
||||
#define it_type(x) m_typeof(M_G3N_TYPE_1(IT_TYPE, x))
|
||||
#define sub_type(x) m_typeof(M_G3N_TYPE_1(SUBTYPE, x))
|
||||
#define key_type(x) m_typeof(M_G3N_TYPE_1(KEY_TYPE, x))
|
||||
#define value_type(x) m_typeof(M_G3N_TYPE_1(VALUE_TYPE, x))
|
||||
#define it_first(x, y) M_G3N_CALL_2(IT_FIRST, y, IT_TYPE, x, TYPE, y)
|
||||
#define it_last(x, y) M_G3N_CALL_i2(IT_LAST, y, IT_TYPE, x, TYPE, y)
|
||||
#define it_end(x, y) M_G3N_CALL_i2(IT_END, y, IT_TYPE, x, TYPE, y)
|
||||
#define it_set(d, s) M_G3N_CALL_2i(IT_SET, d, IT_TYPE, d, IT_TYPE, s)
|
||||
#define it_end_p(i) M_G3N_CALL_1i(IT_END_P, i)
|
||||
#define it_last_p(i) M_G3N_CALL_1i(IT_LAST_P, i)
|
||||
#define it_next(i) M_G3N_CALL_1i(IT_NEXT, i)
|
||||
#define it_previous(i) M_G3N_CALL_1i(IT_PREVIOUS, i)
|
||||
#define it_ref(i) M_G3N_CALL_1i(IT_REF, i)
|
||||
#define it_cref(i) M_G3N_CALL_1i(IT_CREF, i)
|
||||
#define it_equal(x, y) M_G3N_CALL_2i(IT_EQUAL, x, IT_TYPE, x, IT_TYPE, y)
|
||||
#define it_insert(c, i, o) M_G2N_CALL_3(IT_INSERT, c, TYPE, c, IT_TYPE, i, SUBTYPE, o)
|
||||
#define it_remove(c, i) M_G3N_CALL_2(IT_REMOVE, c, TYPE, c, IT_TYPE, i)
|
||||
#define empty_p(x) M_G3N_CALL_1(EMPTY_P, x)
|
||||
#define add(x, y) M_G3N_CALL_2(ADD, x, TYPE, x, TYPE, y)
|
||||
#define sub(x, y) M_G3N_CALL_2(SUB, x, TYPE, x, TYPE, y)
|
||||
#define mul(x, y) M_G3N_CALL_2(MUL, x, TYPE, x, TYPE, y)
|
||||
#define div(x, y) M_G3N_CALL_2(DIV, x, TYPE, x, TYPE, y)
|
||||
#define reset(x) M_G3N_CALL_1(RESET, x)
|
||||
#define get(x, y) M_G3N_CALL_2(GET_KEY, x, TYPE, x, KEY_TYPE, y)
|
||||
#define set_at(x, y, z) M_G3N_CALL_3(SET_KEY, x, TYPE, x, KEY_TYPE, y, VALUE_TYPE, z)
|
||||
#define safe_get(x, y) M_G3N_CALL_2(SAFE_GET_KEY, x, TYPE, x, KEY_TYPE, y)
|
||||
#define erase(x, y) M_G3N_CALL_2(ERASE, x, TYPE, x, KEY_TYPE, y)
|
||||
#define get_size(x) M_G3N_CALL_1(GET_SIZE, x)
|
||||
#define push(x, y) M_G3N_CALL_2(PUSH, x, TYPE, x, SUBTYPE, y)
|
||||
#define pop(x, y) M_G3N_CALL_2(POP, y, SUBTYPE_PTR, x, TYPE, y)
|
||||
#define push_move(x, y) M_G3N_CALL_2(PUSH_MOVE, x, TYPE, x, SUBTYPE_PTR, y)
|
||||
#define pop_move(x, y) M_G3N_CALL_2(POP_MOVE, y, SUBTYPE_PTR, x, TYPE, y)
|
||||
#define reverse(x) M_G3N_CALL_1(REVERSE, x)
|
||||
#define get_str(s, c, b) M_G3N_CALL_3(GET_STR, c, string_t, s, TYPE, c, bool, b)
|
||||
#define parse_str(c, s, e) M_G3N_CALL_3(PARSE_STR, c, TYPE, c, m_g3n_cstring, s, m_g3n_cstring_end, e)
|
||||
#define out_str(x, y) M_G3N_CALL_2(OUT_STR, y, m_g3n_file, x, TYPE, y)
|
||||
#define in_str(x, y) M_G3N_CALL_2(IN_STR, x, TYPE, x, m_g3n_file, y)
|
||||
#define out_serial(x, y) M_G3N_CALL_2(OUT_SERIAL, y, m_serial_write_t, x, TYPE, y)
|
||||
#define in_serial(x, y) M_G3N_CALL_2(IN_SERIAL, x, TYPE, x, m_serial_read_t, y)
|
||||
|
||||
#define let(...) M_LET(__VA_ARGS__)
|
||||
#define print(...) M_PRINT(__VA_ARGS__)
|
||||
|
||||
// for each(item, container)
|
||||
#define each(item, container) \
|
||||
M_G3N_EACHI(item, container, M_C(m_local_it_, __LINE__), M_C(local_pass_, __LINE__))
|
||||
|
||||
/* User code has to register oplists like this:
|
||||
#define M_GENERIC_ORG_2() (USER)
|
||||
#define M_GENERIC_ORG_USER_COMP_1() (CORE)
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_6() FLT1
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_7() STR1
|
||||
*/
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/********************************** INTERNAL *********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Definition of the typeof keyword
|
||||
In C23, we can use the standard keyword.
|
||||
Otherwise we use some extensions of the compilers. */
|
||||
#ifdef _MSC_VER
|
||||
#define m_typeof(x) decltype(x)
|
||||
#elif defined(__GNUC__)
|
||||
#define m_typeof(x) __typeof__(x)
|
||||
#else
|
||||
#define m_typeof(x) typeof(x)
|
||||
#endif
|
||||
|
||||
// Instead of using expensive M_SEQ(1,50), precompute it:
|
||||
#define M_G3N_SEQ_INT \
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, \
|
||||
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, \
|
||||
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50
|
||||
|
||||
/* Generate a sequence of the oplist that have been registered.
|
||||
|
||||
3 levels of indirection are needed:
|
||||
* One level is the organisation.
|
||||
* One level is the component of the organisation.
|
||||
* One level is the oplist within the component of the organisation
|
||||
Return the list of unevaluated oplist that are registered across all organizations, all components.
|
||||
M*LIB Organisation (MLIB) is the default organisation and is always registered
|
||||
Usage Domain: Nb organizations * Nb components * Nb oplist <= M_MAX_NB_ARGUMENT
|
||||
*/
|
||||
#define M_G3N_REGISTERED_ITEMS() \
|
||||
M_CROSS_MAP( M_G3N_IS_PRESENT3, ( comp M_CROSS_MAP(M_G3N_IS_PRESENT2, (MLIB M_MAP(M_G3N_IS_PRESENT, M_G3N_SEQ_INT)), ( M_G3N_SEQ_INT ) ) ), ( M_G3N_SEQ_INT ) )
|
||||
|
||||
#define M_G3N_IS_PRESENT(num) \
|
||||
M_IF(M_PARENTHESIS_P(M_C(M_GENERIC_ORG_, num)() ))(M_DEFERRED_COMMA M_ID M_C(M_GENERIC_ORG_, num)(), )
|
||||
|
||||
#define M_G3N_IS_PRESENT2(el1, num) \
|
||||
M_IF(M_PARENTHESIS_P(M_C4(M_GENERIC_ORG_, el1, _COMP_, num)()))(M_DEFERRED_COMMA M_APPLY(M_C3, el1, _COMP_, M_ID M_C4(M_GENERIC_ORG_, el1, _COMP_, num)()), )
|
||||
|
||||
#define M_G3N_IS_PRESENT3(el1, num) \
|
||||
M_IF(M_OPLIST_P(M_C4(M_GENERIC_ORG_, el1, _OPLIST_, num)()))(M_DEFERRED_COMMA M_C4(M_GENERIC_ORG_, el1, _OPLIST_, num), )
|
||||
|
||||
|
||||
// Dummy unused structure. Just to fill in default case of the _Generic
|
||||
struct m_g3neric_dummy_s;
|
||||
|
||||
// Synonymous for some basic pointers doesn't work well with preprocessing code
|
||||
typedef FILE *m_g3n_file;
|
||||
typedef const char *m_g3n_cstring;
|
||||
typedef const char **m_g3n_cstring_end;
|
||||
|
||||
// If x is of typex, return y else return (typey){O}
|
||||
#define M_AS_LINKED_TYPE(typex, x, typey, y) _Generic(((void)0,(x)), typex: (y), default: (typey) {0})
|
||||
|
||||
// Return IT_TYPE of oplist promoted to a type suitable for a _Generic statement
|
||||
// i.e. transform array type into corresponding pointer type
|
||||
#define M_G3N_GEN_IT_TYPE(oplist) m_typeof( ((void)0, (M_GET_IT_TYPE oplist()){0}))
|
||||
#define M_G3N_GEN_TYPE(oplist) M_GET_GENTYPE oplist()
|
||||
|
||||
// Translate type' into the container type if type == TYPE, IT_TYPE into its iterator
|
||||
// KEY_TYPE, VALUE_TYPE, SUBTYPE into the associated type in the oplist,
|
||||
// or keep 'type' otherwise
|
||||
// Handle also specially SUBTYPE_PTR
|
||||
#define M_G3N_TYPE(type, oplist) M_G3N_TYPE_B(type, oplist())
|
||||
#define M_G3N_TYPE_B(type, oplist) M_GET_METHOD(type, type, SUBTYPE_PTR(M_GET_SUBTYPE oplist *), M_OPFLAT oplist)
|
||||
|
||||
// Call the OPERATOR call of the oplist registered to the variable 'x'
|
||||
// which takes one argument.
|
||||
#define M_G3N_CALL_1(op, x) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( (x), \
|
||||
M_MAP2(M_G3N_CALL_1_func, (op, x) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void)0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_G3N_CALL_1_func(x, oplist) \
|
||||
M_G3N_CALL_1_func_test(M_G3N_GEN_TYPE(oplist), M_PAIR_1 x, M_PAIR_2 x, oplist)
|
||||
#define M_G3N_CALL_1_func_test(gentype, op, x, oplist) \
|
||||
M_IF_METHOD(op, oplist())(M_G3N_CALL_1_func_expand, M_EAT)(gentype, op, x, oplist)
|
||||
#define M_G3N_CALL_1_func_expand(gentype, op, x, oplist) \
|
||||
gentype: M_C(M_CALL_, op)(oplist(), M_AS_TYPE(gentype, x)), \
|
||||
const gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(const gentype, x, gentype, x)),
|
||||
|
||||
// Call the OPERATOR call of the oplist registered to the variable 'svar'
|
||||
// which takes 2 arguments of the given type
|
||||
#define M_G3N_CALL_2(op, svar, type1, var1, type2, var2) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( ((void)0, (svar)), \
|
||||
M_MAP2(M_G3N_CALL_2_func, (op, svar, type1, var1, type2, var2) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_G3N_CALL_2_func(x, oplist) \
|
||||
M_APPLY(M_G3N_CALL_2_func_test, M_G3N_GEN_TYPE(oplist), M_ID x, oplist)
|
||||
#define M_G3N_CALL_2_func_test(gentype, op, svar, type1, var1, type2, var2, oplist) \
|
||||
M_IF_METHOD(op, oplist())(M_G3N_CALL_2_func_expand, M_EAT)(gentype, op, svar, M_G3N_TYPE(type1, oplist), var1, M_G3N_TYPE(type2, oplist), var2, oplist)
|
||||
#define M_G3N_CALL_2_func_expand(gentype, op, svar, type1, var1, type2, var2, oplist) \
|
||||
gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(gentype, svar, type1, var1), M_AS_LINKED_TYPE(gentype, svar, type2, var2) ), \
|
||||
const gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(const gentype, svar, type1, var1), M_AS_LINKED_TYPE(const gentype, svar, type2, var2) ),
|
||||
|
||||
// Call the OPERATOR call of the oplist registered to the variable 'svar'
|
||||
// which takes 3 arguments of the given type
|
||||
#define M_G3N_CALL_3(op, svar, type1, var1, type2, var2, type3, var3) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( ((void)0, (svar)), \
|
||||
M_MAP2(M_G3N_CALL_3_func, (op, svar, type1, var1, type2, var2, type3, var3) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_G3N_CALL_3_func(x, oplist) \
|
||||
M_APPLY(M_G3N_CALL_3_func_test, M_G3N_GEN_TYPE(oplist), M_ID x, oplist)
|
||||
#define M_G3N_CALL_3_func_test(gentype, op, svar, type1, var1, type2, var2, type3, var3, oplist) \
|
||||
M_IF_METHOD(op, oplist())(M_G3N_CALL_3_func_expand, M_EAT)(gentype, op, svar, M_G3N_TYPE(type1, oplist), var1, M_G3N_TYPE(type2, oplist), var2, M_G3N_TYPE(type3, oplist), var3, oplist)
|
||||
#define M_G3N_CALL_3_func_expand(gentype, op, svar, type1, var1, type2, var2, oplist) \
|
||||
gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(gentype, svar, type1, var1), M_AS_LINKED_TYPE(gentype, svar, type2, var2) ), \
|
||||
const gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(const gentype, svar, type1, var1), M_AS_LINKED_TYPE(const gentype, svar, type2, var2) ),
|
||||
|
||||
// Call the OPERATOR call of the oplist registered to the variable 'svar'
|
||||
// which takes 4 arguments of the given type
|
||||
#define M_G3N_CALL_4(op, svar, type1, var1, type2, var2, type3, var3, type4, var4) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( ((void)0, (svar)), \
|
||||
M_MAP2(M_G3N_CALL_4_func, (op, svar, type1, var1, type2, var2, type3, var3, type4, var4) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_G3N_CALL_4_func(x, oplist) \
|
||||
M_APPLY(M_G3N_CALL_4_func_test, M_G3N_GEN_TYPE(oplist), M_ID x, oplist)
|
||||
#define M_G3N_CALL_4_func_test(gentype, op, svar, type1, var1, type2, var2, type3, var3, type4, var4, oplist) \
|
||||
M_IF_METHOD(op, oplist())(M_G3N_CALL_4_func_expand, M_EAT)(gentype, op, svar, M_G3N_TYPE(type1, oplist), var1, M_G3N_TYPE(type2, oplist), var2, M_G3N_TYPE(type3, oplist), var3, M_G3N_TYPE(type4, oplist), var4, oplist)
|
||||
#define M_G3N_CALL_4_func_expand(gentype, op, svar, type1, var1, type2, var2, oplist) \
|
||||
gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(gentype, svar, type1, var1), M_AS_LINKED_TYPE(gentype, svar, type2, var2) ), \
|
||||
const gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(const gentype, svar, type1, var1), M_AS_LINKED_TYPE(const gentype, svar, type2, var2) ),
|
||||
|
||||
// Call the OPERATOR call of the oplist registered to the variable 'x'
|
||||
// which takes one argument, it_type
|
||||
#define M_G3N_CALL_1i(op, x) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( (x), \
|
||||
M_MAP2(M_G3N_CALL_1i_func, (op, x) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void)0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_G3N_CALL_1i_func(x, oplist) \
|
||||
M_G3N_CALL_1_func_test(M_G3N_GEN_IT_TYPE(oplist), M_PAIR_1 x, M_PAIR_2 x, oplist)
|
||||
|
||||
// Call the OPERATOR call of the oplist registered to the variable 'svar'
|
||||
// which takes 2 arguments of the given it_type
|
||||
#define M_G3N_CALL_2i(op, svar, type1, var1, type2, var2) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( ((void)0, (svar)), \
|
||||
M_MAP2(M_G3N_CALL_2i_func, (op, svar, type1, var1, type2, var2) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_G3N_CALL_2i_func(x, oplist) \
|
||||
M_APPLY(M_G3N_CALL_2_func_test, M_G3N_GEN_IT_TYPE(oplist), M_ID x, oplist)
|
||||
|
||||
// Create a variable of type OPERATOR call of the oplist registered to the variable 'x'
|
||||
#define M_G3N_TYPE_1(op, x) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( (x), \
|
||||
M_MAP2(M_G3N_TYPE_1_func, (op, x) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void)0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_G3N_TYPE_1_func(x, oplist) \
|
||||
M_G3N_TYPE_1_func_test(M_G3N_GEN_TYPE(oplist), M_PAIR_1 x, M_PAIR_2 x, oplist)
|
||||
#define M_G3N_TYPE_1_func_test(gentype, op, x, oplist) \
|
||||
M_IF_METHOD(op, oplist())(M_G3N_TYPE_1_func_expand, M_EAT)(gentype, op, x, oplist)
|
||||
#define M_G3N_TYPE_1_func_expand(gentype, op, x, oplist) \
|
||||
gentype: (M_G3N_TYPE(op, oplist)){0}, \
|
||||
const gentype: (M_G3N_TYPE(op, oplist)){0},
|
||||
|
||||
|
||||
// for each item in the container
|
||||
// Same as M_EACH except it uses the generic macros
|
||||
#define M_G3N_EACHI(item, container, l_it, l_pass) \
|
||||
(bool l_pass = true; l_pass; l_pass = false) \
|
||||
for(sub_type(container) *item; l_pass ; l_pass = false) \
|
||||
for(it_type(container) l_it; l_pass ; l_pass = false) \
|
||||
for(it_first(l_it, container) ; \
|
||||
!it_end_p(l_it) \
|
||||
&& (item = it_ref(l_it), true) ; \
|
||||
it_next(l_it))
|
||||
|
||||
|
||||
// TODO: init_with ? How to handle the different type of parameters ? Using EMPLACE_TYPE ?
|
||||
// TODO: support of PUSH_EMPLACE ?
|
||||
// TODO: support of "let" directly to avoid using the post-processing registration of M_LET?
|
||||
|
||||
// Overwrite M_FPRINT & M_PRINT to support global oplists registration
|
||||
#define M_FPRINT_ARG_G3N(f, x) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic(((void)0,(x)), \
|
||||
char: fprintf(f, "%c", M_AS_TYPE(char,x)), \
|
||||
bool: fprintf(f, "%d", M_AS_TYPE(bool,x)), \
|
||||
signed char: fprintf(f, "%hhd", M_AS_TYPE(signed char,x)), \
|
||||
unsigned char: fprintf(f, "%hhu", M_AS_TYPE(unsigned char,x)), \
|
||||
signed short: fprintf(f, "%hd", M_AS_TYPE(signed short,x)), \
|
||||
unsigned short: fprintf(f, "%hu", M_AS_TYPE(unsigned short,x)), \
|
||||
signed int: fprintf(f, "%d", M_AS_TYPE(signed int,x)), \
|
||||
unsigned int: fprintf(f, "%u", M_AS_TYPE(unsigned int,x)), \
|
||||
long int: fprintf(f, "%ld", M_AS_TYPE(long int,x)), \
|
||||
unsigned long int: fprintf(f, "%lu", M_AS_TYPE(unsigned long int,x)), \
|
||||
long long int: fprintf(f, "%lld", M_AS_TYPE(long long int,x)), \
|
||||
unsigned long long int: fprintf(f, "%llu", M_AS_TYPE(unsigned long long int,x)), \
|
||||
float: fprintf(f, "%f", M_AS_TYPE(float,x)), \
|
||||
double: fprintf(f, "%f", M_AS_TYPE(double,x)), \
|
||||
long double: fprintf(f, "%Lf", M_AS_TYPE(long double,x)), \
|
||||
const char *: fprintf(f, "%s", M_AS_TYPE(const char*,x)), \
|
||||
char *: fprintf(f, "%s", M_AS_TYPE(char*,x)), \
|
||||
const void *: fprintf(f, "%p", M_AS_TYPE(const void *,x)), \
|
||||
void *: fprintf(f, "%p", M_AS_TYPE(void *,x)), \
|
||||
M_MAP2(M_G3N_CALL_2_func, (OUT_STR, x, m_g3n_file, f, TYPE, x) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
|
||||
#define M_G3N_FPRINT_ARG(f, x) \
|
||||
M_IF(M_PARENTHESIS_P(x)) \
|
||||
( M_FPRINT_ARG_OUT_STR(f, M_PAIR_2 x, M_PAIR_1 x), \
|
||||
M_FPRINT_ARG_G3N(f, x) )
|
||||
|
||||
/* Override M_PRINT */
|
||||
#undef M_PRINT
|
||||
#define M_PRINT(...) do { M_REDUCE2(M_G3N_FPRINT_ARG, M_SEPARATE_PER_SEMICOLON, stdout, __VA_ARGS__); } while (0)
|
||||
|
||||
#undef M_FPRINT
|
||||
#define M_FPRINT(f,...) do { M_REDUCE2(M_G3N_FPRINT_ARG, M_SEPARATE_PER_SEMICOLON, f, __VA_ARGS__); } while (0)
|
||||
|
||||
// Register CORE component of M*LIB
|
||||
#define M_GENERIC_ORG_MLIB_COMP_1() (CORE)
|
||||
|
||||
|
||||
#endif
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Integer Generator (GENINT) module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -97,7 +97,7 @@ typedef struct m_genint_s {
|
||||
|((M_GEN1NT_ABA_CPT_T)((master) + 1)))
|
||||
|
||||
/* Initialize an integer generator (CONSTRUCTOR).
|
||||
* Initialy, the container is full of all the integers up to 'n-1'
|
||||
* Initially, the container is full of all the integers up to 'n-1'
|
||||
* The typical sequence is to initialize the container, and pop
|
||||
* the integer from it. Each pop integer is **unique** for all threads,
|
||||
* meaning it can be used to index global unique resources shared
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Intrusive List module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -63,7 +63,7 @@
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the oplist of a doubly-linked instrusive list of type.
|
||||
/* Define the oplist of a doubly-linked intrusive list of type.
|
||||
USAGE:
|
||||
ILIST_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define M_ILIST_OPLIST(...) \
|
||||
@@ -100,7 +100,7 @@ typedef struct m_il1st_head_s {
|
||||
INIT_MOVE(M_F(name, _init_move)), \
|
||||
MOVE(M_F(name, _move)), \
|
||||
NAME(name), \
|
||||
TYPE(M_F(name,_ct)), \
|
||||
TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
RESET(M_F(name,_reset)), \
|
||||
SUBTYPE(M_F(name,_subtype_ct)), \
|
||||
EMPTY_P(M_F(name,_empty_p)), \
|
||||
@@ -234,7 +234,7 @@ typedef struct m_il1st_head_s {
|
||||
{ \
|
||||
/* Nothing to do more than clean the list itself */ \
|
||||
M_F(name, _reset)(list); \
|
||||
/* For safety purpose (create invalid represenation of object) */ \
|
||||
/* For safety purpose (create invalid representation of object) */ \
|
||||
list->name.next = NULL; \
|
||||
list->name.prev = NULL; \
|
||||
} \
|
||||
|
||||
+7
-7
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - INTRUSIVE SHARED PTR Module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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,13 +46,13 @@ M_BEGIN_PROTECTED_CODE
|
||||
atomic_int M_F(name, _cpt)
|
||||
|
||||
|
||||
/* Value of the interface field for static intialization (Uses C99 designated element). */
|
||||
/* Value of the interface field for static initialization (Uses C99 designated element). */
|
||||
#define M_ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
|
||||
.M_F(name, _cpt) = ATOMIC_VAR_INIT(0)
|
||||
.M_F(name, _cpt) = M_ATOMIC_VAR_INIT(0)
|
||||
|
||||
/* Value of the interface field for static intialization (Uses C89 designated element). */
|
||||
/* Value of the interface field for static initialization (Uses C89 designated element). */
|
||||
#define M_ISHARED_PTR_STATIC_INIT(name, type) \
|
||||
ATOMIC_VAR_INIT(0)
|
||||
M_ATOMIC_VAR_INIT(0)
|
||||
|
||||
|
||||
/* Define the intrusive shared pointer type and its M_INLINE functions.
|
||||
@@ -95,7 +95,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
CLEAR(M_F(name, _clear)), \
|
||||
RESET(M_F(name, _reset) M_IPTR), \
|
||||
NAME(name), \
|
||||
TYPE(M_F(name, _ct)), \
|
||||
TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
OPLIST(oplist), \
|
||||
SUBTYPE(M_F(name, _subtype_ct)) \
|
||||
)
|
||||
@@ -103,7 +103,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
// Deferred evaluatioin
|
||||
// Deferred evaluation
|
||||
#define M_ISHAR3D_PTR_DEF_P1(arg) M_ID( M_ISHAR3D_PTR_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - LIST module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -109,7 +109,7 @@
|
||||
INIT_MOVE(M_F(name, _init_move)), \
|
||||
SWAP(M_F(name, _swap)), \
|
||||
NAME(name), \
|
||||
TYPE(M_F(name,_ct)), \
|
||||
TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)**), \
|
||||
SUBTYPE(M_F(name,_subtype_ct)), \
|
||||
EMPTY_P(M_F(name,_empty_p)), \
|
||||
IT_TYPE(M_F(name, _it_ct)), \
|
||||
@@ -188,6 +188,23 @@
|
||||
- node_t: alias for M_F(name, _node_t) [ node ]
|
||||
*/
|
||||
#define M_L1ST_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_DEF_TYPE(name, type, oplist, list_t, it_t) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
M_EMPLACE_QUEUE_DEF(name, list_t, M_F(name, _emplace_back), oplist, M_L1ST_EMPLACE_DEF) \
|
||||
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
/* Define the internal contract of a list
|
||||
(there is nothing worthy to be checked) */
|
||||
#define M_L1ST_CONTRACT(v) do { \
|
||||
M_ASSERT (v != NULL); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Define the type of a list */
|
||||
#define M_L1ST_DEF_TYPE(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
/* Define the node of a list, and the list as a pointer to a node */ \
|
||||
typedef struct M_F(name, _s) { \
|
||||
@@ -207,22 +224,9 @@
|
||||
typedef list_t M_F(name, _ct); \
|
||||
typedef it_t M_F(name, _it_ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
|
||||
/* Define the internal contract of a list
|
||||
(there is nothing worthy to be checked) */
|
||||
#define M_L1ST_CONTRACT(v) do { \
|
||||
M_ASSERT (v != NULL); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Internal list function definition
|
||||
/* Internal list function definition
|
||||
- name: prefix to be used
|
||||
- type: type of the elements of the list
|
||||
- oplist: oplist of the type of the elements of the container
|
||||
@@ -290,7 +294,10 @@
|
||||
type *data = M_F(name, _push_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL)) \
|
||||
return; \
|
||||
M_CALL_INIT_SET(oplist, *data, x); \
|
||||
M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \
|
||||
M_ON_EXCEPTION( *v = next->next, M_C3(m_l1st_,name,_del)(next)) { \
|
||||
M_CALL_INIT_SET(oplist, *data, x); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
@@ -300,7 +307,10 @@
|
||||
type *data = M_F(name, _push_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL)) \
|
||||
return NULL; \
|
||||
M_CALL_INIT(oplist, *data); \
|
||||
M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \
|
||||
M_ON_EXCEPTION( *v = next->next, M_C3(m_l1st_,name,_del)(next)) { \
|
||||
M_CALL_INIT(oplist, *data); \
|
||||
} \
|
||||
return data; \
|
||||
} \
|
||||
, /* No INIT */) \
|
||||
@@ -492,7 +502,8 @@
|
||||
M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
M_CALL_INIT_SET(oplist, next->data, x); \
|
||||
M_ON_EXCEPTION( M_C3(m_l1st_,name,_del)(next)) \
|
||||
M_CALL_INIT_SET(oplist, next->data, x); \
|
||||
struct M_F(name, _s) *current = insertion_point->current; \
|
||||
if (M_UNLIKELY (current == NULL)) { \
|
||||
next->next = *list; \
|
||||
@@ -530,21 +541,26 @@
|
||||
M_F(name, _init_set)(list_t list, const list_t org) \
|
||||
{ \
|
||||
M_L1ST_CONTRACT(org); \
|
||||
struct M_F(name, _s) *next, *it_org; \
|
||||
struct M_F(name, _s) *m_volatile next = NULL; \
|
||||
struct M_F(name, _s) *it_org; \
|
||||
struct M_F(name, _s) **update_list; \
|
||||
update_list = list; \
|
||||
it_org = *org; \
|
||||
/* On exceptions, free node and clear list*/ \
|
||||
M_IF_EXCEPTION(*update_list = NULL); \
|
||||
M_ON_EXCEPTION(M_C3(m_l1st_,name,_del)(next), M_F(name, _clear)(list) ) \
|
||||
while (it_org != NULL) { \
|
||||
next = M_C3(m_l1st_,name,_new)(); \
|
||||
*update_list = next; \
|
||||
if (M_UNLIKELY_NOMEM (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \
|
||||
/* FIXME: Partialy initialized list. What to do? */ \
|
||||
*update_list = NULL; \
|
||||
return; \
|
||||
} \
|
||||
update_list = &next->next; \
|
||||
M_CALL_INIT_SET(oplist, next->data, it_org->data); \
|
||||
*update_list = next; \
|
||||
update_list = &next->next; \
|
||||
it_org = it_org->next; \
|
||||
M_IF_EXCEPTION(next = NULL, *update_list = NULL); \
|
||||
} \
|
||||
*update_list = NULL; \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
@@ -554,8 +570,10 @@
|
||||
M_F(name, _set)(list_t list, const list_t org) \
|
||||
{ \
|
||||
if (M_UNLIKELY (list == org)) return; \
|
||||
M_F(name, _clear)(list); \
|
||||
M_F(name, _init_set)(list, org); \
|
||||
M_ON_EXCEPTION(M_F(name, _init)(list) ) { \
|
||||
M_F(name, _clear)(list); \
|
||||
M_F(name, _init_set)(list, org); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
@@ -666,8 +684,6 @@
|
||||
} \
|
||||
*list = previous; \
|
||||
} \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, list_t, M_F(name, _emplace_back), oplist, M_L1ST_EMPLACE_DEF)
|
||||
|
||||
|
||||
/* Internal list function definition using only iterator functions
|
||||
@@ -734,18 +750,16 @@
|
||||
if (M_UNLIKELY (c == ']')) { success = true; goto exit;} \
|
||||
if (M_UNLIKELY (c == 0)) goto exit; \
|
||||
str--; \
|
||||
type item; \
|
||||
M_CALL_INIT(oplist, item); \
|
||||
do { \
|
||||
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
if (b == false || c == 0) { goto exit_clear; } \
|
||||
M_F(name, _push_back)(list, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_QLET(1, item, type, oplist) { \
|
||||
do { \
|
||||
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
|
||||
c = m_core_str_nospace(&str); \
|
||||
if (b == false || c == 0) { c = 0; break; } \
|
||||
M_F(name, _push_back)(list, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
success = (c == ']'); \
|
||||
} \
|
||||
M_F(name, _reverse)(list); \
|
||||
success = (c == ']'); \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
exit: \
|
||||
if (endp) *endp = str; \
|
||||
return success; \
|
||||
@@ -764,15 +778,14 @@
|
||||
if (M_UNLIKELY (c == ']')) return true; \
|
||||
if (M_UNLIKELY (c == EOF)) return false; \
|
||||
ungetc(c, file); \
|
||||
type item; \
|
||||
M_CALL_INIT(oplist, item); \
|
||||
do { \
|
||||
bool b = M_CALL_IN_STR(oplist, item, file); \
|
||||
do { c = fgetc(file); } while (isspace(c)); \
|
||||
if (b == false || c == EOF) { break; } \
|
||||
M_F(name, _push_back)(list, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
M_QLET(1, item, type, oplist) { \
|
||||
do { \
|
||||
bool b = M_CALL_IN_STR(oplist, item, file); \
|
||||
c = m_core_fgetc_nospace(file); \
|
||||
if (b == false || c == EOF) { c = 0; break; } \
|
||||
M_F(name, _push_back)(list, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
M_F(name, _reverse)(list); \
|
||||
return c == ']'; \
|
||||
} \
|
||||
@@ -819,15 +832,14 @@
|
||||
M_F(name,_reset)(list); \
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
|
||||
type item; \
|
||||
M_CALL_INIT(oplist, item); \
|
||||
do { \
|
||||
ret = M_CALL_IN_SERIAL(oplist, item, f); \
|
||||
if (ret != M_SERIAL_OK_DONE) { break; } \
|
||||
M_F(name, _push_back)(list, item); \
|
||||
ret = f->m_interface->read_array_next(local, f); \
|
||||
} while (ret == M_SERIAL_OK_CONTINUE); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
M_QLET(1, item, type, oplist) { \
|
||||
do { \
|
||||
ret = M_CALL_IN_SERIAL(oplist, item, f); \
|
||||
if (ret != M_SERIAL_OK_DONE) { break; } \
|
||||
M_F(name, _push_back)(list, item); \
|
||||
ret = f->m_interface->read_array_next(local, f); \
|
||||
} while (ret == M_SERIAL_OK_CONTINUE); \
|
||||
} \
|
||||
M_F(name, _reverse)(list); \
|
||||
return ret; \
|
||||
} \
|
||||
@@ -885,7 +897,10 @@
|
||||
M_F(name, _subtype_ct) *data = M_F(name, _push_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \
|
||||
M_ON_EXCEPTION( *v = next->next, M_C3(m_l1st_,name,_del)(next)) { \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
@@ -898,7 +913,10 @@
|
||||
M_F(name, _subtype_ct) *data = M_F(name, _push_back_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
M_IF_EXCEPTION(struct M_F(name, _s) *next = v->back); \
|
||||
M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_C3(m_l1st_,name,_del)(next)) { \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
@@ -908,10 +926,15 @@
|
||||
function_name(name_t v \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_IF_EXCEPTION(struct M_F(name, _s) *front = v->front, *back = v->back); \
|
||||
M_F(name, _subtype_ct) *data = M_F(name, _push_front_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->front); \
|
||||
M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \
|
||||
M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_C3(m_l1st_,name,_del)(tofree)) { \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
@@ -927,6 +950,15 @@
|
||||
#define M_L1ST_DUAL_PUSH_DEF_FAILURE(name, type, oplist, list_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(LIST_DUAL_PUSH_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
|
||||
/* Define the internal contract of an dual-push list */
|
||||
#define M_L1ST_DUAL_PUSH_CONTRACT(l) do { \
|
||||
M_ASSERT (l != NULL); \
|
||||
M_ASSERT ( (l->back == NULL && l->front == NULL) \
|
||||
|| (l->back != NULL && l->front != NULL)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Internal dual-push list definition
|
||||
- name: prefix to be used
|
||||
- type: type of the elements of the array
|
||||
@@ -935,7 +967,17 @@
|
||||
- it_t: alias for M_F(name, _it_t) [ iterator of the container ]
|
||||
*/
|
||||
#define M_L1ST_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
M_L1ST_DUAL_PUSH_DEF_TYPE(name, type, oplist, list_t, it_t) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
M_EMPLACE_QUEUE_DEF(name, list_t, M_F(name, _emplace_back), oplist, M_L1ST_EMPLACE_BACK_DEF) \
|
||||
M_EMPLACE_QUEUE_DEF(name, list_t, M_F(name, _emplace_front), oplist, M_L1ST_EMPLACE_FRONT_DEF) \
|
||||
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
/* Define the type of a dual-push list */
|
||||
#define M_L1ST_DUAL_PUSH_DEF_TYPE(name, type, oplist, list_t, it_t) \
|
||||
/* Node of a list (it is liked the singly linked list) */ \
|
||||
struct M_F(name, _s) { \
|
||||
struct M_F(name, _s) *next; \
|
||||
@@ -965,19 +1007,6 @@
|
||||
typedef it_t M_F(name, _it_ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
/* Define the internal contract of an dual-push list */
|
||||
#define M_L1ST_DUAL_PUSH_CONTRACT(l) do { \
|
||||
M_ASSERT (l != NULL); \
|
||||
M_ASSERT ( (l->back == NULL && l->front == NULL) \
|
||||
|| (l->back != NULL && l->front != NULL)); \
|
||||
} while (0)
|
||||
|
||||
/* Internal dual-push list definition
|
||||
- name: prefix to be used
|
||||
@@ -1061,7 +1090,10 @@
|
||||
type *data = M_F(name, _push_back_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL)) \
|
||||
return; \
|
||||
M_CALL_INIT_SET(oplist, *data, x); \
|
||||
M_IF_EXCEPTION(struct M_F(name, _s) *next = v->back); \
|
||||
M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_C3(m_l1st_,name,_del)(next)) { \
|
||||
M_CALL_INIT_SET(oplist, *data, x); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
@@ -1071,7 +1103,10 @@
|
||||
type *data = M_F(name, _push_back_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL)) \
|
||||
return NULL; \
|
||||
M_CALL_INIT(oplist, *data); \
|
||||
M_IF_EXCEPTION(struct M_F(name, _s) *next = v->back); \
|
||||
M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_C3(m_l1st_,name,_del)(next)) { \
|
||||
M_CALL_INIT(oplist, *data); \
|
||||
} \
|
||||
return data; \
|
||||
} \
|
||||
, /* No INIT */ ) \
|
||||
@@ -1164,10 +1199,15 @@
|
||||
M_INLINE void \
|
||||
M_F(name, _push_front)(list_t v, type const x) \
|
||||
{ \
|
||||
M_IF_EXCEPTION(struct M_F(name, _s) *front = v->front, *back = v->back); \
|
||||
type *data = M_F(name, _push_front_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL)) \
|
||||
return; \
|
||||
M_CALL_INIT_SET(oplist, *data, x); \
|
||||
M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->front); \
|
||||
M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \
|
||||
M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_C3(m_l1st_,name,_del)(tofree)) { \
|
||||
M_CALL_INIT_SET(oplist, *data, x); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
@@ -1184,10 +1224,15 @@
|
||||
M_INLINE type * \
|
||||
M_F(name, _push_front_new)(list_t v) \
|
||||
{ \
|
||||
type *data = M_F(name, _push_back_raw)(v); \
|
||||
M_IF_EXCEPTION(struct M_F(name, _s) *front = v->front, *back = v->back); \
|
||||
type *data = M_F(name, _push_front_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL)) \
|
||||
return NULL; \
|
||||
M_CALL_INIT(oplist, *data); \
|
||||
M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->front); \
|
||||
M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \
|
||||
M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_C3(m_l1st_,name,_del)(tofree)) { \
|
||||
M_CALL_INIT(oplist, *data); \
|
||||
} \
|
||||
return data; \
|
||||
} \
|
||||
, /* No INIT */) \
|
||||
@@ -1297,12 +1342,13 @@
|
||||
{ \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
M_ASSERT (insertion_point != NULL); \
|
||||
struct M_F(name, _s) *next = M_C3(m_l1st_,name,_new)(); \
|
||||
struct M_F(name, _s) *m_volatile next = M_C3(m_l1st_,name,_new)(); \
|
||||
if (M_UNLIKELY_NOMEM (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
M_CALL_INIT_SET(oplist, next->data, x); \
|
||||
M_ON_EXCEPTION( M_C3(m_l1st_,name,_del)(next)) \
|
||||
M_CALL_INIT_SET(oplist, next->data, x); \
|
||||
if (M_UNLIKELY (insertion_point->current == NULL)) { \
|
||||
next->next = list->back; \
|
||||
list->back = next; \
|
||||
@@ -1348,34 +1394,41 @@
|
||||
{ \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(org); \
|
||||
struct M_F(name, _s) *next = NULL; \
|
||||
struct M_F(name, _s) *m_volatile next = NULL; \
|
||||
struct M_F(name, _s) *it_org; \
|
||||
struct M_F(name, _s) **update_list; \
|
||||
if (M_UNLIKELY (list == org)) return; \
|
||||
M_F(name, _reset)(list); \
|
||||
update_list = &list->back; \
|
||||
it_org = org->back; \
|
||||
M_ASSERT(*update_list == NULL); \
|
||||
M_ON_EXCEPTION(M_C3(m_l1st_,name,_del)(next) ) \
|
||||
while (it_org != NULL) { \
|
||||
next = M_C3(m_l1st_,name,_new)(); \
|
||||
*update_list = next; \
|
||||
if (M_UNLIKELY_NOMEM (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
update_list = &next->next; \
|
||||
M_CALL_INIT_SET(oplist, next->data, it_org->data); \
|
||||
/* Link new node to the previous one*/ \
|
||||
*update_list = next; \
|
||||
update_list = &next->next; \
|
||||
it_org = it_org->next; \
|
||||
/* so that even on exception, the object is still coherent */ \
|
||||
list->front = next; \
|
||||
*update_list = NULL; \
|
||||
M_IF_EXCEPTION(next = NULL); \
|
||||
} \
|
||||
list->front = next; \
|
||||
*update_list = NULL; \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
M_F(name, _init_set)(list_t list, const list_t org) \
|
||||
{ \
|
||||
M_ASSERT (list != org); \
|
||||
M_F(name, _init)(list); \
|
||||
M_F(name, _set)(list, org); \
|
||||
M_ON_EXCEPTION( M_F(name, _clear)(list)) { \
|
||||
M_F(name, _init)(list); \
|
||||
M_F(name, _set)(list, org); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
@@ -1510,9 +1563,7 @@
|
||||
list->back = previous; \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
} \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, list_t, M_F(name, _emplace_back), oplist, M_L1ST_EMPLACE_BACK_DEF) \
|
||||
M_EMPLACE_QUEUE_DEF(name, list_t, M_F(name, _emplace_front), oplist, M_L1ST_EMPLACE_FRONT_DEF)
|
||||
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define LIST_DEF M_LIST_DEF
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - MEMPOOL module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -55,8 +55,8 @@
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* User shall be able to cutomize the size of the region segment and/or
|
||||
the minimun number of elements.
|
||||
/* User shall be able to customize the size of the region segment and/or
|
||||
the minimum number of elements.
|
||||
The default is the number of elements that fits in 16KB, or 256
|
||||
is the size of the type is too big.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin Mutex & Thread wrapper (compatibility layer)
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - dynamic priority queue module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -30,13 +30,13 @@
|
||||
|
||||
/* Priority queue based on binary heap implementation */
|
||||
|
||||
/* Define a prioqueue of a given type and its associated functions.
|
||||
/* Define a priority queue (prioqueue) of a given type and its associated functions.
|
||||
USAGE: PRIOQUEUE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define M_PRIOQUEUE_DEF(name, ...) \
|
||||
M_PRIOQUEUE_DEF_AS(name, M_F(name,_t), M_F(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a prioqueue of a given type and its associated functions.
|
||||
/* Define a priority queue (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 M_PRIOQUEUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
@@ -82,7 +82,7 @@
|
||||
,MOVE(M_F(name, _move)) \
|
||||
,SWAP(M_F(name, _swap)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_F(name,_ct)) \
|
||||
,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \
|
||||
,SUBTYPE(M_F(name, _subtype_ct)) \
|
||||
,RESET(M_F(name,_reset)) \
|
||||
,PUSH(M_F(name,_push)) \
|
||||
|
||||
+33
-39
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - RED BLACK TREE module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -81,7 +81,7 @@
|
||||
MOVE(M_F(name, _move)), \
|
||||
SWAP(M_F(name, _swap)), \
|
||||
NAME(name), \
|
||||
TYPE(M_F(name,_ct)), \
|
||||
TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
SUBTYPE(M_F(name, _subtype_ct)), \
|
||||
EMPTY_P(M_F(name,_empty_p)), \
|
||||
GET_SIZE(M_F(name, _size)), \
|
||||
@@ -905,7 +905,7 @@ typedef enum {
|
||||
M_ASSERT (M_C3(m_rbtr33_,name,_black_p)(s)); \
|
||||
} \
|
||||
M_ASSERT (p != NULL && u == p->child[nbChild]); \
|
||||
/* if both childreen of s are black */ \
|
||||
/* if both children of s are black */ \
|
||||
/* perform recoloring and recur on parent if black */ \
|
||||
if (s != NULL \
|
||||
&& M_C3(m_rbtr33_,name,_black_p)(s->child[0]) \
|
||||
@@ -983,7 +983,7 @@ typedef enum {
|
||||
it_t it1; \
|
||||
it_t it2; \
|
||||
/* NOTE: We can't compare two tree directly as they can be \
|
||||
structuraly different but functionnaly equal (you get this by \
|
||||
structurally different but functionally equal (you get this by \
|
||||
constructing the tree in a different way). We have to \
|
||||
compare the ordered value within the tree. */ \
|
||||
M_F(name, _it)(it1, t1); \
|
||||
@@ -1072,27 +1072,22 @@ typedef enum {
|
||||
M_RBTR33_CONTRACT(rbtree); \
|
||||
M_ASSERT (str != NULL); \
|
||||
M_F(name,_reset)(rbtree); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
c = *str++; \
|
||||
if (M_UNLIKELY (c == ']')) { success = true; goto exit; } \
|
||||
if (M_UNLIKELY (c == 0)) goto exit; \
|
||||
int c = m_core_str_nospace(&str); \
|
||||
if (M_UNLIKELY (c != '[')) { c = 0; goto exit; } \
|
||||
c = m_core_str_nospace(&str); \
|
||||
if (M_UNLIKELY (c == ']' || c == 0)) goto exit; \
|
||||
str--; \
|
||||
type item; \
|
||||
M_CALL_INIT(oplist, item); \
|
||||
do { \
|
||||
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
if (b == false || c == 0) goto exit_clear; \
|
||||
M_F(name, _push)(rbtree, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
success = (c == ']'); \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
M_QLET(1, item, type, oplist) { \
|
||||
do { \
|
||||
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
|
||||
c = m_core_str_nospace(&str); \
|
||||
if (b == false || c == 0) { c= 0 ; break; }; \
|
||||
M_F(name, _push)(rbtree, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
exit: \
|
||||
if (endp) *endp = str; \
|
||||
return success; \
|
||||
return c == ']'; \
|
||||
} \
|
||||
, /* no parse_str */ ) \
|
||||
\
|
||||
@@ -1109,15 +1104,14 @@ typedef enum {
|
||||
if (M_UNLIKELY (c == ']')) return true; \
|
||||
if (M_UNLIKELY (c == EOF)) return false; \
|
||||
ungetc(c, file); \
|
||||
type item; \
|
||||
M_CALL_INIT(oplist, item); \
|
||||
do { \
|
||||
bool b = M_CALL_IN_STR(oplist, item, file); \
|
||||
do { c = fgetc(file); } while (isspace(c)); \
|
||||
if (b == false || c == EOF) break; \
|
||||
M_F(name, _push)(rbtree, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
M_QLET(1, item, type, oplist) { \
|
||||
do { \
|
||||
bool b = M_CALL_IN_STR(oplist, item, file); \
|
||||
c = m_core_fgetc_nospace(file); \
|
||||
if (b == false || c == EOF) { c = 0; break; } \
|
||||
M_F(name, _push)(rbtree, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
return c == ']'; \
|
||||
} \
|
||||
, /* no in_str */ ) \
|
||||
@@ -1157,17 +1151,17 @@ typedef enum {
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
size_t estimated_size = 0; \
|
||||
type key; \
|
||||
M_F(name,_reset)(t1); \
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
|
||||
M_CALL_INIT(oplist, key); \
|
||||
do { \
|
||||
ret = M_CALL_IN_SERIAL(oplist, key, f); \
|
||||
if (ret != M_SERIAL_OK_DONE) { break; } \
|
||||
M_F(name, _push)(t1, key); \
|
||||
} while ((ret = f->m_interface->read_array_next(local, f)) == M_SERIAL_OK_CONTINUE); \
|
||||
M_CALL_CLEAR(oplist, key); \
|
||||
M_QLET(1, key, type, oplist) { \
|
||||
do { \
|
||||
ret = M_CALL_IN_SERIAL(oplist, key, f); \
|
||||
if (ret != M_SERIAL_OK_DONE) { break; } \
|
||||
M_F(name, _push)(t1, key); \
|
||||
ret = f->m_interface->read_array_next(local, f); \
|
||||
} while (ret == M_SERIAL_OK_CONTINUE); \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
, /* no in_serial */ ) \
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Serial BIN
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
|
||||
+5
-18
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Serial JSON
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -287,25 +287,13 @@ typedef m_serial_write_t m_serial_json_write_t;
|
||||
/*************************** FILE / READ / JSON ********************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/* Helper function to skip a space */
|
||||
M_INLINE int
|
||||
m_ser1al_json_read_skip (FILE *f)
|
||||
{
|
||||
int c;
|
||||
do {
|
||||
// c is an int, and is the value of the character read as unsigned char
|
||||
c = fgetc(f);
|
||||
} while (c != EOF && isspace(c));
|
||||
return c;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_json_read_boolean(m_serial_read_t serial, bool *b){
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
int c = m_ser1al_json_read_skip(f);
|
||||
int c = m_core_fgetc_nospace(f);
|
||||
if (c == 't') {
|
||||
*b = true;
|
||||
c = fgetc(f);
|
||||
@@ -473,7 +461,7 @@ m_ser1al_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, cons
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
int c = m_ser1al_json_read_skip(f);
|
||||
int c = m_core_fgetc_nospace(f);
|
||||
if (c == EOF) return m_core_serial_fail();
|
||||
if (c == '}') return M_SERIAL_OK_DONE;
|
||||
if (c == ',') {
|
||||
@@ -860,9 +848,8 @@ m_ser1al_str_json_getc(const char **p)
|
||||
M_INLINE void
|
||||
m_ser1al_str_json_skip (const char **p)
|
||||
{
|
||||
while (isspace (**p)) {
|
||||
(*p)++;
|
||||
}
|
||||
(void) m_core_str_nospace(p);
|
||||
(*p)--;
|
||||
}
|
||||
|
||||
/* Helper function to read a string with characters not present in reject */
|
||||
|
||||
+40
-12
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SHARED Module
|
||||
* M*LIB - SHARED Pointer Module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -118,7 +118,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
MOVE(M_F(name, _move)), \
|
||||
SWAP(M_F(name, _swap)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_F(name, _ct)) \
|
||||
,TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*) \
|
||||
)
|
||||
|
||||
// OPLIST to handle a counter of atomic type
|
||||
@@ -166,6 +166,7 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
M_SHAR3D_PTR_DEF_TYPE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
M_SHAR3D_PTR_DEF_CORE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
M_EMPLACE_QUEUE_DEF(name, cpt_oplist, M_F(name, _init_with), oplist, M_SHAR3D_PTR_DEF_EMPLACE)
|
||||
|
||||
/* Define the types */
|
||||
#define M_SHAR3D_PTR_DEF_TYPE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
@@ -180,10 +181,11 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef shared_t M_F(name, _ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
\
|
||||
typedef struct M_F(name, combine_s) { \
|
||||
type data; \
|
||||
typedef struct M_F(name, _combine_s) { \
|
||||
struct M_F(name, _s) ptr; \
|
||||
type data; \
|
||||
} M_F(name, combine_ct)[1]; \
|
||||
|
||||
/* Define the core functions */
|
||||
@@ -222,18 +224,18 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
M_F(name, _init_new)(shared_t shared) \
|
||||
{ \
|
||||
/* NOTE: Alloc 1 struct with both structures. */ \
|
||||
struct M_F(name, combine_s) *p = \
|
||||
M_CALL_NEW(oplist, struct M_F(name, combine_s)); \
|
||||
struct M_F(name, _combine_s) *p = \
|
||||
M_CALL_NEW(oplist, struct M_F(name, _combine_s)); \
|
||||
if (M_UNLIKELY_NOMEM (p == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_F(name, combine_s))); \
|
||||
M_MEMORY_FULL(sizeof(struct M_F(name, _combine_s))); \
|
||||
return; \
|
||||
} \
|
||||
struct M_F(name, _s) *ptr = &p->ptr; \
|
||||
ptr->combineAlloc = true; \
|
||||
type *data = &p->data; \
|
||||
M_CALL_INIT( oplist, *data); \
|
||||
ptr->data = data; \
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
ptr->combineAlloc = true; \
|
||||
*shared = ptr; \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
@@ -272,9 +274,10 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
first element, aka data itself. Static analyzer tools don't \
|
||||
seem to detect this and report error. */ \
|
||||
M_CALL_CLEAR(oplist, *(*dest)->data); \
|
||||
M_CALL_DEL(oplist, (*dest)->data); \
|
||||
if (combineAlloc == false) \
|
||||
M_CALL_DEL(oplist, *dest); \
|
||||
if (combineAlloc == false) { \
|
||||
M_CALL_DEL(oplist, (*dest)->data); \
|
||||
} \
|
||||
M_CALL_DEL(oplist, *dest); \
|
||||
} \
|
||||
*dest = NULL; \
|
||||
} \
|
||||
@@ -361,6 +364,30 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
return data; \
|
||||
} \
|
||||
|
||||
/* Definition of the emplace_back function for arrays */
|
||||
#define M_SHAR3D_PTR_DEF_EMPLACE(name, cpt_oplist, function_name, oplist, init_func, exp_emplace_type) \
|
||||
M_INLINE void \
|
||||
function_name(M_F(name, _ct) shared \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
/* NOTE: Alloc 1 struct with both structures. */ \
|
||||
struct M_F(name, _combine_s) *p = \
|
||||
M_CALL_NEW(oplist, struct M_F(name, _combine_s)); \
|
||||
if (M_UNLIKELY_NOMEM (p == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_F(name, _combine_s))); \
|
||||
return; \
|
||||
} \
|
||||
struct M_F(name, _s) *ptr = &p->ptr; \
|
||||
ptr->combineAlloc = true; \
|
||||
M_F(name, _subtype_ct) *data = &p->data; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
ptr->data = data; \
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
*shared = ptr; \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
|
||||
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
@@ -407,6 +434,7 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
\
|
||||
/* Internal Types for oplist */ \
|
||||
typedef shared_t M_F(name, _ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
|
||||
/* Define the core functions */
|
||||
#define M_SHAR3D_RESOURCE_DEF_CORE(name, type, oplist, shared_t, it_t) \
|
||||
|
||||
+14
-14
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SNAPSHOT Module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -31,13 +31,13 @@
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define a Single Producer Single Consummer snapshot and its functions
|
||||
/* Define a Single Producer Single Consumer snapshot and its functions
|
||||
USAGE: SNAPSHOT_SPSC_DEF(name, type[, oplist]) */
|
||||
#define M_SNAPSHOT_SPSC_DEF(name, ...) \
|
||||
M_SNAPSHOT_SPSC_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Single Producer Single Consummer snapshot and its functions
|
||||
/* Define a Single Producer Single Consumer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_SPSC_DEF_AS(name, name_t, type[, oplist]) */
|
||||
#define M_SNAPSHOT_SPSC_DEF_AS(name, name_t, ...) \
|
||||
@@ -48,13 +48,13 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define a Single Producer Multiple Consummer snapshot and its functions
|
||||
/* Define a Single Producer Multiple Consumer snapshot and its functions
|
||||
USAGE: SNAPSHOT_SPMC_DEF(name, type[, oplist]) */
|
||||
#define M_SNAPSHOT_SPMC_DEF(name, ...) \
|
||||
M_SNAPSHOT_SPMC_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Single Producer Multiple Consummer snapshot and its functions
|
||||
/* Define a Single Producer Multiple Consumer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_SPMC_DEF_AS(name, type[, oplist]) */
|
||||
#define M_SNAPSHOT_SPMC_DEF_AS(name, name_t, ...) \
|
||||
@@ -65,13 +65,13 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
|
||||
/* Define a Multiple Producer Multiple Consumer snapshot and its functions
|
||||
USAGE: SNAPSHOT_MPMC_DEF(name, type[, oplist]) */
|
||||
#define M_SNAPSHOT_MPMC_DEF(name, ...) \
|
||||
M_SNAPSHOT_MPMC_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
|
||||
/* Define a Multiple Producer Multiple Consumer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_MPMC_DEF_AS(name, name_t, type[, oplist]) */
|
||||
#define M_SNAPSHOT_MPMC_DEF_AS(name, name_t, ...) \
|
||||
@@ -112,7 +112,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
,SET(M_F(name, _set)) \
|
||||
,CLEAR(M_F(name, _clear)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_F(name, _ct)) \
|
||||
,TYPE(M_F(name, _ct)) , GENTYPE(struct M_F(name,_s)*) \
|
||||
,SUBTYPE(M_F(name, _subtype_ct)) \
|
||||
,OPLIST(oplist) \
|
||||
,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(M_F(name, _init_move)),) \
|
||||
@@ -154,10 +154,10 @@ M_BEGIN_PROTECTED_CODE
|
||||
} while (0)
|
||||
|
||||
// A snapshot is basically an atomic triple buffer (Lock Free)
|
||||
// between a single producer thread and a single consummer thread.
|
||||
// between a single producer thread and a single Consumer thread.
|
||||
#define M_SNAPSH0T_SPSC_MAX_BUFFER 3
|
||||
|
||||
// Defered evaluation of the arguments.
|
||||
// Deferred evaluation of the arguments.
|
||||
#define M_SNAPSH0T_SPSC_DEF_P1(arg) M_ID( M_SNAPSH0T_SPSC_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
@@ -514,7 +514,7 @@ m_snapsh0t_mrsw_write_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
|
||||
// Provide this write bufer to the readers
|
||||
// Provide this write buffer to the readers
|
||||
unsigned int newNext, previous = atomic_load(&s->lastNext);
|
||||
do {
|
||||
newNext = M_SNAPSH0T_SPMC_INT_FLAG(idx, true);
|
||||
@@ -558,7 +558,7 @@ m_snapsh0t_mrsw_read_start(m_snapsh0t_mrsw_ct s)
|
||||
if (idx == M_SNAPSH0T_SPMC_INT_FLAG_W(previous)) {
|
||||
// This is still ok if the index has not changed
|
||||
// We can get previous to true again if the writer has recycled the index,
|
||||
// while we reserved it, and the reader get prempted until its CAS.
|
||||
// while we reserved it, and the reader get preempted until its CAS.
|
||||
if (M_UNLIKELY (M_SNAPSH0T_SPMC_INT_FLAG_N(previous) == true)) goto reforce;
|
||||
break;
|
||||
}
|
||||
@@ -601,7 +601,7 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
} while (0)
|
||||
|
||||
|
||||
// Defered evaluation
|
||||
// Deferred evaluation
|
||||
#define M_SNAPSH0T_SPMC_DEF_P1(arg) M_ID( M_SNAPSH0T_SPMC_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
@@ -714,7 +714,7 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
|
||||
// MPMC is built upon SPMC
|
||||
|
||||
// Defered evaluation
|
||||
// Deferred evaluation
|
||||
#define M_SNAPSH0T_MPMC_DEF_P1(arg) M_ID( M_SNAPSH0T_MPMC_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
|
||||
+56
-46
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Dynamic Size String Module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -238,13 +238,11 @@ m_string_clear(m_string_t v)
|
||||
v->u.stack.buffer[sizeof (m_str1ng_heap_ct) - 1] = CHAR_MAX;
|
||||
}
|
||||
|
||||
/* NOTE: Internaly used by M_STRING_DECL_INIT */
|
||||
M_INLINE void m_str1ng_clear2(m_string_t *v) { m_string_clear(*v); }
|
||||
M_INLINE m_string_ptr m_str1ng_init_ref(m_string_t v) { m_string_init(v); return v; }
|
||||
|
||||
/* Clear the Dynamic string (destructor)
|
||||
and return a heap pointer to the string.
|
||||
The ownership of the data is transfered back to the caller
|
||||
The ownership of the data is transferred back to the caller
|
||||
and the returned pointer has to be released by M_MEMORY_FREE. */
|
||||
M_INLINE char *
|
||||
m_string_clear_get_cstr(m_string_t v)
|
||||
@@ -319,7 +317,7 @@ m_str1ng_fit2size (m_string_t v, size_t size_alloc)
|
||||
// Note: this function may be called in context where the contract
|
||||
// is not fulfilled.
|
||||
const size_t old_alloc = m_string_capacity(v);
|
||||
// This line enables the compiler to completly remove this function
|
||||
// This line enables the compiler to completely remove this function
|
||||
// for very short constant strings.
|
||||
M_ASSUME(old_alloc >= sizeof (m_str1ng_heap_ct) - 1);
|
||||
if (M_UNLIKELY (size_alloc > old_alloc)) {
|
||||
@@ -472,6 +470,9 @@ m_string_set_n(m_string_t v, const m_string_t ref, size_t offset, size_t length)
|
||||
M_INLINE void
|
||||
m_string_init_set(m_string_t v1, const m_string_t v2)
|
||||
{
|
||||
// In case of exception, v1 remains initialized,
|
||||
// but without any allocation done.
|
||||
// Therefore it is safe, not to clear v1 on exception.
|
||||
m_string_init(v1);
|
||||
m_string_set(v1,v2);
|
||||
}
|
||||
@@ -481,6 +482,9 @@ m_string_init_set(m_string_t v1, const m_string_t v2)
|
||||
M_INLINE void
|
||||
m_string_init_set_cstr(m_string_t v1, const char str[])
|
||||
{
|
||||
// In case of exception, v1 remains initialized,
|
||||
// but without any allocation done.
|
||||
// Therefore it is safe, not to clear v1 on exception.
|
||||
m_string_init(v1);
|
||||
m_string_set_cstr(v1, str);
|
||||
}
|
||||
@@ -536,7 +540,7 @@ m_string_push_back (m_string_t v, char c)
|
||||
M_STR1NG_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Concatene the string with the C string */
|
||||
/* Concatenate the string with the C string */
|
||||
M_INLINE void
|
||||
m_string_cat_cstr(m_string_t v, const char str[])
|
||||
{
|
||||
@@ -550,7 +554,7 @@ m_string_cat_cstr(m_string_t v, const char str[])
|
||||
M_STR1NG_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Concatene the string with the other string */
|
||||
/* Concatenate the string with the other string */
|
||||
M_INLINE void
|
||||
m_string_cat(m_string_t v, const m_string_t v2)
|
||||
{
|
||||
@@ -613,7 +617,7 @@ m_string_equal_p(const m_string_t v1, const m_string_t v2)
|
||||
}
|
||||
|
||||
/* Test if the string is equal to the C string
|
||||
(case insentive according to the current locale)
|
||||
(case insensitive according to the current locale)
|
||||
Note: doesn't work with UTF-8 strings.
|
||||
*/
|
||||
M_INLINE int
|
||||
@@ -635,7 +639,7 @@ m_string_cmpi_cstr(const m_string_t v1, const char p2[])
|
||||
}
|
||||
|
||||
/* Test if the string is equal to the other string
|
||||
(case insentive according to the current locale)
|
||||
(case insensitive according to the current locale)
|
||||
Note: doesn't work with UTF-8 strings.
|
||||
*/
|
||||
M_INLINE int
|
||||
@@ -796,7 +800,7 @@ m_string_mid (m_string_t v, size_t index, size_t size)
|
||||
m_string_left(v, size);
|
||||
}
|
||||
|
||||
/* Replace in the string the firt occurence of the C string str1
|
||||
/* Replace in the string the first occurrence of the C string str1
|
||||
into the C string str2 from start
|
||||
By default, start is zero.
|
||||
*/
|
||||
@@ -822,7 +826,7 @@ m_string_replace_cstr (m_string_t v, const char str1[], const char str2[], size_
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Replace in the string the firt occurence of the C string v1
|
||||
/* Replace in the string the first occurrence of the C string v1
|
||||
into the C string v2 from start
|
||||
By default, start is zero.
|
||||
*/
|
||||
@@ -861,7 +865,7 @@ m_string_replace_at (m_string_t v, size_t pos, size_t len, const char str2[])
|
||||
M_STR1NG_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Replace all occurences of str1 into str2 when strlen(str1) >= strlen(str2) */
|
||||
/* Replace all occurrences of str1 into str2 when strlen(str1) >= strlen(str2) */
|
||||
M_INLINE void
|
||||
m_str1ng_replace_all_cstr_1ge2 (m_string_t v, const char str1[], size_t str1len, const char str2[], size_t str2len)
|
||||
{
|
||||
@@ -1072,6 +1076,10 @@ m_string_vprintf (m_string_t v, const char format[], va_list args)
|
||||
size_t alloc = m_string_capacity(v);
|
||||
size = vsnprintf (ptr, alloc, format, args);
|
||||
if (size > 0 && ((size_t) size+1 >= alloc) ) {
|
||||
// Reset the string in a clean state in case of exception
|
||||
// to keep the object in a clearable state
|
||||
M_IF_EXCEPTION( m_str1ng_set_size(v, 0) );
|
||||
M_IF_EXCEPTION( m_str1ng_get_cstr(v)[0] = 0 );
|
||||
// We have to realloc our string to fit the needed size
|
||||
ptr = m_str1ng_fit2size (v, (size_t) size + 1);
|
||||
alloc = m_string_capacity(v);
|
||||
@@ -1118,6 +1126,10 @@ m_string_cat_vprintf (m_string_t v, const char format[], va_list args)
|
||||
size_t alloc = m_string_capacity(v);
|
||||
size = vsnprintf (&ptr[old_size], alloc - old_size, format, args);
|
||||
if (size > 0 && (old_size+(size_t)size+1 >= alloc) ) {
|
||||
// Reset the string in a clean state in case of exception
|
||||
// to keep the object in a clearable state
|
||||
M_IF_EXCEPTION( m_str1ng_set_size(v, old_size) );
|
||||
M_IF_EXCEPTION( m_str1ng_get_cstr(v)[old_size] = 0 );
|
||||
// We have to realloc our string to fit the needed size
|
||||
ptr = m_str1ng_fit2size (v, old_size + (size_t) size + 1);
|
||||
alloc = m_string_capacity(v);
|
||||
@@ -1167,7 +1179,7 @@ m_string_set_si(m_string_t v, int n)
|
||||
|
||||
#if M_USE_STDIO
|
||||
|
||||
/* Get a line/pureline/file from the FILE and store it in the string */
|
||||
/* Get a line/pure-line/file from the FILE and store it in the string */
|
||||
M_INLINE bool
|
||||
m_string_fgets(m_string_t v, FILE *f, m_string_fgets_t arg)
|
||||
{
|
||||
@@ -1180,6 +1192,7 @@ m_string_fgets(m_string_t v, FILE *f, m_string_fgets_t arg)
|
||||
bool retcode = false; /* Nothing has been read yet */
|
||||
/* alloc - size is very unlikely to be bigger than INT_MAX
|
||||
but fgets accepts an int as the size argument */
|
||||
// NOTE: fgets reads at most one less than 'alloc-size' characters from stream
|
||||
while (fgets(&ptr[size], (int) M_MIN( (alloc - size), (size_t) INT_MAX ), f) != NULL) {
|
||||
retcode = true; /* Something has been read */
|
||||
// fgets doesn't return the number of characters read, so we need to count.
|
||||
@@ -1192,8 +1205,12 @@ m_string_fgets(m_string_t v, FILE *f, m_string_fgets_t arg)
|
||||
}
|
||||
m_str1ng_set_size(v, size);
|
||||
M_STR1NG_CONTRACT(v);
|
||||
return retcode; /* Normal terminaison */
|
||||
} else if (ptr[size-1] != '\n' && !feof(f)) {
|
||||
return retcode; /* Normal termination */
|
||||
} else if (alloc <= 1 + size) {
|
||||
// Reset the string in a clean state in case of exception
|
||||
// to keep the object in a clearable state
|
||||
M_IF_EXCEPTION( m_str1ng_set_size(v, size) );
|
||||
M_IF_EXCEPTION( m_str1ng_get_cstr(v)[size] = 0 );
|
||||
/* The string buffer is not big enough:
|
||||
increase it and continue reading */
|
||||
/* v cannot be stack alloc */
|
||||
@@ -1203,7 +1220,7 @@ m_string_fgets(m_string_t v, FILE *f, m_string_fgets_t arg)
|
||||
}
|
||||
m_str1ng_set_size(v, size);
|
||||
M_STR1NG_CONTRACT (v);
|
||||
return retcode; /* Abnormal terminaison */
|
||||
return retcode; /* Abnormal termination */
|
||||
}
|
||||
|
||||
/* Get a word from the FILE and store it in the string.
|
||||
@@ -1255,6 +1272,7 @@ m_string_fget_word (m_string_t v, const char separator[], FILE *f)
|
||||
break;
|
||||
/* Next char is not a separator: continue parsing */
|
||||
m_str1ng_set_size(v, size);
|
||||
M_IF_EXCEPTION( m_str1ng_get_cstr(v)[size] = 0);
|
||||
ptr = m_str1ng_fit2size (v, alloc + alloc/2);
|
||||
alloc = m_string_capacity(v);
|
||||
M_ASSERT (alloc > size + 1);
|
||||
@@ -1333,30 +1351,30 @@ m_string_hash(const m_string_t v)
|
||||
return m_core_hash(m_string_get_cstr(v), m_string_size(v));
|
||||
}
|
||||
|
||||
// Return true if c is a character from charac
|
||||
// Return true if c is a character from the C-String tab
|
||||
M_INLINE bool
|
||||
m_str1ng_strim_char(char c, const char charac[])
|
||||
m_str1ng_strim_char(char c, const char tab[])
|
||||
{
|
||||
for(const char *s = charac; *s; s++) {
|
||||
for(const char *s = tab; *s; s++) {
|
||||
if (c == *s)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Remove any characters from charac that are present
|
||||
in the begining of the string and the end of the string. */
|
||||
/* Remove any characters from tab that are present
|
||||
in the beginning of the string and the end of the string. */
|
||||
M_INLINE void
|
||||
m_string_strim(m_string_t v, const char charac[])
|
||||
m_string_strim(m_string_t v, const char tab[])
|
||||
{
|
||||
M_STR1NG_CONTRACT (v);
|
||||
char *ptr = m_str1ng_get_cstr(v);
|
||||
char *b = ptr;
|
||||
size_t size = m_string_size(v);
|
||||
while (size > 0 && m_str1ng_strim_char(b[size-1], charac))
|
||||
while (size > 0 && m_str1ng_strim_char(b[size-1], tab))
|
||||
size --;
|
||||
if (size > 0) {
|
||||
while (m_str1ng_strim_char(*b, charac))
|
||||
while (m_str1ng_strim_char(*b, tab))
|
||||
b++;
|
||||
M_ASSERT (b >= ptr && size >= (size_t) (b - ptr) );
|
||||
size -= (size_t) (b - ptr);
|
||||
@@ -1374,7 +1392,7 @@ m_string_oor_equal_p(const m_string_t s, unsigned char n)
|
||||
return (s->ptr == NULL) & (s->u.heap.alloc == ~(size_t)n);
|
||||
}
|
||||
|
||||
/* Set the unitialized string to the OOR value */
|
||||
/* Set the uninitialized string to the OOR value */
|
||||
M_INLINE void
|
||||
m_string_oor_set(m_string_t s, unsigned char n)
|
||||
{
|
||||
@@ -1421,6 +1439,7 @@ m_string_get_str(m_string_t v, const m_string_t v2, bool append)
|
||||
if (M_UNLIKELY (!isprint((unsigned char) c))) {
|
||||
targetSize += 3;
|
||||
m_str1ng_set_size(v, size);
|
||||
M_IF_EXCEPTION(m_str1ng_get_cstr(v)[size] = 0);
|
||||
ptr = m_str1ng_fit2size(v, targetSize);
|
||||
int d1 = c & 0x07, d2 = (c>>3) & 0x07, d3 = (c>>6) & 0x07;
|
||||
ptr[size ++] = '\\';
|
||||
@@ -1633,7 +1652,7 @@ m_string_in_serial(m_string_t v, m_serial_read_t serial)
|
||||
It shall be (nearly) branchless on any CPU.
|
||||
It takes a byte, and the previous state and the previous value of the unicode code point.
|
||||
It updates the state and the decoded unicode code point.
|
||||
A decoded unicoded code point is valid only when the state is STARTING.
|
||||
A decoded unicode code point is valid only when the state is STARTING.
|
||||
*/
|
||||
M_INLINE void
|
||||
m_str1ng_utf8_decode(char c, m_str1ng_utf8_state_e *state,
|
||||
@@ -1753,7 +1772,7 @@ m_string_it_set(m_string_it_t it, const m_string_it_t itsrc)
|
||||
}
|
||||
|
||||
/* Set the iterator to the given position in the string.
|
||||
The given position shall reference a valide code point in the string.
|
||||
The given position shall reference a valid code point in the string.
|
||||
*/
|
||||
M_INLINE void
|
||||
m_string_it_pos(m_string_it_t it, const m_string_t str, const size_t n)
|
||||
@@ -2023,14 +2042,14 @@ m_string_utf8_p(m_string_t str)
|
||||
/* Use of Compound Literals to init a constant string.
|
||||
NOTE: The use of the additional structure layer is to ensure
|
||||
that the pointer to char is properly aligned to an int (this
|
||||
is a needed asumption by m_string_hash).
|
||||
is a needed assumption by m_string_hash).
|
||||
Otherwise it could have been :
|
||||
#define M_STRING_CTE(s) \
|
||||
((const m_string_t){{.size = sizeof(s)-1, .alloc = sizeof(s), \
|
||||
.ptr = s}})
|
||||
which produces faster code.
|
||||
Note: This code doesn't work with C++ (use of c99 feature
|
||||
of recursive struct definition and compound literral).
|
||||
of recursive struct definition and compound literal).
|
||||
As such, there is a separate C++ definition.
|
||||
*/
|
||||
#ifndef __cplusplus
|
||||
@@ -2083,16 +2102,6 @@ namespace m_lib {
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(m_string_init_set_cstr, m_string_init_printf)(v, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* NOTE: Use GCC extension (OBSOLETE) */
|
||||
#define M_STRING_DECL_INIT(v) \
|
||||
m_string_t v __attribute__((cleanup(m_str1ng_clear2))) = {{ 0, 0, NULL}}
|
||||
|
||||
/* NOTE: Use GCC extension (OBSOLETE) */
|
||||
#define M_STRING_DECL_INIT_PRINTF(v, format, ...) \
|
||||
M_STRING_DECL_INIT(v); \
|
||||
m_string_printf (v, format, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define the OPLIST of a STRING */
|
||||
#define M_STRING_OPLIST \
|
||||
(INIT(m_string_init),INIT_SET(m_string_init_set), SET(m_string_set), \
|
||||
@@ -2101,7 +2110,7 @@ namespace m_lib {
|
||||
SWAP(m_string_swap), RESET(m_string_reset), \
|
||||
EMPTY_P(m_string_empty_p), \
|
||||
CLEAR(m_string_clear), HASH(m_string_hash), EQUAL(m_string_equal_p), \
|
||||
CMP(m_string_cmp), TYPE(m_string_t), \
|
||||
CMP(m_string_cmp), TYPE(m_string_t), GENTYPE(struct m_string_s*), \
|
||||
PARSE_STR(m_string_parse_str), GET_STR(m_string_get_str), \
|
||||
OUT_STR(m_string_out_str), IN_STR(m_string_in_str), \
|
||||
OUT_SERIAL(m_string_out_serial), IN_SERIAL(m_string_in_serial), \
|
||||
@@ -2115,13 +2124,16 @@ namespace m_lib {
|
||||
,IT_END_P(m_string_end_p) \
|
||||
,IT_EQUAL_P(m_string_it_equal_p) \
|
||||
,IT_NEXT(m_string_next) \
|
||||
,IT_CREF(m_string_cref) \
|
||||
,IT_CREF(m_string_cref), PUSH(m_string_push_u) \
|
||||
,EMPLACE_TYPE(const char*) \
|
||||
)
|
||||
|
||||
/* Register the OPLIST as a global one */
|
||||
#define M_OPL_m_string_t() M_STRING_OPLIST
|
||||
|
||||
/* Register the string_t oplist as a generic type */
|
||||
#define M_GENERIC_ORG_MLIB_COMP_CORE_OPLIST_1() M_STRING_OPLIST
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
/* */
|
||||
@@ -2194,7 +2206,7 @@ namespace m_lib {
|
||||
/* Set the string a to the string (or C string) b */
|
||||
#define m_string_set(a,b) M_STR1NG_SELECT2(m_string_set, m_string_set_cstr, a, b)
|
||||
|
||||
/* Concatene the string (or C string) b to the string a */
|
||||
/* Concatenate the string (or C string) b to the string a */
|
||||
#define m_string_cat(a,b) M_STR1NG_SELECT2(m_string_cat, m_string_cat_cstr, a, b)
|
||||
|
||||
/* Compare the string a to the string (or C string) b and return the sort order */
|
||||
@@ -2270,7 +2282,7 @@ namespace m_lib {
|
||||
HASH(M_F(name,_hash)), \
|
||||
EQUAL(M_F(name,_equal_p)), \
|
||||
CMP(M_F(name,_cmp)), \
|
||||
TYPE(M_F(name,_ct)), \
|
||||
TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
OOR_EQUAL(M_F(name,_oor_equal_p)), \
|
||||
OOR_SET(M_F(name, _oor_set)), \
|
||||
PARSE_STR(M_F(name,_parse_str)), \
|
||||
@@ -2521,7 +2533,7 @@ namespace m_lib {
|
||||
M_F(name, _hash)(const bounded_t s) \
|
||||
{ \
|
||||
M_BOUNDED_STR1NG_CONTRACT(s, max_size); \
|
||||
/* Cannot use m_core_hash: alignment not sufficent */ \
|
||||
/* Cannot use m_core_hash: alignment guarantee is not sufficient */ \
|
||||
return m_core_cstr_hash(s->s); \
|
||||
} \
|
||||
\
|
||||
@@ -2767,8 +2779,6 @@ namespace m_lib {
|
||||
#define string_it_set_ref m_string_it_set_ref
|
||||
|
||||
#define STRING_CTE M_STRING_CTE
|
||||
#define STRING_DECL_INIT M_STRING_DECL_INIT
|
||||
#define STRING_DECL_INIT_PRINTF M_STRING_DECL_INIT_PRINTF
|
||||
#define STRING_OPLIST M_STRING_OPLIST
|
||||
#define M_OPL_string_t M_OPL_m_string_t
|
||||
#define string_sets m_string_sets
|
||||
|
||||
+31
-7
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin Mutex & Thread wrapper
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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,6 +80,12 @@ M_INLINE void m_mutex_lock(m_mutex_t m)
|
||||
mtx_lock(m);
|
||||
}
|
||||
|
||||
/* Try to lock the mutex. Return true on success */
|
||||
M_INLINE bool m_mutex_trylock(m_mutex_t m)
|
||||
{
|
||||
return mtx_trylock(m) == thrd_success;
|
||||
}
|
||||
|
||||
/* Unlock the mutex */
|
||||
M_INLINE void m_mutex_unlock(m_mutex_t m)
|
||||
{
|
||||
@@ -136,7 +142,7 @@ M_INLINE void m_thread_join(m_thread_t t)
|
||||
(void) rc;
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
/* The thread has nothing meaningful to do.
|
||||
Inform the OS to let other threads be scheduled */
|
||||
M_INLINE void m_thread_yield(void)
|
||||
{
|
||||
@@ -187,7 +193,7 @@ M_END_PROTECTED_CODE
|
||||
* We cannot add theses warnings in M_BEGIN_PROTECTED_CODE
|
||||
* as they need to be disabled **BEFORE** including any system header
|
||||
* and m-core includes some system headers.
|
||||
* So we need to disable them explictly here.
|
||||
* So we need to disable them explicitly here.
|
||||
*/
|
||||
#if defined(__clang__) && __clang_major__ >= 4
|
||||
_Pragma("clang diagnostic push")
|
||||
@@ -242,6 +248,12 @@ M_INLINE void m_mutex_lock(m_mutex_t m)
|
||||
EnterCriticalSection(m);
|
||||
}
|
||||
|
||||
/* Try to Lock a mutex. Return true on success */
|
||||
M_INLINE bool m_mutex_trylock(m_mutex_t m)
|
||||
{
|
||||
return TryEnterCriticalSection(m) != 0;
|
||||
}
|
||||
|
||||
/* Unlock a mutex */
|
||||
M_INLINE void m_mutex_unlock(m_mutex_t m)
|
||||
{
|
||||
@@ -294,7 +306,7 @@ M_INLINE void m_thread_join(m_thread_t t)
|
||||
CloseHandle(*t);
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
/* The thread has nothing meaningful to do.
|
||||
Inform the OS to let other threads be scheduled */
|
||||
M_INLINE void m_thread_yield(void)
|
||||
{
|
||||
@@ -390,6 +402,12 @@ M_INLINE void m_mutex_lock(m_mutex_t m)
|
||||
pthread_mutex_lock(m);
|
||||
}
|
||||
|
||||
/* Try to Lock a mutex. Return true on success */
|
||||
M_INLINE bool m_mutex_trylock(m_mutex_t m)
|
||||
{
|
||||
return pthread_mutex_trylock(m) == 0;
|
||||
}
|
||||
|
||||
/* Unlock the mutex */
|
||||
M_INLINE void m_mutex_unlock(m_mutex_t m)
|
||||
{
|
||||
@@ -453,7 +471,7 @@ M_INLINE void m_thread_join(m_thread_t t)
|
||||
M_ASSERT (_rc == 0);
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
/* The thread has nothing meaningful to do.
|
||||
Inform the OS to let other threads be scheduled */
|
||||
M_INLINE void m_thread_yield(void)
|
||||
{
|
||||
@@ -555,6 +573,12 @@ M_INLINE void m_mutex_lock(m_mutex_t m)
|
||||
xSemaphoreTake(m->handle, portMAX_DELAY);
|
||||
}
|
||||
|
||||
/* Try to Lock a mutex. Return true on success */
|
||||
M_INLINE bool m_mutex_trylock(m_mutex_t m)
|
||||
{
|
||||
return xSemaphoreTake(m->handle, 0) == pdTRUE;
|
||||
}
|
||||
|
||||
/* Unlock the mutex */
|
||||
M_INLINE void m_mutex_unlock(m_mutex_t m)
|
||||
{
|
||||
@@ -659,7 +683,7 @@ M_INLINE void m_thread_join(m_thread_t t)
|
||||
t->SemHandle = 0;
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
/* The thread has nothing meaningful to do.
|
||||
Inform the OS to let other threads be scheduled */
|
||||
M_INLINE void m_thread_yield(void)
|
||||
{
|
||||
@@ -681,7 +705,7 @@ typedef struct {
|
||||
} m_once_t[1];
|
||||
|
||||
// Initial value for m_once_t
|
||||
#define M_ONCE_INIT_VALUE { { ATOMIC_VAR_INIT(0) } }
|
||||
#define M_ONCE_INIT_VALUE { { M_ATOMIC_VAR_INIT(0) } }
|
||||
|
||||
// Call the function exactly once
|
||||
M_INLINE void m_once_call(m_once_t o, void (*func)(void))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - TREE module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -532,7 +532,7 @@ typedef int32_t m_tr33_index_t;
|
||||
M_INLINE it_t \
|
||||
M_F(name, _insert_child_raw)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
/* Insert a node as a child of another, making the current childreen \
|
||||
/* Insert a node as a child of another, making the current children \
|
||||
of the nodes their siblings */ \
|
||||
m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \
|
||||
m_tr33_index_t child = it.tree->tab[it.index].child; \
|
||||
@@ -1157,7 +1157,7 @@ typedef int32_t m_tr33_index_t;
|
||||
\
|
||||
M_INLINE void \
|
||||
M_F(name, _set)(tree_t tree, const tree_t ref) { \
|
||||
/* No optimum, but good enought for present time */ \
|
||||
/* No optimum, but good enough currently */ \
|
||||
M_F(name, _clear)(tree); \
|
||||
M_F(name, _init_set)(tree, ref); \
|
||||
} \
|
||||
@@ -1213,7 +1213,7 @@ typedef int32_t m_tr33_index_t;
|
||||
return (size_t) tree->capacity; \
|
||||
} \
|
||||
\
|
||||
/* Service not really usefull as the affectation operator works with it */\
|
||||
/* Service not really useful as the affectation operator works with it */ \
|
||||
M_INLINE void \
|
||||
M_F(name, _it_set)(it_t *dst, it_t src ){ \
|
||||
*dst = src; \
|
||||
@@ -1339,7 +1339,6 @@ M_INLINE bool \
|
||||
M_F(name, _parse_str)(tree_t tree, const char str[], const char **endp) { \
|
||||
M_TR33_CONTRACT(tree); \
|
||||
int cmd = 0; \
|
||||
type item; \
|
||||
it_t it; \
|
||||
M_F(name, _reset)(tree); \
|
||||
bool success = false; \
|
||||
@@ -1348,50 +1347,47 @@ M_F(name, _parse_str)(tree_t tree, const char str[], const char **endp) { \
|
||||
c = *++str; \
|
||||
if (M_UNLIKELY (c == ']')) { success = true; str++; goto exit; } \
|
||||
if (M_UNLIKELY (c == 0)) goto exit; \
|
||||
M_CALL_INIT(oplist, item); \
|
||||
it = M_F(name, _it_end)(tree); \
|
||||
while (true) { \
|
||||
c = *str++; \
|
||||
if (c != '{') goto exit_clear; \
|
||||
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
|
||||
c = *str++; \
|
||||
if (b == false || c == 0) { goto exit_clear; } \
|
||||
/* Insert the item as the root or as a right sibling or as a child */ \
|
||||
switch (cmd) { \
|
||||
case 0: it = M_F(name, _set_root)(tree, item); break; \
|
||||
case 1: it = M_F(name, _insert_right)(it, item); break; \
|
||||
case 2: it = M_F(name, _insert_child)(it, item); break; \
|
||||
default: M_ASSERT(0); \
|
||||
} \
|
||||
if (c == ',') { \
|
||||
/* The current item has some children */ \
|
||||
M_QLET(1, item, type, oplist) { \
|
||||
it = M_F(name, _it_end)(tree); \
|
||||
while (true) { \
|
||||
c = *str++; \
|
||||
if (c != '[') { goto exit_clear; } \
|
||||
/* next is a child: push_down */ \
|
||||
cmd = 2; \
|
||||
continue; \
|
||||
} \
|
||||
/* The current item has no children. */ \
|
||||
if (c != '}') { goto exit_clear; } \
|
||||
/* Scan the next character to decide where to move (right or up) */ \
|
||||
c = *str++; \
|
||||
if (c == ']') { \
|
||||
do { \
|
||||
/* move up. It we cannot, we have reached the end */ \
|
||||
if (!M_F(name, _it_up)(&it)) { goto exit_success; } \
|
||||
if (c != '{') break; \
|
||||
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
|
||||
c = *str++; \
|
||||
if (b == false || c == 0) break; \
|
||||
/* Insert the item as the root or as a right sibling or as a child */ \
|
||||
switch (cmd) { \
|
||||
case 0: it = M_F(name, _set_root)(tree, item); break; \
|
||||
case 1: it = M_F(name, _insert_right)(it, item); break; \
|
||||
case 2: it = M_F(name, _insert_child)(it, item); break; \
|
||||
default: M_ASSERT(0); \
|
||||
} \
|
||||
if (c == ',') { \
|
||||
/* The current item has some children */ \
|
||||
c = *str++; \
|
||||
if (c != '}') { goto exit_clear; } \
|
||||
c = *str++; \
|
||||
} while (c == ']'); \
|
||||
if (c != '[') break; \
|
||||
/* next is a child: push_down */ \
|
||||
cmd = 2; \
|
||||
continue; \
|
||||
} \
|
||||
/* The current item has no children. */ \
|
||||
if (c != '}') break; \
|
||||
/* Scan the next character to decide where to move (right or up) */ \
|
||||
c = *str++; \
|
||||
if (c == ']') { \
|
||||
do { \
|
||||
/* move up. It we cannot, we have reached the end */ \
|
||||
if (!M_F(name, _it_up)(&it)) { success = true; break; } \
|
||||
c = *str++; \
|
||||
if (c != '}') goto do_break; \
|
||||
c = *str++; \
|
||||
} while (c == ']'); \
|
||||
} \
|
||||
if (c != ',') { do_break: break; } \
|
||||
/* next is a sibling: push_right */ \
|
||||
cmd = 1; \
|
||||
} \
|
||||
if (c != ',') { goto exit_clear; } \
|
||||
/* next is a sibling: push_right */ \
|
||||
cmd = 1; \
|
||||
} \
|
||||
exit_success: \
|
||||
success = true; \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
exit: \
|
||||
if (endp) *endp = str; \
|
||||
M_TR33_CONTRACT(tree); \
|
||||
@@ -1440,7 +1436,6 @@ M_INLINE bool \
|
||||
M_F(name, _in_str)(tree_t tree, FILE *f) { \
|
||||
M_TR33_CONTRACT(tree); \
|
||||
int cmd = 0; \
|
||||
type item; \
|
||||
it_t it; \
|
||||
M_F(name, _reset)(tree); \
|
||||
bool success = false; \
|
||||
@@ -1450,50 +1445,47 @@ M_F(name, _in_str)(tree_t tree, FILE *f) { \
|
||||
if (M_UNLIKELY (c == ']')) { success = true; goto exit; } \
|
||||
ungetc(c, f); \
|
||||
if (M_UNLIKELY (c == 0)) goto exit; \
|
||||
M_CALL_INIT(oplist, item); \
|
||||
it = M_F(name, _it_end)(tree); \
|
||||
while (true) { \
|
||||
c = fgetc(f); \
|
||||
if (c != '{') goto exit_clear; \
|
||||
bool b = M_CALL_IN_STR(oplist, item, f); \
|
||||
c = fgetc(f); \
|
||||
if (b == false || c == 0) { goto exit_clear; } \
|
||||
/* Insert the item as the root or as a right sibling or as a child */ \
|
||||
switch (cmd) { \
|
||||
case 0: it = M_F(name, _set_root)(tree, item); break; \
|
||||
case 1: it = M_F(name, _insert_right)(it, item); break; \
|
||||
case 2: it = M_F(name, _insert_child)(it, item); break; \
|
||||
default: M_ASSERT(0); \
|
||||
} \
|
||||
if (c == ',') { \
|
||||
/* The current item has some children */ \
|
||||
M_QLET(1, item, type, oplist) { \
|
||||
it = M_F(name, _it_end)(tree); \
|
||||
while (true) { \
|
||||
c = fgetc(f); \
|
||||
if (c != '[') { goto exit_clear; } \
|
||||
/* next is a child: push_down */ \
|
||||
cmd = 2; \
|
||||
continue; \
|
||||
} \
|
||||
/* The current item has no children. */ \
|
||||
if (c != '}') { goto exit_clear; } \
|
||||
/* Scan the next character to decide where to move (right or up) */ \
|
||||
c = fgetc(f); \
|
||||
if (c == ']') { \
|
||||
do { \
|
||||
/* move up. It we cannot, we have reached the end */ \
|
||||
if (!M_F(name, _it_up)(&it)) { goto exit_success; } \
|
||||
if (c != '{') break; \
|
||||
bool b = M_CALL_IN_STR(oplist, item, f); \
|
||||
c = fgetc(f); \
|
||||
if (b == false || c == 0) break; \
|
||||
/* Insert the item as the root or as a right sibling or as a child */ \
|
||||
switch (cmd) { \
|
||||
case 0: it = M_F(name, _set_root)(tree, item); break; \
|
||||
case 1: it = M_F(name, _insert_right)(it, item); break; \
|
||||
case 2: it = M_F(name, _insert_child)(it, item); break; \
|
||||
default: M_ASSERT(0); \
|
||||
} \
|
||||
if (c == ',') { \
|
||||
/* The current item has some children */ \
|
||||
c = fgetc(f); \
|
||||
if (c != '}') { goto exit_clear; } \
|
||||
c = fgetc(f); \
|
||||
} while (c == ']'); \
|
||||
if (c != '[') break; \
|
||||
/* next is a child: push_down */ \
|
||||
cmd = 2; \
|
||||
continue; \
|
||||
} \
|
||||
/* The current item has no children. */ \
|
||||
if (c != '}') break; \
|
||||
/* Scan the next character to decide where to move (right or up) */ \
|
||||
c = fgetc(f); \
|
||||
if (c == ']') { \
|
||||
do { \
|
||||
/* move up. It we cannot, we have reached the end */ \
|
||||
if (!M_F(name, _it_up)(&it)) { success = true ; break; } \
|
||||
c = fgetc(f); \
|
||||
if (c != '}') goto do_break; \
|
||||
c = fgetc(f); \
|
||||
} while (c == ']'); \
|
||||
} \
|
||||
if (c != ',') { do_break: break; } \
|
||||
/* next is a sibling: push_right */ \
|
||||
cmd = 1; \
|
||||
} \
|
||||
if (c != ',') { goto exit_clear; } \
|
||||
/* next is a sibling: push_right */ \
|
||||
cmd = 1; \
|
||||
} \
|
||||
exit_success: \
|
||||
success = true; \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
exit: \
|
||||
M_TR33_CONTRACT(tree); \
|
||||
return success; \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - try / catch mechanism for M*LIB
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
|
||||
/*
|
||||
* Start a protected section of code 'name' where all exceptions are catched
|
||||
* Start a protected section of code 'name' where all exceptions are caught
|
||||
* by the associated CATCH section.
|
||||
*/
|
||||
#define M_TRY(name) \
|
||||
@@ -156,6 +156,17 @@ struct m_exception_s {
|
||||
/********************************** INTERNAL *********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
#undef M_IF_EXCEPTION
|
||||
#define M_IF_EXCEPTION(...) __VA_ARGS__
|
||||
|
||||
#undef M_ON_EXCEPTION
|
||||
#define M_ON_EXCEPTION(...) \
|
||||
for(bool cont = true; cont; cont = false) \
|
||||
M_DEFER_TRY_INJECT_PRE(cont, __VA_ARGS__) \
|
||||
for( ; cont ; cont = false) \
|
||||
M_DEFER_TRY_INJECT_POST(cont, __VA_ARGS__) \
|
||||
for( ; cont; cont = false)
|
||||
|
||||
/*
|
||||
* Define the C++ back-end.
|
||||
* It is fully different from C back-end as it reuses the classic try of the C++.
|
||||
@@ -249,7 +260,7 @@ namespace m_lib {
|
||||
// Use of builtin setjmp / longjmp for GCC
|
||||
// There are at least twice faster at worst, and reduce stack consumption
|
||||
// See https://gcc.gnu.org/onlinedocs/gcc/Nonlocal-Gotos.html
|
||||
// CLANG doesn't support these builtins officialy (https://groups.google.com/g/llvm-dev/c/9QgfdW23K8M)
|
||||
// CLANG doesn't support these builtins officially (https://groups.google.com/g/llvm-dev/c/9QgfdW23K8M)
|
||||
#define m_try_setjmp(x) __builtin_setjmp(x)
|
||||
#define m_try_longjmp(x,v) __builtin_longjmp(x, v)
|
||||
typedef intptr_t m_try_jmp_buf[5];
|
||||
@@ -281,7 +292,7 @@ typedef intptr_t m_try_jmp_buf[5];
|
||||
// this point in the stack frame. Each nodes are linked together, so that we can
|
||||
// analyze the stack frame on exception.
|
||||
typedef struct m_try_s {
|
||||
enum { M_STATE_TRY, M_STATE_EXCEPTION_IN_PROGRESS, M_STATE_EXCEPTION_CATCHED,
|
||||
enum { M_STATE_TRY, M_STATE_EXCEPTION_IN_PROGRESS, M_STATE_EXCEPTION_CAUGHT,
|
||||
M_STATE_CLEAR_JMPBUF, M_STATE_CLEAR_CB } kind;
|
||||
struct m_try_s *next;
|
||||
union {
|
||||
@@ -354,7 +365,7 @@ extern M_ATTR_NO_RETURN M_ATTR_COLD_FUNCTION void m_throw(const struct m_excepti
|
||||
} \
|
||||
/* No exception found. \
|
||||
Display the information and halt program . */ \
|
||||
M_RAISE_FATAL("Exception '%u' raised by (%s:%d) is not catched. Program aborted.\n", \
|
||||
M_RAISE_FATAL("Exception '%u' raised by (%s:%d) is not caught. Program aborted.\n", \
|
||||
exception->error_code, exception->filename, exception->line); \
|
||||
}
|
||||
|
||||
@@ -376,8 +387,8 @@ m_catch(m_try_t state, unsigned error_code, const struct m_exception_s **excepti
|
||||
*exception = &m_global_exception;
|
||||
if (error_code != 0 && m_global_exception.error_code != error_code)
|
||||
return false;
|
||||
// The exception has been catched.
|
||||
state->kind = M_STATE_EXCEPTION_CATCHED;
|
||||
// The exception has been caught.
|
||||
state->kind = M_STATE_EXCEPTION_CAUGHT;
|
||||
// Unstack the try block, so that next throw command in the CATCH block
|
||||
// will reach the upper TRY block.
|
||||
m_global_error_list = state->next;
|
||||
@@ -413,7 +424,7 @@ m_try_clear(m_try_t state)
|
||||
|
||||
// Implement the M_LET injection macros, so that the CLEAR operator is called on exception
|
||||
// Helper functions
|
||||
// Each mechanisme provide 3 helper functions:
|
||||
// Each mechanism provide 3 helper functions:
|
||||
// * pre: which is called before the constructor
|
||||
// * post: which is called after the constructor
|
||||
// * final: which is called before the destructor.
|
||||
@@ -574,5 +585,9 @@ m_try_jump_final(m_try_t state)
|
||||
#undef M_MEMORY_FULL
|
||||
#define M_MEMORY_FULL(size) M_THROW(M_ERROR_MEMORY, (intptr_t)(size))
|
||||
|
||||
// Add attribute volatile if exceptions are enabled
|
||||
#undef m_volatile
|
||||
#define m_volatile volatile
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - TUPLE module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -134,6 +134,7 @@ namespace m_lib {
|
||||
M_TUPL3_DEFINE_CLEAR(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_GETTER_FIELD(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_SETTER_FIELD(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_EMPLACE_FIELD(name, __VA_ARGS__) \
|
||||
M_TUPL3_IF_ONE(CMP, __VA_ARGS__)(M_TUPL3_DEFINE_CMP(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(CMP, __VA_ARGS__)(M_TUPL3_DEFINE_CMP_ORDER(name, __VA_ARGS__),) \
|
||||
M_TUPL3_DEFINE_CMP_FIELD(name, __VA_ARGS__) \
|
||||
@@ -348,6 +349,25 @@ namespace m_lib {
|
||||
}
|
||||
|
||||
|
||||
/* Define the EMPLACE_field methods for all params. */
|
||||
#define M_TUPL3_DEFINE_EMPLACE_FIELD(name, ...) \
|
||||
M_REDUCE3(M_TUPL3_DEFINE_EMPLACE_FIELD_PROTO, M_TUPL3_DEFINE_EMPLACE_G, name, __VA_ARGS__)
|
||||
|
||||
#define M_TUPL3_DEFINE_EMPLACE_G(a, b) a b
|
||||
|
||||
#define M_TUPL3_DEFINE_EMPLACE_FIELD_PROTO(name, id, a) \
|
||||
M_EMPLACE_QUEUE_DEF(M_TUPL3_GET_FIELD a, M_F(name, _ct), M_C3(name, _emplace_, M_TUPL3_GET_FIELD a), M_TUPL3_GET_OPLIST a, M_TUPL3_EMPLACE_DEF)
|
||||
|
||||
#define M_TUPL3_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
M_INLINE void \
|
||||
function_name(name_t v \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_CALL_CLEAR(oplist, v->name); \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, v->name, exp_emplace_type); \
|
||||
}
|
||||
|
||||
|
||||
/* Define the CMP method by calling CMP methods for all params. */
|
||||
#define M_TUPL3_DEFINE_CMP(name, ...) \
|
||||
M_INLINE int M_F(name, _cmp)(M_F(name,_ct) const e1 , \
|
||||
@@ -730,7 +750,7 @@ namespace m_lib {
|
||||
SET(M_F(name,_set)), \
|
||||
CLEAR(M_F(name, _clear)), \
|
||||
NAME(name), \
|
||||
TYPE(M_F(name,_ct)), \
|
||||
TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
OPLIST( (__VA_ARGS__) ), \
|
||||
M_IF_METHOD_ALL(CMP, __VA_ARGS__)(CMP(M_F(name, _cmp)),), \
|
||||
M_IF_METHOD_ALL(HASH, __VA_ARGS__)(HASH(M_F(name, _hash)),), \
|
||||
|
||||
+60
-31
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - VARIANT module
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -106,36 +106,23 @@
|
||||
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__),) \
|
||||
M_VAR1ANT_IF_ALL(INIT, __VA_ARGS__)(M_VAR1ANT_DEFINE_INIT_FIELD, M_EAT)(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_DEFINE_INIT_SETTER_FIELD(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_DEFINE_SETTER_FIELD(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_DEFINE_GETTER_FIELD(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_DEFINE_RESET_FUNC(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL(HASH, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_HASH(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(EQUAL, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_EQUAL(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(GET_STR, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_GET_STR(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL2(PARSE_STR, INIT, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_PARSE_STR(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(OUT_STR, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_OUT_STR(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL2(IN_STR, INIT, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_IN_STR(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(OUT_SERIAL, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_OUT_SERIAL(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL2(IN_SERIAL, INIT, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_IN_SERIAL(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(INIT_MOVE, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(INIT_MOVE, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_MOVE(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(INIT_MOVE, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_MOVER(name, __VA_ARGS__),) \
|
||||
M_VAR1ANT_IF_ALL(SWAP, __VA_ARGS__) \
|
||||
(M_VAR1ANT_DEFINE_SWAP(name, __VA_ARGS__),)
|
||||
M_VAR1ANT_IF_ALL(HASH, __VA_ARGS__)(M_VAR1ANT_DEFINE_HASH, M_EAT)(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL(EQUAL, __VA_ARGS__)(M_VAR1ANT_DEFINE_EQUAL, M_EAT)(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL(GET_STR, __VA_ARGS__)(M_VAR1ANT_DEFINE_GET_STR, M_EAT)(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL2(PARSE_STR, INIT, __VA_ARGS__)(M_VAR1ANT_DEFINE_PARSE_STR, M_EAT)(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL(OUT_STR, __VA_ARGS__)(M_VAR1ANT_DEFINE_OUT_STR, M_EAT)(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL2(IN_STR, INIT, __VA_ARGS__)(M_VAR1ANT_DEFINE_IN_STR, M_EAT)(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL(OUT_SERIAL, __VA_ARGS__)(M_VAR1ANT_DEFINE_OUT_SERIAL, M_EAT)(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL2(IN_SERIAL, INIT, __VA_ARGS__)(M_VAR1ANT_DEFINE_IN_SERIAL, M_EAT)(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL(INIT_MOVE, __VA_ARGS__)(M_VAR1ANT_DEFINE_INIT_MOVE, M_EAT)(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL(INIT_MOVE, __VA_ARGS__)(M_VAR1ANT_DEFINE_MOVE, M_EAT)(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL(INIT_MOVE, __VA_ARGS__)(M_VAR1ANT_DEFINE_MOVER, M_EAT)(name, __VA_ARGS__) \
|
||||
M_VAR1ANT_IF_ALL(SWAP, __VA_ARGS__)(M_VAR1ANT_DEFINE_SWAP, M_EAT)(name, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Get the field name, the type, the oplist or the methods
|
||||
@@ -199,7 +186,17 @@
|
||||
typedef struct M_F(name, _s) *M_F(name, _ptr); \
|
||||
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
|
||||
/* Define internal type for oplist */ \
|
||||
typedef name_t M_F(name, _ct);
|
||||
typedef name_t M_F(name, _ct); \
|
||||
/* Save alias for the types of arguments */ \
|
||||
M_MAP3(M_VAR1ANT_DEFINE_GENTYPE_ELE, name, __VA_ARGS__)
|
||||
|
||||
#define M_VAR1ANT_DEFINE_GENTYPE_ELE(name, num, a) \
|
||||
typedef \
|
||||
M_IF_METHOD(GENTYPE, M_VAR1ANT_GET_OPLIST a)( M_GET_GENTYPE M_VAR1ANT_GET_OPLIST a, M_VAR1ANT_GET_TYPE a) \
|
||||
M_C4(m_var1ant_, name, _gentype_, num); \
|
||||
typedef const \
|
||||
M_IF_METHOD(GENTYPE, M_VAR1ANT_GET_OPLIST a)( M_GET_GENTYPE M_VAR1ANT_GET_OPLIST a, M_VAR1ANT_GET_TYPE a) \
|
||||
M_C4(m_var1ant_, name, _const_gentype_, num);
|
||||
|
||||
#define M_VAR1ANT_DEFINE_UNION_ELE(name, a) \
|
||||
, M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value)
|
||||
@@ -325,15 +322,22 @@
|
||||
|
||||
/* Define the INIT_SET of a given type function. */
|
||||
#define M_VAR1ANT_DEFINE_INIT_SETTER_FIELD(name, ...) \
|
||||
M_MAP2(M_VAR1ANT_DEFINE_INIT_SETTER_FIELD_FUNC, name, __VA_ARGS__)
|
||||
M_MAP3(M_VAR1ANT_DEFINE_INIT_SETTER_FIELD_FUNC, name, __VA_ARGS__)
|
||||
|
||||
#define M_VAR1ANT_DEFINE_INIT_SETTER_FIELD_FUNC(name, a) \
|
||||
#define M_VAR1ANT_DEFINE_INIT_SETTER_FIELD_FUNC(name, num, a) \
|
||||
M_INLINE void \
|
||||
M_C3(name, _init_set_, M_VAR1ANT_GET_FIELD a)(M_F(name,_ct) my, \
|
||||
M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a ) { \
|
||||
my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \
|
||||
M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \
|
||||
M_VAR1ANT_GET_FIELD a); \
|
||||
} \
|
||||
M_INLINE void \
|
||||
M_C4(m_var1ant_, name, _init_set_, num)(M_F(name,_ct) my, \
|
||||
M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a ) { \
|
||||
my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \
|
||||
M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \
|
||||
M_VAR1ANT_GET_FIELD a); \
|
||||
}
|
||||
|
||||
|
||||
@@ -774,8 +778,10 @@ M_INLINE void \
|
||||
CLEAR(M_F(name, _clear)), \
|
||||
RESET(M_F(name, _reset)), \
|
||||
NAME(name), \
|
||||
TYPE(M_F(name,_ct)), \
|
||||
TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
EMPTY_P(M_F(name,_empty_p)), \
|
||||
SIZE( M_NARGS(__VA_ARGS__) ), \
|
||||
INIT_WITH( API_1(M_VAR1ANT_INIT_WITH) ), \
|
||||
M_IF_METHOD_ALL(HASH, __VA_ARGS__)(HASH(M_F(name, _hash)),), \
|
||||
M_IF_METHOD_ALL(EQUAL, __VA_ARGS__)(EQUAL(M_F(name, _equal_p)),), \
|
||||
M_IF_METHOD_ALL(GET_STR, __VA_ARGS__)(GET_STR(M_F(name, _get_str)),), \
|
||||
@@ -810,6 +816,29 @@ M_INLINE void \
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
/* INIT_WITH macro using _Generic
|
||||
Expand as:
|
||||
_Generic ( (x),
|
||||
M_C4(m_var1ant_, name, _gentype_, num) : M_C4(m_var1ant_, name, _init_set_, num)(x, M_AS_TYPE() ),
|
||||
...
|
||||
)
|
||||
*/
|
||||
#define M_VAR1ANT_INIT_WITH(oplist, dest, src) \
|
||||
M_VAR1ANT_INIT_WITH_B(M_GET_NAME oplist, M_GET_SIZE oplist, dest, src)
|
||||
#define M_VAR1ANT_INIT_WITH_B(name, num, dest, src) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( (src), \
|
||||
M_MAP2(M_VAR1ANT_INIT_WITH_FUNC, (name,dest,src), M_SEQ(1, num)) \
|
||||
struct m_var1ant_dummy_s *: /* cannot happen */ (void)0 ) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_VAR1ANT_INIT_WITH_FUNC(triplet, num) \
|
||||
M_VAR1ANT_INIT_WITH_FUNC_EXPAND(M_TRIPLE_1 triplet, M_TRIPLE_2 triplet, M_TRIPLE_3 triplet, num)
|
||||
#define M_VAR1ANT_INIT_WITH_FUNC_EXPAND(name, dest, src, num) \
|
||||
M_C4(m_var1ant_, name, _gentype_, num) : M_C4(m_var1ant_, name, _init_set_, num)(dest, M_AS_TYPE(M_C4(m_var1ant_, name, _gentype_, num), src) ), \
|
||||
M_C4(m_var1ant_, name, _const_gentype_, num): M_C4(m_var1ant_, name, _init_set_, num)(dest, M_AS_TYPE(M_C4(m_var1ant_, name, _const_gentype_, num), src) ),
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define VARIANT_DEF2 M_VARIANT_DEF2
|
||||
#define VARIANT_DEF2_AS M_VARIANT_DEF2_AS
|
||||
|
||||
+11
-11
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB / WORKER - Extra worker interface
|
||||
*
|
||||
* Copyright (c) 2017-2023, Patrick Pelissier
|
||||
* Copyright (c) 2017-2024, 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:
|
||||
@@ -185,7 +185,7 @@ typedef struct m_worker_sync_s {
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
/* Output a valid oplist with the given type.
|
||||
input is (fieldname, type) or (fieldname, type, oplist)
|
||||
input is (field-name, type) or (field-name, type, oplist)
|
||||
Output shall be : M_OPEXTEND(M_GLOBAL_OPLIST_OR_DEF(type_or_oplist)(), TYPE(type)) / M_OPEXTEND(oplist, TYPE(type))
|
||||
*/
|
||||
#define M_WORK3R_SPAWN_EXTEND_P0(...) M_BY_NARGS(M_WORK3R_SPAWN_EXTEND_P0, M_ID __VA_ARGS__) __VA_ARGS__
|
||||
@@ -377,7 +377,7 @@ m_work3r_thread(void *arg)
|
||||
if (w.block == NULL) break;
|
||||
// Execute the work order
|
||||
m_work3r_exec(&w);
|
||||
// Consumme fully the work order in the queue
|
||||
// Consume fully the work order in the queue
|
||||
m_work3r_queue_pop_release(g->queue_g);
|
||||
// Signal that a worker has finished.
|
||||
m_mutex_lock(g->lock);
|
||||
@@ -395,7 +395,7 @@ m_work3r_thread(void *arg)
|
||||
@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 (or NULL if none)
|
||||
@clearFunc: function to clear the state of a worker before terminaning (or NULL if none)
|
||||
@clearFunc: function to clear the state of a worker before terminating (or NULL if none)
|
||||
*/
|
||||
M_INLINE void
|
||||
m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
|
||||
@@ -432,7 +432,7 @@ m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*reset
|
||||
@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)
|
||||
@clearFunc: function to clear the state of a worker before terminating (optional)
|
||||
*/
|
||||
#define m_worker_init(...) m_worker_init(M_DEFAULT_ARGS(5, (0, 0, NULL, NULL), __VA_ARGS__))
|
||||
|
||||
@@ -444,12 +444,12 @@ m_worker_clear(m_worker_t g)
|
||||
// Push the terminate order on the queue
|
||||
for(unsigned int i = 0; i < g->numWorker_g; i++) {
|
||||
m_work3r_order_ct w = M_WORK3R_EMPTY_ORDER;
|
||||
// Normaly all worker threads shall be waiting at this
|
||||
// Normally 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.
|
||||
m_work3r_queue_push_blocking (g->queue_g, w, true);
|
||||
}
|
||||
// Wait for thread terminanison
|
||||
// Wait for thread termination
|
||||
for(unsigned int i = 0; i < g->numWorker_g; i++) {
|
||||
m_thread_join(g->worker[i].id);
|
||||
}
|
||||
@@ -532,9 +532,9 @@ m_work3r_spawn_function(m_worker_sync_t block, std::function<void(void *data)> f
|
||||
M_INLINE bool
|
||||
m_worker_sync_p(m_worker_sync_t block)
|
||||
{
|
||||
/* If the number of spawns is greated than the number
|
||||
/* If the number of spawns is greater than the number
|
||||
of terminated spawns, some spawns are still working.
|
||||
So wait for terminaison */
|
||||
So wait for termination */
|
||||
return (atomic_load(&block->num_spawn) == atomic_load (&block->num_terminated_spawn));
|
||||
}
|
||||
|
||||
@@ -542,7 +542,7 @@ m_worker_sync_p(m_worker_sync_t block)
|
||||
M_INLINE void
|
||||
m_worker_sync(m_worker_sync_t block)
|
||||
{
|
||||
M_WORK3R_DEBUG ("Waiting for thread terminasion.\n");
|
||||
M_WORK3R_DEBUG ("Waiting for thread termination.\n");
|
||||
// Fast case: all workers have finished
|
||||
if (m_worker_sync_p(block)) return;
|
||||
// Slow case: perform a locked wait to put this thread to waiting state
|
||||
@@ -574,7 +574,7 @@ m_worker_count(m_worker_t g)
|
||||
|
||||
/* Spawn the 'core' block computation into another thread if
|
||||
a worker thread is available. Compute it in the current thread otherwise.
|
||||
'block' shall be the initialised synchronised block for all threads.
|
||||
'block' shall be the initialised synchronized block for all threads.
|
||||
'input' is the list of input variables of the 'core' block within "( )"
|
||||
'output' is the list of output variables of the 'core' block within "( )"
|
||||
Output variables are only available after a synchronisation block.
|
||||
|
||||
Loaded 100 of 163 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user