92 Commits
Author SHA1 Message Date
Patrick Pelissier 66d2aa26d3 Fix clang warning 2024-05-15 21:19:43 +02:00
Patrick Pelissier 1ae904dff2 Add support of INITçWITH for variant
in C11 / provided all types of the variant are exclusive.
2024-05-15 20:46:20 +02:00
Patrick Pelissier 4549f4ab91 Improve comments 2024-05-14 21:29:47 +02:00
Patrick Pelissier 75d5627378 Simplify logic and should increase performance 2024-05-13 23:25:11 +02:00
Patrick Pelissier 8cbd27e629 Fix overflow 2024-05-12 22:59:58 +02:00
Patrick Pelissier 333cc2ccf8 Provide prefetch on non GCC target & compatible 2024-05-12 22:59:58 +02:00
Patrick Pelissier 000dba1da5 Correct API documentation 2024-05-11 09:43:20 +02:00
Patrick Pelissier 11946f155d Update 2024-05-11 09:21:10 +02:00
Patrick Pelissier 99713e873c Add example of multi B+Tree 2024-05-11 09:19:10 +02:00
Patrick Pelissier ea5c993ff0 Add bulk_update for DICT OA 2024-05-09 19:28:46 +02:00
Patrick Pelissier 22d62f94bb Add WIP bulk functions for DICT/OA 2024-05-09 14:10:22 +02:00
Patrick Pelissier 8fd79f07d5 Mark the functions to be optimized
those that shall not be.
2024-05-07 10:05:49 +02:00
Patrick Pelissier 29fe80a6af Adding M_HOT_ATTRIBUTE 2024-05-07 10:05:23 +02:00
Patrick Pelissier e787b64978 Fix issue in C wrapper 2024-05-07 09:51:33 +02:00
Patrick Pelissier 4f9db5eba6 Remove unused header 2024-05-07 08:20:59 +02:00
Patrick Pelissier db5990de03 DICT:
* Reduce  memory allocation usage
2024-05-05 19:26:07 +02:00
Patrick Pelissier d4383ef854 DICT:
* Reduce  memory allocation usage
* Add more assertions
2024-05-05 11:32:28 +02:00
Patrick Pelissier d10c8c1b41 Fix comment 2024-05-05 10:18:26 +02:00
Patrick Pelissier 3c669548a2 Update to dev version 0.7.3 2024-05-04 19:56:51 +02:00
Patrick Pelissier ec11230b5e Fix shrink_to_fit for dict 2024-05-03 19:16:51 +02:00
Patrick Pelissier 567473869b Update documentation 2024-05-03 16:42:51 +02:00
Patrick Pelissier 0b6733fdcb Ass _reserve method for standard dict 2024-05-03 16:40:35 +02:00
Patrick Pelissier 8e330862e1 [Coverage] Adding missing tests 2024-05-03 10:03:22 +02:00
Patrick Pelissier b2adc77d76 Update issues 2024-05-02 22:47:03 +02:00
Patrick Pelissier 82cbe9e282 Reformat 2024-05-02 17:12:48 +02:00
Patrick Pelissier 93429c8bf3 Simplify GET OA_DICT code 2024-05-02 16:25:03 +02:00
Patrick Pelissier 150bef4d4d Add more assertion and control for new dict. 2024-05-02 14:05:00 +02:00
Patrick Pelissier 562fd875e9 Improve test suite 2024-05-02 14:04:38 +02:00
Patrick Pelissier 5513a9df1b Fix issue in new dict for case of erase all / reset scenario 2024-05-02 01:15:15 +02:00
Patrick Pelissier 6fd2610eec Fix valgrind warning 2024-05-01 23:39:49 +02:00
Patrick Pelissier 11bf5e4691 Fix C++ compatibility and compound literals... 2024-05-01 23:08:29 +02:00
Patrick Pelissier cf0d82a706 Update 2024-05-01 22:57:33 +02:00
Patrick Pelissier b0cc17ea86 Update documentation with newest dictionary properties 2024-05-01 22:56:14 +02:00
Patrick Pelissier 04d4bf6866 Complete new version of normal dictionary :
* limits: max elements is 0.75*2^32
* much faster
* use less memory
2024-05-01 22:39:36 +02:00
Patrick Pelissier 738123d4a7 Fix the example 2024-05-01 22:17:59 +02:00
Patrick Pelissier a3ece09e66 Add new tests for exception and bitsets 2024-04-29 22:44:02 +02:00
Patrick Pelissier 8109c094db Update comments 2024-04-29 22:43:46 +02:00
Patrick Pelissier 2c81582419 Improve static analyzer report 2024-04-29 22:35:27 +02:00
Patrick Pelissier f8c79d9259 Add support for exception for emplace function for list/array 2024-04-27 09:04:47 +02:00
Patrick Pelissier c7a894b34e Fix format 2024-04-27 09:04:20 +02:00
Patrick Pelissier 5c36e045ff Add proper support for exception for DEQUE 2024-04-27 08:55:51 +02:00
Patrick Pelissier 0f883d2ecf Simplify code 2024-04-26 23:59:11 +02:00
Patrick Pelissier 9dfcf41b64 Improve detection of error 2024-04-23 21:14:36 +02:00
Patrick Pelissier 1416f4e225 Fix issue 2024-04-23 21:13:37 +02:00
Patrick Pelissier 16c6a13fb1 Make string functions exception aware 2024-04-22 23:41:23 +02:00
Patrick Pelissier 9382cdc0f7 Improve exception integration tests 2024-04-22 23:00:04 +02:00
Patrick Pelissier ced2719760 Make string functions exception aware 2024-04-22 22:59:54 +02:00
Patrick Pelissier 1798530284 Fix issue in string_fgets
where it could be blocked infinity in the parsing
2024-04-22 22:51:59 +02:00
Patrick Pelissier 68f890a015 Improve exception integration tests 2024-04-22 22:47:11 +02:00
Patrick Pelissier 5805038943 Make string functions exception aware 2024-04-22 22:47:00 +02:00
Patrick Pelissier 2395ceb3d2 Remove obsolete and undocumented STRING_DECL_INIT macro 2024-04-20 00:42:38 +02:00
Patrick Pelissier 2b455c5c6b Fix test issue in C++ 2024-04-20 00:42:07 +02:00
Patrick Pelissier d466e76702 Factorize common test function 2024-04-13 08:19:05 +02:00
Patrick Pelissier 9d33c85e13 Fix issue in _push_front_new
Make list services compatible with exception
2024-04-13 08:02:07 +02:00
Patrick Pelissier 4e24e7a533 Improve exception integration tests 2024-04-13 08:01:36 +02:00
Patrick Pelissier 0914c26b8d Update test suite
testing more functions in exception scenario
2024-04-11 01:00:06 +02:00
Patrick Pelissier c245285123 Make more array/list functions exception aware 2024-04-11 00:55:47 +02:00
Patrick Pelissier be4ff6f94d Make list functions exception aware 2024-04-08 23:12:23 +02:00
Patrick Pelissier aa055d0b00 Add tests for exception + lists 2024-04-08 23:10:14 +02:00
Patrick Pelissier e7d6e0d6ac Generate dependency for new files 2024-04-08 23:08:39 +02:00
Patrick Pelissier 8f97a194ae Add m_volatile 2024-04-08 23:08:16 +02:00
Patrick Pelissier b191baec8b Make array functions exception aware 2024-04-06 19:14:36 +02:00
Patrick Pelissier e4a85cdc61 Add tests for exception+array 2024-04-06 19:13:38 +02:00
Patrick Pelissier 12ee3213b0 Simplify M_ON_EXCEPTION / M_IF_EXCEPTION 2024-04-06 19:13:08 +02:00
Patrick Pelissier 6cba7ad8ba Update 2024-04-06 19:12:35 +02:00
Patrick Pelissier 955c8bfb81 Adding new example of generic 2024-04-04 22:35:08 +02:00
Patrick Pelissier 8602a259fd Adding let & print as synonymous in m-generic mode 2024-04-04 22:31:27 +02:00
Patrick Pelissier 7404e63b53 Fix C++ / G++ introduced issue 2024-03-31 22:22:41 +02:00
Patrick Pelissier c539eb57b7 Prepare exception aware integration 2024-03-31 21:55:02 +02:00
Patrick Pelissier 3c4943015b Fix introduced issue with TCC 2024-03-27 00:28:06 +01:00
Patrick Pelissier c9fef6d80a Fix issues in reworked lock:
* starving of writer threads by reader threads
* monopolization of memory bus by reader threads.
2024-03-26 23:11:57 +01:00
Patrick Pelissier 5174781a7a Improve internal backoff to perform
lazy initialization of the seed.
2024-03-26 23:11:03 +01:00
Patrick Pelissier 7bf9f6a377 Update comments 2024-03-26 22:47:13 +01:00
Patrick Pelissier 7575681e27 Rewrite Read / Write lock to be less costly 2024-03-26 22:41:41 +01:00
Patrick Pelissier cfab3cf0cf Add m_mutex_trylock function 2024-03-26 22:41:04 +01:00
Patrick Pelissier a523a97a0e Update doc 2024-03-18 22:44:53 +01:00
Patrick Pelissier 6f75bb938b Update doc 2024-03-18 22:32:16 +01:00
Patrick Pelissier a22046bc2a Update doc 2024-03-15 14:40:47 +01:00
Patrick Pelissier 84ee15b2e7 Remove workaround
This header is already quite demanding on compiler compliance , so there is no need to implement workaround for old compilers.
2024-03-15 14:40:36 +01:00
Patrick Pelissier fd6a8f1361 Update doc 2024-03-14 23:27:23 +01:00
Patrick Pelissier d22e75d7a0 Make I/O functions exception aware.
Simplify their logic
Fix other bugs.
2024-03-08 00:15:08 +01:00
Patrick Pelissier ca25dfb537 Add missing TYPE operator name in the error message if it is missing in the oplist 2024-02-27 01:12:29 +01:00
Patrick Pelissier e2159109b3 Update analysis of issues 2024-02-24 12:17:30 +01:00
Patrick Pelissier cc6bdbf06c Add missing method name in the error message
if the method is missing.
2024-02-23 22:52:05 +01:00
PpHd cd37efc69d Merge pull request #115 from derskythe/feat-styled-readme
Refine explanations and improve formatting in README.md
2024-02-08 13:32:47 +01:00
DerSkythe db08e62f1a Fix incorrect word-wrap of defines 2024-02-08 15:31:52 +04:00
DerSkythe 3be653d55a Improve README.md formatting and clarifications
Corrections were made according PR #115
2024-02-08 11:48:40 +04:00
DerSkythe e351730ad0 Refine explanations and improve formatting in README.md
Several corrections and readability enhancements were applied to the README.md file. This includes fixing typos, changing the format of code examples, refining links to sections, and adjusting the indenting of API documentation listings for better readability. General explanations and instructions about the API usage and the constructor and destructor behavior were also improved.
2024-02-07 00:58:25 +04:00
Patrick Pelissier d7a232364f Update infrastructure to the fact that the bench directory has been deleted 2024-01-19 22:27:33 +01:00
Patrick Pelissier f7580e7ce9 Move bench directory to https://github.com/P-p-H-d/c-stl-comparison
since it is better to have the comparison centralized in one place.
2024-01-19 21:53:20 +01:00
Patrick Pelissier 26cec1591a * Remove some obsolete macros
* Fix spelling
* A little bit of refactoring
2024-01-19 21:37:47 +01:00
Patrick Pelissier 52b58c5a51 Happy new year 2024 2024-01-19 21:37:47 +01:00
153 changed files with 7608 additions and 16425 deletions

No files matched your search

+2 -3
View File
@@ -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,7 +34,7 @@ DESTDIR=
# Package name & version.
PACKAGE=m_lib-$(VERSION)
VERSION=0.7.2
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-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
@@ -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'
+4509 -4389
View File
File diff suppressed because it is too large. Load diff
-512
View File
@@ -1,512 +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-thread.exe -lpthread
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${BOOST}" bench-boost.cpp common.c -o bench-boost.exe -lpthread
@./bench-boost.exe 42
@./bench-boost.exe 41
@./bench-boost-thread.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
# VERSTABLE shall point to the source directory of VERSTABLE (where the headers are)
bench-verstable:
@if test -n "$${VERSTABLE}" ; then $(MAKE) bench-verstable0 ; else echo "Nothing to be done for VERSTABLE." ; fi
bench-verstable0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${VERSTABLE}/ bench-verstable.c common.c -o bench-verstable.exe
@./bench-verstable.exe 40
@./bench-verstable.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
-140
View File
@@ -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);
}
-200
View File
@@ -1,200 +0,0 @@
#define NDEBUG
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "m-thread.h"
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/lockfree/queue.hpp>
#include "common.h"
using namespace std;
/********************************************************************************************/
static void
test_dict2(size_t n)
{
boost::unordered_flat_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++) {
boost::unordered_flat_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)
{
boost::unordered_flat_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++) {
boost::unordered_flat_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; }
};
inline std::size_t hash_value(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)
{
boost::unordered_flat_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());
boost::unordered_flat_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)
{
boost::unordered_flat_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();
boost::unordered_flat_map<string, string>::iterator it = dict.find(s1);
if (it != dict.end())
s ++;
}
g_result = s;
}
/********************************************************************************************/
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[] = {
{ 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},
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
};
int main(int argc, const char *argv[])
{
test("BOOST", numberof(table), table, argc, argv);
exit(0);
}
-204
View File
@@ -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);
}
-266
View File
@@ -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);
}
-96
View File
@@ -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);
}
-183
View File
@@ -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);
}
-144
View File
@@ -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);
}
-138
View File
@@ -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);
}
-138
View File
@@ -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);
}
-101
View File
@@ -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;
}
-139
View File
@@ -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);
}
-202
View File
@@ -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);
}
-123
View File
@@ -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);
}
-202
View File
@@ -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);
}
-170
View File
@@ -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);
}
-116
View File
@@ -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);
}
-74
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
-99
View File
@@ -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);
}
-90
View File
@@ -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;
}
-269
View File
@@ -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);
}
-113
View File
@@ -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);
}
-179
View File
@@ -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);
}
-185
View File
@@ -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);
}
-159
View File
@@ -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);
}
-96
View File
@@ -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);
}
-122
View File
@@ -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);
}
-193
View File
@@ -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);
}
-278
View File
@@ -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);
}
-323
View File
@@ -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
-221
View File
@@ -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);
}
-215
View File
@@ -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);
}
-94
View File
@@ -1,94 +0,0 @@
#define NDEBUG
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "m-core.h"
#include "common.h"
#define NAME umap_ulong
#define KEY_TY unsigned long
#define VAL_TY unsigned long
#include "verstable.h"
static void
test_dict(size_t n)
{
umap_ulong dict;
umap_ulong_init(&dict);
for (size_t i = 0; i < n; i++) {
unsigned long value = rand_get();
unsigned long key = rand_get();
umap_ulong_insert(&dict, key, value);
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
umap_ulong_itr it = umap_ulong_get(&dict, rand_get());
if (!umap_ulong_is_end(it) )
s += it.data->val;
}
g_result = s;
umap_ulong_cleanup(&dict);
}
/********************************************************************************************/
#ifndef CHAR_ARRAY_SIZE
#define CHAR_ARRAY_SIZE 256
#endif
typedef char char_array_t[CHAR_ARRAY_SIZE];
typedef struct { char_array_t a; } char_encap;// Cannot use char_array_t directly
static bool char_equal_p (const char_encap a, const char_encap b) { return strcmp(a.a,b.a)==0; }
static size_t char_hash(const char_encap a) { return m_core_hash (a.a, strlen(a.a)); }
#define NAME umap_char_array
#define KEY_TY char_encap
#define VAL_TY char_encap
#define HASH_FN char_hash
#define CMPR_FN char_equal_p
#include "verstable.h"
static void
test_dict_big(size_t n)
{
umap_char_array dict;
umap_char_array_init(&dict);
for (size_t i = 0; i < n; i++) {
char_encap s1, s2;
sprintf(s1.a, "%u", rand_get());
sprintf(s2.a, "%u", rand_get());
umap_char_array_insert(&dict, s1, s2);
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
char_encap s1;
sprintf(s1.a, "%u", rand_get());
umap_char_array_itr it = umap_char_array_get(&dict, s1);
if (!umap_char_array_is_end(it) )
s ++;
}
g_result = s;
umap_char_array_cleanup(&dict);
}
/********************************************************************************************/
const config_func_t table[] = {
{ 40, "dict", 1000000, 0, test_dict, 0},
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
};
int main(int argc, const char *argv[])
{
test("CTL", numberof(table), table, argc, argv);
exit(0);
}
-42
View File
@@ -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
View File
@@ -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
View File
@@ -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
-71
View File
@@ -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();
}
-22
View File
@@ -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
-344
View File
@@ -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;
}
-266
View File
@@ -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
View File
@@ -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;
}
-53
View File
@@ -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
-22
View File
@@ -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
-73
View File
@@ -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);
}
-53
View File
@@ -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);
}
-33
View File
@@ -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 *~
-8
View File
@@ -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
-34
View File
@@ -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
View File
@@ -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
+132 -41
View File
@@ -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
@@ -47,24 +80,51 @@ of the GAIA by adding support for identification of specialization like this:
==> self shall be the destination?
- How to initialize the specialization field of the container? provide custom initialization functions? It seems to be the hard point.
* INIT: Force a default to NULL ?
* INIT_SET: Force the same value than the src? We may want another pool!
* INIT_MOVE: Force the same value than the src. Mandatory
* MOVE: Assume the same value. Mandatory
* SET: Use the already define pool
* INIT_WITH: Force a default to NULL?
==> init_emplace ?
-- How can we handle containers that allocate on initialization? It cannot, so this solution seems broken
==> Modify constructor prototype to add allocators (except for MOVE/INIT_MOVE)
* INIT(dest) ==> INIT(dest, context)
* INIT(dest, src) ==> INIT_SET(dest, context, src)
* INIT_WITH(dest, ...) ==> INIT_WITH(dest, context, ...)
* INIT emplace(dest [custom]) ==> INIT_emplace(dest, context, [custom])
==> How to pass context? Inherited from master container? A CONTEXT may be present in the parent container but the child may not accept CONTEXT... Same than the Heap Allocator is not the same between different types... The allocator of the parent may be different from the one of the child... ==> Force context to be the same ?
==> If a type A uses CONTEXT, all containers constructed from A shall use CONTEXT too
-- Need to use an oplist for context or force basic type?
Use GAIA interface and a local variable with force naming : m_local_context for example.
* TODO #31 : Uniformize parametrisation options of containers :ENHANCEMENT:
** 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
@@ -141,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
@@ -224,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.
@@ -268,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:
@@ -303,19 +367,25 @@ unsigned get_small_hash(int64_t x) {
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.
@@ -367,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:
@@ -387,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
@@ -410,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
@@ -426,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
@@ -446,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
@@ -484,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:
@@ -510,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:
@@ -547,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
@@ -621,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
+1
View File
@@ -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
+55
View File
@@ -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);
}
+11 -10
View File
@@ -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);
+117
View File
@@ -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 -1
View File
@@ -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:
+36 -17
View File
@@ -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:
@@ -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 *********************************/
+2 -2
View File
@@ -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
+7 -4
View File
@@ -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)
{
+56 -71
View File
@@ -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)
@@ -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 */ ) \
+28 -28
View File
@@ -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; \
} \
+11 -11
View File
@@ -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);
}
+37 -55
View File
@@ -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:
@@ -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); \
} \
+232 -139
View File
@@ -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 2
#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,12 +479,12 @@ 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.
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 usefull to terminate with a proper error message rather than
Quite useful to terminate with a proper error message rather than
a garbage of error due to incorrect code generation in the methods
expansion.
*/
@@ -467,7 +497,7 @@ 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.
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
C11 static Assert is not usable in expression,
@@ -476,7 +506,7 @@ M_BEGIN_PROTECTED_CODE
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
explicity precense of the macro static_assert.
explicitly presence of the macro static_assert.
*/
#ifdef __cplusplus
# define M_STATIC_ASSERT(cond, error, msg) \
@@ -518,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.
@@ -760,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)
@@ -903,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:
@@ -1398,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.
*/
@@ -1497,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()
@@ -1515,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__)))
@@ -1534,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.
@@ -1741,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:
@@ -1804,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:
@@ -2314,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)
@@ -2368,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) \
@@ -2456,7 +2480,7 @@ done
#define M_ID(...) __VA_ARGS__
/* Globber the input */
/* Remove the input from preprocessing evaluation */
#define M_EAT(...)
@@ -2477,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)
@@ -2488,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)
@@ -2680,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
@@ -2828,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))
@@ -2884,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
@@ -2913,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
@@ -3449,78 +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_SUBTYPE_PTR(...) M_GET_METHOD(SUBTYPE_PTR, 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__)
@@ -3590,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
@@ -3739,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_ASSERT(false, 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_ASSERT(false, 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.
@@ -3783,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.
@@ -4252,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 **********************/
/************************************************************/
@@ -4362,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.
@@ -4482,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,
@@ -4990,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.
@@ -5004,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 */
@@ -5027,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;
+51 -69
View File
@@ -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); \
} \
}
+867 -646
View File
File diff suppressed because it is too large. Load diff
+3 -3
View File
@@ -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,7 +105,7 @@
*
* 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 */
+8 -23
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Generic 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:
@@ -82,6 +82,9 @@
#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__))
@@ -109,24 +112,6 @@
#define m_typeof(x) typeof(x)
#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
// 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, \
@@ -183,7 +168,7 @@ typedef const char **m_g3n_cstring_end;
// which takes one argument.
#define M_G3N_CALL_1(op, x) \
M_G3N_BEGIN_PROTECTED_CODE \
_Generic( ((void)0, (x)), \
_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
@@ -247,7 +232,7 @@ typedef const char **m_g3n_cstring_end;
// which takes one argument, it_type
#define M_G3N_CALL_1i(op, x) \
M_G3N_BEGIN_PROTECTED_CODE \
_Generic( ((void)0, (x)), \
_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
@@ -268,7 +253,7 @@ typedef const char **m_g3n_cstring_end;
// 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( ((void)0, (x)), \
_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
@@ -329,7 +314,7 @@ typedef const char **m_g3n_cstring_end;
( M_FPRINT_ARG_OUT_STR(f, M_PAIR_2 x, M_PAIR_1 x), \
M_FPRINT_ARG_G3N(f, x) )
/* Ovverride M_PRINT */
/* 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)
+2 -2
View File
@@ -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
+3 -3
View File
@@ -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(...) \
@@ -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; \
} \
+4 -4
View File
@@ -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,11 +46,11 @@ 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) = 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) \
M_ATOMIC_VAR_INIT(0)
@@ -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 */
+141 -90
View File
@@ -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:
@@ -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
View File
@@ -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 -1
View File
@@ -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:
+3 -3
View File
@@ -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, ...) \
+32 -38
View File
@@ -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:
@@ -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
View File
@@ -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
View File
@@ -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 */
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* 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:
+13 -13
View File
@@ -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, ...) \
@@ -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 */
+47 -40
View File
@@ -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)
@@ -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), \
@@ -2524,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); \
} \
\
@@ -2770,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
+30 -6
View File
@@ -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)
{
+78 -86
View File
@@ -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; \
+23 -8
View File
@@ -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 -1
View File
@@ -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:
+59 -30
View File
@@ -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); \
}
@@ -776,6 +780,8 @@ M_INLINE void \
NAME(name), \
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
View File
@@ -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.
+1 -1
View File
@@ -1,4 +1,4 @@
REM Copyright (c) 2017-2023, Patrick Pelissier
REM Copyright (c) 2017-2024, Patrick Pelissier
REM All rights reserved.
REM
REM Redistribution and use in source and binary forms, with or without
+4 -4
View File
@@ -86,7 +86,7 @@ all:
depend:
$(RM) depend
echo "" > depend
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.depend/g'`
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.depend/g'` `ls except-*.c|$(SED) 's/\.c/\.depend/g'`
$(CXX) --version 2> /dev/null && $(MAKE) `ls check-*.cpp|$(SED) 's/\.cpp/\.depend/g'` || echo "Skip C++ tests"
cat *.depend > depend
$(RM) *.depend
@@ -102,7 +102,7 @@ exe: depend
@echo All executable generated
check: depend
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'` `ls fail-*.c|$(SED) 's/\.c/\.log.err/g'` CC="$(CC)" CFLAGS="$(CFLAGS)"
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'` `ls fail-*.c|$(SED) 's/\.c/\.log.err/g'` `ls except-*.c|$(SED) 's/\.c/\.log/g'` CC="$(CC)" CFLAGS="$(CFLAGS)"
@echo All tests passed
check-stl: depend
@@ -254,9 +254,9 @@ sanitize:
.c.analyzer:
awk '/START_COVERAGE/ { printit=1} (printit == 0) { print }' $< > $<.first.c
awk ' printit { print } /END_COVERAGE/ { printit=1}' $< > $<.end.c
$(CC) $(CPPFLAGS) -E -DNDEBUG -DWITHIN_COVERAGE $< |grep -v '^#' |awk ' /END_COVERAGE/ { printit=0} printit { print } /START_COVERAGE/ { printit=1 }' |perl -p -e "s/;(?![\"'])/;\n/g ; s/}(?![\"'])/}\n/g ; s/{(?![\"'])/{\n/g" > $<.middle.c
$(CC) $(CPPFLAGS) -E -DWITHIN_ANALYZER $< |grep -v '^#' |awk ' /END_COVERAGE/ { printit=0} printit { print } /START_COVERAGE/ { printit=1 }' |perl -p -e "s/;(?![\"'])/;\n/g ; s/}(?![\"'])/}\n/g ; s/{(?![\"'])/{\n/g" > $<.middle.c
cat $<.first.c $<.middle.c $<.end.c > $<.c
$(CC) $(CPPFLAGS) -fanalyzer -Wall -W -Wno-analyzer-malloc-leak -O2 -g $<.c -o $<.exe 2> `basename $< .c`.analyzer $(LDFLAGS)
$(CC) $(CPPFLAGS) -fanalyzer -Wall -W -Wno-analyzer-malloc-leak -Wno-stringop-truncation -O2 -g $<.c -o $<.exe 2> `basename $< .c`.analyzer $(LDFLAGS)
$(RM) $<.first.c $<.end.c $<.middle.c $<.c $<.exe
analyze:
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2023, Patrick Pelissier
* Copyright (c) 2021-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 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2023, Patrick Pelissier
* Copyright (c) 2021-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 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2023-2023, Patrick Pelissier
* Copyright (c) 2021-2024-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 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2023, Patrick Pelissier
* Copyright (c) 2021-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 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2023, Patrick Pelissier
* Copyright (c) 2021-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 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2023 Patrick Pelissier
* Copyright (c) 2021-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 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2023, Patrick Pelissier
* Copyright (c) 2021-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 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2023-2023, Patrick Pelissier
* Copyright (c) 2021-2024-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:
Loaded 100 of 153 files, more files were not shown because too many files have changed in this diff. Show more