346 Commits
Author SHA1 Message Date
Patrick Pelissier 43fdd10e77 Release 0.7.0 2022-12-27 20:01:44 +01:00
Patrick Pelissier b1183de0f8 Update example to allow more example of promotion. 2022-12-25 23:12:02 +01:00
Patrick Pelissier 3a3ef7454c Fix conflict issue between INIT_WITH_VAI macro and API transformation.
Since both used M_MAP2_C macro, the final expansion was stopped if an
API generic transformation was requested in INIT_WITH_VAI.
Duplicate M_MAP2_C internally for API transformation.
2022-12-24 23:04:42 +01:00
Patrick Pelissier 5f946b728b Update example to include more integration of the different features
(enabling to test more).
2022-12-24 23:03:48 +01:00
Patrick Pelissier 9cc03ff81b Add macro M_INIT_WITH_THROUGH_EMPLACE_TYPE that provides an INIT_WITH
method that scans the different methods provided in EMPLACE_TYPE and
try to search for a matching one.
2022-12-23 11:49:08 +01:00
Patrick Pelissier 89d4db174e Fix format 2022-12-23 11:48:15 +01:00
Patrick Pelissier f5bbc0a7fb Implement multiple kind of workarounds for GCC 12
as it produces more false warnings

Include missing header in C++ mode
2022-12-22 20:42:20 +01:00
Patrick Pelissier 9da0d1d94b Add new internal macro M_TAIL_3 2022-12-22 15:49:10 +01:00
Patrick Pelissier fafaaafdbf Avoid warning for M_RET_ARG if there is the exact number of argument.
Add internal M_TRIPLE_* macros (TBC)
2022-12-22 14:05:46 +01:00
Patrick Pelissier 38f4107b19 Support of keyptr /valueptr iterator 2022-12-04 23:39:42 +01:00
Patrick Pelissier cbefdab4bb Add check of B+TREE map against C++ map 2022-12-04 21:26:20 +01:00
Patrick Pelissier bcd0c46e8b Simplify & factorize the instances of the check against C++ 2022-11-30 23:56:29 +01:00
Patrick Pelissier f25bb73e58 Add comparison to C++ unorder_map 2022-11-30 00:30:45 +01:00
Patrick Pelissier ea3584e048 Rename internal macro to internal namespace 2022-11-29 23:16:55 +01:00
Patrick Pelissier 85473610a4 Update doc 2022-11-22 22:51:40 +01:00
Patrick Pelissier f9f0b307fc Provide even shorter example using EMPLACE_TYPE 2022-11-10 13:50:00 +01:00
Patrick Pelissier d17fa4530b Update comments 2022-11-05 13:36:57 +01:00
Patrick Pelissier 3806495e2d Fix spelling 2022-11-04 10:41:38 +01:00
Patrick Pelissier 15f58d5738 Update example comments. 2022-10-23 21:01:44 +02:00
Patrick Pelissier 4de7da1c05 Adding bench for emhash
https://github.com/ktprime/emhash
2022-10-15 10:24:18 +02:00
Patrick Pelissier 93229c61f2 Update comments 2022-10-12 23:26:33 +02:00
Patrick Pelissier 3f0e8956b8 Add emplace method for buffer. 2022-10-11 22:47:14 +02:00
Patrick Pelissier b82670b643 Add emplace support for concurrent. 2022-10-10 23:08:30 +02:00
Patrick Pelissier 64800dbd3f Use of type from oplist rather than meta name
(more coherent)
2022-10-10 23:06:02 +02:00
Patrick Pelissier 2d9d9fbd9f Remove obsolete macros 2022-10-10 22:54:48 +02:00
Patrick Pelissier f0ba5d17f4 Rework fuzzer support to be fully generic. 2022-10-10 22:47:43 +02:00
Patrick Pelissier e51c988222 Add initial support for fuzzing 2022-10-07 23:39:54 +02:00
Patrick Pelissier 0be3900beb Enable support for external testsuite from stdin
instead of pseudo random values.
This will enable to connect it to a fuzzer.
2022-10-07 23:28:12 +02:00
Patrick Pelissier f60ce0320a Port to new API version of STC. 2022-10-07 22:47:53 +02:00
Patrick Pelissier 77008b8622 Fix leak of memory in non optimized _safe_get
of B+Tree.
2022-10-03 23:07:13 +02:00
Patrick Pelissier a7617002c5 Update documentation for emplace generation. 2022-10-03 22:54:42 +02:00
Patrick Pelissier bc73616bde Add test cases for emplace generation
for dict & B+tree
2022-10-03 22:40:44 +02:00
Patrick Pelissier d6b9b054c2 Fix emplace generation
(incorrect value oplist)
2022-10-03 22:34:13 +02:00
Patrick Pelissier 9eed4be97c Add emplace support for B+Tree 2022-10-03 22:16:50 +02:00
Patrick Pelissier 2519927178 Fix build in case of no MPFR and warnings are treated as errors. 2022-10-02 22:31:50 +02:00
Patrick Pelissier 0fec33b38e * Add emplace generation for dict/hashmap.
(still need more tests).
* Factorize emplace generation for R+TREE/Prioqueue
2022-10-02 22:24:22 +02:00
Patrick Pelissier dc2b6d2b2d Fix detection of GMP / MPFR. 2022-10-02 22:16:45 +02:00
Patrick Pelissier bc63edc595 Fix emplace generation for asso array 2022-10-02 21:41:21 +02:00
Patrick Pelissier 6241a3093c Factor comments. 2022-10-02 21:35:52 +02:00
Patrick Pelissier fb53a464d7 Update comments 2022-10-01 20:41:45 +02:00
Patrick Pelissier aba26b75a2 Fix chapter in documentation 2022-10-01 11:40:23 +02:00
Patrick Pelissier 775ec6f91b Make M_ASSERT_INDEX more robust
in case it is called with a signed integer.
The trick was using x-x to represent 0 so that
the compiler won't complain with the comparaison
x >= 0 when it is called with unsigned number.
2022-10-01 11:38:11 +02:00
Patrick Pelissier 95bc7063a0 Remove some warning with clang:
it complains about using a GNU extension
in GNU mode (gnu11)!
2022-10-01 11:36:14 +02:00
Patrick Pelissier 731d3ecf1a Update error chapter of the documentation 2022-10-01 09:50:38 +02:00
Patrick Pelissier 0d1817e7ca Add tiny example of no stdio support. 2022-10-01 09:50:24 +02:00
Patrick Pelissier 1a5b428bfb Fix proper support of no stdio
and add macro M_RAISE_FATAL to raise a fatal error
with the default is using stdio.
2022-10-01 09:50:09 +02:00
Patrick Pelissier bd49e31f3b Add definition macros for emplace/associative array container. 2022-09-29 23:48:46 +02:00
Patrick Pelissier 2dba83e3c5 Remove M_USE_STDLIB
(It wasn't working at all).
2022-09-28 22:16:04 +02:00
Patrick Pelissier 75e9766da9 Fix wrong generation for emplace / value 2022-09-26 23:43:39 +02:00
Patrick Pelissier d2f8aa1c0d Update documentation. 2022-09-25 22:15:44 +02:00
Patrick Pelissier 4aa4b7693f Add M_C5_EMPTY macro
Add M_CROSS_MAP2 macro
Add emplace generation  for associative array if both key & value are emplace types
Add test cases.
2022-09-25 22:13:51 +02:00
Patrick Pelissier d50b450927 Update documentation. 2022-09-25 00:36:27 +02:00
Patrick Pelissier 5674cdbfc5 Add new macro M_CROSS_MAP
enabling to map a function to each pair
of arguments given two arglists.
2022-09-25 00:30:23 +02:00
Patrick Pelissier 3641829198 M_INC (resp. M_DEC) of M_UNDERFLOW (resp. M_OVERFLOW)
will keep the initial error.
2022-09-16 18:46:13 +02:00
Patrick Pelissier 10a759b09e Add another function for generation 2022-09-15 23:25:42 +02:00
Patrick Pelissier b5a3b36c1b * Add M_C3_EMPTY function.
* Add WIP generator for emplace functions for associative array. What is missing is the hard part (even what is done cannot be said as easy!) Generation of both N x M functions. It probably needs a new MAP function for this.
2022-09-15 23:25:38 +02:00
Patrick Pelissier b0c3839f2b Add serial methods in documentation. 2022-09-15 21:39:17 +02:00
Patrick Pelissier 3aa3e95e4c Remove constraint of calling string_end_p
before string_next or string_get_cref
This generates slighty more code but it is much saner
from user point of view.
2022-09-13 00:18:15 +02:00
Patrick Pelissier 87f1e53e13 Add more basic iteration code generation analysis 2022-09-13 00:03:40 +02:00
Patrick Pelissier d7b45cc220 Fix issue in string_previous 2022-09-11 23:14:52 +02:00
Patrick Pelissier d8142a9764 Add precision on documentation. 2022-09-10 16:38:27 +02:00
Patrick Pelissier 8780f58739 Fix description of string_unocde_t 2022-09-10 16:35:38 +02:00
Patrick Pelissier e352104df8 Update documentation with new function. 2022-09-10 16:30:57 +02:00
Patrick Pelissier cbb2b452bb Add string_previous function
to iterate on the previous UTF8 code point.
2022-09-10 16:30:45 +02:00
Patrick Pelissier 6e947c6262 Add more corner cases. 2022-09-10 16:21:19 +02:00
Patrick Pelissier 18f04da4ec Robustness/fix:
string_next won't advance if the end of string is reached.
2022-09-10 16:19:58 +02:00
Patrick Pelissier 3dad6ef65c Update string API description. 2022-09-10 16:16:42 +02:00
Patrick Pelissier 41c4f5fe5c Add string functions :
* string_it_get_pos to return the position in the steam
* string_it_pos to start iterating from a given position.
2022-09-10 16:16:13 +02:00
Patrick Pelissier cfeedf19f8 Rework to be more compliant (as far as it is possible)
to real cases.
2022-09-10 15:56:36 +02:00
Patrick Pelissier 2ab410bd6a Update comments to reflect that we work
on UTF8 code points and not Unicode characters.
2022-09-10 10:39:04 +02:00
Patrick Pelissier aefbc5b2f5 Factorize the test of the start of an UTF8 code point
in a separate function
2022-09-10 10:34:54 +02:00
Patrick Pelissier abec9c37fa Clarify API
It iterates over UTF-8 code points, not Unicode characters
They can be different (!)
2022-09-10 10:32:34 +02:00
Patrick Pelissier 442b0e7cea Reduce size of struct string_it_t on 64 bits
by storing an offset to the next character
instead of a pointer. An offset can be stored as a
BYTE instead of a PTR since UT-8 can use at most
4 characters per code point.
2022-09-10 09:59:06 +02:00
Patrick Pelissier 0b853c6d52 Fix bug on bitset_resize function in case of increase of size:
the first limb may not be cleared properly in some cases.
(Reported by David M. Lary)
2022-09-04 19:27:38 +02:00
Patrick Pelissier cc7fc66899 Add bitset_ctz function 2022-08-29 19:31:19 +02:00
Patrick Pelissier 6b994c2928 Add m_core_ctz32 & m_core_ctz64 functions
(Count trailing zeros)
2022-08-29 19:30:09 +02:00
Patrick Pelissier e6fe36d3cd Revert "Perform coverage check by continuous integration tests."
as the numbers of lines generated by the generation macros
(which are included in the coverage measure)
through the C preprocessor depend on the exact version
of the C preprocessor.
There is no reliable way to get a measure on it,
except by always targeting the same compiler.
So, this measure of coverage (number of lines)
is not suitable for CIT. Ratio seems also not reliable enough.

This reverts commit f45ededf8b.
2022-08-22 23:53:10 +02:00
Patrick Pelissier f45ededf8b Perform coverage check by continuous integration tests. 2022-08-20 23:33:48 +02:00
Patrick Pelissier ed27bedcb4 Make coverage perfoms a check that the computed coverage is at least
not lower than the reference coverage, ensuring no regression
on the coverage of the tests can occur.

NOTE: some tests (m-i-shared) perform some dynamic test cases
where the exact coverage depend on the exact dynamic behavior
of the test. And this behavior is not always reproducible
(for exact the calls to m_core_backoff_wait may not occur
if the threads are not trying to grab the resource at the
exact same time).
As such, the reference of such tests is taken from the worst
case of execution of the coverage (with the lowest number
of lines covered).
2022-08-20 23:29:02 +02:00
Patrick Pelissier eb1a7a0435 Add more tests for tree 2022-08-19 23:16:42 +02:00
Patrick Pelissier de00fdc5f7 Update documentation 2022-08-13 23:50:51 +02:00
Patrick Pelissier 8febe12c5c Make stdlib an optional header 2022-08-09 00:20:32 +02:00
Patrick Pelissier 1368b201eb Fix warnings in release mode. 2022-08-09 00:19:55 +02:00
Patrick Pelissier 4ca166b0b9 Update examples to remove warnings with assertion disabled. 2022-08-09 00:19:26 +02:00
Patrick Pelissier c13533cf21 Fix naming 2022-08-08 01:22:05 +02:00
Patrick Pelissier 9fdf0f76e7 Add documentation of generic tree. 2022-08-08 01:20:30 +02:00
Patrick Pelissier 308f513edc As the allocated array offers write access to the index -1
remove if conditions to always access the array even for -1
The term tab[-1] will be filled with no pertinent value, but
we don't care about it.
2022-08-02 23:21:39 +02:00
Patrick Pelissier 900bcc3819 The internal array of the tree always allocates one more term,
so that the index -1 in the array exists and can be written.
2022-08-02 23:02:59 +02:00
Patrick Pelissier b6e0994dfc Add test case for _init_set with empty tree. 2022-08-02 23:02:33 +02:00
Patrick Pelissier 121339d948 Add _move_* functions for generic tree. 2022-08-01 22:17:26 +02:00
Patrick Pelissier c5bb84013a Create _raw methods for insertions. 2022-08-01 22:13:41 +02:00
Patrick Pelissier 65b49268d3 Fix allow_realloc for tree 2022-07-30 16:14:03 +02:00
Patrick Pelissier ecebd62f86 Update API compatibility documentation due to the _str to _cstr suffix change.
Note: the old (& still official) naming for the string functions
is still compatible since we have changed only the new namings (with m_ prefix).
See #99
2022-07-30 12:02:58 +02:00
Patrick Pelissier 6a8c9a703d Rename string functions as per latests changes 2022-07-30 12:02:32 +02:00
Patrick Pelissier ad05ae9aa5 Rename the string _suffix for Bounded Strings from _str to _cstr
See #99
2022-07-30 12:01:36 +02:00
Patrick Pelissier abffe201e5 Change the suffix of the functions dealing with C-String to _cstr
instead of _str.
See #99 for details.
2022-07-30 12:00:55 +02:00
Patrick Pelissier ee2bc27bda Fix issue in serial-bin
Note: this is a classic c error, so it may be interresting to discover
why the static analysis tools didn't report this error.
2022-07-30 04:40:09 +02:00
Patrick Pelissier 14b94865b7 Starting document tree. 2022-07-28 23:25:57 +02:00
Patrick Pelissier 6e1ceafcc2 Add more tests for tree. 2022-07-28 23:22:07 +02:00
Patrick Pelissier 58746560e9 Add comment 2022-07-28 23:21:54 +02:00
Patrick Pelissier 082adca3e6 Add test case 2022-07-27 23:48:59 +02:00
Patrick Pelissier ee1dc2a8e8 Fix issue in _graft_child 2022-07-27 23:48:40 +02:00
Patrick Pelissier 92e2d835bd Add more generic random tests 2022-07-26 23:12:41 +02:00
Patrick Pelissier 22aba04b47 Activate optimisation for coverage 2022-07-26 23:12:19 +02:00
Patrick Pelissier 399c615915 Fix issue in unlink 2022-07-26 23:04:15 +02:00
Patrick Pelissier cbdba0941a Adding more test cases 2022-07-26 22:49:07 +02:00
Patrick Pelissier 90c54a48d0 Remove uneeded test 2022-07-26 22:48:47 +02:00
Patrick Pelissier 22b18830f7 Improve test suite by performing no op swap operation randomly 2022-07-24 21:12:59 +02:00
Patrick Pelissier dab085e3a7 Fix other issue 2022-07-24 21:11:08 +02:00
Patrick Pelissier 66fac10a98 Fix corner case 2022-07-24 21:09:35 +02:00
Patrick Pelissier e5fb5ddde1 Fix some issues in insertion 2022-07-24 20:40:31 +02:00
Patrick Pelissier dcf20fbbd6 Add some tests for swap_at 2022-07-24 00:48:18 +02:00
Patrick Pelissier 5d659877fe Fix some bugs in the swap of node in a tree 2022-07-24 00:47:43 +02:00
Patrick Pelissier a30dd69aaa Add more tests for tree 2022-07-18 23:42:25 +02:00
Patrick Pelissier b1f698bb7b Fix tree _prune function 2022-07-18 23:42:13 +02:00
Patrick Pelissier 2323420a87 Add more test cases 2022-07-15 17:23:56 +02:00
Patrick Pelissier 7e120a3615 Add missing assertions 2022-07-15 16:54:51 +02:00
Patrick Pelissier 804db294ca Update test suite 2022-07-15 16:48:54 +02:00
Patrick Pelissier d12aa6c263 Don't expand tree contract for coverage 2022-07-15 00:32:26 +02:00
Patrick Pelissier d59e87d2bf Adding tests for OUT_STR/IN_STR 2022-07-07 22:21:29 +02:00
Patrick Pelissier 8f3c0af548 Add OUT_STR & IN_STR methods for tree 2022-07-07 22:21:14 +02:00
Patrick Pelissier 1f3013c445 Adding more corner cases 2022-07-07 22:10:00 +02:00
Patrick Pelissier f13e99ab1a Add coverage computation for tree 2022-07-07 22:09:51 +02:00
Patrick Pelissier fb8ad84675 Add more tests 2022-07-05 22:46:24 +02:00
Patrick Pelissier 12608afe10 Fix issue in comparing tree 2022-07-05 22:46:13 +02:00
Patrick Pelissier f97e92b4cb Complement basic tests 2022-07-04 20:47:53 +02:00
Patrick Pelissier a74e26e3de Add random generated insertion in a tree 2022-07-04 20:38:51 +02:00
Patrick Pelissier a30b783692 First basic test of tree container 2022-06-28 23:28:45 +02:00
Patrick Pelissier e64a6a22e7 Fix issues in tree 2022-06-28 23:28:09 +02:00
Patrick Pelissier 76892afa13 Fix some warnings. 2022-06-27 23:35:05 +02:00
Patrick Pelissier dcb1eb0d94 First version of IO for the tree container 2022-06-25 17:29:04 +02:00
Patrick Pelissier 950ea224ff Adding untested classic functions for tree (_init_set, _set, _equal, _hash, ...) 2022-06-18 15:26:19 +02:00
Patrick Pelissier b22a844007 update doc 2022-06-17 22:56:37 +02:00
Patrick Pelissier 502756c731 Simplify the control flow to count for utf8 encoded characters 2022-06-16 23:58:23 +02:00
Patrick Pelissier e38dc19ea1 Add current restriction on worker_spawn 2022-06-15 00:55:41 +02:00
Patrick Pelissier 2bebb2b4a1 Update example with new tree functions 2022-06-13 23:21:06 +02:00
Patrick Pelissier 5b7be93c1a Update tree:
* fix swap and add an additional argument to swap or not the child
* add sort functions for the children of a nodes
2022-06-13 23:21:06 +02:00
Patrick Pelissier d04270ae3f Proper use of API transformation for CMP operator in tuples 2022-06-13 23:21:06 +02:00
Patrick Pelissier 1bef7c1977 Fix formatting 2022-06-13 23:21:06 +02:00
Patrick Pelissier ae037ff7af Fix location of library in makefile 2022-06-13 22:12:56 +02:00
Patrick Pelissier a4267d60df Add usage of emplace with tuple 2022-06-04 23:44:22 +02:00
Patrick Pelissier 47e32ab2b3 Add support for EMPLACE_TYPE in TUPLE generations.
As a consequence, the oplist arguments for TUPLE_OPLIST
are much more rigorous. It shall really be the real oplists
of the types used to create the tuple, otherwise a compilation
error may be generated.
2022-06-04 23:41:18 +02:00
Patrick Pelissier 5ac08e42d8 Adding const for the type generation in emplace 2022-06-04 23:40:36 +02:00
Patrick Pelissier 9c59684b61 Fix the OPLIST args of TUPLE_OPLIST so that the given oplists match the types used for the definition of the tuple 2022-06-04 23:34:46 +02:00
Patrick Pelissier f26e1e5a12 Fix issue in case of recursive call of INIT_WITH with conditionnal INIT_WITH 2022-06-04 23:27:13 +02:00
Patrick Pelissier 1cde4633e6 Adding more corner cases 2022-06-04 23:26:03 +02:00
Patrick Pelissier 1393f8e9aa Update comments 2022-06-04 16:03:06 +02:00
Patrick Pelissier bfffa1d245 Update comments & naming 2022-06-04 16:02:58 +02:00
Patrick Pelissier 3a6b568ccc Update example to count the number of lines 2022-06-04 14:55:32 +02:00
Patrick Pelissier 453a920af8 Add methods to scan in post-order a sub-tree 2022-06-04 14:54:51 +02:00
Patrick Pelissier 1fd86ffc2e Update & fix 2022-06-03 22:59:55 +02:00
Patrick Pelissier 96a0639a8a Add more functions for TREE 2022-06-03 21:43:33 +02:00
Patrick Pelissier c12d0a3f23 Update comments 2022-06-03 21:43:15 +02:00
Patrick Pelissier cac8790405 Start working on example with generic tree 2022-06-01 19:52:28 +02:00
Patrick Pelissier ccd9726e01 Fix some warnings / errors 2022-06-01 19:51:50 +02:00
Patrick Pelissier 5516b50b3a Add WIP / untested generic tree datastructure 2022-05-31 23:00:19 +02:00
Patrick Pelissier b5a3e010d8 Add {} for if 2022-05-26 22:13:24 +02:00
Patrick Pelissier 2d7d267252 Update doc 2022-05-26 18:33:43 +02:00
Patrick Pelissier bd5d7aaada Fix wrong prototype in docs 2022-05-24 23:58:20 +02:00
Patrick Pelissier 18b6be8e00 Update doc 2022-05-24 23:56:34 +02:00
Patrick Pelissier 958abfef93 Make INIT_SET operator optional 2022-05-24 23:30:14 +02:00
Patrick Pelissier 198be1062b Update doc 2022-05-24 23:25:37 +02:00
Patrick Pelissier 0cfee02641 Make INIT operator optional 2022-05-24 23:22:36 +02:00
Patrick Pelissier 48dc38508a Factorize the documentation by using the generic interface (WIP) 2022-05-23 23:49:57 +02:00
Patrick Pelissier e763204bf7 Fix example 2022-05-22 22:54:25 +02:00
Patrick Pelissier 370baf56ab Factorize the documentation by using the generic interface (WIP) 2022-05-22 00:22:36 +02:00
Patrick Pelissier 4fd6bcbf99 Factorize the documentation by using the generic interface (WIP) 2022-05-19 22:41:19 +02:00
Patrick Pelissier 59d1e23dea Factorize the documentation by using the generic interface (WIP) 2022-05-19 22:28:53 +02:00
Patrick Pelissier cb173f2f81 Update doc 2022-05-19 21:45:16 +02:00
Patrick Pelissier d047174c2f Update doc 2022-05-19 21:43:42 +02:00
Patrick Pelissier df25159d03 Add generic interface chapter & start factorizing duplicate specification 2022-05-19 00:30:47 +02:00
Patrick Pelissier 99618a687e Update doc 2022-05-19 00:00:36 +02:00
Patrick Pelissier a1b226e185 Update doc 2022-05-16 23:37:04 +02:00
Patrick Pelissier e93df4332a Fix issue for 16 bits architecture 2022-05-14 09:16:41 +02:00
Patrick Pelissier 5a1f768b03 Update comment about lock-free property 2022-05-14 09:16:41 +02:00
Patrick Pelissier e854bc8fc9 Remove warning in C++ mode for using C++ class 2022-05-12 00:00:10 +02:00
Patrick Pelissier 9ab958708d Update doc:
clarify operators
2022-05-11 23:26:36 +02:00
Patrick Pelissier 85ea92d83b Review of m-core.h
* Add control of MSVC preprocessor
* Add comments
* Remove useless evaluation pass
* Rewrite some evaluation pass to be faster.
2022-05-11 21:38:47 +02:00
Patrick Pelissier 22a406ac51 Add new test case (M_MAP + M_SEQ) 2022-05-11 21:38:47 +02:00
Patrick Pelissier 58eed79413 Register the oplist associated to unsigned 2022-05-04 22:25:15 +02:00
Patrick Pelissier e83dea8212 Fix warnings for Visual C++ 2022-05-10 23:49:20 +02:00
Patrick Pelissier c829827f48 Fix warnings for Visual C++ 2022-05-10 23:34:48 +02:00
Patrick Pelissier b47cf05a59 Update doc 2022-05-10 23:14:47 +02:00
Patrick Pelissier 22a93514ff Add EMPLACE test for priority queue 2022-05-10 23:10:58 +02:00
Patrick Pelissier 154865f0f1 Add EMPLACE support for priority queue 2022-05-10 23:10:44 +02:00
Patrick Pelissier 71151770fd Fix wrong type 2022-05-09 22:55:57 +02:00
Patrick Pelissier 72623ce13e Adding test cases for I/O methods 2022-05-09 22:52:28 +02:00
Patrick Pelissier 94f20d56e9 Adding OUT_STR / IN_STR / PARSE_STR / GET_STR / IN_SERIAL / OUT_SERIAL methods 2022-05-09 22:51:46 +02:00
Patrick Pelissier 9e8ad9bfd9 Fix format 2022-05-09 22:48:56 +02:00
Patrick Pelissier e51a5be776 Add check of prioqueue against STL C++ 2022-05-09 22:25:09 +02:00
Patrick Pelissier 7d647340c6 Update 2022-05-09 22:24:48 +02:00
Patrick Pelissier c6ea3c0616 Fix spelling 2022-05-09 20:16:33 +02:00
Patrick Pelissier 9ab90be6d4 Add check of B+Tree / Set 2022-05-09 20:12:55 +02:00
Patrick Pelissier 10440320d1 Remove IT_REF from exported oplist as the items shall appear as not modifiable by algorithms 2022-05-09 20:12:39 +02:00
Patrick Pelissier fc7e93403a Update copyright year 2022-05-09 20:06:05 +02:00
Patrick Pelissier b0c4418584 Fix M_ALGO_EXTRACT: the source oplist wasn't transformed into a global one. 2022-05-09 20:03:26 +02:00
Patrick Pelissier 5f73eb7788 Add test for support C++ class in M*LIB 2022-05-06 23:08:27 +02:00
Patrick Pelissier a554312573 Update doc 2022-05-06 23:07:10 +02:00
Patrick Pelissier 8a1fd391d1 Fix reverse issue 2022-05-06 01:27:34 +02:00
Patrick Pelissier 95b104ee48 Issue in generation of functions:
if the method in the oplist uses API_* transformation,
if this method is a macro itself,
it may delay the expansion too much and
the macro may not be expanded at all in the final code generation.

Fix issue by adding a supplementary evaluation in the macro expansion.
Add test cases
2022-05-06 01:10:31 +02:00
Patrick Pelissier c3df69d011 Add tests for generic API + macros 2022-05-04 22:16:01 +02:00
Patrick Pelissier 73468a3e24 Update doc 2022-05-02 23:15:58 +02:00
Patrick Pelissier f254f98e42 Update doc 2022-05-02 21:40:49 +02:00
Patrick Pelissier d37076dd37 Update comments 2022-05-02 21:11:12 +02:00
Patrick Pelissier 5ef9376148 Improve example (adding ADD/SUB/MUL/DIV operators 2022-04-29 19:55:29 +02:00
Patrick Pelissier d8abda7583 Fix issue (implicit const cast) 2022-04-29 19:55:02 +02:00
Patrick Pelissier 892c755389 Improve example to show emplace support 2022-04-28 23:10:57 +02:00
Patrick Pelissier aba2f90c9d Add test for emplace generation for variant 2022-04-28 23:10:40 +02:00
Patrick Pelissier dc487c7e64 Add support for EMPLACE_TYPE for variant 2022-04-28 23:10:27 +02:00
Patrick Pelissier 18b1bd9518 Fix makefile if MPFR not found 2022-04-28 23:06:41 +02:00
Patrick Pelissier 845ab1fef0 Update comment 2022-04-28 23:03:04 +02:00
Patrick Pelissier 94bfac3f75 Improve example by adding also mpfr 2022-04-28 22:22:05 +02:00
Patrick Pelissier bd5c9ce2a7 Add MPFR detection 2022-04-28 22:10:36 +02:00
Patrick Pelissier f5934a6274 Add emplace type example 2022-04-27 21:57:28 +02:00
Patrick Pelissier c6f71fddc7 Add test for stable_sort 2022-04-26 21:35:51 +02:00
Patrick Pelissier 74764e2d6f Fix issues in stable_sort: wrong assertion & missing init_move 2022-04-26 21:35:51 +02:00
Patrick Pelissier 9b00a8c54e Update documentation 2022-04-25 22:10:19 +02:00
Patrick Pelissier 66735e99c3 Add check sanitize to Continuous Integration 2022-04-23 10:40:39 +02:00
Patrick Pelissier 80acbb4343 Ensure proper order of commands in case of parallelism 2022-04-23 10:37:42 +02:00
Patrick Pelissier 2fb912d43d Should remove warning with Visual C++ 2022-04-23 10:34:54 +02:00
Patrick Pelissier 8c8dc6de7c Add new example 2022-04-23 10:21:46 +02:00
Patrick Pelissier 677acdd14e Use of new M_INIT_EMPLACE_VAI macro 2022-04-23 10:21:33 +02:00
Patrick Pelissier 6caeea98b9 Add M_INIT_EMPLACE_VAI macro for INIT_WITH containers with emplace support 2022-04-23 10:21:17 +02:00
Patrick Pelissier c5d37ce028 Update comments 2022-04-23 10:03:51 +02:00
Patrick Pelissier 112b405df6 Reformat 2022-04-23 10:01:39 +02:00
Patrick Pelissier 47385d58e5 Update documentation with new generated functions 2022-04-23 09:20:11 +02:00
Patrick Pelissier c8275c8f63 Add test cases for generated emplace functions 2022-04-23 09:19:58 +02:00
Patrick Pelissier 0c1e888a78 Add emplace generation for RB Tree 2022-04-23 09:19:42 +02:00
Patrick Pelissier 6a1ff3e080 Add emplace generation for oplist with CMP operator 2022-04-23 09:18:20 +02:00
Patrick Pelissier 6d41eba5ed Update documentation for emplace functions 2022-04-22 22:51:45 +02:00
Patrick Pelissier c0abcc6d60 Add tests for new emplace functions 2022-04-22 22:51:36 +02:00
Patrick Pelissier da71c81195 Add emplace functions for list / deque 2022-04-22 22:51:17 +02:00
Patrick Pelissier 8e0d17e85c Add test for emplace string_t from const char * 2022-04-21 23:11:24 +02:00
Patrick Pelissier 6d98c273c1 Add EMPLACE_TYPE from const char * 2022-04-21 23:11:11 +02:00
Patrick Pelissier 85f6ff34aa Add test cases for generated emplace functions 2022-04-20 22:43:12 +02:00
Patrick Pelissier 759c24be63 Add request for generation for emplace functions 2022-04-20 22:43:12 +02:00
Patrick Pelissier d85955ef60 Add generation of emplace functions 2022-04-20 22:43:12 +02:00
Patrick Pelissier 3a53044198 Add M_EMPLACE macros to enables generic generation of EMPLACE functions 2022-04-20 22:43:12 +02:00
Patrick Pelissier 4d5cd9c635 Code generation shows no difference between && or & for simple & typical OOR values
So let's use the logical comparaison which is clearer.
2022-04-19 22:07:01 +02:00
Patrick Pelissier 57b88160ae Add asm generation for typical OOR_EQUAL_P functions 2022-04-19 20:57:03 +02:00
Patrick Pelissier 33ba602aef Reformat 2022-04-18 22:10:32 +02:00
Patrick Pelissier 3632388315 Reorder macros to group then by logical entity. Remove M_INVERT obsolete macro 2022-04-18 21:22:45 +02:00
Patrick Pelissier 6ee82e885b Update comments 2022-04-18 11:09:12 +02:00
Patrick Pelissier 2f92cee416 Update code for generated asm analysis 2022-04-18 11:08:59 +02:00
Patrick Pelissier 9269473e10 Remove M_APPLY_SIZEOF 2022-04-18 10:04:11 +02:00
Patrick Pelissier c8611ce708 Update comments 2022-04-18 09:44:13 +02:00
Patrick Pelissier d8fd43e9e9 Update comments & avoid using M_ID for internal macros 2022-04-18 09:41:43 +02:00
Patrick Pelissier a2e471620d Add support for '_' meta keyword 2022-04-18 09:24:32 +02:00
Patrick Pelissier ffa3821acf Add tests for M_KEYWORD_TO_VA_ARGS 2022-04-17 19:01:32 +02:00
Patrick Pelissier 5c98d47d8c Add M_KEYWORD_TO_VA_ARGS 2022-04-17 19:01:21 +02:00
Patrick Pelissier 0875eaac03 Add more tests 2022-04-17 18:51:27 +02:00
Patrick Pelissier 60734bdb2b Avoid using M_ID / M_OPFLAT in context where it could be used recursively 2022-04-15 23:44:07 +02:00
Patrick Pelissier e71b19424b Simplify definition of M_EMPTY_P & M_PARENTHESIS_P 2022-04-14 23:50:40 +02:00
Patrick Pelissier daac0169d5 Reformat 2022-04-14 23:47:11 +02:00
Patrick Pelissier baacc0df52 Add test cases for M_AND, M_OR, M_AND3 & M_OR3 2022-04-13 22:49:01 +02:00
Patrick Pelissier c6921536f7 Add M_AND3 & M_OR3 macros 2022-04-13 22:48:40 +02:00
Patrick Pelissier 4abf0ad2b2 Simplify code 2022-04-11 22:34:08 +02:00
Patrick Pelissier 379d555d35 Remove M_IF_DEFAULT1 from documentation 2022-04-10 23:12:32 +02:00
Patrick Pelissier 8c01acb8d2 Remove M_IF_DEFAULT1 (bad interface).
Fix warning in M_DEFAULT_ARGS in some cases.
2022-04-10 23:10:58 +02:00
Patrick Pelissier 2c2c3c21ba Add test for string_search in C11 2022-04-10 23:09:50 +02:00
Patrick Pelissier 50fd27e07b Use of M_DEFAULT_ARGS instead of M_IF_DEFAULT1 2022-04-10 23:09:29 +02:00
Patrick Pelissier 3309035814 Reducing preprocessing time for ALGO_FOR_EACH ALGO_TRANSFORM ALGO_EXTRACT 2022-04-10 11:28:12 +02:00
Patrick Pelissier b691758fa9 Update comments 2022-04-10 11:10:01 +02:00
Patrick Pelissier 7c9afcec8b Update vocabulary 2022-04-09 16:31:57 +02:00
Patrick Pelissier 06ac05526a Update doc 2022-04-09 09:02:26 +02:00
Patrick Pelissier 69cef8249a Update comments and move section 2022-04-09 00:11:51 +02:00
Patrick Pelissier 473df16a5a Update description & assertion of HASH functions 2022-04-08 23:38:33 +02:00
Patrick Pelissier e1abf0528c Rename M_DEFAULT_OPLIST in M_BASIC_OPLIST (cleaner name) 2022-04-08 22:54:29 +02:00
Patrick Pelissier ef0b335f67 Rename M_CHECK_DEFAULT_TYPE in M_CHECK_BASIC_TYPE, and makes it more stricter in C11. Start separating default macros from basic macros (that perform control & check) 2022-04-08 20:57:06 +02:00
Patrick Pelissier 1a866a3dc4 Update README 2022-04-08 20:55:35 +02:00
Patrick Pelissier ed437b9e05 Document SPMC & MPMC snapshots 2022-04-03 19:14:42 +02:00
Patrick Pelissier eea85872fd Simplify code 2022-04-03 19:14:25 +02:00
Patrick Pelissier 9d33e4cd5a Update name of library 2022-04-01 23:47:53 +02:00
Patrick Pelissier 530cc8d2a2 Update comments 2022-03-31 22:16:10 +02:00
Patrick Pelissier 9baca84825 Add operator EMPLACE_TYPE, to be used by future emplace methods 2022-03-30 23:11:07 +02:00
Patrick Pelissier 58538e4822 Fix spelling 2022-03-28 23:27:57 +02:00
Patrick Pelissier e31a8dc407 Update benchmark with new available specialized function 2022-03-26 16:09:25 +01:00
Patrick Pelissier 7875263092 Update documentation 2022-03-26 16:09:02 +01:00
Patrick Pelissier de3b8509bf Add tests for m_string_set_si & m_string_set_ui 2022-03-26 16:08:51 +01:00
Patrick Pelissier a19e1acfff Add function m_string_set_si & m_string_set_ui for converting an integer into a string. 2022-03-26 16:08:28 +01:00
Patrick Pelissier e613b5c624 Proper define of NDEBUG to avoid adding assertions in string benchmarks 2022-03-25 22:45:08 +01:00
Patrick Pelissier ccfddb0685 Update LIBSRT to be the source/build directory 2022-03-25 22:37:23 +01:00
Patrick Pelissier b8cd679679 Move generating macro into the m_ namespace and create a wrapper using historical names for compatibility with existing code 2022-03-24 20:46:49 +01:00
Patrick Pelissier fc26e472ab Move bitset functions to M* namespace 2022-03-23 22:39:18 +01:00
Patrick Pelissier fc8c7349d6 Reformat 2022-03-23 21:35:22 +01:00
Patrick Pelissier a4d9b8df17 Moving internal types to internal namespace 2022-03-22 23:37:35 +01:00
Patrick Pelissier f26da68aa4 Fix regression for C++ / CLANG 2022-03-21 23:27:37 +01:00
Patrick Pelissier 144182b540 Move the worker functions into the m_ namespace and create compatibility layer 2022-03-21 23:15:14 +01:00
Patrick Pelissier a834ca4921 Add missing public function 2022-03-21 23:13:34 +01:00
Patrick Pelissier d1fc216836 Move internal type to internal namespace 2022-03-20 19:02:01 +01:00
Patrick Pelissier 5e57338928 Rename string_ into m_string_ in header files (Test files still test classic API) 2022-03-20 18:30:32 +01:00
Patrick Pelissier f3376b6f0e Move internal functions to internal namespace 2022-03-20 11:50:05 +01:00
Patrick Pelissier 5e001fdd9d Move internal type to correct internal namespace 2022-03-19 17:01:20 +01:00
Patrick Pelissier 9fda06276c Move m_once_t to the public interface 2022-03-19 16:44:40 +01:00
Patrick Pelissier df79c306d9 Move the internal types toye the internal namespace 2022-03-19 16:44:18 +01:00
Patrick Pelissier e4955e6851 Move internal types to the internal namespace 2022-03-19 16:43:55 +01:00
Patrick Pelissier 0fec9e7ac4 Fix format 2022-03-19 11:46:28 +01:00
Patrick Pelissier 5be8bb435b Move WORKER_OPLIST to internal namespace 2022-03-19 11:44:58 +01:00
Patrick Pelissier 35b915ab10 Rename internal functions/types to the internal prefix 2022-03-19 10:47:27 +01:00
Patrick Pelissier 80c57e996d Add pottery string in bench 2022-03-19 08:32:10 +01:00
Patrick Pelissier 511293d580 Provide example of hash function 2022-03-17 23:03:04 +01:00
Patrick Pelissier fe2b816447 Add more example in C11 for showing more possibility 2022-03-17 19:37:12 +01:00
Patrick Pelissier 093b7dc1e8 Update example with new possibility & state of the art 2022-03-17 19:34:18 +01:00
Patrick Pelissier 811fa57cbc Fix generic API: remove the need of superfluous () 2022-03-17 19:33:46 +01:00
Patrick Pelissier 359ad20a6a Update documentation with generic API transformation 2022-03-16 22:44:19 +01:00
Patrick Pelissier ac9989e4ff Add generic API transformation
in the framework responsible of expanding
the call to a method from an operator.

The generic API transformation can
support a wide range of call
(Limited to 9 arguments maximum)
2022-03-16 22:29:57 +01:00
Patrick Pelissier 7268551737 Add micro utilities macros for handling list 2022-03-16 22:29:56 +01:00
Patrick Pelissier 823b1974bb Update comments 2022-03-16 22:29:56 +01:00
Patrick Pelissier 382f636206 Fix build issue of bench 2022-03-16 22:27:37 +01:00
Patrick Pelissier 9a1b4abcf9 Add missing small names 2022-03-15 19:29:18 +01:00
Patrick Pelissier a0fc57687b Fix format 2022-03-15 19:24:53 +01:00
Patrick Pelissier 02897f982f Add m_ prefix for the string API 2022-03-15 19:24:14 +01:00
Patrick Pelissier 07a5d0ed0a Define M_USE_SMALL_NAME user macro 2022-03-15 19:04:45 +01:00
Patrick Pelissier 017995ade6 Update README 2022-03-14 22:13:04 +01:00
Patrick Pelissier 9711b2280c Reorder the list of libraries in alphabetic order 2022-03-14 19:33:36 +01:00
Patrick Pelissier 619331916f Add reference to STR & POTTERY string libraries 2022-03-14 19:32:46 +01:00
Patrick Pelissier d7909f7312 Move internal function / macros with the m_string prefix to the internal m_str1ng prefix 2022-03-14 19:29:33 +01:00
Patrick Pelissier 22674f2b46 Fix format 2022-03-14 19:28:49 +01:00
Patrick Pelissier 845736c489 Fix format 2022-03-14 19:28:23 +01:00
Patrick Pelissier 501f9db465 Add bench of big dict for pottery 2022-03-14 19:08:27 +01:00
Patrick Pelissier 8dd440a582 Add note about the string_t format 2022-03-13 22:48:08 +01:00
Patrick Pelissier dd7f090b4b Add bench for POTTERY 2022-03-13 21:56:49 +01:00
Patrick Pelissier dc14a2677b Reformat & cleanup error messages 2022-03-13 21:10:07 +01:00
Patrick Pelissier 8b1ed7f0ae Fix help usage 2022-03-13 21:09:46 +01:00
Patrick Pelissier 19b01b404d Migrate to 2022 2022-03-12 20:25:45 +01:00
Patrick Pelissier ec780d2d4d Add POTTERY library reference 2022-03-12 20:20:45 +01:00
Patrick Pelissier 07790f6711 Add CPU information for MacOS 2022-03-12 20:09:59 +01:00
Patrick Pelissier f72d2b6c67 Add STC bench 2022-03-12 12:04:49 +01:00
Patrick Pelissier e35d631012 Fix path of MS Visual Studio 2022 2022-03-12 11:59:06 +01:00
Patrick Pelissier 3499a08207 Add support for MS Visual Studio 2022 2022-03-12 11:51:27 +01:00
Patrick Pelissier 0ac23e512e Fix CTL bench 2022-03-12 11:40:38 +01:00
PpHd 1852fabcd2 Merge pull request #98
Fix a few typos
2021-12-23 17:48:04 +01:00
Tim Gates 7b6bfac7cb docs: Fix a few typos
There are small typos in:
- example/ex-algo03.c
- m-algo.h
- m-core.h
- m-dict.h
- m-string.h

Fixes:
- Should read `occurrence` rather than `occurence`.
- Should read `fulfilled` rather than `fullfilled`.
- Should read `dictionaries` rather than `dictionnaries`.
- Should read `environment` rather than `environement`.
- Should read `unordered` rather than `undordered`.
2021-12-23 10:00:44 +11:00
Patrick Pelissier e72aa5fb79 Update doc 2021-12-03 22:59:33 +01:00
Patrick Pelissier f4b02b92cc Update documentation 2021-12-03 22:48:43 +01:00
Patrick Pelissier 39edcc560f Fix name of variable 2021-12-03 22:28:44 +01:00
Patrick Pelissier 50669a320c Add m_ prefix for GENINT module,
as it is purely internal (no need to prevent user space breakage).

It will put more stuff in the global m_ prefix
2021-12-03 22:08:15 +01:00
Patrick Pelissier d22c0b05ef Display CPU information 2021-12-03 21:50:36 +01:00
Patrick Pelissier 689be30803 Update README with an implicit constraint 2021-12-03 21:40:09 +01:00
Patrick Pelissier b393a83d38 Add example of JSON serialization on string 2021-12-03 21:39:41 +01:00
Patrick Pelissier 1a1339da6b Remove deprecated features 2021-11-20 13:05:50 +01:00
Patrick Pelissier 9926b51da0 Revert 829c20ba8 as there is an issue in calling M_KEYWORD_P within M_IF. 2021-11-20 10:15:31 +01:00
Patrick Pelissier 761447dea3 V0.6.1 2021-11-13 19:51:32 +01:00
Patrick Pelissier 829c20ba8a Update M_KEYWORD_P to support () . Add more recognized keywords (type, list, LIST, queue, QUEUE, INIT_WITH) 2021-11-13 19:51:23 +01:00
Patrick Pelissier 9ac734e191 Fix documentation 2021-11-12 20:03:36 +01:00
Patrick Pelissier 5420fc6c51 Fix documentation 2021-11-12 20:02:07 +01:00
126 changed files with 11264 additions and 5098 deletions

No files matched your search

+15
View File
@@ -11,6 +11,8 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: CPU Information
run: lscpu || sysctl -a|grep cpu || echo "CPU information not available"
- name: make check C99
run: make clean && make check -j 2 CC="cc -std=c99 -Wno-unknown-warning-option -Werror"
- name: make check C11
@@ -29,6 +31,8 @@ jobs:
run: sudo apt-get update
- name: install multilib
run: sudo apt-get install gcc-multilib g++-multilib
- name: CPU Information
run: lscpu || echo "CPU information not available"
- name: make check C99 (32bits)
working-directory: ./tests
run: make clean && make check -j 2 CC="gcc -m32 -std=c99 -Wno-unknown-warning-option -Werror"
@@ -47,6 +51,8 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: CPU Information
run: lscpu || echo "CPU information not available"
- name: Clone TCC
shell: bash
run: git clone https://repo.or.cz/tinycc.git
@@ -60,6 +66,15 @@ jobs:
shell: bash
run: make CC="/tmp/tcc/bin/tcc -std=c99" check
build_linux_sanitize:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: make sanitize
working-directory: ./tests
run: make sanitize -j 2
build_windows_mingw:
runs-on: windows-latest
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 2-Clause License
Copyright (c) 2017-2021, Patrick Pelissier
Copyright (c) 2017-2022, Patrick Pelissier
All rights reserved.
Redistribution and use in source and binary forms, with or without
+7 -7
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2017-2021, Patrick Pelissier
# Copyright (c) 2017-2022, Patrick Pelissier
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -34,14 +34,14 @@ DESTDIR=
# Package name & version.
PACKAGE=m_lib-$(VERSION)
VERSION=0.6.0
VERSION=0.7.0
# Define the contain of the distribution tarball
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tuple.h m-variant.h m-worker.h
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tree.h m-tuple.h m-variant.h m-worker.h
DOC1=LICENSE README.md
DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/depend.png doc/DEV.md doc/ISSUES.org doc/oplist.odp doc/oplist.png
EXAMPLE=example/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json example/Makefile example/ex-defer01.c example/ex-string01.c example/ex-string02.c example/ex-astar.c example/ex-string03.c example/ex11-tstc.c
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.c tests/test-mcmempool.c tests/test-mconcurrent.c tests/test-mcore.c tests/test-mdeque.c tests/test-mdict.c tests/test-mfuncobj.c tests/test-mgenint.c tests/test-milist.c tests/test-mlist.c tests/test-mmempool.c tests/test-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.c tests/test-mshared.c tests/test-msnapshot.c tests/test-mstring.c tests/test-mtuple.c tests/test-mvariant.c tests/test-mworker.c tests/tgen-bitset.c tests/tgen-marray.c tests/tgen-mdict.c tests/tgen-mlist.c tests/tgen-mstring.c tests/tgen-openmp.c tests/tgen-queue.c tests/tgen-shared.c tests/tgen-mserial.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt tests/fail-chain-oplist.c tests/fail-incompatible.c tests/fail-no-oplist.c tests/test-mishared.c tests/check-array.cpp tests/check-deque.cpp tests/check-dplist.cpp tests/check-list.cpp tests/check-rbtree.cpp tests/check-uset.cpp tests/check-generic.hpp
EXAMPLE=example/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex11-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json example/Makefile example/ex-defer01.c example/ex-string01.c example/ex-string02.c example/ex-astar.c example/ex-string03.c example/ex11-tstc.c example/ex-no-stdio.c example/ex11-count-lines.c example/ex11-json-net.c example/ex11-rbtree02.c
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.c tests/test-mcmempool.c tests/test-mconcurrent.c tests/test-mcore.c tests/test-mdeque.c tests/test-mdict.c tests/test-mfuncobj.c tests/test-mgenint.c tests/test-milist.c tests/test-mlist.c tests/test-mmempool.c tests/test-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.c tests/test-mshared.c tests/test-msnapshot.c tests/test-mstring.c tests/test-mtuple.c tests/test-mvariant.c tests/test-mworker.c tests/tgen-bitset.c tests/tgen-marray.c tests/tgen-mdict.c tests/tgen-mlist.c tests/tgen-mstring.c tests/tgen-openmp.c tests/tgen-queue.c tests/tgen-shared.c tests/tgen-mserial.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt tests/fail-chain-oplist.c tests/fail-incompatible.c tests/fail-no-oplist.c tests/test-mishared.c tests/check-array.cpp tests/check-deque.cpp tests/check-dplist.cpp tests/check-list.cpp tests/check-rbtree.cpp tests/check-uset.cpp tests/check-generic.hpp tests/test-mtree.c tests/check-bptree-map.cpp tests/check-bptree-set.cpp tests/check-prioqueue.cpp tests/check-umap.cpp
.PHONY: all test check doc clean distclean depend install uninstall dist
@@ -68,8 +68,8 @@ clean:
cd example && $(MAKE) clean
cd bench && $(MAKE) clean
$(RM) README.html depend.dot
$(RM) -r 'm*lib-$(VERSION)'
$(RM) 'm*lib-$(VERSION).tar.bz2'
$(RM) -r 'm_lib-$(VERSION)'
$(RM) 'm_lib-$(VERSION).tar.bz2'
distclean: clean
cd tests && $(MAKE) distclean
+2310 -2394
View File
File diff suppressed because it is too large. Load diff
+50 -9
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2017-2021, Patrick Pelissier
# Copyright (c) 2017-2022, Patrick Pelissier
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,7 @@ N=4
BENCH_DEF=
RM=rm -rf
.PHONY: all pgo container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain bench-rigtorp-mpmc-queue bench-cmc
.PHONY: all pgo container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-emhash bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain bench-rigtorp-mpmc-queue bench-cmc
all: container queue mempool string plain
@@ -39,7 +39,7 @@ pgo:
#########################################################################
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-cmc bench-sparsepp bench-densehashmap bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-uthash bench-qlibc bench-libsrt bench-nedtries bench-rigtorp-hashmap bench-ctl
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-cmc bench-sparsepp bench-densehashmap bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-emhash bench-hopscotchmap bench-uthash bench-qlibc bench-libsrt bench-nedtries bench-rigtorp-hashmap bench-ctl bench-stc bench-pottery
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-rigtorp-mpmc-queue
@@ -118,7 +118,7 @@ bench-stl:
bench-qt:
@if test -n "$${QT}" ; then $(MAKE) bench-qt0 ; else echo "Nothing to be done for QT." ; fi
bench-qt0:
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -fPIC `PKG_CONFIG_PATH="$${QT}" pkg-config --libs --cflags Qt5Core` bench-qt.cpp common.c -o bench-qt.exe
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -fPIC bench-qt.cpp common.c -o bench-qt.exe `PKG_CONFIG_PATH="$${QT}" pkg-config --libs --cflags Qt5Core`
@./bench-qt.exe 10
@./bench-qt.exe 20
@./bench-qt.exe 30
@@ -162,12 +162,12 @@ bench-cmc0:
@./bench-cmc.exe 30
@./bench-cmc.exe 40
# LIBDYNAMIC shall point to the the directory containing the file libdynamic.pc
# LIBDYNAMIC shall point to the the source directory where the source is built
bench-libdynamic:
@if test -n "$${LIBDYNAMIC}" ; then $(MAKE) bench-libdynamic0 ; else echo "Nothing to be done for LIBDYNAMIC." ; fi
bench-libdynamic0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-libdynamic.c common.c -o bench-libdynamic.exe `PKG_CONFIG_PATH="$${LIBDYNAMIC}" pkg-config --libs --cflags libdynamic`
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-libdynamic.c common.c -o bench-libdynamic.exe -I$${LIBDYNAMIC}/src $${LIBDYNAMIC}/.libs/libdynamic.a
@./bench-libdynamic.exe 20
@./bench-libdynamic.exe 40
@./bench-libdynamic.exe 41
@@ -239,6 +239,17 @@ bench-emilib0:
@./bench-emilib.exe 46
@./bench-emilib.exe 43
# EMHASh shall point to the directory where the headers are
bench-emhash:
@if test -n "$${EMHASH}" ; then $(MAKE) bench-emhash0 ; else echo "Nothing to be done for EMHASH." ; fi
bench-emhash0:
$(CXX) -std=c++14 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${EMHASH}" bench-emhash.cpp common.c -o bench-emhash.exe
@./bench-emhash.exe 41
@./bench-emhash.exe 42
@./bench-emhash.exe 46
@./bench-emhash.exe 43
# HOPSCOTCHMAP shall point to the directory where the source are
bench-hopscotchmap:
@if test -n "$${HOPSCOTCHMAP}" ; then $(MAKE) bench-hopscotchmap0 ; else echo "Nothing to be done for HOPSCOTCHMAP." ; fi
@@ -276,7 +287,7 @@ bench-libsrt:
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-libsrt0 ; else echo "Nothing to be done for LIBSRT." ; fi
bench-libsrt0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/include/libsrt" bench-libsrt.c common.c -o bench-libsrt.exe $${LIBSRT}/lib/libsrt.a
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/src" bench-libsrt.c common.c -o bench-libsrt.exe $${LIBSRT}/src/.libs/libsrt.a
@./bench-libsrt.exe 20
@./bench-libsrt.exe 50
@@ -351,6 +362,32 @@ bench-ctl0:
@./bench-ctl.exe 40
@./bench-ctl.exe 50
# STC shall point to the source directory (not where the headers are)
bench-stc:
@if test -n "$${STC}" ; then $(MAKE) bench-stc0 ; else echo "Nothing to be done for STC." ; fi
bench-stc0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${STC}/include bench-stc.c common.c -o bench-stc.exe
@./bench-stc.exe 10
@./bench-stc.exe 20
@./bench-stc.exe 30
@./bench-stc.exe 40
@./bench-stc.exe 41
@./bench-stc.exe 50
# POTTERY shall point to the source directory (not where the headers are)
bench-pottery:
@if test -n "$${POTTERY}" ; then $(MAKE) bench-pottery0 ; else echo "Nothing to be done for POTTERY." ; fi
bench-pottery0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -DPOTTERY_AVAILABLE=1 -I $${POTTERY}/include bench-pottery.c common.c -o bench-pottery.exe
@./bench-pottery.exe 10
@./bench-pottery.exe 20
@./bench-pottery.exe 30
@./bench-pottery.exe 40
@./bench-pottery.exe 41
@./bench-pottery.exe 50
############################################################################
bench-mlib-json: bench-mlib
@@ -389,12 +426,12 @@ bench-maxdict:
############################################################################
# BSTRLIB shall point to the BSTRLIB sources
# LIBSRT shall point to the LIBSRT install directory
# LIBSRT shall point to the LIBSRT sources
bench-string:
@if test -n "$${BSTRLIB}" ; then $(MAKE) bench-string-step1 BENCH_DEF="-DBENCH_CAN_USE_BSTRLIB -I ${BSTRLIB} $${BSTRLIB}/obj/bstrlib.o $${BSTRLIB}/obj/bstraux.o $${BSTRLIB}/obj/bstrwrap.o" ; else $(MAKE) bench-string-step1 ; fi
bench-string-step1:
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/include/libsrt $${LIBSRT}/lib/libsrt.a" ; else $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF)"; fi
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/src $${LIBSRT}/src/.libs/libsrt.a" ; else $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF)"; fi
#NOTE: Need to build by hand sds.o since it is not build by default and sds.c is not compatible with C++
bench-string-step2:
@@ -404,6 +441,9 @@ bench-string-step4:
@if test -n "$${GLIB}" ; then $(MAKE) bench-string-step5 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_GLIB $$(pkg-config --cflags --libs glib-2.0)" ; else $(MAKE) bench-string-step5 BENCH_DEF="$(BENCH_DEF)"; fi
bench-string-step5:
@if test -n "$${POTTERY}" ; then $(MAKE) bench-string-step6 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_POTTERY -I$${POTTERY}/include -I$${POTTERY}/util/ $${POTTERY}/util/pottery/string/string.c" ; else $(MAKE) bench-string-step6 BENCH_DEF="$(BENCH_DEF)"; fi
bench-string-step6:
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -DBENCH_CAN_USE_STL -DBENCH_CAN_USE_MSTARLIB bench-string.cpp common.c $(BENCH_DEF) -o bench-string.exe
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -DBENCH_CAN_USE_STL -DBENCH_CAN_USE_MSTARLIB bench-string-2.cpp common.c $(BENCH_DEF) -o bench-string-2.exe
@./bench-string.exe
@@ -411,6 +451,7 @@ bench-string-step5:
@./bench-string-2.exe 2000000 1
@./bench-string-2.exe 2000000 2
@./bench-string-2.exe 2000000 4
@./bench-string-2.exe 2000000 5
bench-string-pgo:
$(MAKE) bench-string XCFLAGS="-fprofile-generate=pgo"
+3 -2
View File
@@ -125,14 +125,15 @@ pair_ulong_copy(pair_ulong *self) {
#define T pair_ulong
#include <ctl/unordered_map.h>
// It seems broken: it doesn't output the expected result.
static void
test_dict(size_t n)
{
umap_pair_ulong dict = umap_pair_ulong_init(pair_ulong_hash, pair_ulong_equal);
for (size_t i = 0; i < n; i++) {
umap_pair_ulong_insert(&dict, (pair_ulong) { rand_get(), rand_get() });
unsigned long value = rand_get();
unsigned long key = rand_get();
umap_pair_ulong_insert(&dict, (pair_ulong) { key, value });
}
rand_init();
unsigned int s = 0;
+138
View File
@@ -0,0 +1,138 @@
#define NDEBUG
#include <vector>
#include <list>
#include <iterator>
#include <map>
#include <set>
#include <unordered_map>
#include <algorithm>
#include <string>
#include <sstream>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "hash_table7.hpp"
using namespace emhash7;
using namespace std;
#include "common.h"
/********************************************************************************************/
static void
test_dict2(size_t n)
{
HashMap<unsigned long, unsigned long> dict;
for (size_t i = 0; i < n; i++) {
dict[rand_get()] = rand_get();
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
HashMap<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
if (it != dict.end())
s += it->second;
}
g_result = s;
}
static void
test_dict2_linear(size_t n)
{
HashMap<unsigned long, unsigned long> dict;
for (size_t i = 0; i < n; i++) {
dict[i] = rand_get();
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
HashMap<unsigned long, unsigned long>::iterator it = dict.find(i);
if (it != dict.end())
s += it->second;
}
g_result = s;
}
/********************************************************************************************/
struct char_array_s {
char a[256];
char_array_s () { a[0] = 0 ; }
char_array_s ( const char_array_s & other) { strcpy(a, other.a); }
bool operator==(const char_array_s &other) const { return strcmp(a, other.a) == 0; }
};
namespace std {
template <> struct hash<char_array_s> {
std::size_t operator()(const char_array_s &k) const {
size_t hash = 0;
const char *s = k.a;
while (*s) hash = hash * 31421 + (*s++) + 6927;
return hash;
};
};
}
static void
test_dict_big(size_t n)
{
HashMap<char_array_s, char_array_s> dict;
for (size_t i = 0; i < n; i++) {
char_array_s s1, s2;
sprintf(s1.a, "%u", rand_get());
sprintf(s2.a, "%u", rand_get());
dict[s1] = s2;
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
char_array_s s1;
sprintf(s1.a, "%u", rand_get());
HashMap<char_array_s, char_array_s>::iterator it = dict.find(s1);
if (it != dict.end())
s ++;
}
g_result = s;
}
/********************************************************************************************/
static void
test_dict_str(size_t n)
{
HashMap<string, string> dict;
for (size_t i = 0; i < n; i++) {
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
dict[s1] = s2;
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
HashMap<string, string>::iterator it = dict.find(s1);
if (it != dict.end())
s ++;
}
g_result = s;
}
/********************************************************************************************/
const config_func_t table[] = {
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
{ 42,"dict", 1000000, 0, test_dict2, 0},
{ 43, "DictStr", 1000000, 0, test_dict_str, 0},
{ 46, "DictLinear", 1000000, 0, test_dict2_linear, 0}
};
int main(int argc, const char *argv[])
{
test("EMHASH", numberof(table), table, argc, argv);
exit(0);
}
+24 -28
View File
@@ -55,12 +55,8 @@ static void test_deque(size_t n)
}
unsigned int s = 0;
deque_uint_it_t it1, it2;
deque_uint_it(it1, a1);
deque_uint_it(it2, a2);
while (!deque_uint_end_p(it1)) {
for(deque_uint_it(it1, a1), deque_uint_it(it2, a2) ; !deque_uint_end_p(it1) ; deque_uint_next(it1), deque_uint_next(it2)) {
s += *deque_uint_cref(it1 ) * *deque_uint_cref(it2 );
deque_uint_next(it1);
deque_uint_next(it2);
}
g_result = s;
}
@@ -876,8 +872,8 @@ bench_vector_string_init(size_t n)
{
vector_string_init(vstring);
for(size_t i = 0; i < n; i++)
{
M_LET( (s, "%zu", i, i, i, i), string_t) {
{
M_LET( (s, "%zu", i), string_t) {
vector_string_push_back(vstring, s);
}
}
@@ -901,8 +897,8 @@ static void
bench_vector_string_bin_run(size_t n)
{
if (vector_string_size(vstring) != n) {
printf("Size are different!\n");
abort();
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring));
abort();
}
FILE *f = fopen("tmp-serial.dat", "wb");
@@ -920,8 +916,8 @@ bench_vector_string_bin_run(size_t n)
fclose(f);
if (vector_string_size(vstring2) != n) {
printf("Size are different!\n");
abort();
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring2));
abort();
}
}
@@ -929,8 +925,8 @@ static void
bench_vector_string_json_run(size_t n)
{
if (vector_string_size(vstring) != n) {
printf("Size are different!\n");
abort();
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring));
abort();
}
FILE *f = fopen("tmp-serial.json", "wt");
@@ -948,8 +944,8 @@ bench_vector_string_json_run(size_t n)
fclose(f);
if (vector_string_size(vstring2) != n) {
printf("Size are different!\n");
abort();
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring2));
abort();
}
}
@@ -957,8 +953,8 @@ static void
bench_vector_string_clear(void)
{
if (!vector_string_equal_p(vstring, vstring2)) {
printf("Array are different!\n");
abort();
fprintf(stderr, "ERROR: Array are different after deserialization!\n");
abort();
}
vector_string_clear(vstring);
vector_string_clear(vstring2);
@@ -986,8 +982,8 @@ static void
bench_vector_ulong_bin_run(size_t n)
{
if (vector_ulong_size(vulong) != n) {
printf("Size are different!\n");
abort();
fprintf(stderr, "ERROR: Size are different!\n");
abort();
}
FILE *f = fopen("tmp-serial.dat", "wb");
@@ -1005,8 +1001,8 @@ bench_vector_ulong_bin_run(size_t n)
fclose(f);
if (vector_ulong_size(vulong2) != n) {
printf("Size are different!\n");
abort();
fprintf(stderr, "ERROR: Size are different!\n");
abort();
}
}
@@ -1014,8 +1010,8 @@ static void
bench_vector_ulong_json_run(size_t n)
{
if (vector_ulong_size(vulong) != n) {
printf("Size are different!\n");
abort();
fprintf(stderr, "ERROR: Size are different!\n");
abort();
}
FILE *f = fopen("tmp-serial.json", "wt");
@@ -1033,8 +1029,8 @@ bench_vector_ulong_json_run(size_t n)
fclose(f);
if (vector_ulong_size(vulong2) != n) {
printf("Size are different!\n");
abort();
fprintf(stderr, "ERROR: Size are different!\n");
abort();
}
}
@@ -1042,8 +1038,8 @@ static void
bench_vector_ulong_clear(void)
{
if (!vector_ulong_equal_p(vulong, vulong2)) {
printf("Array are different!\n");
abort();
fprintf(stderr, "ERROR: Array are different after deserialization!\n");
abort();
}
vector_ulong_clear(vulong);
vector_ulong_clear(vulong2);
@@ -1085,6 +1081,6 @@ const config_func_t table[] = {
int main(int argc, const char *argv[])
{
test("M-LIB", numberof(table), table, argc, argv);
test("M*LIB", numberof(table), table, argc, argv);
exit(0);
}
+1 -1
View File
@@ -32,7 +32,7 @@ struct Pixel
unsigned char r, g, b;
};
ARRAY_DEF(array_pixel, struct Pixel, (INIT(M_NOTHING_DEFAULT)) )
ARRAY_DEF(array_pixel, struct Pixel, (INIT(M_NOTHING_DEFAULT), INIT_SET(M_MEMCPY_DEFAULT) ))
void UseMlib(void)
{
+269
View File
@@ -0,0 +1,269 @@
#define NDEBUG
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "common.h"
/********************************************************************************************/
#define POTTERY_VECTOR_PREFIX vec_uint
#define POTTERY_VECTOR_VALUE_TYPE unsigned int
#define POTTERY_VECTOR_LIFECYCLE_BY_VALUE 1
#include "pottery/vector/pottery_vector_static.t.h"
static void test_array(size_t n)
{
vec_uint_t a1, a2;
vec_uint_init(&a1);
vec_uint_init(&a2);
for(size_t i = 0; i < n; i++) {
vec_uint_insert_last(&a1, rand_get() );
vec_uint_insert_last(&a2, rand_get() );
}
unsigned int s = 0;
for(unsigned long i = 0; i < n; i++) {
s += *vec_uint_at(&a1, i ) * *vec_uint_at(&a2, i );
}
g_result = s;
vec_uint_destroy(&a1);
vec_uint_destroy(&a2);
}
/********************************************************************************************/
typedef struct foo_s {
struct foo_s* next;
struct foo_s* previous;
int data;
} foo_t;
#define POTTERY_DOUBLY_LINKED_LIST_PREFIX foo_list
#define POTTERY_DOUBLY_LINKED_LIST_VALUE_TYPE foo_t
#include "pottery/doubly_linked_list/pottery_doubly_linked_list_static.t.h"
static void test_list(size_t n)
{
foo_list_t a1, a2;
foo_list_init(&a1);
foo_list_init(&a2);
for(size_t i = 0; i < n; i++) {
foo_t *tmp = malloc(sizeof (foo_t));
if (tmp == NULL) abort();
tmp->data = rand_get();
foo_list_link_last(&a1, tmp);
tmp = malloc(sizeof (foo_t));
if (tmp == NULL) abort();
tmp->data = rand_get();
foo_list_link_last(&a2, tmp);
}
unsigned int s = 0;
for(foo_t *it1 = foo_list_first(&a1), *it2 = foo_list_first(&a2) ;
foo_list_entry_exists(&a1, it1) ;
it1 = foo_list_next(&a1, it1), it2 = foo_list_next(&a2, it2)) {
s += it1->data * it2->data;
}
g_result = s;
for(foo_t *it1 = foo_list_first(&a1);
foo_list_entry_exists(&a1, it1) ;
) {
foo_t *tmp = it1;
it1 = foo_list_next(&a1, it1);
free(tmp);
}
for(foo_t *it1 = foo_list_first(&a2);
foo_list_entry_exists(&a2, it1) ;
) {
foo_t *tmp = it1;
it1 = foo_list_next(&a2, it1);
free(tmp);
}
}
/********************************************************************************************/
// ERROR: it returns the wrong result.
#define POTTERY_TREE_MAP_PREFIX set_ulong
#define POTTERY_TREE_MAP_VALUE_TYPE unsigned long
#define POTTERY_TREE_MAP_LIFECYCLE_MOVE_BY_VALUE 1
#define POTTERY_TREE_MAP_COMPARE_THREE_WAY(a,b) ((a) < (b) ? -1 : (a) > (b))
#define POTTERY_TREE_MAP_LIFECYCLE_DESTROY(a) (void) a
#include "pottery/tree_map/pottery_tree_map_static.t.h"
static void test_rbtree(size_t n)
{
set_ulong_t tree;
set_ulong_init(&tree);
for (size_t i = 0; i < n; i++) {
set_ulong_insert(&tree, rand_get() );
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
unsigned long j = rand_get();
if (set_ulong_find(&tree, &j ) != NULL)
s += j;
}
g_result = s;
set_ulong_destroy(&tree);
}
/********************************************************************************************/
#include "m-core.h" // For M_HASH_DEFAULT
typedef struct bar_s {
unsigned long key;
unsigned long value;
} bar_t;
#define POTTERY_OPEN_HASH_MAP_PREFIX map_ulong
#define POTTERY_OPEN_HASH_MAP_VALUE_TYPE bar_t
#define POTTERY_OPEN_HASH_MAP_KEY_TYPE unsigned long
#define POTTERY_OPEN_HASH_MAP_REF_KEY(v) v->key
#define POTTERY_OPEN_HASH_MAP_KEY_HASH(x) M_HASH_DEFAULT(x)
#define POTTERY_OPEN_HASH_MAP_KEY_EQUAL(x, y) x == y
#define POTTERY_OPEN_HASH_MAP_LIFECYCLE_MOVE(p,q) memcpy(p, q, sizeof (bar_t))
#include "pottery/open_hash_map/pottery_open_hash_map_static.t.h"
static void
test_dict(size_t n)
{
map_ulong_t dict;
map_ulong_init(&dict);
for (size_t i = 0; i < n; i++) {
unsigned long value = rand_get();
unsigned long key = rand_get();
bar_t * kyle = pottery_null;
map_ulong_emplace_key(&dict, key, &kyle, pottery_null);
kyle->key = key;
kyle->value = value;
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
bar_t *kyle = map_ulong_find(&dict, rand_get());
if (kyle != NULL)
s += kyle->value;
}
g_result = s;
map_ulong_destroy(&dict);
}
/********************************************************************************************/
typedef struct {
char a[256];
} char_array_t;
static inline void char_init (char_array_t *a) { a->a[0] = 0; }
static inline void char_set (char_array_t *a, const char_array_t b) { strcpy(a->a, b.a); }
static inline bool char_equal_p (const char_array_t a, const char_array_t b) { return strcmp(a.a,b.a)==0; }
static inline void char_clear (char_array_t *a) { (void)a; }
static inline size_t char_hash(const char_array_t *a) {
size_t hash = 0;
const char *s = a->a;
while (*s) hash = hash * 31421 + (*s++) + 6927;
return hash;
}
typedef struct bars_s {
char_array_t key;
char_array_t value;
} bars_t;
#define POTTERY_OPEN_HASH_MAP_PREFIX map_achar
#define POTTERY_OPEN_HASH_MAP_VALUE_TYPE bars_t
#define POTTERY_OPEN_HASH_MAP_KEY_TYPE char_array_t
#define POTTERY_OPEN_HASH_MAP_REF_KEY(v) v->key
#define POTTERY_OPEN_HASH_MAP_KEY_HASH(x) char_hash(&x)
#define POTTERY_OPEN_HASH_MAP_KEY_EQUAL(x, y) char_equal_p(x, y)
#define POTTERY_OPEN_HASH_MAP_LIFECYCLE_MOVE(p,q) memcpy(p, q, sizeof (bars_t))
#include "pottery/open_hash_map/pottery_open_hash_map_static.t.h"
static void
test_dict_big(size_t n)
{
map_achar_t dict;
map_achar_init(&dict);
for (size_t i = 0; i < n; i++) {
char_array_t s1, s2;
sprintf(s1.a, "%u", rand_get());
sprintf(s2.a, "%u", rand_get());
bars_t * kyle = pottery_null;
map_achar_emplace_key(&dict, s1, &kyle, pottery_null);
char_set(&kyle->key, s1);
char_set(&kyle->value, s2);
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
char_array_t s1;
sprintf(s1.a, "%u", rand_get());
bars_t *kyle = map_achar_find(&dict, s1);
if (kyle != NULL)
s ++;
}
g_result = s;
map_achar_destroy(&dict);
}
/********************************************************************************************/
#define POTTERY_VECTOR_PREFIX vec_float
#define POTTERY_VECTOR_VALUE_TYPE float
#define POTTERY_VECTOR_LIFECYCLE_BY_VALUE 1
#include "pottery/vector/pottery_vector_static.t.h"
#define POTTERY_INTRO_SORT_PREFIX sort_float
#define POTTERY_INTRO_SORT_VALUE_TYPE float
#define POTTERY_INTRO_SORT_LIFECYCLE_MOVE_BY_VALUE 1
#define POTTERY_INTRO_SORT_COMPARE_THREE_WAY(x, y) ( *x < *y ? -1 : *x > *y)
#include "pottery/intro_sort/pottery_intro_sort_static.t.h"
static void test_sort(size_t n)
{
vec_float_t a1;
vec_float_init(&a1);
for(size_t i = 0; i < n; i++) {
vec_float_insert_last(&a1, rand_get() );
}
sort_float(vec_float_at(&a1, 0), n);
g_result = *vec_float_at(&a1, 0);
vec_float_destroy(&a1);
}
/********************************************************************************************/
const config_func_t table[] = {
{ 10, "List", 10000000, 0, test_list, 0},
{ 20, "Array", 100000000, 0, test_array, 0},
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
{ 40, "dict", 1000000, 0, test_dict, 0},
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
{ 50, "Sort",10000000, 0, test_sort, 0},
};
int main(int argc, const char *argv[])
{
test("POTTERY", numberof(table), table, argc, argv);
exit(0);
}
+193
View File
@@ -0,0 +1,193 @@
#define NDEBUG
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "common.h"
/********************************************************************************************/
#define i_val unsigned int
#define i_tag uint
#include <stc/cvec.h>
static void test_array(size_t n)
{
cvec_uint a1 = cvec_uint_init(), a2 = cvec_uint_init();
for(size_t i = 0; i < n; i++) {
cvec_uint_push_back(&a1, rand_get() );
cvec_uint_push_back(&a2, rand_get() );
}
unsigned int s = 0;
for(unsigned long i = 0; i < n; i++) {
s += *cvec_uint_at(&a1, i ) * *cvec_uint_at(&a2, i );
}
g_result = s;
cvec_uint_drop(&a1);
cvec_uint_drop(&a2);
}
/********************************************************************************************/
#define i_val unsigned int
#define i_tag uint
#include <stc/clist.h>
static void test_list(size_t n)
{
clist_uint a1 = clist_uint_init(), a2 = clist_uint_init();
for(size_t i = 0; i < n; i++) {
clist_uint_push_front(&a1, rand_get() );
clist_uint_push_front(&a2, rand_get() );
}
unsigned int s = 0;
for(clist_uint_iter it1 = clist_uint_begin(&a1), it2 = clist_uint_begin(&a2) ;
it1.ref != clist_uint_end(&a1).ref ;
clist_uint_next(&it1), clist_uint_next(&it2) ) {
s += *it1.ref * *it2.ref;
}
g_result = s;
clist_uint_drop(&a1);
clist_uint_drop(&a2);
}
/********************************************************************************************/
#define i_tag ulong
#define i_key unsigned long
#include <stc/csset.h>
static void test_rbtree(size_t n)
{
csset_ulong tree = csset_ulong_init();
for (size_t i = 0; i < n; i++) {
csset_ulong_insert(&tree, rand_get() );
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
unsigned long j = rand_get();
if (csset_ulong_get(&tree, j ) != NULL)
s+= j;
}
g_result = s;
csset_ulong_drop(&tree);
}
/********************************************************************************************/
#define i_tag ulong
#define i_key unsigned long
#define i_val unsigned long
#include <stc/cmap.h>
static void
test_dict(size_t n)
{
cmap_ulong dict = cmap_ulong_init();
for (size_t i = 0; i < n; i++) {
unsigned long value = rand_get();
unsigned long key = rand_get();
cmap_ulong_insert_or_assign(&dict, key, value);
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
const cmap_ulong_value*val = cmap_ulong_get(&dict, rand_get());
if (val != NULL)
s += val->second;
}
g_result = s;
cmap_ulong_drop(&dict);
}
/********************************************************************************************/
typedef struct {
char a[256];
} char_array_t;
static inline void char_init (char_array_t *a) { a->a[0] = 0; }
static inline void char_set (char_array_t *a, const char_array_t b) { strcpy(a->a, b.a); }
static inline bool char_equal_p (const char_array_t *a, const char_array_t *b) { return strcmp(a->a,b->a)==0; }
static inline void char_clear (char_array_t *a) { (void)a; }
static inline size_t char_hash(const char_array_t *a) {
size_t hash = 0;
const char *s = a->a;
while (*s) hash = hash * 31421 + (*s++) + 6927;
return hash;
}
#define i_tag achar
#define i_key char_array_t
#define i_val char_array_t
#define i_hash char_hash
#define i_eq char_equal_p
#include <stc/cmap.h>
static void
test_dict_big(size_t n)
{
cmap_achar dict = cmap_achar_init();
for (size_t i = 0; i < n; i++) {
char_array_t s1, s2;
sprintf(s1.a, "%u", rand_get());
sprintf(s2.a, "%u", rand_get());
cmap_achar_insert_or_assign(&dict, s1, s2);
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
char_array_t s1;
sprintf(s1.a, "%u", rand_get());
const cmap_achar_value*val = cmap_achar_get(&dict, s1);
if (val != NULL)
s ++;
}
g_result = s;
cmap_achar_drop(&dict);
}
/********************************************************************************************/
#define i_val float
#define i_tag float
#include <stc/cvec.h>
static void test_sort(size_t n)
{
cvec_float a1 = cvec_float_init();
for(size_t i = 0; i < n; i++) {
cvec_float_push_back(&a1, rand_get() );
}
cvec_float_sort(&a1);
g_result = *cvec_float_at(&a1, 0);
cvec_float_drop(&a1);
}
/********************************************************************************************/
const config_func_t table[] = {
{ 10, "List", 10000000, 0, test_list, 0},
{ 20, "Array", 100000000, 0, test_array, 0},
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
{ 40, "dict", 1000000, 0, test_dict, 0},
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
{ 50, "Sort",10000000, 0, test_sort, 0},
};
int main(int argc, const char *argv[])
{
test("STC", numberof(table), table, argc, argv);
exit(0);
}
+77 -12
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - String Bench
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -22,11 +22,14 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define NDEBUG
#include <string>
#include <sstream>
#include <string>
#include <vector>
#define M_USE_SMALL_NAME 0
#include "common.h"
#include "m-string.h"
@@ -43,6 +46,10 @@ extern "C" {
#include "bstraux.h"
#endif
#if defined(BENCH_CAN_USE_POTTERY)
#include "pottery/string/string.h"
#endif
/*
* BENCH
* 2000000
@@ -104,27 +111,28 @@ size_t bench_stl(unsigned n)
size_t bench_mlib(unsigned n)
{
string_t *tab = (string_t*) malloc (n * sizeof (string_t));
m_string_t *tab = (m_string_t*) malloc (n * sizeof (m_string_t));
assert (tab != 0);
// P1
for(unsigned i = 0; i < n; i++) {
string_init(tab[i]);
string_printf(tab[i], "%u", rand_get());
m_string_init(tab[i]);
m_string_set_ui(tab[i], rand_get());
}
// P2
string_t str;
string_init(str);
m_string_t str;
m_string_init(str);
for(unsigned i = 0; i < n; i++) {
string_cat(str, tab[permutation_tab[i]]);
m_string_cat(str, tab[permutation_tab[i]]);
}
// P3
string_replace_all_str(str, "1234", "WELL");
string_replace_all_str(str, "56789", "DONE");
size_t length = string_size(str);
m_string_replace_all_cstr(str, "1234", "WELL");
m_string_replace_all_cstr(str, "56789", "DONE");
size_t length = m_string_size(str);
// Clean
string_clear(str);
m_string_clear(str);
for(unsigned i = 0; i < n; i++) {
string_clear(tab[i]);
m_string_clear(tab[i]);
}
free(tab);
return length;
@@ -217,6 +225,57 @@ size_t bench_sds(unsigned n)
}
#endif
#if defined(BENCH_CAN_USE_POTTERY)
size_t pottery_find_cstr(string_t *b, size_t index, const char *pattern)
{
// I cannot find such function in the API
const char *s = string_cstr(b);
const char *r = strstr(&s[index], pattern);
return r == NULL ? SIZE_MAX : r - s;
}
void pottery_replace_all_str(string_t *str, const char *s, const char *d)
{
size_t i = 0;
while (true) {
i = pottery_find_cstr(str, i, s);
if (i==SIZE_MAX) return;
string_remove(str, i, strlen(s));
string_insert_cstr(str, i, d);
}
}
size_t bench_pottery(unsigned n)
{
string_t *tab = (string_t*) malloc (n * sizeof (string_t));
assert (tab != 0);
// P1
for(unsigned i = 0; i < n; i++) {
string_init(&tab[i]);
string_append_format(&tab[i], "%u", rand_get());
}
// P2
string_t str;
string_init(&str);
for(unsigned i = 0; i < n; i++) {
string_append_string(&str, &tab[permutation_tab[i]]);
}
// P3
pottery_replace_all_str(&str, "1234", "WELL");
pottery_replace_all_str(&str, "56789", "DONE");
size_t length = string_length(&str);
// Clean
string_clear(&str);
for(unsigned i = 0; i < n; i++) {
string_clear(&tab[i]);
}
free(tab);
return length;
}
#endif
int main(int argc, const char *argv[])
{
@@ -247,6 +306,12 @@ int main(int argc, const char *argv[])
length = bench_bstrlib(n);
name = "BSTRLIB";
break;
#endif
#if defined(BENCH_CAN_USE_POTTERY)
case 5:
length = bench_pottery(n);
name = "POTTERY";
break;
#endif
default:
exit(0);
+197 -48
View File
@@ -35,8 +35,8 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Update of integrating M*LIB, LIBSRT, SDS & GLIB
Copyright (c) 2018-2021 Patrick Pelissier
/* Update of integrating M*LIB, LIBSRT, SDS, GLIB & POTTERY
Copyright (c) 2018-2022 Patrick Pelissier
*/
/*
@@ -48,11 +48,13 @@
*
*/
#define NDEBUG
#include <stdio.h>
#include <time.h>
#include <limits.h>
#define NDEBUG
#define M_USE_SMALL_NAME 0
#include "common.h"
#ifdef BENCH_CAN_USE_MSTARLIB
@@ -83,6 +85,10 @@ extern "C" {
#include "gmodule.h"
#endif
#if defined(BENCH_CAN_USE_POTTERY)
#include "pottery/string/string.h"
#endif
/* Time of a test */
#define TEST_SECONDS (5)
@@ -433,11 +439,11 @@ int testSRT_concat (int count) {
int testMLIB_emptyCtor (int count) {
int i, c = 0;
for (c=i=0; i < count; i++) {
string_t b;
string_init(b);
m_string_t b;
m_string_init(b);
BARRIER(&b);
c += string_size(b) ^i;
string_clear(b);
c += m_string_size(b) ^i;
m_string_clear(b);
}
return c;
}
@@ -445,11 +451,11 @@ int testMLIB_emptyCtor (int count) {
int testMLIB_nonemptyCtor (int count) {
int i, c = 0;
for (c=i=0; i < count; i++) {
string_t b;
string_init_set_str(b, TESTSTRING1);
m_string_t b;
m_string_init_set_cstr(b, TESTSTRING1);
BARRIER(&b);
c += string_size(b) ^i;
string_clear(b);
c += m_string_size(b) ^i;
m_string_clear(b);
}
return c;
}
@@ -457,93 +463,93 @@ int testMLIB_nonemptyCtor (int count) {
int testMLIB_smallnonemptyCtor (int count) {
int i, c = 0;
for (c=i=0; i < count; i++) {
string_t b;
string_init_set_str(b, SMALLTESTSTRING1);
m_string_t b;
m_string_init_set_cstr(b, SMALLTESTSTRING1);
BARRIER(&b);
c += string_size(b) ^i;
string_clear(b);
c += m_string_size(b) ^i;
m_string_clear(b);
}
return c;
}
int testMLIB_cstrAssignment (int count) {
int i, c = 0;
string_t b;
string_init(b);
m_string_t b;
m_string_init(b);
for (c=i=0; i < count; i++) {
string_set_str(b, TESTSTRING1);
m_string_set_cstr(b, TESTSTRING1);
BARRIER(&b);
c += string_size(b) ^i;
c += m_string_size(b) ^i;
}
string_clear(b);
m_string_clear(b);
return c;
}
int testMLIB_extraction (int count) {
int i, c = 0;
string_t b;
string_init_set_str(b, TESTSTRING1);
m_string_t b;
m_string_init_set_cstr(b, TESTSTRING1);
for (c=i=0; i < count; i++) {
c += string_get_char(b, (i & 7));
c += string_get_char(b, (i & 7) ^ 8);
c += string_get_char(b, (i & 7) ^ 4) ^i;
c += m_string_get_char(b, (i & 7));
c += m_string_get_char(b, (i & 7) ^ 8);
c += m_string_get_char(b, (i & 7) ^ 4) ^i;
BARRIER(&b);
}
string_clear(b);
m_string_clear(b);
return c;
}
int testMLIB_scan (int count) {
int i, c = 0;
string_t b;
string_init_set_str(b, "Dot. 123. Some more data.");
m_string_t b;
m_string_init_set_cstr(b, "Dot. 123. Some more data.");
for (c=i=0; i < count; i++) {
c += string_search_char (b, '.');
c += string_search_str (b, "123");
c += string_search_pbrk (b, "sm") ^i;
c += m_string_search_char (b, '.');
c += m_string_search_cstr (b, "123");
c += m_string_search_pbrk (b, "sm") ^i;
BARRIER(&b);
}
string_clear(b);
m_string_clear(b);
return c;
}
int testMLIB_concat (int count) {
int i, j, c = 0;
string_t a, accum;
string_init_set_str(a, TESTSTRING1);
string_init (accum);
m_string_t a, accum;
m_string_init_set_cstr(a, TESTSTRING1);
m_string_init (accum);
for (j=0; j < count; j++) {
string_set_str(accum, "");
m_string_set_cstr(accum, "");
for (i=0; i < 250; i++) {
string_cat(accum, a);
string_cat_str(accum, "!!");
m_string_cat(accum, a);
m_string_cat_cstr(accum, "!!");
BARRIER(&accum);
c += string_size(accum) ^i;
c += m_string_size(accum) ^i;
}
}
string_clear(a);
string_clear(accum);
m_string_clear(a);
m_string_clear(accum);
return c;
}
int testMLIB_replace (int count) {
int j, c = 0;
string_t a;
string_init_set_str(a, TESTSTRING1);
m_string_t a;
m_string_init_set_cstr(a, TESTSTRING1);
for (j=0; j < count; j++) {
string_replace_at(a, 11, 4, "XXXXXX");
string_replace_at(a, 23, 2, "XXXXXX");
string_replace_at(a, 4, 8, "XX");
m_string_replace_at(a, 11, 4, "XXXXXX");
m_string_replace_at(a, 23, 2, "XXXXXX");
m_string_replace_at(a, 4, 8, "XX");
BARRIER(&a);
c += string_size(a) ^j;
c += m_string_size(a) ^j;
}
string_clear(a);
m_string_clear(a);
return c;
}
#endif
@@ -774,6 +780,118 @@ int testGLIB_concat (int count) {
//int testGLIB_replace (int count): not available
#endif
#ifdef BENCH_CAN_USE_POTTERY
int testPOTTERY_emptyCtor (int count) {
int i, c = 0;
for (c=i=0; i < count; i++) {
string_t b;
string_init(&b);
BARRIER(&b);
c += string_length(&b) ^i;
string_clear(&b);
}
return c;
}
int testPOTTERY_nonemptyCtor (int count) {
int i, c = 0;
for (c=i=0; i < count; i++) {
string_t b;
string_init_cstr(&b, TESTSTRING1);
BARRIER(&b);
c += string_length(&b) ^i;
string_clear(&b);
}
return c;
}
int testPOTTERY_smallnonemptyCtor (int count) {
int i, c = 0;
for (c=i=0; i < count; i++) {
string_t b;
string_init_cstr(&b, SMALLTESTSTRING1);
BARRIER(&b);
c += string_length(&b) ^i;
string_clear(&b);
}
return c;
}
int testPOTTERY_cstrAssignment (int count) {
int i, c = 0;
string_t b;
string_init(&b);
for (c=i=0; i < count; i++) {
string_set_cstr(&b, TESTSTRING1);
BARRIER(&b);
c += string_length(&b) ^i;
}
string_clear(&b);
return c;
}
int testPOTTERY_extraction (int count) {
int i, c = 0;
string_t b;
string_init_cstr(&b, TESTSTRING1);
for (c=i=0; i < count; i++) {
c += string_cstr(&b)[(i & 7)];
c += string_cstr(&b)[(i & 7) ^ 8];
c += string_cstr(&b)[(i & 7) ^ 4] ^i;
BARRIER(&b);
}
string_clear(&b);
return c;
}
size_t pottery_find_cstr(string_t *b, const char *pattern)
{
// I cannot find such function in the API
const char *s = string_cstr(b);
const char *r = strstr(s, pattern);
return r == NULL ? SIZE_MAX : r - s;
}
int testPOTTERY_scan (int count) {
int i, c = 0;
string_t b;
string_init_cstr(&b, "Dot. 123. Some more data.");
for (c=i=0; i < count; i++) {
c += string_find_char (&b, 0, '.');
c += pottery_find_cstr (&b, "123");
c += string_find_chars_cstr (&b, 0, "sm") ^i;
BARRIER(&b);
}
string_clear(&b);
return c;
}
int testPOTTERY_concat (int count) {
int i, j, c = 0;
string_t a, accum;
string_init_cstr(&a, TESTSTRING1);
string_init (&accum);
for (j=0; j < count; j++) {
string_set_cstr(&accum, "");
for (i=0; i < 250; i++) {
string_append_string(&accum, &a);
string_append_cstr(&accum, "!!");
BARRIER(&accum);
c += string_length(&accum) ^i;
}
}
string_clear(&a);
string_clear(&accum);
return c;
}
// No replace function available
#endif
#define NTESTS 8
struct flags {
@@ -999,6 +1117,37 @@ int benchTest (const struct flags * runflags) {
}
#endif
#ifdef BENCH_CAN_USE_POTTERY
if (runflags->runtest[0]) {
c += timeTest (cps, testPOTTERY_emptyCtor, 100000);
print ("POTTERY", "empty constructor", cps);
}
if (runflags->runtest[1]) {
c += timeTest (cps, testPOTTERY_nonemptyCtor, 100000);
print ("POTTERY", "non-empty constructor", cps);
}
if (runflags->runtest[2]) {
c += timeTest (cps, testPOTTERY_smallnonemptyCtor, 100000);
print ("POTTERY", "small non-empty constructor", cps);
}
if (runflags->runtest[3]) {
c += timeTest (cps, testPOTTERY_cstrAssignment, 100000);
print ("POTTERY", "Char * assignment", cps);
}
if (runflags->runtest[4]) {
c += timeTest (cps, testPOTTERY_extraction, 100000);
print ("POTTERY", "char extraction", cps);
}
if (runflags->runtest[5]) {
c += timeTest (cps, testPOTTERY_scan, 100000);
print ("POTTERY", "scan", cps);
}
if (runflags->runtest[6]) {
c += timeTest (cps, testPOTTERY_concat, 10);
print ("POTTERY", "concatenation", cps * 250);
}
#endif
return c;
}
+2 -2
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - common functions for bench module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -147,7 +147,7 @@ select_config(int func, size_t n, const config_func_t functions[])
fprintf(stderr, " %d: %s\n", functions[i].num, functions[i].funcname);
}
fprintf(stderr,
"USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--grapĥ]\n"
"USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--graph]\n"
"[--repeat number] [--best|--average|--best-within] [--quiet]\n");
exit(-1);
}
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - common functions for bench module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* MLIB - TEST module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
+8
View File
@@ -73,3 +73,11 @@ V0.5.*: * M_INVERT is renamed into M_REVERSE to be more coherent with the REVERS
* Rename CLEAN operator in RESET operator.
* Rename GET_SET_KEY operator in SAFE_GET_KEY operator.
V0.6.*: * Rename M_DEFAULT_OPLIST in M_BASIC_OPLIST
* Remove experimental macro M_IF_DEFAULT1.
* Remove M_INVERT
* String functions with _str suffix for C strings have been renamed with _cstr suffix (like string_cat_str ==> m_string_cat_cstr)
Note: the compatible layer still keeps the old naming,
so except if you are using the prefixed version of the strings
or the bounded strings API, you won't need to upgrade your code.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 113 KiB

+6 -3
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2017-2021, Patrick Pelissier
# Copyright (c) 2017-2022, Patrick Pelissier
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -23,6 +23,7 @@
CC=cc -std=c99
CFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -g
GMP_DIR=
MPFR_DIR=$(GMP_DIR)
CPPFLAGS=-I..
LDFLAGS=-pthread
RM=rm -f
@@ -30,7 +31,7 @@ RM=rm -f
.SUFFIXES: .c .exe
.c.exe:
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) `cat config` $< -o $@
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@ `cat config`
all: config
$(MAKE) `ls ex-*.c|sed -e 's/\.c/\.exe/g'`
@@ -38,7 +39,9 @@ all: config
config:
printf "#include <gmp.h>\nint main(void){mpz_t z; mpz_init(z); return 0;}\n" > config-test.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp config-test.c -o config-test.exe 2> /dev/null && echo "-DHAVE_GMP=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0" > config
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib config-test.c -lgmp -o config-test.exe 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=0 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0 -DHAVE_MPFR=0 " > config
printf "#include <mpfr.h>\nint main(void){mpfr_t z; mpfr_init(z); return 0;}\n" > config-test.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -I$(GMP_DIR)/include -I$(MPFR_DIR)/include -L$(GMP_DIR)/lib -L$(MPFR_DIR)/lib config-test.c -lmpfr -lgmp -o config-test.exe 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -I$(MPFR_DIR)/include -L$(MPFR_DIR)/lib -lmpfr -lgmp" > config || echo "MPFR not available"
$(RM) config-test.c config-test.exe
clean:
+3 -3
View File
@@ -3,11 +3,11 @@
#include "m-algo.h"
#include "m-string.h"
/* Define a dictionnary (or hash_map or undordered_map)
/* Define a dictionnary (or hash_map or unordered_map)
* from a string_t to int */
DICT_DEF2(dict, string_t, int)
/* Register the oplist of this dictionnary globally */
#define M_OPL_dict_t() DICT_OPLIST(dict, STRING_OPLIST, M_DEFAULT_OPLIST)
#define M_OPL_dict_t() DICT_OPLIST(dict, STRING_OPLIST, M_BASIC_OPLIST)
/* Define an array of integer */
ARRAY_DEF(vector_int, int)
@@ -23,7 +23,7 @@ ARRAY_DEF(vector_int, int)
int main(void)
{
int s;
int s = 0;
// Init keys as a vector_int_t, initialize it (and prepare its destruction)
M_LET(keys, vector_int_t)
// Initialize m as a dictionnary and initialize it with the given database
+1 -1
View File
@@ -19,7 +19,7 @@ int main(void)
M_LET(s, string_t)
// Let v be a vector of integer and initialize it.
M_LET( (v, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), vector_int_t) {
int sum, product;
int sum = 0, product = 0;
// Compute the sum of theses integers.
ALGO_REDUCE(sum, v, vector_int_t, add);
+9 -9
View File
@@ -24,7 +24,7 @@
/* Generate prototypes and inline functions
for basic types.
For integer and floats, there is no need to specify
an oplist. M_DEFAULT_OPLIST will be used.
an oplist. M_BASIC_OPLIST will be used.
*/
ARRAY_DEF(r_bool, bool)
@@ -105,7 +105,7 @@ test_int(int n)
But with an explicit oplist.
This generates exactly the same code than r_int
*/
ARRAY_DEF(r_int2, signed int, M_DEFAULT_OPLIST)
ARRAY_DEF(r_int2, signed int, M_BASIC_OPLIST)
static int
test_int2(int n)
@@ -180,7 +180,7 @@ test_float(int n)
/* Same with type double and an explicit oplist*/
ARRAY_DEF(r_double, double, M_DEFAULT_OPLIST)
ARRAY_DEF(r_double, double, M_BASIC_OPLIST)
static int
test_double(int n)
@@ -231,7 +231,7 @@ test_cstring(int n)
r_cstring_init(array);
for(int i = 0; i < n; i++) {
char buffer[10];
char buffer[16];
// Create a string from the integer
sprintf(buffer, "%d", i);
// We need to make an explicit copy of the string
@@ -478,7 +478,7 @@ test_rockme2b(int n)
/* Same with a structure type defined as a tuple.
We first define a tuple. No need to specify the oplist as it uses basic C types
so M_DEFAULT_OPLIST is used.
so M_BASIC_OPLIST is used.
Then we define the array, giving it the oplist definition of the tuple:
the macro TUPLE_OPLIST is used to build it based on the tuple name,
@@ -486,7 +486,7 @@ test_rockme2b(int n)
*/
TUPLE_DEF2(rock_you, (n, int), (other, float))
ARRAY_DEF(r_rockme3, rock_you_t, TUPLE_OPLIST(rock_you, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
ARRAY_DEF(r_rockme3, rock_you_t, TUPLE_OPLIST(rock_you, M_BASIC_OPLIST, M_BASIC_OPLIST))
static int
test_rockme3(int n)
@@ -520,7 +520,7 @@ test_rockme3(int n)
/* Same with a structure type defined as a tuple using global registeration.
We first define a tuple. No need to specify the oplist as it uses basic C types
so M_DEFAULT_OPLIST is used.
so M_BASIC_OPLIST is used.
Then we register the oplist of rock_us_t by defining a macro based
on M_OPL_ + type name + () which expands with the oplist of the type.
@@ -533,7 +533,7 @@ test_rockme3(int n)
*/
TUPLE_DEF2(rock_us, (n, int), (other, float))
#define M_OPL_rock_us_t() TUPLE_OPLIST(rock_us, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
#define M_OPL_rock_us_t() TUPLE_OPLIST(rock_us, M_BASIC_OPLIST, M_BASIC_OPLIST)
ARRAY_DEF(r_rockme4, rock_us_t)
@@ -612,7 +612,7 @@ int main (int argc, const char *argv[])
s = test_rockme3(n);
printf ("S[rockme3] = %d\n", s);
s = test_rockme3(n);
s = test_rockme4(n);
printf ("S[rockme4] = %d\n", s);
exit(0);
+1
View File
@@ -96,6 +96,7 @@ static void data_node_clear(data_node *obj)
and gives the minimum oplist allowing M*LIB to handle
properly the object 'data_node' with the API convention
to respect for calling the methods.
The Manual defines the different supported API.
*/
ARRAY_DEF(/* the array prefix */ array_data_node,
/* the object type */ data_node,
+2 -2
View File
@@ -5,13 +5,13 @@
// The number 5 is the number of elements in a node of the B+TREE
BPTREE_DEF2(map_employee_id, 5, int, string_t)
// Register the oplist of this map globally.
#define M_OPL_map_employee_id_t() BPTREE_OPLIST2(map_employee_id, M_DEFAULT_OPLIST, STRING_OPLIST)
#define M_OPL_map_employee_id_t() BPTREE_OPLIST2(map_employee_id, M_BASIC_OPLIST, STRING_OPLIST)
// Define a map string -> int named map_employee_name
// The number 5 is the number of elements in a node of the B+TREE
BPTREE_DEF2(map_employee_name, 5, string_t, int)
// Register the oplist of this map globally.
#define M_OPL_map_employee_name_t() BPTREE_OPLIST2(map_employee_name, STRING_OPLIST, M_DEFAULT_OPLIST)
#define M_OPL_map_employee_name_t() BPTREE_OPLIST2(map_employee_name, STRING_OPLIST, M_BASIC_OPLIST)
int main(void)
{
+5
View File
@@ -1,5 +1,10 @@
#include "m-core.h"
/* This example show how to use the M_LET_IF macro
that enables to construct an object and continue
if the construction succeeds.
*/
// Stubs defined for the example. Real code will use soundio library.
struct SoundIo { int x; };
struct SoundIoDevice { int x; };
+1 -1
View File
@@ -6,7 +6,7 @@
// Define a dictionnary of string --> int
// named 'dict_str'
DICT_DEF2(dict_str, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
DICT_DEF2(dict_str, string_t, STRING_OPLIST, int, M_BASIC_OPLIST)
int main(void)
{
+3 -3
View File
@@ -1,10 +1,10 @@
#include "m-dict.h"
// Let's define a dictionary of 'unsigned int' --> 'char
DICT_DEF2(dict_m32, unsigned int, M_DEFAULT_OPLIST, char, M_DEFAULT_OPLIST)
DICT_DEF2(dict_m32, unsigned int, M_BASIC_OPLIST, char, M_BASIC_OPLIST)
// Let's create a synonym for its oplist.
#define M32_OPLIST DICT_OPLIST(dict_m32, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
#define M32_OPLIST DICT_OPLIST(dict_m32, M_BASIC_OPLIST, M_BASIC_OPLIST)
#if 1 // Non macro version.
@@ -14,7 +14,7 @@ int main(void) {
dict_m32_set_at (h, 5, 10); // h[5] = 10
char *k = dict_m32_get(h, 10); // No 10 in h, so k == NULL
int is_missing = (k != NULL); // true
assert (is_missing);
assert (is_missing); (void) is_missing;
dict_m32_erase(h, 5); // h is now empty
dict_m32_it_t it; // iterate over all dictionnary
for (dict_m32_it (it, h) ; !dict_m32_end_p (it); dict_m32_next(it)) {
+3 -2
View File
@@ -28,11 +28,11 @@ int main(void)
M_LET (grow, list_string_t)
M_LET (tmpstr, string_t) { // And let's create also a string_t
// add string elements to the list
// add string elements to the list in different ways
list_string_push_back (grow, STRING_CTE("AB"));
string_printf(tmpstr, "%d", 12);
list_string_push_back (grow, tmpstr);
list_string_push_back (grow, STRING_CTE("CD"));
list_string_emplace_back (grow, "CD");
// Serialize the list of string into a big string.
list_string_get_str (tmpstr, grow, false);
@@ -75,6 +75,7 @@ int main(void)
// Split a string into a list.
string_set_str(tmpstr, "HELLO;JOHN;HOW;ARE;YOU");
astring_split(grow, tmpstr, ';');
// Iterate over the splitted list
for M_EACH (item, grow, list_string_t) {
printf ("Split Item = %s\n", string_get_cstr(*item) );
}
+2 -2
View File
@@ -25,8 +25,8 @@
/* Define the needed data structure : */
// Define a dictionnary of constant string --> integer and register it.
DICT_DEF2(dict_mph, const char *, M_CSTR_OPLIST, uint32_t, M_DEFAULT_OPLIST)
#define M_OPL_dict_mph_t() DICT_OPLIST(dict_mph, M_CSTR_OPLIST, M_DEFAULT_OPLIST)
DICT_DEF2(dict_mph, const char *, M_CSTR_OPLIST, uint32_t, M_BASIC_OPLIST)
#define M_OPL_dict_mph_t() DICT_OPLIST(dict_mph, M_CSTR_OPLIST, M_BASIC_OPLIST)
// Define an array of integer to store the value and register it.
ARRAY_DEF(array_value, uint32_t) // Start from 1. 0 is 'None'
-70
View File
@@ -1,70 +0,0 @@
#if HAVE_GMP
#include <stdio.h>
#include <gmp.h>
#include "m-variant.h"
#include "m-string.h"
#include "m-dict.h"
#include "m-array.h"
/* Define a variant over two integers named integer_t
Notice than mpz_t has special init & clear functions
mpz_init & mpz_clear.
This is handle by the library.
*/
VARIANT_DEF2(my_integer,
(n, long long, M_DEFAULT_OPLIST),
(z, mpz_t, M_CLASSIC_OPLIST(mpz)))
/* Define the oplist associated to this variant */
#define MY_INTEGER_OPLIST VARIANT_OPLIST(my_integer, M_DEFAULT_OPLIST, M_CLASSIC_OPLIST(mpz))
/* Define a dictionary of string --> integer named dict_my_t */
DICT_DEF2(my_dict,
string_t, STRING_OPLIST,
my_integer_t, MY_INTEGER_OPLIST)
/* Define the oplist associated to this dictionary */
#define MY_DICT_OPLIST DICT_OPLIST(my_dict, STRING_OPLIST, MY_INTEGER_OPLIST)
/* Define an array of such dictionary named array_my_t */
ARRAY_DEF(my_array, my_dict_t, MY_DICT_OPLIST)
/* Define the oplist associated to this array of dictionary of variant */
#define MY_ARRAY_OPLIST ARRAY_OPLIST(my_array, MY_DICT_OPLIST)
int main(void)
{
M_LET(z, MY_INTEGER_OPLIST) /* Define & init & clear an instance of a variant of integer */
M_LET(dict, MY_DICT_OPLIST) /* Define & init & clear an instance of a dictionary of variant */
M_LET(array, MY_ARRAY_OPLIST) /* Define & init & clear an intance of an array of dictionary of variant */
M_LET(gmp, M_CLASSIC_OPLIST(mpz)) /* M_LET allows even with non container type */
{
my_integer_set_n (z, 17LL); // Set z as the long long 17
my_dict_set_at(dict, STRING_CTE("n1"), z); // Push it in the dictionary
mpz_set_str(gmp, "25446846874687468746874687468746874686874", 10); // Set gmp to a very long integer.
my_integer_set_z (z, gmp); // Set z as the mpz_t variable
my_dict_set_at(dict, STRING_CTE("n2"), z); // Push it in the dictionary
my_array_push_back (array, dict); // Push the dictionary in the array
// Iterate over the array container
for M_EACH(item, array, MY_ARRAY_OPLIST) {
// Iterate over the dictionary container
for M_EACH(p, *item, MY_DICT_OPLIST) {
// Dictionary iterator are pair (key,value)
if (my_integer_n_p(p->value)) {
printf ("It is a long long, value = %lld\n",
*my_integer_cget_n(p->value));
}
if (my_integer_z_p(p->value)) {
printf ("It is a mpz_t, value =");
mpz_out_str(stdout, 10, *my_integer_cget_z(p->value));
printf("\n");
}
}
}
} /* All variables are automatically cleared beyond this point */
}
#else
// Nothing to do
int main(void) { return 0; }
#endif
+2 -2
View File
@@ -84,8 +84,8 @@ DICT_DEF2(dict_json, string_t, STRING_OPLIST, json_t, JSON_OPLIST)
ARRAY_DEF(array_json, json_t, JSON_OPLIST)
VARIANT_DEF2(variant_json,
(boolean, bool, M_OPEXTEND(M_DEFAULT_OPLIST, OUT_STR(boolean_out_str), IN_STR(boolean_in_str M_IPTR)) ),
(real, float, M_OPEXTEND (M_DEFAULT_OPLIST, OUT_STR(real_out_str), IN_STR(real_in_str M_IPTR))),
(boolean, bool, M_OPEXTEND(M_BASIC_OPLIST, OUT_STR(boolean_out_str), IN_STR(boolean_in_str M_IPTR)) ),
(real, float, M_OPEXTEND (M_BASIC_OPLIST, OUT_STR(real_out_str), IN_STR(real_in_str M_IPTR))),
(array, array_json_t, ARRAY_OPLIST(array_json, JSON_OPLIST)),
(dict, dict_json_t, DICT_OPLIST(dict_json, STRING_OPLIST, JSON_OPLIST)))
+5 -5
View File
@@ -10,7 +10,7 @@
order to show/test the good chaining of the structures */
TUPLE_DEF2(symbol, (type, int), (name, string_t))
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_DEFAULT_OPLIST, STRING_OPLIST)
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_BASIC_OPLIST, STRING_OPLIST)
ARRAY_DEF(symbol_list, symbol_t)
#define M_OPL_symbol_list_t() ARRAY_OPLIST(symbol_list, M_OPL_symbol_t())
@@ -19,13 +19,13 @@ TUPLE_DEF2(record, (fields, symbol_list_t))
#define M_OPL_record_t() TUPLE_OPLIST(record, M_OPL_symbol_list_t())
TUPLE_DEF2(my_tuple, (name, string_t), (value, int))
#define M_OPL_my_tuple_t() TUPLE_OPLIST(my_tuple)
#define M_OPL_my_tuple_t() TUPLE_OPLIST(my_tuple, STRING_OPLIST, M_BASIC_OPLIST)
ARRAY_DEF(my_list_of_tuple, my_tuple_t)
#define M_OPL_my_list_of_tuple_t() ARRAY_OPLIST(my_list_of_tuple)
TUPLE_DEF2(my_tuple_of_tuple, (name, string_t), (inner_tuple, my_tuple_t))
#define M_OPL_my_tuple_of_tuple_t() TUPLE_OPLIST(my_tuple_of_tuple)
#define M_OPL_my_tuple_of_tuple_t() TUPLE_OPLIST(my_tuple_of_tuple, STRING_OPLIST, M_OPL_my_tuple_t() )
LIST_DEF(list_of_tuple_of_tuple, my_tuple_of_tuple_t)
#define M_OPL_list_of_tuple_of_tuple_t() LIST_OPLIST(list_of_tuple_of_tuple, M_OPL_my_tuple_of_tuple_t() )
@@ -37,11 +37,11 @@ BUFFER_DEF(trbuff, my_triple_tuple_t, 100, BUFFER_QUEUE)
#define M_OPL_trbuff_t() BUFFER_OPLIST(trbuff, M_OPL_my_triple_tuple_t())
TUPLE_DEF2(my_junction, (active, bool), (buffer, trbuff_t))
#define M_OPL_my_junction_t() TUPLE_OPLIST(my_junction, M_DEFAULT_OPLIST, M_OPL_trbuff_t())
#define M_OPL_my_junction_t() TUPLE_OPLIST(my_junction, M_BASIC_OPLIST, M_OPL_trbuff_t())
TUPLE_DEF2(mlib_point, (x, int), (y, int))
#define M_OPL_mlib_point_t() \
TUPLE_OPLIST(mlib_point, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
TUPLE_OPLIST(mlib_point, M_BASIC_OPLIST, M_BASIC_OPLIST)
TUPLE_DEF2(mlib_points, (first_ref, mlib_point_ptr, M_PTR_OPLIST),
(second_ref, mlib_point_ptr, M_PTR_OPLIST),
+8 -1
View File
@@ -3,7 +3,14 @@
#include "m-array.h"
#include "m-string.h"
// Let's create an array of string_t and register it globaly
/* This example show ARRAY_DEF usage with string,
M_LET macro usage with complex initialization condition:
how to initialize a dynamic array and initialize it with the given arguments.
It show also the M_EACH keywork
*/
// Let's create a dynamic array of string_t and register it globaly
// a so called std::vector<std::string> in C++
ARRAY_DEF(vector_string, string_t)
#define M_OPL_vector_string_t() ARRAY_OPLIST(vector_string, STRING_OPLIST)
+16
View File
@@ -0,0 +1,16 @@
/*
* Micro example to test if M*LIB supports not using stdio.h
*/
#define M_USE_STDIO 0
#define M_RAISE_FATAL(...) abort()
#include "m-array.h"
ARRAY_DEF(arr, int)
int main(void) {
arr_t a;
arr_init(a);
arr_push_back(a, 4);
arr_clear(a);
return 0;
}
+1 -2
View File
@@ -5,8 +5,7 @@
#include "m-rbtree.h"
// Let's define one utility function.
void *xmalloc(size_t n);
void *xmalloc(size_t n)
static void *xmalloc(size_t n)
{
void *p = malloc (n);
if (!p) abort();
+3 -2
View File
@@ -5,7 +5,7 @@
/* Definition of an associative map string_t --> size_t */
DICT_DEF2(dict_str, string_t, size_t)
#define M_OPL_dict_str_t() DICT_OPLIST(dict_str, STRING_OPLIST, M_DEFAULT_OPLIST)
#define M_OPL_dict_str_t() DICT_OPLIST(dict_str, STRING_OPLIST, M_BASIC_OPLIST)
/* Definition of an array of string_t */
ARRAY_DEF(vector_str, string_t)
@@ -26,13 +26,14 @@ int main(void)
// Count the words.
M_LET(map, dict_str_t) {
// Count the words:
// Count the words into the dictionnary 'map'
for M_EACH(w, words, vector_str_t) {
(*dict_str_safe_get(map, *w)) ++;
}
// Print the count:
for M_EACH(p, map, dict_str_t) {
// In C11 version we can use the M_PRINT macro that simplifies formatting.
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
M_PRINT(p->value, " occurences of ", p->key, "\n");
#else
+1 -1
View File
@@ -11,7 +11,7 @@ TUPLE_DEF2(employee,
(age, int),
(idnum, int))
/* Register globaly the employee_t oplist */
#define M_OPL_employee_t() TUPLE_OPLIST(employee, STRING_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
#define M_OPL_employee_t() TUPLE_OPLIST(employee, STRING_OPLIST, M_BASIC_OPLIST, M_BASIC_OPLIST)
/* Define an array of employee, register the oplist and define further algorithms on it */
ARRAY_DEF(vector_employee, employee_t)
+201
View File
@@ -0,0 +1,201 @@
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "m-tuple.h"
#include "m-tree.h"
#include "m-worker.h"
#include "m-string.h"
#include "m-atomic.h"
/* Sort the atomic unsigned int with the biggest value first. */
static inline int atomic_uint_cmp(const atomic_uint *a, const atomic_uint *b)
{
unsigned ai = atomic_load(a), bi = atomic_load(b);
return ai > bi ? -1 : ai < bi;
}
/* Disable HASH for atomic as the default hash method won't work */
#define M_OPL_atomic_uint() M_OPEXTEND(M_BASIC_OPLIST, HASH(0), CMP(API_6(atomic_uint_cmp)))
/* Define a directory as the number of lines of the files in this directory
and the name of the directory
(Only sort with the number value by disable the sort compare for the string).
*/
TUPLE_DEF2( dir, (nlines, atomic_uint), (name, string_t, M_OPEXTEND(STRING_OPLIST, CMP(0))))
#define M_OPL_dir_t() TUPLE_OPLIST(dir, M_BASIC_OPLIST, M_STRING_OPLIST)
/* A hierarchical tree of directory */
M_TREE_DEF(tree, dir_t)
/* Maximum number of characters read by file */
#define MAX_READ_BUFFER 8192
/* Maximum number of directory to scan */
#define MAX_DIRECTORY 100000
static tree_it_t
add_directory(tree_it_t parent, const string_t dirname)
{
// TODO: return dir_emplace_child(parent, 0, dirname); to simplify this function.
// which is too complex for what she does.
dir_t data;
tree_it_t it;
dir_init_emplace(data, 0, dirname);
if (tree_end_p(parent)) {
it = tree_set_root( tree_tree(parent), data);
} else {
it = tree_insert_child(parent, data);
}
dir_clear(data);
return it;
}
/* count the number of end of line character in the buffer */
static unsigned
count_eol(const char buffer[], size_t num)
{
unsigned count = 0;
for(size_t i = 0; i < num; i++) {
count += buffer[i] == '\n';
}
return count;
}
static bool
is_a_c_file(const string_t filename)
{
return (string_end_with_str_p(filename, ".c")
|| string_end_with_str_p(filename, ".h")
|| string_end_with_str_p(filename, ".cpp")
|| string_end_with_str_p(filename, ".hpp"));
}
static void
scan_file(tree_it_t parent, const string_t filename)
{
if (!is_a_c_file(filename)) return;
FILE *f = fopen(string_get_cstr(filename), "rt");
if (f == NULL) {
fprintf(stderr, "ERROR: Cannot open %s as a text file.\n", string_get_cstr(filename) );
exit(1);
}
/* Read the FILE per bulk of MAX_READ_BUFFER */
char buffer[MAX_READ_BUFFER];
unsigned count = 0;
size_t num;
do {
num = fread (buffer, 1, MAX_READ_BUFFER, f);
count += count_eol(buffer, num);
} while (num == MAX_READ_BUFFER);
fclose(f);
/* Adding the number of lines to the parent directory */
dir_t *d = tree_ref(parent);
atomic_fetch_add( &(*d)->nlines, count );
}
static void
scan_directories(tree_it_t parent, const string_t dirname)
{
tree_it_t it = add_directory(parent, dirname);
string_t filename;
string_init(filename);
DIR *dir = opendir(string_get_cstr(dirname));
if (dir == NULL) {
fprintf(stderr, "ERROR: Cannot open %s as a directory.\n", string_get_cstr(dirname) );
exit(1);
}
// Scan all entries in the directory
struct dirent *entry = readdir(dir);
while (entry) {
// Ignore hidden entries (including '.' and '..')
if (entry->d_name[0] != '.') {
// Construct the path to the filename
string_sets(filename, dirname, "/", entry->d_name);
// Get the property of this filename
struct stat buf;
int err = stat(string_get_cstr(filename), &buf);
if (err != 0) {
fprintf(stderr, "ERROR: Cannot stat %s\n", string_get_cstr(filename));
exit(2);
}
// Further scanning in function of the kind of entry
if (S_ISDIR(buf.st_mode)) {
scan_directories(it, filename);
} else {
scan_file(it, filename);
}
}
// Next entry in the directory
entry = readdir(dir);
}
closedir(dir);
string_clear(filename);
}
static void
consolidate_directories(tree_t directories)
{
// Scan all entries, first the childreen, then the parent
for(tree_it_t it = tree_it_post(directories) ; !tree_end_p(it) ; tree_next_post(&it) ) {
dir_t *parent = tree_up_ref(it);
dir_t *myself = tree_ref(it);
if (parent != NULL) {
// Add the child number of lines to the parent
atomic_fetch_add_explicit(&(*parent)->nlines, (*myself)->nlines, memory_order_relaxed);
}
// Sort the data of the childreen by the number of lines
tree_sort_child(it);
}
}
static void
print_result(tree_t directories)
{
// Scan all entries, first the parent, then the childreen
for(tree_it_t it = tree_it(directories) ; !tree_end_p(it) ; tree_next(&it) ) {
int i, depth = tree_depth(it);
for(i = 0; i < depth; i++) printf("+");
for( ; i < 8; i++) printf(" ");
const dir_t *d = tree_cref(it);
printf("%6u %s\n", (unsigned) (*d)->nlines, string_get_cstr( (*d)->name ) );
}
}
int main(int argc, const char *argv[])
{
tree_t directories;
string_t str;
printf("Count the number of C/C++ lines of code\n");
if (argc < 2) {
fprintf(stderr, "ERROR. Usage is '%s <directory>'.\n", argv[0]);
exit(1);
}
/* Init the tree, reserve for at least the number of max directory
and prevent any further increase of allocation:
this is to ensure that other threads can deref a dir safely */
tree_init(directories);
tree_reserve(directories, MAX_DIRECTORY);
tree_lock(directories, true);
string_init_set_str(str, argv[1]);
tree_it_t it = tree_it_end(directories);
/* Main processing */
scan_directories(it, str);
consolidate_directories(directories);
print_result(directories);
/* Clear everything & quit */
string_clear(str);
tree_clear(directories);
exit(0);
}
+79
View File
@@ -0,0 +1,79 @@
// Based on https://github.com/nanopb/nanopb/blob/master/examples/simple/simple.c
#include <stdio.h>
#include "m-serial-json.h"
#include "m-tuple.h"
#include "m-string.h"
// Define a structure with one field
TUPLE_DEF2(SimpleMessage,
(lucky_number, int))
int main(void)
{
string_t buffer;
m_serial_return_code_t status;
string_init(buffer);
/* Encode our message */
{
SimpleMessage_t message;
SimpleMessage_init(message);
/* Create a stream that will write to our buffer. */
m_serial_str_json_write_t stream;
m_serial_str_json_write_init(stream, buffer);
/* Fill in the lucky number */
message->lucky_number = 13;
/* Now we are ready to encode the message! */
status = SimpleMessage_out_serial(stream, message);
/* Then just check for any errors.. */
if (status != M_SERIAL_OK_DONE)
{
printf("Encoding failed: %d\n", status);
return 1;
}
/* Clear the objets */
m_serial_str_json_write_clear(stream);
SimpleMessage_clear(message);
}
/* Now we could transmit the message over network, store it in a file
* but we are doing it right now.
*/
{
/* Allocate another space for the decoded message. */
SimpleMessage_t message;
SimpleMessage_init(message);
/* Create a stream that reads from the buffer. */
m_serial_str_json_read_t stream;
m_serial_str_json_read_init(stream, string_get_cstr(buffer));
/* Now we are ready to decode the message. */
status = SimpleMessage_in_serial(message, stream);
/* Check for errors... */
if (status != M_SERIAL_OK_DONE)
{
printf("Decoding failed: %d\n", status);
return 1;
}
/* Print the data contained in the message. */
printf("Your lucky number was %d!\n", message->lucky_number);
/* Clear the objets */
m_serial_str_json_read_clear(stream);
SimpleMessage_clear(message);
}
string_clear(buffer);
return 0;
}
+4 -1
View File
@@ -2,6 +2,8 @@
#include "m-tuple.h"
#include "m-array.h"
/* Basic example to show JSON serialization */
// Let's define a 'person' composed of several fields.
TUPLE_DEF2(person,
(surname, string_t),
@@ -9,7 +11,7 @@ TUPLE_DEF2(person,
(present, bool)
)
// Register the oplist of this tuple globaly
#define M_OPL_person_t() TUPLE_OPLIST(person, M_DEFAULT_OPLIST, STRING_OPLIST, M_DEFAULT_OPLIST )
#define M_OPL_person_t() TUPLE_OPLIST(person, STRING_OPLIST, M_BASIC_OPLIST, M_BOOL_OPLIST )
// Let's define an array of person
ARRAY_DEF(base, person_t)
@@ -48,6 +50,7 @@ int main(void)
M_LET(base, base_t) {
// Read the JSON file and fill-in base
read(base, "ex11-json01.json");
base_emplace_back(base, STRING_CTE("John"), 40, false);
// Print the contents of base:
printf ("List of presents:\n");
for M_EACH(el, base, base_t) {
+241
View File
@@ -0,0 +1,241 @@
#if HAVE_GMP && HAVE_MPFR
#include <stdio.h>
#include <gmp.h>
#include <mpfr.h>
#include "m-variant.h"
#include "m-string.h"
#include "m-dict.h"
#include "m-array.h"
#include "m-algo.h"
// GMP doesn't provide a fast hash function (It is needed for being able to use mpz_t as key in a hashmap)
static inline size_t
mpz_fast_hash(const mpz_t z)
{
mp_size_t n = z->_mp_size;
mp_limb_t *p = z->_mp_d;
M_HASH_DECL(hash);
if (n <= 0) {
M_HASH_UP (hash, 0x7F5C1458);
if (n == 0) {
return M_HASH_FINAL (hash);
}
n = -n;
}
while (n-- > 0) {
M_HASH_UP (hash, *p++);
}
return M_HASH_FINAL (hash);
}
/* Define the OPLIST of a mpz_t and register it globally */
#define M_OPL_mpz_t() \
(INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), \
INIT_WITH(API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)), \
EQUAL( API( mpz_cmp, EQ(0), ARG1, ARG2)), \
CMP(mpz_cmp), \
HASH(mpz_fast_hash), \
OUT_STR( API( mpz_out_str, VOID, ARG1, 10, ARG2)), \
IN_STR( API( mpz_inp_str, GT(0), ARG1, ARG2, 10)), \
ADD(mpz_add), SUB(mpz_sub), MUL(mpz_mul), DIV(mpz_div), \
EMPLACE_TYPE( LIST( (_si, mpz_init_set_si, int), \
(_ui, mpz_init_set_ui, unsigned), \
(_d, mpz_init_set_d, double), \
(_cstr, API(mpz_init_set_str, VOID, ARG1, ARG2, 10), const char *), \
(_str, API(mpz_init_set_str, VOID, ARG1, ARG2, 10), char *) )), \
TYPE(mpz_t) )
// MPFR doesn't provide a fast hash function (It is needed for being able to use mpz_t as key in a hashmap)
static size_t
mpfr_fast_hash (const mpfr_t f)
{
mp_limb_t *p = f->_mpfr_d;
mp_size_t n = (f->_mpfr_prec-1)/(sizeof(mp_limb_t)*CHAR_BIT)+1;
M_HASH_DECL (h);
M_HASH_UP (h, f->_mpfr_exp);
if (MPFR_SIGN (f) < 0)
M_HASH_UP (h, 1);
/* Special value: NAN, INF and ZERO */
if (mpfr_nan_p (f) || mpfr_inf_p (f) || mpfr_zero_p (f))
return M_HASH_FINAL (h);
/* Mantissa */
do {
M_HASH_UP (h, *p++);
} while (--n > 0);
return M_HASH_FINAL (h);
}
/* Define the OPLIST of a mpfr_t and register it globally */
#define M_OPL_mpfr_t() \
(INIT(mpfr_init), INIT_SET(API(mpfr_init_set, VOID, ARG1, ARG2, MPFR_RNDN)), SET(API(mpfr_set, VOID, ARG1, ARG2, MPFR_RNDN)), CLEAR(mpfr_clear), \
INIT_WITH(API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)), \
EQUAL( API( mpfr_cmp, EQ(0), ARG1, ARG2)), \
CMP(mpfr_cmp), \
HASH(mpfr_fast_hash), \
OUT_STR( API( mpfr_out_str, VOID, ARG1, 10, 0, ARG2, MPFR_RNDN)), \
IN_STR( API( mpfr_inp_str, GT(0), ARG1, ARG2, 10, MPFR_RNDN)), \
ADD( API(mpfr_add, VOID, ARG1, ARG2, ARG3, MPFR_RNDN)), \
SUB( API(mpfr_sub, VOID, ARG1, ARG2, ARG3, MPFR_RNDN)), \
MUL( API(mpfr_mul, VOID, ARG1, ARG2, ARG3, MPFR_RNDN)), \
DIV( API(mpfr_div, VOID, ARG1, ARG2, ARG3, MPFR_RNDN)), \
EMPLACE_TYPE( LIST( (_si, API(mpfr_init_set_si, VOID, ARG1, ARG2, MPFR_RNDN), int), \
(_ui, API(mpfr_init_set_ui, VOID, ARG1, ARG2, MPFR_RNDN), unsigned), \
(_d, API(mpfr_init_set_d, VOID, ARG1, ARG2, MPFR_RNDN), double), \
(_ld, API(mpfr_init_set_ld, VOID, ARG1, ARG2, MPFR_RNDN), long double), \
(_z, API(mpfr_init_set_z, VOID, ARG1, ARG2, MPFR_RNDN), mpz_t), \
(_zptr, API(mpfr_init_set_z, VOID, ARG1, ARG2, MPFR_RNDN), mpz_ptr), \
(_cstr, API(mpfr_init_set_str, VOID, ARG1, ARG2, 10, MPFR_RNDN), const char *), \
(_str, API(mpfr_init_set_str, VOID, ARG1, ARG2, 10, MPFR_RNDN), char *) )), \
TYPE(mpfr_t) )
/* Define a variant over three kind of numbers named my_number_t
Notice than mpz_t/mpfr_t has special init & clear functions.
This is handle by the library.
*/
VARIANT_DEF2(my_number,
(n, long long),
(z, mpz_t),
(fr, mpfr_t) )
/* Define the oplist associated to this variant and register it */
#define M_OPL_my_number_t() VARIANT_OPLIST(my_number, M_BASIC_OPLIST, M_OPL_mpz_t(), M_OPL_mpfr_t() )
/* Define a dictionary of string_t --> my_number_t named my_dict_t */
DICT_DEF2(my_dict, string_t, my_number_t)
/* Define the oplist associated to this dictionary and register it */
#define M_OPL_my_dict_t() DICT_OPLIST(my_dict, STRING_OPLIST, M_OPL_my_number_t() )
/* Define an array of such dictionary named my_array_t */
ARRAY_DEF(my_array, my_dict_t)
/* Define the oplist associated to this array of dictionary of variant and register it */
#define M_OPL_my_array_t() ARRAY_OPLIST(my_array, M_OPL_my_dict_t())
// Show how to define an array of mpz_t & mpfr_t and some algorithms on then
// (Not needed for the sequel of this example)
ARRAY_DEF(array_mpz, mpz_t)
#define M_OPL_array_mpz_t() ARRAY_OPLIST(array_mpz, M_OPL_mpz_t())
ALGO_DEF(array_mpz, array_mpz_t)
ARRAY_DEF(array_mpfr, mpfr_t)
#define M_OPL_array_mpfr_t() ARRAY_OPLIST(array_mpfr, M_OPL_mpfr_t())
ALGO_DEF(array_mpfr, array_mpfr_t)
static void
compute_roots(array_mpfr_t roots, const array_mpz_t pol)
{
assert( array_mpz_size(pol) == 3);
// Initialize mpfr_t variables from the mpz_t values in the array 'pol'
// & clear then once the brackets end.
M_LET( (a, (*array_mpz_get(pol, 0))),
(b, (*array_mpz_get(pol, 1))),
(c, (*array_mpz_get(pol, 2))),
delta, tmp, mpfr_t) {
// Reset the output array
array_mpfr_reset(roots);
// Compute the results
mpfr_mul(delta, b, b, MPFR_RNDN);
mpfr_mul_ui(tmp, a, 4, MPFR_RNDN);
mpfr_mul(tmp, tmp, c, MPFR_RNDN);
mpfr_sub(delta, delta, tmp, MPFR_RNDN);
mpfr_sqrt(delta, delta, MPFR_RNDN);
mpfr_neg(tmp, b, MPFR_RNDN);
mpfr_add(tmp, tmp, delta, MPFR_RNDN);
mpfr_div(tmp, tmp, a, MPFR_RNDN);
mpfr_div_2ui(tmp, tmp, 1, MPFR_RNDN);
// Push first root
array_mpfr_push_back(roots, tmp);
mpfr_neg(tmp, b, MPFR_RNDN);
mpfr_sub(tmp, tmp, delta, MPFR_RNDN);
mpfr_div(tmp, tmp, a, MPFR_RNDN);
mpfr_div_2ui(tmp, tmp, 1, MPFR_RNDN);
// Push second root
array_mpfr_push_back(roots, tmp);
}
}
int main(void)
{
M_LET(z, my_number_t) /* Define & init & clear an instance of a variant of my_number_t */
M_LET(dict, my_dict_t) /* Define & init & clear an instance of a dictionary of variant */
M_LET(array, my_array_t) /* Define & init & clear an intance of an array of dictionary of variant */
M_LET(gmp, mpz_t) /* M_LET allows even with non container type */
{
my_number_set_n (z, 17LL); // Set z as the long long 17
my_dict_set_at(dict, STRING_CTE("n1"), z); // Push it in the dictionary
mpz_set_str(gmp, "25446846874687468746874687468746874686874", 10); // Set gmp to a very long integer.
my_number_set_z (z, gmp); // Set z as the mpz_t variable
my_dict_set_at(dict, STRING_CTE("n2"), z); // Push it in the dictionary
my_array_push_back (array, dict); // Push the dictionary in the array
// Let's add a new element in the array through a mpfr_t set to 42.17
M_LET( (fr, ("42.17")), mpfr_t) {
my_number_set_fr(z, fr); // Set z as this variable.
}
my_dict_set_at(dict, STRING_CTE("n3"), z); // Push it in the dictionary
my_number_emplace_fr_si(z, 42); // Directly emplace the variant as a mpfr_t with a signed integer for init
my_dict_set_at(dict, STRING_CTE("n4"), z); // Push it in the dictionary
my_number_emplace_z_ui(z, 189); // Directly emplace the variant as a mpz_t with an unsigned integer for init
my_dict_set_at(dict, STRING_CTE("n5"), z); // Push it in the dictionary
my_array_push_back (array, dict); // Push the dictionary in the array
// Iterate over the array container
for M_EACH(item, array, my_array_t) {
// Iterate over the dictionary '*item' container which is of type my_dict_t
for M_EACH(p, *item, my_dict_t) {
// Dictionary iterator are pair (key,value)
printf("Key is '%s'. ", string_get_cstr(p->key));
// In function of the type of value
if (my_number_n_p(p->value)) {
printf ("It is a long long, value = %lld\n",
*my_number_cget_n(p->value));
}
if (my_number_z_p(p->value)) {
printf ("It is a mpz_t, value = ");
mpz_out_str(stdout, 10, *my_number_cget_z(p->value));
printf("\n");
}
if (my_number_fr_p(p->value)) {
printf ("It is a mpfr_t, value = ");
mpfr_out_str(stdout, 10, 0, *my_number_cget_fr(p->value), MPFR_RNDN);
printf("\n");
}
}
printf("Next element of array\n");
}
// Print all the array in one step. Need to be done in C11 only
M_PRINT("\nThe array is equal to ", (array, my_array_t), "\n");
} /* All variables are automatically cleared beyond this point */
// Define an array of mpz_t as { 1, 2, 1 } (with auto promotion from integer)
// The auto-promotion uses _Generic feature and is available only in C11.
M_LET ( (az, (1), ("2"), (1.0)), array_mpz_t)
M_LET ( roots, array_mpfr_t) {
// Compute roots
compute_roots(roots, az);
// Display of roots:
M_PRINT("Roots of ", (az, array_mpz_t), " are ", (roots, array_mpfr_t), "\n");
}
}
#else
// Nothing to do
int main(void) { return 0; }
#endif
+106
View File
@@ -0,0 +1,106 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "m-rbtree.h"
#include "m-string.h"
// Let's define a Red Black Tree over the constant C strings
// Notice that we need to specify the oplist for this case
// so that M*LIB handle the pointers to const char correctly.
RBTREE_DEF(tree_cstr, const char *, M_CSTR_OPLIST)
// The classic C way
// It is probably the best for beginner in M*LIB to start like this.
static void classic1(void)
{
tree_cstr_t tree;
tree_cstr_init(tree);
tree_cstr_push (tree, "Hello");
tree_cstr_push (tree, "World");
tree_cstr_push (tree, "How");
tree_cstr_push (tree, "Are");
tree_cstr_push (tree, "You");
printf("\nUsing C string, the generated (sorted) tree is ");
tree_cstr_out_str(stdout, tree);
printf ("\n");
const char *present = tree_cstr_get(tree, "How") == NULL ? "not " : "";
printf("The word 'How' is %spresent\n", present);
present = tree_cstr_get(tree, "Not") == NULL ? "not " : "";
printf("The word 'Not' is %spresent\n", present);
tree_cstr_clear(tree);
}
// Let's define another Red Black Tree over the M*LIB strings
// Notice that we don't need to specify the oplist for this case.
RBTREE_DEF(tree_str, string_t)
// The classic C way
// It is probably the best for beginner in M*LIB to start like this.
static void classic2(void)
{
tree_str_t tree;
tree_str_init(tree);
// STRING_CTE enables to construct a temporary const string_t from a const char *
// usable for function call.
tree_str_push (tree, STRING_CTE("Hello"));
tree_str_push (tree, STRING_CTE("World"));
tree_str_push (tree, STRING_CTE("How"));
tree_str_push (tree, STRING_CTE("Are"));
tree_str_push (tree, STRING_CTE("You"));
printf("\nUsing M*LIB string_t, the generated (sorted) tree is ");
tree_str_out_str(stdout, tree);
printf ("\n");
const char *present = tree_str_get(tree, STRING_CTE("How")) == NULL ? "not " : "";
printf("The word 'How' is %spresent\n", present);
present = tree_str_get(tree, STRING_CTE("Not")) == NULL ? "not " : "";
printf("The word 'Not' is %spresent\n", present);
tree_str_clear(tree);
}
// Registering the oplist helps writting the macro
// as we can only refer to the type in the macro.
#define M_OPL_tree_str_t() RBTREE_OPLIST(tree_str, STRING_OPLIST)
static void macro(void)
{
// Using macro (shorter but may be unfamiliar syntax for novive with M*LIB)
// This will declare the variable 'tree' as a 'tree_str_t' and initialize with
// the given initialization list '("Hello"), ("World"), ("How"), ("Are"), ("You")'
// The strings are given within '()' so that the constructor performs an emplace
// of the value to push in the tree (to initialize a string_t with a const char * type)
// instead of a push (which takes a compliant string_t as argument).
// An alternative is to use STRING_CTE for the arguments.
M_LET( (tree, ("Hello"), ("World"), ("How"), ("Are"), ("You")), tree_str_t) {
// In C11, the M_PRINT macro allows the use of a simplified syntax for printing.
M_PRINT("\nUsing M*LIB string_t + macro, the generated (sorted) tree is ", (tree, tree_str_t), "\n");
const char *present = tree_str_get(tree, STRING_CTE("How")) == NULL ? "not " : "";
printf("The word 'How' is %spresent\n", present);
present = tree_str_get(tree, STRING_CTE("Not")) == NULL ? "not " : "";
printf("The word 'Not' is %spresent\n", present);
}
}
int main(void)
{
classic1();
classic2();
macro();
return 0;
}
+1 -1
View File
@@ -7,7 +7,7 @@
// Let's define a tuple composed of (offset, value) and register it
TUPLE_DEF2(symbol, (offset, long), (value, long))
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_BASIC_OPLIST, M_BASIC_OPLIST)
// Let's define an array of such tuple and register it
ARRAY_DEF(array_symbol, symbol_t)
+5 -5
View File
@@ -12,14 +12,14 @@
// Define a basic structure (POD structure) using a tuple to get the default functions
TUPLE_DEF2(Point, (x, float), (y, float))
#define M_OPL_Point_t() TUPLE_OPLIST(Point, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
#define M_OPL_Point_t() TUPLE_OPLIST(Point, M_BASIC_OPLIST, M_BASIC_OPLIST)
// NOTE: array, list, deque don't have a native find function.
// We'll use the algorithm header to create a find function for such containers.
// Define a set of int & register its oplist
DICT_SET_DEF(cset_i, int)
#define M_OPL_cset_i_t() DICT_SET_OPLIST(cset_i, M_DEFAULT_OPLIST)
#define M_OPL_cset_i_t() DICT_SET_OPLIST(cset_i, M_BASIC_OPLIST)
// Define an array of Point, register its oplist & include some basic algorithms
ARRAY_DEF(cvec_p, Point_t)
@@ -28,17 +28,17 @@ ALGO_DEF(cvec_p, cvec_p_t)
// Define a deque of int, including some basic algorithms
DEQUE_DEF(cdeq_i, int)
#define M_OPL_cdeq_i_t() DEQUE_OPLIST(cdeq_i, M_DEFAULT_OPLIST)
#define M_OPL_cdeq_i_t() DEQUE_OPLIST(cdeq_i, M_BASIC_OPLIST)
ALGO_DEF(cdeq_i, cdeq_i_t)
// Define a backward list, including some basic algorithms
LIST_DEF(clist_i, int)
#define M_OPL_clist_i_t() LIST_OPLIST(clist_i, M_DEFAULT_OPLIST)
#define M_OPL_clist_i_t() LIST_OPLIST(clist_i, M_BASIC_OPLIST)
ALGO_DEF(clist_i, clist_i_t)
// Define an unordered map of int to int
DICT_DEF2(csmap_i, int, int)
#define M_OPL_csmap_i_t() DICT_OPLIST(csmap_i, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
#define M_OPL_csmap_i_t() DICT_OPLIST(csmap_i, M_BASIC_OPLIST, M_BASIC_OPLIST)
int main(void)
{
+61 -42
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - ALGO module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -28,10 +28,10 @@
#include "m-core.h"
/* Define different kind of basic algorithms named 'name' over the container
which oplist is 'contOp', as static inline functions.
which oplist is 'cont_oplist', as static inline functions.
USAGE:
ALGO_DEF(algogName, containerOplist|type if oplist has been registered) */
#define ALGO_DEF(name, cont_oplist) \
#define M_ALGO_DEF(name, cont_oplist) \
M_BEGIN_PROTECTED_CODE \
M_ALG0_DEF_P1(name, M_GLOBAL_OPLIST(cont_oplist)) \
M_END_PROTECTED_CODE
@@ -39,41 +39,45 @@
/* Map a function (or a macro) to all elements of a container.
USAGE:
ALGO_FOR_EACH(container, containerOplist, function[, extra arguments of function]) */
#define ALGO_FOR_EACH(container, cont_oplist, ...) \
ALGO_FOR_EACH(container, containerOplist|type_if_registered_oplist, function[, extra arguments of function]) */
#define M_ALGO_FOR_EACH(container, cont_oplist, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(M_ALG0_FOR_EACH(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__), \
M_ALG0_FOR_EACH_ARG(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__ ))
(M_ALG0_FOR_EACH, M_ALG0_FOR_EACH_ARG) \
(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__)
/* Map a function (or a macro) to all elements of a container
into another container.
and store it into another container.
USAGE:
ALGO_TRANSFORM(contDst, contDOplist, contSrc, contSrcOplist,
ALGO_TRANSFORM(contDst, contDOplist|type_if_registered_oplist, contSrc, contSrcOplist|type_if_registered_oplist,
function[, extra arguments of function]) */
#define ALGO_TRANSFORM(contD, contDop, contS, contSop, ...) \
#define M_ALGO_TRANSFORM(contD, contDop, contS, contSop, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(M_ALG0_TRANSFORM(contD, M_GLOBAL_OPLIST(contDop), contS, M_GLOBAL_OPLIST(contSop), __VA_ARGS__), \
M_ALG0_TRANSFORM_ARG(contD, M_GLOBAL_OPLIST(contDop), contS, M_GLOBAL_OPLIST(contSop), __VA_ARGS__ ))
(M_ALG0_TRANSFORM, M_ALG0_TRANSFORM_ARG) \
(contD, M_GLOBAL_OPLIST(contDop), contS, M_GLOBAL_OPLIST(contSop), __VA_ARGS__)
/* Extract a subset of a container to copy into another container.
USAGE:
ALGO_EXTRACT(contDst, contDstOplist, contSrc, contSrcOplist
ALGO_EXTRACT(contDst, contDstOplist|type_if_registered_oplist, contSrc, contSrcOplist|type_if_registered_oplist
[, function [, extra arguments of function]]) */
#define ALGO_EXTRACT(contD, contDop, contS, ...) \
#define M_ALGO_EXTRACT(contD, contDop, contS, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(M_ALG0_EXTRACT(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__), \
M_IF_NARGS_EQ2(__VA_ARGS__) \
(M_ALG0_EXTRACT_FUNC(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__), \
M_ALG0_EXTRACT_ARG(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__ )))
(M_ALG0_EXTRACT, \
M_IF_NARGS_EQ2(__VA_ARGS__)(M_ALG0_EXTRACT_FUNC, M_ALG0_EXTRACT_ARG)) \
(contD, contDop, contS, __VA_ARGS__)
/* Perform a Reduce operation over a container.
USAGE:
ALGO_REDUCE(dstVar, container, contOplist, reduceFunc
[, mapFunc[, extraParameters of map function]]) */
#define ALGO_REDUCE(dest, cont, contOp, ...) \
ALGO_REDUCE(dstVar, container, contOplist|type_if_registered_oplist, reduceFunc
[, mapFunc[, extraParameters of map function]])
or
ALGO_REDUCE( (dstVar, dstOplist|type_if_registered_oplist), container, contOplist|type_if_registered_oplist, reduceFunc
[, mapFunc[, extraParameters of map function]])
if the destination variable is not of the same type than the elements of the containers.
*/
#define M_ALGO_REDUCE(dest, cont, contOp, ...) \
M_IF(M_PARENTHESIS_P(dest)) \
(M_ALG0_REDUCE_DISPATCH(M_PAIR_1 dest, M_GLOBAL_OPLIST(M_PAIR_2 dest), M_GLOBAL_TYPE(M_PAIR_2 dest),cont, M_GLOBAL_OPLIST(contOp), __VA_ARGS__), \
M_ALG0_REDUCE_DISPATCH(dest, M_GET_OPLIST M_GLOBAL_OPLIST(contOp), M_GET_SUBTYPE M_GLOBAL_OPLIST(contOp), cont, contOp, __VA_ARGS__)) \
@@ -82,9 +86,9 @@
/* Insert into the container 'contDst' at position 'position' all the values
of container 'contSrc'.
USAGE:
ALGO_INSERT_AT(containerDst, containerDstOPLIST|containerDstType, containerDstIterator, containerSrc, containerSrcOPLIST|containerSrcType)
ALGO_INSERT_AT(containerDst, containerDstOPLIST|type_if_registered_oplist, containerDstIterator, containerSrc, containerSrcOPLIST|type_if_registered_oplist)
*/
#define ALGO_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) \
#define M_ALGO_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) \
M_ALG0_INSERT_AT(contDst, M_GLOBAL_OPLIST(contDstOp), position, contSrc, M_GLOBAL_OPLIST(contSrcOp) )
@@ -505,7 +509,7 @@
*/
#define M_ALG0_FIND_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
/* It supposes that the container is not sorted */ \
/* Find the next occurence from it (included) of data */ \
/* Find the next occurrence from it (included) of data */ \
static inline void \
M_C(name, _find_again) (it_t it, type_t const data) \
{ \
@@ -516,7 +520,7 @@
} \
} \
\
/* Find the first occurence of data */ \
/* Find the first occurrence of data */ \
static inline void \
M_C(name, _find) (it_t it, container_t const l, type_t const data) \
{ \
@@ -533,7 +537,7 @@
return !M_CALL_IT_END_P(cont_oplist, it); \
} \
\
/* Find the last occurence of data in the container */ \
/* Find the last occurrence of data in the container */ \
/* For the definition of _find_last, if the methods \
PREVIOUS & IT_LAST are defined, then search backwards */ \
M_IF_METHOD2(PREVIOUS, IT_LAST, cont_oplist) \
@@ -550,7 +554,7 @@
} \
} \
, \
/* Otherwise search forward, but don't stop on the first occurence */ \
/* Otherwise search forward, but don't stop on the first occurrence */ \
static inline void \
M_C(name, _find_last) (it_t it, container_t const l, type_t const data) \
{ \
@@ -566,7 +570,7 @@
} \
) /* End of alternative of _find_last */ \
\
/* Count the number of occurence of data in the container */ \
/* Count the number of occurrence of data in the container */ \
static inline size_t \
M_C(name, _count) (container_t const l, type_t const data) \
{ \
@@ -613,7 +617,7 @@
*/
#define M_ALG0_FIND_IF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, test_t, eq_t, call_test, call_eq) \
\
/* Find the next occurence that matches the condition */ \
/* Find the next occurrence that matches the condition */ \
static inline void \
M_C3(name, _find_again_, suffix) (it_t it, test_t func) \
{ \
@@ -624,7 +628,7 @@
} \
} \
\
/* Find the first occurence that matches the condition */ \
/* Find the first occurrence that matches the condition */ \
static inline void \
M_C3(name, _find_, suffix) (it_t it, container_t l, test_t func) \
{ \
@@ -632,7 +636,7 @@
M_C3(name, _find_again_, suffix)(it, func); \
} \
\
/* Count the number of occurence that matches the condition */ \
/* Count the number of occurrence that matches the condition */ \
static inline size_t \
M_C3(name, _count_, suffix) (container_t const l, test_t func) \
{ \
@@ -685,7 +689,7 @@
} \
} \
\
/* Fill the container with exactly 'n' occurence of 'value' */ \
/* Fill the container with exactly 'n' occurrence of 'value' */ \
M_IF_METHOD(PUSH, cont_oplist)( \
static inline void \
M_C(name, _fill_n) (container_t l, size_t n, type_t const value) \
@@ -961,7 +965,7 @@
M_CALL_IT_NEXT(cont_oplist, itSrc), \
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
type_t const *srcItem = M_CALL_IT_REF(cont_oplist, itSrc); \
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
M_CALL_ADD(type_oplist, *dstItem, *dstItem, *srcItem); \
} \
} \
@@ -979,7 +983,7 @@
M_CALL_IT_NEXT(cont_oplist, itSrc), \
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
type_t const *srcItem = M_CALL_IT_REF(cont_oplist, itSrc); \
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
M_CALL_SUB(type_oplist, *dstItem, *dstItem, *srcItem); \
} \
} \
@@ -997,7 +1001,7 @@
M_CALL_IT_NEXT(cont_oplist, itSrc), \
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
type_t const *srcItem = M_CALL_IT_REF(cont_oplist, itSrc); \
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
M_CALL_MUL(type_oplist, *dstItem, *dstItem, *srcItem); \
} \
} \
@@ -1015,7 +1019,7 @@
M_CALL_IT_NEXT(cont_oplist, itSrc), \
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
type_t const *srcItem = M_CALL_IT_REF(cont_oplist, itSrc); \
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
M_CALL_DIV(type_oplist, *dstItem, *dstItem, *srcItem); \
} \
} \
@@ -1067,8 +1071,9 @@
} while (0)
#define M_ALG0_EXTRACT(contDst, contDstOplist, \
contSrc, contSrcOplist) do { \
#define M_ALG0_EXTRACT(contDst, contDstOplist, contSrc, contSrcOplist) \
M_ALG0_EXTRACT_P1(contDst, M_GLOBAL_OPLIST(contDstOplist), contSrc, M_GLOBAL_OPLIST(contSrcOplist))
#define M_ALG0_EXTRACT_P1(contDst, contDstOplist, contSrc, contSrcOplist) do{ \
M_CALL_RESET(contDstOplist, contDst); \
for M_EACH(_item, contSrc, contSrcOplist) { \
M_IF_METHOD(PUSH, contDstOplist)( \
@@ -1080,8 +1085,9 @@
M_IF_METHOD(REVERSE, contDstOplist) (M_CALL_REVERSE(contDstOplist, contDst);, ) \
} while (0)
#define M_ALG0_EXTRACT_FUNC(contDst, contDstOplist, \
contSrc, contSrcOplist, \
#define M_ALG0_EXTRACT_FUNC(contDst, contDstOplist, contSrc, contSrcOplist, condFunc) \
M_ALG0_EXTRACT_FUNC_P1(contDst, M_GLOBAL_OPLIST(contDstOplist), contSrc, M_GLOBAL_OPLIST(contSrcOplist), condFunc)
#define M_ALG0_EXTRACT_FUNC_P1(contDst, contDstOplist, contSrc, contSrcOplist, \
condFunc) do { \
M_CALL_RESET(contDstOplist, contDst); \
for M_EACH(_item, contSrc, contSrcOplist) { \
@@ -1096,8 +1102,11 @@
M_IF_METHOD(REVERSE, contDstOplist) (M_CALL_REVERSE(contDstOplist, contDst);, ) \
} while (0)
#define M_ALG0_EXTRACT_ARG(contDst, contDstOplist, \
contSrc, contSrcOplist, \
#define M_ALG0_EXTRACT_ARG(contDst, contDstOplist, contSrc, contSrcOplist, \
condFunc, ...) \
M_ALG0_EXTRACT_ARG_P1(contDst, M_GLOBAL_OPLIST(contDstOplist), contSrc, M_GLOBAL_OPLIST(contSrcOplist), \
condFunc, __VA_ARGS__)
#define M_ALG0_EXTRACT_ARG_P1(contDst, contDstOplist, contSrc, contSrcOplist, \
condFunc, ...) do { \
M_CALL_RESET(contDstOplist, contDst); \
for M_EACH(_item, contSrc, contSrcOplist) { \
@@ -1200,4 +1209,14 @@
} \
} while (0)
#if M_USE_SMALL_NAME
#define ALGO_DEF M_ALGO_DEF
#define ALGO_FOR_EACH M_ALGO_FOR_EACH
#define ALGO_TRANSFORM M_ALGO_TRANSFORM
#define ALGO_EXTRACT M_ALGO_EXTRACT
#define ALGO_REDUCE M_ALGO_REDUCE
#define ALGO_INSERT_AT M_ALGO_INSERT_AT
#endif
#endif
+46 -33
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - dynamic ARRAY module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -29,14 +29,14 @@
/* Define a dynamic array of the given type and its associated functions.
USAGE: ARRAY_DEF(name, type [, oplist_of_the_type]) */
#define ARRAY_DEF(name, ...) \
ARRAY_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
#define M_ARRAY_DEF(name, ...) \
M_ARRAY_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
/* Define a dynamic array of the given type and its associated functions
as the provided type name_t with the iterator named it_t
USAGE: ARRAY_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
#define ARRAY_DEF_AS(name, name_t, it_t, ...) \
#define M_ARRAY_DEF_AS(name, name_t, it_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_ARRA4_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
@@ -45,11 +45,11 @@
/* Define the oplist of a dynamic array given its name and its oplist.
If no oplist is given it is assumed to be M_DEFAULT_OPLIST
If no oplist is given it is assumed to be M_BASIC_OPLIST
USAGE: ARRAY_OPLIST(name[, oplist of the type]) */
#define ARRAY_OPLIST(...) \
#define M_ARRAY_OPLIST(...) \
M_ARRA4_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
((__VA_ARGS__, M_BASIC_OPLIST), \
(__VA_ARGS__ )))
@@ -57,7 +57,7 @@
USAGE:
array_t global_variable = ARRAY_INIT_VALUE();
*/
#define ARRAY_INIT_VALUE() \
#define M_ARRAY_INIT_VALUE() \
{ { 0, 0, NULL } }
/********************************************************************************/
@@ -109,7 +109,7 @@
,RESET(M_C(name,_reset)) \
,KEY_TYPE(size_t) \
,VALUE_TYPE(M_C(name, _subtype_ct)) \
,KEY_OPLIST(M_DEFAULT_OPLIST) \
,KEY_OPLIST(M_BASIC_OPLIST) \
,VALUE_OPLIST(oplist) \
,M_IF_METHOD(SET, oplist)(SET_KEY(M_C(name, _set_at)) ,) \
,GET_KEY(M_C(name, _get)) \
@@ -144,8 +144,12 @@
} while (0)
/* Deferred evaluation for the array definition,
so that all arguments are evaluated before further expansion */
#define M_ARRA4_DEF_P1(arg) M_ARRA4_DEF_P2 arg
so that all arguments are fully evaluated before further expansion
(ensuring good performance)
and performed a final step evaluation of the returning expansion
(ensuring delayed evaluation are still expanded)
*/
#define M_ARRA4_DEF_P1(arg) M_ID( M_ARRA4_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_ARRA4_DEF_P2(name, type, oplist, array_t, it_t) \
@@ -207,12 +211,6 @@
M_ARRA4_CONTRACT(v); \
} \
\
static inline void M_ATTR_DEPRECATED \
M_C(name, _clean)(array_t v) \
{ \
M_C(name, _reset)(v); \
} \
\
static inline void \
M_C(name, _clear)(array_t v) \
{ \
@@ -483,11 +481,6 @@
M_ARRA4_CONTRACT(v); \
return &v->ptr[idx]; \
} \
static inline M_ATTR_DEPRECATED type * \
M_C(name, _get_at)(array_t v, size_t idx) \
{ \
return M_C(name, _safe_get)(v, idx); \
} \
, /* No INIT */) \
\
M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \
@@ -821,10 +814,9 @@
if (m_core_clz64(size-1) & 1) \
th += th; \
\
/* Pass 1: insertion sort (stable) */ \
/* Pass 1: Partial insertion sort (stable) up to 'th' size */ \
for(size_t k = 0 ; k < size; ) { \
size_t max = size - k < 2*th ? size - k : th; \
M_ASSUME(max >= th); \
for(size_t i = 1; i < max; i++) { \
size_t j = i; \
while (j > 0 && M_CALL_CMP(oplist, tab[k+j-1], tab[k+j]) > 0) { \
@@ -838,7 +830,7 @@
/* N Pass of merge sort (stable) */ \
while (th < size) { \
type *dest = tmp; \
/* Pass n: Merge */ \
/* Pass n: Merge 2 sections of 'th' elements */ \
for(size_t k = 0 ; k < size; ) { \
type *el1 = &tab[k]; \
type *el2 = &tab[k+th]; \
@@ -850,10 +842,10 @@
k += n1+n2; \
for (;;) { \
if (M_CALL_CMP(oplist, *el1, *el2) <= 0) { \
M_CALL_SET(oplist, *dest, *el1); \
M_DO_INIT_MOVE(oplist, *dest, *el1); \
dest++; \
el1++; \
if (-- n1 == 0) { \
if (M_UNLIKELY(-- n1 == 0)) { \
if (n2 > 0) { \
memcpy (dest, el2, n2 * sizeof (type)); \
dest += n2; \
@@ -861,10 +853,10 @@
break; \
} \
} else { \
M_CALL_SET(oplist, *dest, *el2); \
M_DO_INIT_MOVE(oplist, *dest, *el2); \
dest++; \
el2++; \
if (-- n2 == 0) { \
if (M_UNLIKELY(-- n2 == 0)) { \
if (n1 > 0) { \
memcpy (dest, el1, n1 * sizeof (type)); \
dest += n1; \
@@ -903,11 +895,11 @@
\
M_IF_METHOD(GET_STR, oplist)( \
static inline void \
M_C(name, _get_str)(string_t str, array_t const array, \
M_C(name, _get_str)(m_string_t str, array_t const array, \
bool append) \
{ \
M_ARRA4_CONTRACT(array); \
(append ? string_cat_str : string_set_str) (str, "["); \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
it_t it; \
for (M_C(name, _it)(it, array) ; \
!M_C(name, _end_p)(it); \
@@ -915,9 +907,9 @@
type const *item = M_C(name, _cref)(it); \
M_CALL_GET_STR(oplist, str, *item, true); \
if (!M_C(name, _last_p)(it)) \
string_push_back (str, M_GET_SEPARATOR oplist); \
m_string_push_back (str, M_GET_SEPARATOR oplist); \
} \
string_push_back (str, ']'); \
m_string_push_back (str, ']'); \
} \
, /* no GET_STR */ ) \
\
@@ -1105,5 +1097,26 @@
a1->size = newSize; \
} \
} \
\
M_EMPLACE_QUEUE_DEF(name, array_t, M_C(name, _emplace_back), oplist, M_ARRA4_EMPLACE_DEF)
/* Definition of the emplace_back function for arrays */
#define M_ARRA4_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
static inline void \
function_name(name_t v \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
M_C(name, _subtype_ct) *data = M_C(name, _push_raw)(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
} \
#if M_USE_SMALL_NAME
#define ARRAY_DEF M_ARRAY_DEF
#define ARRAY_DEF_AS M_ARRAY_DEF_AS
#define ARRAY_OPLIST M_ARRAY_OPLIST
#define ARRAY_INIT_VALUE M_ARRAY_INIT_VALUE
#endif
#endif
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Thin stdatomic wrapper for C++ compatibility
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
+244 -162
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - BITSET module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,9 +33,9 @@
M_BEGIN_PROTECTED_CODE
// Define the basic limb of a bitset
typedef uint64_t bitset_limb_ct;
typedef uint64_t m_b1tset_limb_ct;
// And its size in bits
#define M_B1TSET_LIMB_BIT (sizeof(bitset_limb_ct) * CHAR_BIT)
#define M_B1TSET_LIMB_BIT (sizeof(m_b1tset_limb_ct) * CHAR_BIT)
// bitset grow policy. n is limb size
#define M_B1TSET_INC_ALLOC_SIZE(n) ((n) < 4 ? 4 : (n) * 2)
@@ -54,35 +54,35 @@ typedef uint64_t bitset_limb_ct;
M_ASSERT (t->size < ((size_t)-1) - M_B1TSET_LIMB_BIT); \
M_ASSERT (t->size == 0 || t->ptr != NULL); \
M_ASSERT (t->alloc == 0 || t->ptr != NULL); \
M_ASSERT ((t->size % M_B1TSET_LIMB_BIT) == 0 || (t->ptr[ (t->size-1) / M_B1TSET_LIMB_BIT] & ~(((((bitset_limb_ct)1)<<(t->size % M_B1TSET_LIMB_BIT))<<1)-1)) == 0); \
M_ASSERT ((t->size % M_B1TSET_LIMB_BIT) == 0 || (t->ptr[ (t->size-1) / M_B1TSET_LIMB_BIT] & ~(((((m_b1tset_limb_ct)1)<<(t->size % M_B1TSET_LIMB_BIT))<<1)-1)) == 0); \
} while (0)
/********************************** EXTERNAL ************************************/
/* Define a type of variable 'bits' or array of packed booleans */
typedef struct bitset_s {
typedef struct m_bitset_s {
size_t size; // Size is the number of bits
size_t alloc; // Alloc is the number of allocated limbs
bitset_limb_ct *ptr; // Pointer to the allocated limbs
} bitset_t[1];
m_b1tset_limb_ct *ptr; // Pointer to the allocated limbs
} m_bitset_t[1];
/* Pointer to a bitset_t */
typedef struct bitset_s *bitset_ptr;
/* Pointer to a m_bitset_t */
typedef struct m_bitset_s *m_bitset_ptr;
/* Constant Pointer to a bitset_t */
typedef const struct bitset_s *bitset_srcptr;
/* Constant Pointer to a m_bitset_t */
typedef const struct m_bitset_s *m_bitset_srcptr;
/* Iterator on a bitset */
typedef struct bitset_it_s {
typedef struct m_bitset_it_s {
size_t index; // index to the array of bit
bool value; // value used for _ref & _cref to store the value
struct bitset_s *set; // the associated bitset
} bitset_it_t[1];
struct m_bitset_s *set; // the associated bitset
} m_bitset_it_t[1];
/* Initialize a bitset (CONSTRUCTOR) */
static inline void
bitset_init(bitset_t t)
m_bitset_init(m_bitset_t t)
{
M_ASSERT (t != NULL);
M_STATIC_ASSERT (M_POWEROF2_P(M_B1TSET_LIMB_BIT), MLIB_INTERNAL, "M*LIB: BITSET LIMB shall be a power of 2.");
@@ -94,23 +94,17 @@ bitset_init(bitset_t t)
/* Clean a bitset */
static inline void
bitset_reset(bitset_t t)
m_bitset_reset(m_bitset_t t)
{
M_B1TSET_CONTRACT(t);
t->size = 0;
}
static inline void M_ATTR_DEPRECATED
bitset_clean(bitset_t t)
{
bitset_reset(t);
}
/* Clear a bitset (DESTRUCTOR) */
static inline void
bitset_clear(bitset_t t)
m_bitset_clear(m_bitset_t t)
{
bitset_reset(t);
m_bitset_reset(t);
M_MEMORY_FREE(t->ptr);
// This is not really needed, but is safer
// This representation is invalid and will be detected by the contract.
@@ -121,14 +115,14 @@ bitset_clear(bitset_t t)
/* Set a bitset to another one */
static inline void
bitset_set(bitset_t d, const bitset_t s)
m_bitset_set(m_bitset_t d, const m_bitset_t s)
{
M_B1TSET_CONTRACT(d);
M_B1TSET_CONTRACT(s);
if (M_UNLIKELY (d == s)) return;
const size_t needAlloc = M_B1TSET_TO_ALLOC (s->size);
if (s->size > M_B1TSET_FROM_ALLOC (d->alloc)) {
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, d->ptr, needAlloc);
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, d->ptr, needAlloc);
if (M_UNLIKELY (ptr == NULL)) {
M_MEMORY_FULL(needAlloc);
return ;
@@ -136,23 +130,23 @@ bitset_set(bitset_t d, const bitset_t s)
d->ptr = ptr;
d->alloc = needAlloc;
}
memcpy (d->ptr, s->ptr, needAlloc * sizeof(bitset_limb_ct) );
memcpy (d->ptr, s->ptr, needAlloc * sizeof(m_b1tset_limb_ct) );
d->size = s->size;
M_B1TSET_CONTRACT(d);
}
/* Initialize & set a bitset to another one (CONSTRUCTOR) */
static inline void
bitset_init_set(bitset_t d, const bitset_t s)
m_bitset_init_set(m_bitset_t d, const m_bitset_t s)
{
M_ASSERT (d != s);
bitset_init(d);
bitset_set(d, s);
m_bitset_init(d);
m_bitset_set(d, s);
}
/* Initialize & move a bitset (CONSTRUCTOR) from another one (DESTRUCTOR) */
static inline void
bitset_init_move(bitset_t d, bitset_t s)
m_bitset_init_move(m_bitset_t d, m_bitset_t s)
{
M_B1TSET_CONTRACT(s);
d->size = s->size;
@@ -166,15 +160,15 @@ bitset_init_move(bitset_t d, bitset_t s)
/* Move a bitset from another one (DESTRUCTOR) */
static inline void
bitset_move(bitset_t d, bitset_t s)
m_bitset_move(m_bitset_t d, m_bitset_t s)
{
bitset_clear(d);
bitset_init_move (d, s);
m_bitset_clear(d);
m_bitset_init_move (d, s);
}
/* Set the bit 'i' in the bitset to the value 'x' */
static inline void
bitset_set_at(bitset_t v, size_t i, bool x)
m_bitset_set_at(m_bitset_t v, size_t i, bool x)
{
M_B1TSET_CONTRACT(v);
M_ASSERT (v->ptr != NULL);
@@ -182,27 +176,27 @@ bitset_set_at(bitset_t v, size_t i, bool x)
const size_t offset = i / M_B1TSET_LIMB_BIT;
const size_t index = i % M_B1TSET_LIMB_BIT;
// This is a branchless version as x can only be 0 or 1 with only one variable shift.
const bitset_limb_ct mask = ((bitset_limb_ct)1)<<index;
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (0-(bitset_limb_ct)x));
const m_b1tset_limb_ct mask = ((m_b1tset_limb_ct)1)<<index;
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (0-(m_b1tset_limb_ct)x));
M_B1TSET_CONTRACT (v);
}
/* Flip the bit 'i' in the bitset */
static inline void
bitset_flip_at(bitset_t v, size_t i)
m_bitset_flip_at(m_bitset_t v, size_t i)
{
M_B1TSET_CONTRACT(v);
M_ASSERT (v->ptr != NULL);
M_ASSERT_INDEX(i, v->size);
size_t offset = i / M_B1TSET_LIMB_BIT;
size_t index = i % M_B1TSET_LIMB_BIT;
v->ptr[offset] ^= ((bitset_limb_ct)1)<<index;
v->ptr[offset] ^= ((m_b1tset_limb_ct)1)<<index;
M_B1TSET_CONTRACT (v);
}
/* Push back the boolean 'x' in the bitset (increasing the bitset) */
static inline void
bitset_push_back (bitset_t v, bool x)
m_bitset_push_back (m_bitset_t v, bool x)
{
M_B1TSET_CONTRACT (v);
if (M_UNLIKELY (v->size >= M_B1TSET_FROM_ALLOC (v->alloc))) {
@@ -210,14 +204,14 @@ bitset_push_back (bitset_t v, bool x)
const size_t needAlloc = M_B1TSET_INC_ALLOC_SIZE(v->alloc);
// Check for integer overflow
if (M_UNLIKELY (needAlloc <= v->alloc)) {
M_MEMORY_FULL(needAlloc * sizeof(bitset_limb_ct));
M_MEMORY_FULL(needAlloc * sizeof(m_b1tset_limb_ct));
return;
}
// Alloc memory
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, v->ptr, needAlloc);
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, needAlloc);
// Check if success
if (M_UNLIKELY (ptr == NULL) ) {
M_MEMORY_FULL(needAlloc * sizeof(bitset_limb_ct));
M_MEMORY_FULL(needAlloc * sizeof(m_b1tset_limb_ct));
return;
}
v->ptr = ptr;
@@ -233,15 +227,15 @@ bitset_push_back (bitset_t v, bool x)
v->ptr[offset] = 0;
}
// This is a branchless version as x can only be 0 or 1 with only one variable shift.
const bitset_limb_ct mask = ((bitset_limb_ct)1)<<index;
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (0-(bitset_limb_ct)x));
const m_b1tset_limb_ct mask = ((m_b1tset_limb_ct)1)<<index;
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (0-(m_b1tset_limb_ct)x));
v->size ++;
M_B1TSET_CONTRACT (v);
}
/* Resize the bitset to have exactly 'size' bits */
static inline void
bitset_resize (bitset_t v, size_t size)
m_bitset_resize (m_bitset_t v, size_t size)
{
M_B1TSET_CONTRACT (v);
// Check for overflow
@@ -253,9 +247,9 @@ bitset_resize (bitset_t v, size_t size)
size_t newAlloc = M_B1TSET_TO_ALLOC (size);
if (newAlloc > v->alloc) {
// Allocate more limbs to store the bitset.
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, v->ptr, newAlloc);
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, newAlloc);
if (M_UNLIKELY (ptr == NULL) ) {
M_MEMORY_FULL(newAlloc * sizeof(bitset_limb_ct));
M_MEMORY_FULL(newAlloc * sizeof(m_b1tset_limb_ct));
return;
}
v->ptr = ptr;
@@ -265,7 +259,7 @@ bitset_resize (bitset_t v, size_t size)
const size_t old_size = v->size;
const size_t offset = size / M_B1TSET_LIMB_BIT;
const size_t index = size % M_B1TSET_LIMB_BIT;
const bitset_limb_ct mask = (((bitset_limb_ct)1)<<index)-1;
const m_b1tset_limb_ct mask = (((m_b1tset_limb_ct)1)<<index)-1;
if (size < old_size) {
// Resize down the bitset: clear unused bits
if (M_LIKELY(index != 0)) {
@@ -274,8 +268,8 @@ bitset_resize (bitset_t v, size_t size)
}
} else if (size > old_size) {
// Resize up the bitset: set to 0 new bits.
const size_t old_offset = old_size / M_B1TSET_LIMB_BIT;
for(size_t i = old_offset+1 ; i < offset; i++) {
const size_t old_offset = (old_size + M_B1TSET_LIMB_BIT - 1)/ M_B1TSET_LIMB_BIT;
for(size_t i = old_offset ; i < offset; i++) {
v->ptr[i] = 0;
}
if (M_LIKELY(index != 0)) {
@@ -289,7 +283,7 @@ bitset_resize (bitset_t v, size_t size)
/* Reserve allocation in the bitset to accomodate at least 'size' bits without reallocation */
static inline void
bitset_reserve (bitset_t v, size_t alloc)
m_bitset_reserve (m_bitset_t v, size_t alloc)
{
M_B1TSET_CONTRACT (v);
size_t oldAlloc = M_B1TSET_TO_ALLOC (v->size);
@@ -305,9 +299,9 @@ bitset_reserve (bitset_t v, size_t alloc)
v->ptr = NULL;
} else {
// Allocate more memory or reduce memory usage
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, v->ptr, newAlloc);
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, newAlloc);
if (M_UNLIKELY (ptr == NULL) ) {
M_MEMORY_FULL(newAlloc * sizeof(bitset_limb_ct));
M_MEMORY_FULL(newAlloc * sizeof(m_b1tset_limb_ct));
return;
}
v->ptr = ptr;
@@ -321,22 +315,22 @@ bitset_reserve (bitset_t v, size_t alloc)
* It doesn't return a pointer to the data, but the data itself.
*/
static inline bool
bitset_get(const bitset_t v, size_t i)
m_bitset_get(const m_bitset_t v, size_t i)
{
M_B1TSET_CONTRACT(v);
M_ASSERT (v->ptr != NULL);
M_ASSERT_INDEX(i, v->size);
size_t offset = i / M_B1TSET_LIMB_BIT;
size_t index = i % M_B1TSET_LIMB_BIT;
return ( v->ptr[offset] & (((bitset_limb_ct)1) << index) ) != 0;
return ( v->ptr[offset] & (((m_b1tset_limb_ct)1) << index) ) != 0;
}
/* bitset_cget is the exact same service than bitset_get */
#define bitset_cget bitset_get
/* m_bitset_cget is the exact same service than m_bitset_get */
#define m_bitset_cget m_bitset_get
/* Pop back the last bit in the bitset */
static inline void
bitset_pop_back(bool *dest, bitset_t v)
m_bitset_pop_back(bool *dest, m_bitset_t v)
{
M_B1TSET_CONTRACT (v);
M_ASSERT_INDEX (0, v->size);
@@ -345,7 +339,7 @@ bitset_pop_back(bool *dest, bitset_t v)
// Prepare clearing popped bit
const size_t offset = v->size / M_B1TSET_LIMB_BIT;
const size_t index = v->size % M_B1TSET_LIMB_BIT;
const bitset_limb_ct mask = ((bitset_limb_ct)1)<<index;
const m_b1tset_limb_ct mask = ((m_b1tset_limb_ct)1)<<index;
if (dest) {
// Read popped bit
*dest = (v->ptr[offset] & mask) != 0;
@@ -356,25 +350,25 @@ bitset_pop_back(bool *dest, bitset_t v)
/* Return the front bit value in the bitset */
static inline bool
bitset_front(bitset_t v)
m_bitset_front(m_bitset_t v)
{
M_B1TSET_CONTRACT (v);
M_ASSERT_INDEX (0, v->size);
return bitset_get(v, 0);
return m_bitset_get(v, 0);
}
/* Return the back bit value in the bitset */
static inline bool
bitset_back(bitset_t v)
m_bitset_back(m_bitset_t v)
{
M_B1TSET_CONTRACT (v);
M_ASSERT_INDEX (0, v->size);
return bitset_get(v, v->size-1);
return m_bitset_get(v, v->size-1);
}
/* Test if the bitset is empty (no bits stored)*/
static inline bool
bitset_empty_p(bitset_t v)
m_bitset_empty_p(m_bitset_t v)
{
M_B1TSET_CONTRACT (v);
return v->size == 0;
@@ -382,7 +376,7 @@ bitset_empty_p(bitset_t v)
/* Return the number of bits of the bitset */
static inline size_t
bitset_size(bitset_t v)
m_bitset_size(m_bitset_t v)
{
M_B1TSET_CONTRACT (v);
return v->size;
@@ -390,7 +384,7 @@ bitset_size(bitset_t v)
/* Return the capacity in limbs of the bitset */
static inline size_t
bitset_capacity(bitset_t v)
m_bitset_capacity(m_bitset_t v)
{
M_B1TSET_CONTRACT (v);
return M_B1TSET_FROM_ALLOC (v->alloc);
@@ -398,26 +392,26 @@ bitset_capacity(bitset_t v)
/* Swap the bit at index i and j of the bitset */
static inline void
bitset_swap_at (bitset_t v, size_t i, size_t j)
m_bitset_swap_at (m_bitset_t v, size_t i, size_t j)
{
M_ASSERT_INDEX(i, v->size);
M_ASSERT_INDEX(j, v->size);
bool i_val = bitset_get(v, i);
bool j_val = bitset_get(v, j);
bitset_set_at (v, i, j_val);
bitset_set_at (v, j, i_val);
bool i_val = m_bitset_get(v, i);
bool j_val = m_bitset_get(v, j);
m_bitset_set_at (v, i, j_val);
m_bitset_set_at (v, j, i_val);
}
/* Swap the bitsets */
static inline void
bitset_swap (bitset_t v1, bitset_t v2)
m_bitset_swap (m_bitset_t v1, m_bitset_t v2)
{
M_B1TSET_CONTRACT (v1);
M_B1TSET_CONTRACT (v2);
M_SWAP (size_t, v1->size, v2->size);
M_SWAP (size_t, v1->alloc, v2->alloc);
M_SWAP (bitset_limb_ct *, v1->ptr, v2->ptr);
M_SWAP (m_b1tset_limb_ct *, v1->ptr, v2->ptr);
M_B1TSET_CONTRACT (v1);
M_B1TSET_CONTRACT (v2);
}
@@ -426,11 +420,11 @@ bitset_swap (bitset_t v1, bitset_t v2)
* integrating the carry in the lowest position.
* Return the new carry.
*/
static inline bitset_limb_ct
m_b1tset_lshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
static inline m_b1tset_limb_ct
m_b1tset_lshift(m_b1tset_limb_ct ptr[], size_t n, m_b1tset_limb_ct carry)
{
for(size_t i = 0; i < n; i++) {
bitset_limb_ct v = ptr[i];
m_b1tset_limb_ct v = ptr[i];
ptr[i] = (v << 1) | carry;
carry = (v >> (M_B1TSET_LIMB_BIT-1) );
}
@@ -441,11 +435,11 @@ m_b1tset_lshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
* integrating the carry in the lowest position.
* Return the new carry.
*/
static inline bitset_limb_ct
m_b1tset_rshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
static inline m_b1tset_limb_ct
m_b1tset_rshift(m_b1tset_limb_ct ptr[], size_t n, m_b1tset_limb_ct carry)
{
for(size_t i = n - 1; i < n; i--) {
bitset_limb_ct v = ptr[i];
m_b1tset_limb_ct v = ptr[i];
ptr[i] = (v >> 1) | (carry << (M_B1TSET_LIMB_BIT-1) );
carry = v & 1;
}
@@ -455,20 +449,20 @@ m_b1tset_rshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
/* Insert a new bit at position 'key' of value 'value' in the bitset 'set'
shifting the set accordingly */
static inline void
bitset_push_at(bitset_t set, size_t key, bool value)
m_bitset_push_at(m_bitset_t set, size_t key, bool value)
{
M_B1TSET_CONTRACT (set);
// First push another value to extend the array to the right size
bitset_push_back(set, false);
m_bitset_push_back(set, false);
M_ASSERT (set->ptr != NULL);
M_ASSERT_INDEX(key, set->size);
// Then shift it
size_t offset = key / M_B1TSET_LIMB_BIT;
size_t index = key % M_B1TSET_LIMB_BIT;
bitset_limb_ct v = set->ptr[offset];
bitset_limb_ct mask = (((bitset_limb_ct)1)<<index)-1;
bitset_limb_ct carry = (v >> (M_B1TSET_LIMB_BIT-1) );
m_b1tset_limb_ct v = set->ptr[offset];
m_b1tset_limb_ct mask = (((m_b1tset_limb_ct)1)<<index)-1;
m_b1tset_limb_ct carry = (v >> (M_B1TSET_LIMB_BIT-1) );
v = (v & mask) | ((unsigned int) value << index) | ((v & ~mask) << 1);
set->ptr[offset] = v;
size_t size = (set->size + M_B1TSET_LIMB_BIT - 1) / M_B1TSET_LIMB_BIT;
@@ -483,23 +477,23 @@ bitset_push_at(bitset_t set, size_t key, bool value)
/* Pop a new bit at position 'key' in the bitset
* and return in *dest its value if *dest exists */
static inline void
bitset_pop_at(bool *dest, bitset_t set, size_t key)
m_bitset_pop_at(bool *dest, m_bitset_t set, size_t key)
{
M_B1TSET_CONTRACT (set);
M_ASSERT (set->ptr != NULL);
M_ASSERT_INDEX(key, set->size);
if (dest) {
*dest = bitset_get (set, key);
*dest = m_bitset_get (set, key);
}
// Shift it
size_t offset = key / M_B1TSET_LIMB_BIT;
size_t index = key % M_B1TSET_LIMB_BIT;
size_t size = (set->size + M_B1TSET_LIMB_BIT - 1) / M_B1TSET_LIMB_BIT;
bitset_limb_ct v, mask, carry;
m_b1tset_limb_ct v, mask, carry;
carry = m_b1tset_rshift(&set->ptr[offset+1], size - offset - 1, false);
v = set->ptr[offset];
mask = (((bitset_limb_ct)1)<<index)-1;
mask = (((m_b1tset_limb_ct)1)<<index)-1;
v = (v & mask) | ((v>>1) & ~mask) | (carry << (M_B1TSET_LIMB_BIT-1)) ;
set->ptr[offset] = v;
// Decrease size
@@ -509,7 +503,7 @@ bitset_pop_at(bool *dest, bitset_t set, size_t key)
/* Test if two bitsets are equal */
static inline bool
bitset_equal_p (const bitset_t set1, const bitset_t set2)
m_bitset_equal_p (const m_bitset_t set1, const m_bitset_t set2)
{
M_B1TSET_CONTRACT (set1);
M_B1TSET_CONTRACT (set2);
@@ -526,7 +520,7 @@ bitset_equal_p (const bitset_t set1, const bitset_t set2)
/* Initialize an iterator to the first bit of the biset */
static inline void
bitset_it(bitset_it_t it, bitset_t set)
m_bitset_it(m_bitset_it_t it, m_bitset_t set)
{
M_B1TSET_CONTRACT (set);
it->index = 0;
@@ -535,7 +529,7 @@ bitset_it(bitset_it_t it, bitset_t set)
/* Initialize an iterator to reference the same bit as the given one*/
static inline void
bitset_it_set(bitset_it_t it, const bitset_it_t itorg)
m_bitset_it_set(m_bitset_it_t it, const m_bitset_it_t itorg)
{
M_ASSERT (it != NULL && itorg != NULL);
it->index = itorg->index;
@@ -544,7 +538,7 @@ bitset_it_set(bitset_it_t it, const bitset_it_t itorg)
/* Initialize an iterator to reference the last bit of the bitset*/
static inline void
bitset_it_last(bitset_it_t it, bitset_t set)
m_bitset_it_last(m_bitset_it_t it, m_bitset_t set)
{
M_B1TSET_CONTRACT (set);
it->index = set->size-1;
@@ -553,7 +547,7 @@ bitset_it_last(bitset_it_t it, bitset_t set)
/* Initialize an iterator to reference no valid bit of the bitset*/
static inline void
bitset_it_end(bitset_it_t it, bitset_t set)
m_bitset_it_end(m_bitset_it_t it, m_bitset_t set)
{
M_B1TSET_CONTRACT (set);
it->index = set->size;
@@ -562,7 +556,7 @@ bitset_it_end(bitset_it_t it, bitset_t set)
/* Test if an iterator references no valid bit of the bitset anymore */
static inline bool
bitset_end_p(const bitset_it_t it)
m_bitset_end_p(const m_bitset_it_t it)
{
M_ASSERT (it != NULL && it->set != NULL);
return (it->index) >= (it->set->size);
@@ -570,7 +564,7 @@ bitset_end_p(const bitset_it_t it)
/* Test if an iterator references the last (or end) bit of the bitset anymore */
static inline bool
bitset_last_p(const bitset_it_t it)
m_bitset_last_p(const m_bitset_it_t it)
{
M_ASSERT (it != NULL && it->set != NULL);
/* NOTE: Can not compute 'size-1' due to potential overflow
@@ -580,7 +574,7 @@ bitset_last_p(const bitset_it_t it)
/* Test if both iterators reference the same bit */
static inline bool
bitset_it_equal_p(const bitset_it_t it1, const bitset_it_t it2)
m_bitset_it_equal_p(const m_bitset_it_t it1, const m_bitset_it_t it2)
{
M_ASSERT (it1 != NULL && it2 != NULL);
return it1->index == it2->index && it1->set == it2->set;
@@ -588,7 +582,7 @@ bitset_it_equal_p(const bitset_it_t it1, const bitset_it_t it2)
/* Move the iterator to the next bit */
static inline void
bitset_next(bitset_it_t it)
m_bitset_next(m_bitset_it_t it)
{
M_ASSERT (it != NULL && it->set != NULL);
it->index++;
@@ -596,7 +590,7 @@ bitset_next(bitset_it_t it)
/* Move the iterator to the previous bit */
static inline void
bitset_previous(bitset_it_t it)
m_bitset_previous(m_bitset_it_t it)
{
M_ASSERT (it != NULL && it->set != NULL);
it->index--;
@@ -607,22 +601,22 @@ bitset_previous(bitset_it_t it)
/* Return a pointer to the bit referenced by the iterator
* Only one reference is possible at a time per iterator */
static inline const bool *
bitset_cref(bitset_it_t it)
m_bitset_cref(m_bitset_it_t it)
{
M_ASSERT (it != NULL && it->set != NULL);
it->value = bitset_get(it->set, it->index);
it->value = m_bitset_get(it->set, it->index);
return &it->value;
}
/* Output the bitset as a formatted text in a FILE */
static inline void
bitset_out_str(FILE *file, const bitset_t set)
m_bitset_out_str(FILE *file, const m_bitset_t set)
{
M_B1TSET_CONTRACT (set);
M_ASSERT(file != NULL);
fputc ('[', file);
for(size_t i = 0; i < set->size; i++) {
const bool b = bitset_get (set, i);
const bool b = m_bitset_get (set, i);
const char c = b ? '1' : '0';
fputc (c, file);
}
@@ -631,17 +625,17 @@ bitset_out_str(FILE *file, const bitset_t set)
/* Input the bitset from a formatted text in a FILE */
static inline bool
bitset_in_str(bitset_t set, FILE *file)
m_bitset_in_str(m_bitset_t set, FILE *file)
{
M_B1TSET_CONTRACT (set);
M_ASSERT(file != NULL);
bitset_reset(set);
m_bitset_reset(set);
int c = fgetc(file);
if (M_UNLIKELY (c != '[')) return false;
c = fgetc(file);
while (c == '0' || c == '1') {
const bool b = (c == '1');
bitset_push_back (set, b);
m_bitset_push_back (set, b);
c = fgetc(file);
}
M_B1TSET_CONTRACT (set);
@@ -650,19 +644,19 @@ bitset_in_str(bitset_t set, FILE *file)
/* Parse the bitset from a formatted text in a C string */
static inline bool
bitset_parse_str(bitset_t set, const char str[], const char **endptr)
m_bitset_parse_str(m_bitset_t set, const char str[], const char **endptr)
{
M_B1TSET_CONTRACT (set);
M_ASSERT(str != NULL);
bool success = false;
bitset_reset(set);
m_bitset_reset(set);
char c = *str++;
if (M_UNLIKELY(c != '[')) goto exit;
c = *str++;
do {
if (M_UNLIKELY(c != '0' && c != '1')) goto exit;
const bool b = (c == '1');
bitset_push_back (set, b);
m_bitset_push_back (set, b);
c = *str++;
} while (c != ']' && c != 0);
M_B1TSET_CONTRACT (set);
@@ -674,15 +668,15 @@ bitset_parse_str(bitset_t set, const char str[], const char **endptr)
/* Set the bitset from a formatted text in a C string */
static inline bool
bitset_set_str(bitset_t dest, const char str[])
m_bitset_set_str(m_bitset_t dest, const char str[])
{
return bitset_parse_str(dest, str, NULL);
return m_bitset_parse_str(dest, str, NULL);
}
/* Perform an AND operation between the bitsets,
* up to the minimum size of both bitsets */
static inline void
bitset_and(bitset_t dest, const bitset_t src)
m_bitset_and(m_bitset_t dest, const m_bitset_t src)
{
M_B1TSET_CONTRACT(dest);
M_B1TSET_CONTRACT(src);
@@ -698,7 +692,7 @@ bitset_and(bitset_t dest, const bitset_t src)
/* Perform an OR operation between the bitsets,
* up to the minimum size of both bitsets */
static inline void
bitset_or(bitset_t dest, const bitset_t src)
m_bitset_or(m_bitset_t dest, const m_bitset_t src)
{
M_B1TSET_CONTRACT(dest);
M_B1TSET_CONTRACT(src);
@@ -714,7 +708,7 @@ bitset_or(bitset_t dest, const bitset_t src)
/* Perform an XOR operation between the bitsets,
* up to the minimum size of both bitsets */
static inline void
bitset_xor(bitset_t dest, const bitset_t src)
m_bitset_xor(m_bitset_t dest, const m_bitset_t src)
{
M_B1TSET_CONTRACT(dest);
M_B1TSET_CONTRACT(src);
@@ -725,7 +719,7 @@ bitset_xor(bitset_t dest, const bitset_t src)
dest->ptr[i] ^= src->ptr[i];
if (M_LIKELY(m)) {
// Last limb needs to be masked too
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
m_b1tset_limb_ct mask = (((m_b1tset_limb_ct)1) << m) - 1;
dest->ptr[n] = (dest->ptr[n] ^ src->ptr[n]) & mask;
}
// Reduce the dest size to the minimum size between both
@@ -735,7 +729,7 @@ bitset_xor(bitset_t dest, const bitset_t src)
/* Perform a NOT operation of the bitset */
static inline void
bitset_not(bitset_t dest)
m_bitset_not(m_bitset_t dest)
{
M_B1TSET_CONTRACT(dest);
size_t s = dest->size;
@@ -745,7 +739,7 @@ bitset_not(bitset_t dest)
dest->ptr[i] = ~ (dest->ptr[i]);
if (M_LIKELY(m)) {
// Last limb needs to be masked too
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
m_b1tset_limb_ct mask = (((m_b1tset_limb_ct)1) << m) - 1;
dest->ptr[n] = (~ dest->ptr[n]) & mask;
}
M_B1TSET_CONTRACT(dest);
@@ -753,7 +747,7 @@ bitset_not(bitset_t dest)
/* Copute a hash of the bitset */
static inline size_t
bitset_hash(const bitset_t set)
m_bitset_hash(const m_bitset_t set)
{
M_B1TSET_CONTRACT(set);
size_t s = set->size;
@@ -766,7 +760,7 @@ bitset_hash(const bitset_t set)
/* Count the number of leading zero */
static inline size_t
bitset_clz(const bitset_t set)
m_bitset_clz(const m_bitset_t set)
{
M_B1TSET_CONTRACT(set);
size_t s = set->size;
@@ -775,9 +769,9 @@ bitset_clz(const bitset_t set)
}
size_t n = (s -1) / M_B1TSET_LIMB_BIT;
size_t m = s % M_B1TSET_LIMB_BIT;
bitset_limb_ct limb = set->ptr[n];
m_b1tset_limb_ct limb = set->ptr[n];
if (m) {
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
m_b1tset_limb_ct mask = (((m_b1tset_limb_ct)1) << m) - 1;
limb &= mask;
} else {
m = M_B1TSET_LIMB_BIT;
@@ -792,16 +786,42 @@ bitset_clz(const bitset_t set)
return s;
}
/* Count the number of trailing zero */
static inline size_t
m_bitset_ctz(const m_bitset_t set)
{
M_B1TSET_CONTRACT(set);
size_t s = set->size;
if (M_UNLIKELY (s == 0)) {
return 0;
}
size_t i = 0, n = (s -1) / M_B1TSET_LIMB_BIT;
size_t m = s % M_B1TSET_LIMB_BIT;
m_b1tset_limb_ct limb = set->ptr[0];
s = 0;
while (limb == 0 && i < n) {
s += M_B1TSET_LIMB_BIT;
limb = set->ptr[++i];
}
if (i == n && m != 0) {
m_b1tset_limb_ct mask = (((m_b1tset_limb_ct)1) << m) - 1;
limb &= mask;
}
unsigned ctz = m_core_ctz64(limb);
s += (ctz == 64) ? m : ctz;
return s;
}
// For GCC or CLANG or ICC
#if defined(__GNUC__)
static inline size_t m_b1tset_popcount64(bitset_limb_ct limb)
static inline size_t m_b1tset_popcount64(m_b1tset_limb_ct limb)
{
return (size_t) __builtin_popcountll(limb);
}
#else
// MSVC __popcnt64 may not exist on the target architecture (no emulation layer)
// Use emulation layer: https://en.wikipedia.org/wiki/Hamming_weight
static inline size_t m_b1tset_popcount64(bitset_limb_ct limb)
static inline size_t m_b1tset_popcount64(m_b1tset_limb_ct limb)
{
limb = limb - ((limb >> 1) & 0x5555555555555555ULL);
limb = (limb & 0x3333333333333333ULL) + ((limb >> 2) & 0x3333333333333333ULL);
@@ -812,7 +832,7 @@ static inline size_t m_b1tset_popcount64(bitset_limb_ct limb)
/* Count the number of 1 */
static inline size_t
bitset_popcount(const bitset_t set)
m_bitset_popcount(const m_bitset_t set)
{
M_B1TSET_CONTRACT(set);
size_t s = 0;
@@ -823,46 +843,108 @@ bitset_popcount(const bitset_t set)
}
/* Oplist for a bitset */
#define BITSET_OPLIST \
(INIT(bitset_init) \
,INIT_SET(bitset_init_set) \
#define M_BITSET_OPLIST \
(INIT(m_bitset_init) \
,INIT_SET(m_bitset_init_set) \
,INIT_WITH(API_1(M_INIT_VAI)) \
,SET(bitset_set) \
,CLEAR(bitset_clear) \
,INIT_MOVE(bitset_init_move) \
,MOVE(bitset_move) \
,SWAP(bitset_swap) \
,TYPE(bitset_t) \
,SET(m_bitset_set) \
,CLEAR(m_bitset_clear) \
,INIT_MOVE(m_bitset_init_move) \
,MOVE(m_bitset_move) \
,SWAP(m_bitset_swap) \
,TYPE(m_bitset_t) \
,SUBTYPE(bool) \
,EMPTY_P(bitset_empty_p), \
,GET_SIZE(bitset_size) \
,IT_TYPE(bitset_it_t) \
,IT_FIRST(bitset_it) \
,IT_SET(bitset_it_set) \
,IT_LAST(bitset_it_last) \
,IT_END(bitset_it_end) \
,IT_END_P(bitset_end_p) \
,IT_LAST_P(bitset_last_p) \
,IT_EQUAL_P(bitset_it_equal_p) \
,IT_NEXT(bitset_next) \
,IT_PREVIOUS(bitset_previous) \
,IT_CREF(bitset_cref) \
,RESET(bitset_reset) \
,PUSH(bitset_push_back) \
,POP(bitset_pop_back) \
,HASH(bitset_hash) \
,GET_STR(bitset_get_str) \
,OUT_STR(bitset_out_str) \
,PARSE_STR(bitset_parse_str) \
,IN_STR(bitset_in_str) \
,EQUAL(bitset_equal_p) \
,EMPTY_P(m_bitset_empty_p), \
,GET_SIZE(m_bitset_size) \
,IT_TYPE(m_bitset_it_t) \
,IT_FIRST(m_bitset_it) \
,IT_SET(m_bitset_it_set) \
,IT_LAST(m_bitset_it_last) \
,IT_END(m_bitset_it_end) \
,IT_END_P(m_bitset_end_p) \
,IT_LAST_P(m_bitset_last_p) \
,IT_EQUAL_P(m_bitset_it_equal_p) \
,IT_NEXT(m_bitset_next) \
,IT_PREVIOUS(m_bitset_previous) \
,IT_CREF(m_bitset_cref) \
,RESET(m_bitset_reset) \
,PUSH(m_bitset_push_back) \
,POP(m_bitset_pop_back) \
,HASH(m_bitset_hash) \
,GET_STR(m_bitset_get_str) \
,OUT_STR(m_bitset_out_str) \
,PARSE_STR(m_bitset_parse_str) \
,IN_STR(m_bitset_in_str) \
,EQUAL(m_bitset_equal_p) \
)
/* Register the OPLIST as a global one */
#define M_OPL_bitset_t() BITSET_OPLIST
#define M_OPL_m_bitset_t() M_BITSET_OPLIST
// TODO: set_at2, insert_v, remove_v
#if M_USE_SMALL_NAME
#define bitset_s m_bitset_s
#define bitset_t m_bitset_t
#define bitset_ptr m_bitset_ptr
#define bitset_srcptr m_bitset_srcptr
#define bitset_it_s m_bitset_it_s
#define bitset_it_t m_bitset_it_t
#define bitset_init m_bitset_init
#define bitset_reset m_bitset_reset
#define bitset_clear m_bitset_clear
#define bitset_set m_bitset_set
#define bitset_init_set m_bitset_init_set
#define bitset_init_move m_bitset_init_move
#define bitset_move m_bitset_move
#define bitset_set_at m_bitset_set_at
#define bitset_flip_at m_bitset_flip_at
#define bitset_push_back m_bitset_push_back
#define bitset_resize m_bitset_resize
#define bitset_reserve m_bitset_reserve
#define bitset_get m_bitset_get
#define bitset_pop_back m_bitset_pop_back
#define bitset_front m_bitset_front
#define bitset_back m_bitset_back
#define bitset_empty_p m_bitset_empty_p
#define bitset_size m_bitset_size
#define bitset_capacity m_bitset_capacity
#define bitset_swap_at m_bitset_swap_at
#define bitset_swap m_bitset_swap
#define bitset_push_at m_bitset_push_at
#define bitset_pop_at m_bitset_pop_at
#define bitset_equal_p m_bitset_equal_p
#define bitset_it m_bitset_it
#define bitset_it_set m_bitset_it_set
#define bitset_it_last m_bitset_it_last
#define bitset_it_end m_bitset_it_end
#define bitset_end_p m_bitset_end_p
#define bitset_last_p m_bitset_last_p
#define bitset_it_equal_p m_bitset_it_equal_p
#define bitset_next m_bitset_next
#define bitset_previous m_bitset_previous
#define bitset_cref m_bitset_cref
#define bitset_out_str m_bitset_out_str
#define bitset_in_str m_bitset_in_str
#define bitset_parse_str m_bitset_parse_str
#define bitset_set_str m_bitset_set_str
#define bitset_and m_bitset_and
#define bitset_or m_bitset_or
#define bitset_xor m_bitset_xor
#define bitset_not m_bitset_not
#define bitset_hash m_bitset_hash
#define bitset_clz m_bitset_clz
#define bitset_ctz m_bitset_ctz
#define bitset_popcount m_bitset_popcount
#define bitset_get_str m_bitset_get_str
#define BITSET_OPLIST M_BITSET_OPLIST
#define M_OPL_bitset_t M_OPL_m_bitset_t
#endif
M_END_PROTECTED_CODE
#endif
@@ -873,20 +955,20 @@ M_END_PROTECTED_CODE
M_BEGIN_PROTECTED_CODE
/* Output to a string_t 'str' the formatted text representation of the bitset 'set'
/* Output to a m_string_t 'str' the formatted text representation of the bitset 'set'
or append it to the strinf (append=true) */
static inline void
bitset_get_str(string_t str, const bitset_t set, bool append)
m_bitset_get_str(m_string_t str, const m_bitset_t set, bool append)
{
M_B1TSET_CONTRACT (set);
M_ASSERT(str != NULL);
(append ? string_cat_str : string_set_str) (str, "[");
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "[");
for(size_t i = 0; i < set->size; i++) {
const bool b = bitset_get (set, i);
const bool b = m_bitset_get (set, i);
const char c = b ? '1' : '0';
string_push_back (str, c);
m_string_push_back (str, c);
}
string_push_back (str, ']');
m_string_push_back (str, ']');
}
M_END_PROTECTED_CODE
+43 -38
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - B+TREE module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,8 +34,8 @@
OR
BPTREE_DEF2(name, N, key_t, value_t)
*/
#define BPTREE_DEF2(name, N, key_type, ...) \
BPTREE_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name, _itref_t), N, key_type, __VA_ARGS__)
#define M_BPTREE_DEF2(name, N, key_type, ...) \
M_BPTREE_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name, _itref_t), N, key_type, __VA_ARGS__)
/* Define a B+tree of size 'N' that maps a 'key' to a 'value'
@@ -45,7 +45,7 @@
OR
BPTREE_DEF2_AS(name, name_t, it_t, itref_t, N, key_t, value_t)
*/
#define BPTREE_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \
#define M_BPTREE_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \
M_BEGIN_PROTECTED_CODE \
M_BPTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, N, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 1, 0, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, itref_t ), \
@@ -56,14 +56,14 @@
/* Define a B+tree of a given type, of size N.
with its associated functions
USAGE: BPTREE_DEF(name, N, type, [, oplist_of_the_type]) */
#define BPTREE_DEF(name, N, ...) \
BPTREE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), N, __VA_ARGS__)
#define M_BPTREE_DEF(name, N, ...) \
M_BPTREE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), N, __VA_ARGS__)
/* Define a B+tree of a given type, of size N.
as the given name name_t with its associated functions
USAGE: BPTREE_DEF_AS(name, name_t, it_t, N, type, [, oplist_of_the_type]) */
#define BPTREE_DEF_AS(name, name_t, it_t, N, ...) \
#define M_BPTREE_DEF_AS(name, name_t, it_t, N, ...) \
M_BEGIN_PROTECTED_CODE \
M_BPTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, N, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 0, 0, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, M_C(name, _itref_ct) ), \
@@ -79,8 +79,8 @@
OR
BPTREE_MULTI_DEF2(name, N, key_t, value_t)
*/
#define BPTREE_MULTI_DEF2(name, N, key_type, ...) \
BPTREE_MULTI_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), N, key_type, __VA_ARGS__)
#define M_BPTREE_MULTI_DEF2(name, N, key_type, ...) \
M_BPTREE_MULTI_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), N, key_type, __VA_ARGS__)
/* Define a B+tree of size 'N' that maps a 'key' to a 'value',
@@ -91,7 +91,7 @@
OR
BPTREE_MULTI_DEF2_AS(name, name_t, it_t, itref_t, N, key_t, value_t)
*/
#define BPTREE_MULTI_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \
#define M_BPTREE_MULTI_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \
M_BEGIN_PROTECTED_CODE \
M_BPTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, N, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 1, 1, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, itref_t ), \
@@ -103,15 +103,15 @@
allowing multiple equal keys to exist,
with its associated functions
USAGE: BPTREE_MULTI_DEF(name, N, type, [, oplist_of_the_type]) */
#define BPTREE_MULTI_DEF(name, N, ...) \
BPTREE_MULTI_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), N, __VA_ARGS__)
#define M_BPTREE_MULTI_DEF(name, N, ...) \
M_BPTREE_MULTI_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), N, __VA_ARGS__)
/* Define a B+tree of a given type, of size N.
allowing multiple equal keys to exist,
as the given name name_t with its associated functions
USAGE: BPTREE_MULTI_DEF_AS(name, name_t, it_t, N, type, [, oplist_of_the_type]) */
#define BPTREE_MULTI_DEF_AS(name, name_t, it_t, N, ...) \
#define M_BPTREE_MULTI_DEF_AS(name, name_t, it_t, N, ...) \
M_BEGIN_PROTECTED_CODE \
M_BPTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, N, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 0, 1, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, M_C(name, _itref_ct) ), \
@@ -120,21 +120,22 @@
/* Define the oplist of a B+TREE used as a set of type (from BPTREE_DEF).
USAGE: BPTREE_OPLIST(name [, oplist_of_the_type]) */
#define BPTREE_OPLIST(...) \
USAGE: BPTREE_OPLIST(name [, oplist_of_the_type])
NOTE: IT_REF is not exported so that the container appears as not modifiable
by algorithm. */
#define M_BPTREE_OPLIST(...) \
M_BPTR33_KEY_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
((__VA_ARGS__, M_BASIC_OPLIST ), \
(__VA_ARGS__ )))
/* Define the oplist of a B+TREE used as a map of a key type to a value type (from BPTREE_DEF2).
USAGE: BPTREE_OPLIST2(name[, key_oplist, value_oplist])
NOTE: IT_REF is not exported so that the contained appears as not modifiable
by algorithm.
*/
#define BPTREE_OPLIST2(...) \
NOTE: IT_REF is not exported so that the container appears as not modifiable
by algorithm. */
#define M_BPTREE_OPLIST2(...) \
M_BPTR33_OPLIST2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST ), \
((__VA_ARGS__, M_BASIC_OPLIST, M_BASIC_OPLIST ), \
(__VA_ARGS__ )))
@@ -173,7 +174,6 @@
IT_END_P(M_C(name,_end_p)), \
IT_EQUAL_P(M_C(name,_it_equal_p)), \
IT_NEXT(M_C(name,_next)), \
IT_REF(M_C(name,_ref)), \
IT_CREF(M_C(name,_cref)), \
RESET(M_C(name,_reset)), \
PUSH(M_C(name,_push)), \
@@ -304,7 +304,7 @@
/* Deferred evaluation for the b+tree definition,
so that all arguments are evaluated before further expansion */
#define M_BPTR33_DEF_P1(arg) M_BPTR33_DEF_P2 arg
#define M_BPTR33_DEF_P1(arg) M_ID( M_BPTR33_DEF_P2 arg )
/* Validate the key oplist before going further */
#define M_BPTR33_DEF_P2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
@@ -475,11 +475,6 @@
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
} \
\
static inline void M_ATTR_DEPRECATED M_C(name, _clean)(tree_t b) \
{ \
M_C(name, _reset)(b); \
} \
\
static inline void M_C(name, _clear)(tree_t b) \
{ \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
@@ -776,17 +771,13 @@
value_t v; \
M_CALL_INIT(value_oplist, v); \
M_C(name, _set_at)(b, key, v); \
M_CALL_CLEAR(value_oplist, v); \
, \
M_C(name, _push)(b, key); \
) \
ret = M_C(name, _get)(b, key); \
} \
return ret; \
} \
static inline M_ATTR_DEPRECATED value_t * \
M_C(name, _get_at)(tree_t b, key_t const key) \
{ \
return M_C(name, _safe_get)(b, key); \
} \
\
static inline int \
@@ -1256,11 +1247,11 @@
, /* NO HASH METHOD */ ) \
\
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \
static inline void M_C(name, _get_str)(string_t str, \
static inline void M_C(name, _get_str)(m_string_t str, \
const tree_t t1, bool append) { \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
M_ASSERT(str != NULL); \
(append ? string_cat_str : string_set_str) (str, "["); \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
/* NOTE: The print is really naive, and not really efficient */ \
bool commaToPrint = false; \
it_t it; \
@@ -1268,18 +1259,18 @@
!M_C(name, _end_p)(it); \
M_C(name, _next)(it)) { \
if (commaToPrint) \
string_push_back (str, M_GET_SEPARATOR key_oplist); \
m_string_push_back (str, M_GET_SEPARATOR key_oplist); \
commaToPrint = true; \
subtype_t const *ref1 = M_C(name, _cref)(it); \
M_IF(isMap)( \
M_CALL_GET_STR(key_oplist, str, *ref1->key_ptr, true); \
string_cat_str(str, ":"); \
m_string_cat_cstr(str, ":"); \
M_CALL_GET_STR(value_oplist,str, *ref1->value_ptr, true) \
, \
M_CALL_GET_STR(key_oplist, str, *ref1, true); \
); \
} \
string_push_back (str, ']'); \
m_string_push_back (str, ']'); \
} \
, /* NO GET_STR */ ) \
\
@@ -1478,5 +1469,19 @@
} \
, /* no in_serial */ ) \
\
M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF(M_INV(isMap), name, tree_t, key_oplist, value_oplist)
#if M_USE_SMALL_NAME
#define BPTREE_DEF2 M_BPTREE_DEF2
#define BPTREE_DEF2_AS M_BPTREE_DEF2_AS
#define BPTREE_DEF M_BPTREE_DEF
#define BPTREE_DEF_AS M_BPTREE_DEF_AS
#define BPTREE_MULTI_DEF2 M_BPTREE_MULTI_DEF2
#define BPTREE_MULTI_DEF2_AS M_BPTREE_MULTI_DEF2_AS
#define BPTREE_MULTI_DEF M_BPTREE_MULTI_DEF
#define BPTREE_MULTI_DEF_AS M_BPTREE_MULTI_DEF_AS
#define BPTREE_OPLIST M_BPTREE_OPLIST
#define BPTREE_OPLIST2 M_BPTREE_OPLIST2
#endif
#endif
+124 -93
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Fixed size (Bounded) QUEUE & STACK interface
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -40,29 +40,29 @@
* - if the pop of an element is not complete until the call to pop_release (preventing push until this call).
*/
typedef enum {
BUFFER_QUEUE = 0, BUFFER_STACK = 1,
BUFFER_BLOCKING_PUSH = 0, BUFFER_UNBLOCKING_PUSH = 2,
BUFFER_BLOCKING_POP = 0, BUFFER_UNBLOCKING_POP = 4,
BUFFER_BLOCKING = 0, BUFFER_UNBLOCKING = 6,
BUFFER_THREAD_SAFE = 0, BUFFER_THREAD_UNSAFE = 8,
BUFFER_PUSH_INIT_POP_MOVE = 16,
BUFFER_PUSH_OVERWRITE = 32,
BUFFER_DEFERRED_POP = 64
} buffer_policy_e;
M_BUFFER_QUEUE = 0, M_BUFFER_STACK = 1,
M_BUFFER_BLOCKING_PUSH = 0, M_BUFFER_UNBLOCKING_PUSH = 2,
M_BUFFER_BLOCKING_POP = 0, M_BUFFER_UNBLOCKING_POP = 4,
M_BUFFER_BLOCKING = 0, M_BUFFER_UNBLOCKING = 6,
M_BUFFER_THREAD_SAFE = 0, M_BUFFER_THREAD_UNSAFE = 8,
M_BUFFER_PUSH_INIT_POP_MOVE = 16,
M_BUFFER_PUSH_OVERWRITE = 32,
M_BUFFER_DEFERRED_POP = 64
} m_buffer_policy_e;
/* Define a lock based buffer.
If size is 0, then the size will only be defined at run-time when initializing the buffer,
otherwise the size will be a compile time constant.
USAGE: BUFFER_DEF(name, type, size_of_buffer_or_0, policy[, oplist]) */
#define BUFFER_DEF(name, type, m_size, ... ) \
BUFFER_DEF_AS(name, M_C(name, _t), type, m_size, __VA_ARGS__)
#define M_BUFFER_DEF(name, type, m_size, ... ) \
M_BUFFER_DEF_AS(name, M_C(name, _t), type, m_size, __VA_ARGS__)
/* Define a lock based buffer
as the provided type name_t.
USAGE: BUFFER_DEF_AS(name, name_t, type, size_of_buffer_or_0, policy[, oplist of type]) */
#define BUFFER_DEF_AS(name, name_t, type, m_size, ... ) \
#define M_BUFFER_DEF_AS(name, name_t, type, m_size, ... ) \
M_BEGIN_PROTECTED_CODE \
M_BUFF3R_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, type, m_size,__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), name_t ), \
@@ -72,9 +72,9 @@ typedef enum {
/* Define the oplist of a lock based buffer given its name and its oplist.
USAGE: BUFFER_OPLIST(name[, oplist of the type]) */
#define BUFFER_OPLIST(...) \
#define M_BUFFER_OPLIST(...) \
M_BUFF3R_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
((__VA_ARGS__, M_BASIC_OPLIST), \
(__VA_ARGS__ )))
@@ -84,8 +84,8 @@ typedef enum {
Size of created queue shall be a power of 2 and is defined at run-time.
USAGE: QUEUE_MPMC_DEF(name, type, policy, [oplist of type])
*/
#define QUEUE_MPMC_DEF(name, type, ...) \
QUEUE_MPMC_DEF_AS(name, M_C(name,_t), type, __VA_ARGS__)
#define M_QUEUE_MPMC_DEF(name, type, ...) \
M_QUEUE_MPMC_DEF_AS(name, M_C(name,_t), type, __VA_ARGS__)
/* Define a nearly lock-free queue for Many Producer Many Consummer
@@ -95,7 +95,7 @@ typedef enum {
Size of created queue shall be a power of 2 and is defined at run-time.
USAGE: QUEUE_MPMC_DEF_AS(name, name_t, type, policy, [oplist of type])
*/
#define QUEUE_MPMC_DEF_AS(name, name_t, type, ...) \
#define M_QUEUE_MPMC_DEF_AS(name, name_t, type, ...) \
M_BEGIN_PROTECTED_CODE \
M_QU3UE_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), name_t ), \
@@ -109,8 +109,8 @@ typedef enum {
Size of created queue shall be a power of 2 and is defined at run-time.
USAGE: QUEUE_SPSC_DEF(name, type, policy, [oplist of type])
*/
#define QUEUE_SPSC_DEF(name, type, ...) \
QUEUE_SPSC_DEF_AS(name, M_C(name, _t), type, __VA_ARGS__)
#define M_QUEUE_SPSC_DEF(name, type, ...) \
M_QUEUE_SPSC_DEF_AS(name, M_C(name, _t), type, __VA_ARGS__)
/* Define a wait-free queue for Single Producer Single Consummer
@@ -120,7 +120,7 @@ typedef enum {
Size of created queue shall be a power of 2 and is defined at run-time.
USAGE: QUEUE_SPSC_DEF_AS(name, name_t, type, policy, [oplist of type])
*/
#define QUEUE_SPSC_DEF_AS(name, name_t, type, ...) \
#define M_QUEUE_SPSC_DEF_AS(name, name_t, type, ...) \
M_BEGIN_PROTECTED_CODE \
M_QU3UE_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), name_t ), \
@@ -155,7 +155,7 @@ typedef union m_buff3r_number_s {
static inline void
m_buff3r_number_init(m_buff3r_number_ct n, unsigned int policy)
{
if (!M_BUFF3R_POLICY_P(policy, BUFFER_THREAD_UNSAFE))
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
atomic_init(&n->a, 0U);
else
n->u = 0UL;
@@ -164,7 +164,7 @@ m_buff3r_number_init(m_buff3r_number_ct n, unsigned int policy)
static inline unsigned int
m_buff3r_number_load(m_buff3r_number_ct n, unsigned int policy)
{
if (!M_BUFF3R_POLICY_P(policy, BUFFER_THREAD_UNSAFE))
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
// Perform a memory acquire so that further usage of the buffer
// is synchronized.
return atomic_load_explicit(&n->a, memory_order_acquire);
@@ -175,7 +175,7 @@ m_buff3r_number_load(m_buff3r_number_ct n, unsigned int policy)
static inline void
m_buff3r_number_store(m_buff3r_number_ct n, unsigned int v, unsigned int policy)
{
if (!M_BUFF3R_POLICY_P(policy, BUFFER_THREAD_UNSAFE))
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
// This function is used in context where a relaxed access is sufficient.
atomic_store_explicit(&n->a, v, memory_order_relaxed);
else
@@ -185,7 +185,7 @@ m_buff3r_number_store(m_buff3r_number_ct n, unsigned int v, unsigned int policy)
static inline void
m_buff3r_number_set(m_buff3r_number_ct n, m_buff3r_number_ct v, unsigned int policy)
{
if (!M_BUFF3R_POLICY_P(policy, BUFFER_THREAD_UNSAFE))
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
// This function is used in context where a relaxed access is sufficient.
atomic_store_explicit(&n->a, atomic_load_explicit(&v->a, memory_order_relaxed), memory_order_relaxed);
else
@@ -195,7 +195,7 @@ m_buff3r_number_set(m_buff3r_number_ct n, m_buff3r_number_ct v, unsigned int pol
static inline unsigned int
m_buff3r_number_inc(m_buff3r_number_ct n, unsigned int policy)
{
if (!M_BUFF3R_POLICY_P(policy, BUFFER_THREAD_UNSAFE))
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
return atomic_fetch_add(&n->a, 1U);
else
return n->u ++;
@@ -204,7 +204,7 @@ m_buff3r_number_inc(m_buff3r_number_ct n, unsigned int policy)
static inline unsigned int
m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
{
if (!M_BUFF3R_POLICY_P(policy, BUFFER_THREAD_UNSAFE))
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
return atomic_fetch_sub(&n->a, 1U);
else
return n->u --;
@@ -235,7 +235,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
/* Deferred evaluation for the definition,
so that all arguments are evaluated before further expansion */
#define M_BUFF3R_DEF_P1(arg) M_BUFF3R_DEF_P2 arg
#define M_BUFF3R_DEF_P1(arg) M_ID( M_BUFF3R_DEF_P2 arg )
/* Validate the value oplist before going further */
#define M_BUFF3R_DEF_P2(name, type, m_size, policy, oplist, buffer_t) \
@@ -243,7 +243,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
/* Stop processing with a compilation failure */
#define M_BUFF3R_DEF_FAILURE(name, type, m_size, policy, oplist, buffer_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(BUFFER_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(M_BUFFER_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
/* Define the buffer type using mutex lock and its functions.
- name: main prefix of the container
@@ -259,7 +259,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
by multiple writing threads. No need to align if there is no thread */ \
typedef union M_C(name, _el_s) { \
type x; \
char align[M_BUFF3R_POLICY_P(policy, BUFFER_THREAD_UNSAFE) ? 1 : M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
char align[M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE) ? 1 : M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
} M_C(name, _el_ct); \
\
typedef struct M_C(name, _s) { \
@@ -276,7 +276,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
size_t idx_cons; /* Index of the consumption threads */ \
/* number[0] := Number of elements in the buffer */ \
/* number[1] := [OPTION] Number of elements being deferred in the buffer */ \
m_buff3r_number_ct number[1 + M_BUFF3R_POLICY_P(policy, BUFFER_DEFERRED_POP)]; \
m_buff3r_number_ct number[1 + M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)]; \
/* If fixed size, array of elements, otherwise pointer to element */ \
M_C(name, _el_ct) M_BUFF3R_IF_CTE_SIZE(m_size)(data[m_size], *data); \
} buffer_t[1]; \
@@ -298,15 +298,15 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_ASSERT(size <= UINT_MAX); \
v->idx_prod = v->idx_cons = v->overwrite = 0; \
m_buff3r_number_init (v->number[0], policy); \
if (M_BUFF3R_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
m_buff3r_number_init (v->number[1], policy); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_init(v->mutexPush); \
m_mutex_init(v->mutexPop); \
m_cond_init(v->there_is_data); \
m_cond_init(v->there_is_room_for_data); \
} else { \
M_ASSERT(M_BUFF3R_POLICY_P((policy), BUFFER_UNBLOCKING)); \
M_ASSERT(M_BUFF3R_POLICY_P((policy), M_BUFFER_UNBLOCKING)); \
} \
\
M_BUFF3R_IF_CTE_SIZE(m_size)( /* Statically allocated */ , \
@@ -316,7 +316,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
return; \
} \
) \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
for(size_t i = 0; i < size; i++) { \
M_CALL_INIT(oplist, v->data[i].x); \
} \
@@ -336,22 +336,22 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_C3(m_buff3r_,name,_clear_obj)(buffer_t v) \
{ \
M_BUFF3R_CONTRACT(v,m_size); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
for(size_t i = 0; i < M_BUFF3R_SIZE(m_size); i++) { \
M_CALL_CLEAR(oplist, v->data[i].x); \
} \
} else { \
size_t i = M_BUFF3R_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \
size_t i = M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK) ? 0 : v->idx_cons; \
while (i != v->idx_prod) { \
M_CALL_CLEAR(oplist, v->data[i].x); \
i++; \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_STACK) && i >= M_BUFF3R_SIZE(m_size)) \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK) && i >= M_BUFF3R_SIZE(m_size)) \
i = 0; \
} \
} \
v->idx_prod = v->idx_cons = 0; \
m_buff3r_number_store (v->number[0], 0U, policy); \
if (M_BUFF3R_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
m_buff3r_number_store(v->number[1], 0U, policy); \
M_BUFF3R_CONTRACT(v,m_size); \
} \
@@ -366,7 +366,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
v->data = NULL; \
) \
v->overwrite = 0; \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_clear(v->mutexPush); \
m_mutex_clear(v->mutexPop); \
m_cond_clear(v->there_is_data); \
@@ -378,18 +378,18 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_C(name, _reset)(buffer_t v) \
{ \
M_BUFF3R_CONTRACT(v,m_size); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_lock(v->mutexPush); \
m_mutex_lock(v->mutexPop); \
} \
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
if (M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) \
if (M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) \
M_C3(m_buff3r_,name,_clear_obj)(v); \
v->idx_prod = v->idx_cons = 0; \
m_buff3r_number_store (v->number[0], 0U, policy); \
if (M_BUFF3R_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
m_buff3r_number_store(v->number[1], 0U, policy); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_cond_broadcast(v->there_is_room_for_data); \
m_mutex_unlock(v->mutexPop); \
m_mutex_unlock(v->mutexPush); \
@@ -413,22 +413,22 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_ASSERT (dest != v); \
M_BUFF3R_CONTRACT(v,m_size); \
M_C(name, _init)(dest, M_BUFF3R_SIZE(m_size)); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_lock(v->mutexPush); \
m_mutex_lock(v->mutexPop); \
} \
\
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
for(size_t i = 0; i < M_BUFF3R_SIZE(m_size); i++) { \
M_CALL_INIT_SET(oplist, dest->data[i].x, v->data[i].x); \
} \
} else { \
size_t i = M_BUFF3R_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \
size_t i = M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK) ? 0 : v->idx_cons; \
while (i != v->idx_prod) { \
M_CALL_INIT_SET(oplist, dest->data[i].x, v->data[i].x); \
i++; \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_STACK) && i >= M_BUFF3R_SIZE(m_size)) \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK) && i >= M_BUFF3R_SIZE(m_size)) \
i = 0; \
} \
} \
@@ -436,10 +436,10 @@ M_C(name, _init)(buffer_t v, size_t size) \
dest->idx_prod = v->idx_prod; \
dest->idx_cons = v->idx_cons; \
m_buff3r_number_set (dest->number[0], v->number[0], policy); \
if (M_BUFF3R_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
m_buff3r_number_set(dest->number[1], v->number[1], policy); \
\
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_unlock(v->mutexPop); \
m_mutex_unlock(v->mutexPush); \
} \
@@ -458,7 +458,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_BUFF3R_CONTRACT(v,m_size); \
\
if (dest == v) return; \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
/* Case of deadlock: A := B, B:=C, C:=A (all in //) \
Solution: order the lock by increasing memory */ \
if (dest < v) { \
@@ -477,16 +477,16 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
M_C3(m_buff3r_,name,_clear_obj)(dest); \
\
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
for(size_t i = 0; i < M_BUFF3R_SIZE(m_size); i++) { \
M_CALL_INIT_SET(oplist, dest->data[i].x, v->data[i].x); \
} \
} else { \
size_t i = M_BUFF3R_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \
size_t i = M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK) ? 0 : v->idx_cons; \
while (i != v->idx_prod) { \
M_CALL_INIT_SET(oplist, dest->data[i].x, v->data[i].x); \
i++; \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_STACK) && i >= M_BUFF3R_SIZE(m_size)) \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK) && i >= M_BUFF3R_SIZE(m_size)) \
i = 0; \
} \
} \
@@ -494,10 +494,10 @@ M_C(name, _init)(buffer_t v, size_t size) \
dest->idx_prod = v->idx_prod; \
dest->idx_cons = v->idx_cons; \
m_buff3r_number_set (dest->number[0], v->number[0], policy); \
if (M_BUFF3R_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
m_buff3r_number_set(dest->number[1], v->number[1], policy); \
\
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
/* It may be false, but it is not wrong! */ \
m_cond_broadcast(v->there_is_room_for_data); \
m_cond_broadcast(v->there_is_data); \
@@ -525,7 +525,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
we considered the queue as empty when the number of \
deferred pop has reached 0, not the number of items in the \
buffer is 0. */ \
if (M_BUFF3R_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
return m_buff3r_number_load (v->number[1], policy) == 0; \
else \
return m_buff3r_number_load (v->number[0], policy) == 0; \
@@ -552,9 +552,9 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_BUFF3R_CONTRACT(v,m_size); \
\
/* Producer Mutex lock (mutex lock performs an acquire memory barrier) */ \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_lock(v->mutexPush); \
while (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \
while (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_OVERWRITE) \
&& M_C(name, _full_p)(v)) { \
if (!blocking) { \
m_mutex_unlock(v->mutexPush); \
@@ -562,20 +562,20 @@ M_C(name, _init)(buffer_t v, size_t size) \
} \
m_cond_wait(v->there_is_room_for_data, v->mutexPush); \
} \
} else if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \
} else if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_OVERWRITE) \
&& M_C(name, _full_p)(v)) \
return false; \
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
\
size_t previousSize, idx = v->idx_prod; \
/* INDEX computation if we have to overwrite the last element */ \
if (M_UNLIKELY (M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \
if (M_UNLIKELY (M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_OVERWRITE) \
&& M_C(name, _full_p)(v))) { \
v->overwrite++; \
/* Let's overwrite the last element */ \
/* Compute the index of the last push element */ \
idx--; \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_STACK)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK)) { \
idx = idx >= M_BUFF3R_SIZE(m_size) ? M_BUFF3R_SIZE(m_size)-1 : idx; \
} \
/* Update data in the buffer */ \
@@ -584,7 +584,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
} else { \
/* Add a new item in the buffer */ \
/* PUSH data in the buffer */ \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, v->data[idx].x, data); \
} else { \
M_CALL_INIT_SET(oplist, v->data[idx].x, data); \
@@ -592,7 +592,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
\
/* Increment production INDEX of the buffer */ \
idx++; \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_STACK)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK)) { \
idx = (idx == M_BUFF3R_SIZE(m_size)) ? 0 : idx; \
} \
v->idx_prod = idx; \
@@ -603,14 +603,14 @@ M_C(name, _init)(buffer_t v, size_t size) \
that performs a release memory barrier. */ \
/* Increment number of elements of the buffer */ \
previousSize = m_buff3r_number_inc (v->number[0], policy); \
if (M_BUFF3R_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \
if (M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) { \
previousSize = m_buff3r_number_inc (v->number[1], policy); \
} \
/* From this point, consummer may read the data in the table */ \
} \
\
/* Producer unlock (mutex unlock performs a release memory barrier) */ \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_unlock(v->mutexPush); \
/* If the number of items in the buffer was 0, some consummer \
may be waiting. Signal to them the availibility of the data \
@@ -633,7 +633,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_ASSERT (data != NULL); \
\
/* Consummer lock (mutex lock performs an acquire memory barrier) */ \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_lock(v->mutexPop); \
while (M_C(name, _empty_p)(v)) { \
if (!blocking) { \
@@ -647,9 +647,9 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
\
/* POP data from the buffer and update INDEX */ \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_STACK)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_STACK)) { \
/* FIFO queue */ \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, *data, v->data[v->idx_cons].x); \
} else { \
M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_cons].x); \
@@ -658,7 +658,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
} else { \
/* STACK queue */ \
v->idx_prod --; \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, *data, v->data[v->idx_prod].x); \
} else { \
M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_prod].x); \
@@ -671,7 +671,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
that performs a release memory barrier. */ \
/* Decrement number of elements in the buffer */ \
size_t previousSize; \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) { \
previousSize = m_buff3r_number_dec (v->number[0], policy); \
} else { \
m_buff3r_number_dec (v->number[1], policy); \
@@ -679,12 +679,12 @@ M_C(name, _init)(buffer_t v, size_t size) \
/* Space may be reused by a producer thread from this point */ \
\
/* Consummer unlock (mutex unlock perfoms a release memory barrier) */ \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_unlock(v->mutexPop); \
/* If the number of items in the buffer was the max, some producer \
may be waiting. Signal to them the availibility of the free room \
We cannot only signal one thread. */ \
if ((!M_BUFF3R_POLICY_P((policy), BUFFER_DEFERRED_POP)) \
if ((!M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) \
&& previousSize == M_BUFF3R_SIZE(m_size)) { \
m_mutex_lock(v->mutexPush); \
m_cond_broadcast(v->there_is_room_for_data); \
@@ -701,14 +701,14 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_C(name, _push)(buffer_t v, type const data) \
{ \
return M_C(name, _push_blocking)(v, data, \
!M_BUFF3R_POLICY_P((policy), BUFFER_UNBLOCKING_PUSH)); \
!M_BUFF3R_POLICY_P((policy), M_BUFFER_UNBLOCKING_PUSH)); \
} \
\
static inline bool \
M_C(name, _pop)(type *data, buffer_t v) \
{ \
return M_C(name, _pop_blocking)(data, v, \
!M_BUFF3R_POLICY_P((policy), BUFFER_UNBLOCKING_POP)); \
!M_BUFF3R_POLICY_P((policy), M_BUFFER_UNBLOCKING_POP)); \
} \
\
static inline size_t \
@@ -728,7 +728,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_C(name, _pop_release)(buffer_t v) \
{ \
/* Decrement the effective number of elements in the buffer */ \
if (M_BUFF3R_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \
if (M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) { \
size_t previousSize = m_buff3r_number_dec (v->number[0], policy); \
if (previousSize == M_BUFF3R_SIZE(m_size)) { \
m_mutex_lock(v->mutexPush); \
@@ -737,6 +737,8 @@ M_C(name, _init)(buffer_t v, size_t size) \
} \
} \
} \
\
M_EMPLACE_QUEUE_DEF(name, buffer_t, M_C(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
@@ -752,7 +754,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
/* Deferred evaluation for the definition,
so that all arguments are evaluated before further expansion */
#define M_QU3UE_MPMC_DEF_P1(arg) M_QU3UE_MPMC_DEF_P2 arg
#define M_QU3UE_MPMC_DEF_P1(arg) M_ID( M_QU3UE_MPMC_DEF_P2 arg )
/* Validate the value oplist before going further */
#define M_QU3UE_MPMC_DEF_P2(name, type, policy, oplist, buffer_t) \
@@ -832,8 +834,12 @@ M_C(name, _init)(buffer_t v, size_t size) \
/* Thread has been preempted by another one. */ \
return false; \
} \
/* If it is interrupted here, it may block pop method (not push) */ \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
/* If it is interrupted here, it may block all pop methods (not push) \
even if there is other threads that have pushed data later in the \
queue as all pop threads will try to enqueue this particular element \
but always fail. The won't try to enqueue other elements. \
As such, this queue is not strictly lock-free.*/ \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, table->Tab[i].x, x); \
} else { \
M_CALL_INIT_SET(oplist, table->Tab[i].x, x); \
@@ -863,7 +869,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
/* Thread has been preempted by another one */ \
return false; \
} \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, *ptr, table->Tab[i].x); \
} else { \
M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \
@@ -879,7 +885,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_ASSERT (buffer != NULL); \
M_ASSERT( M_POWEROF2_P(size)); \
M_ASSERT (0 < size && size <= UINT_MAX); \
M_ASSERT(((policy) & (BUFFER_STACK|BUFFER_THREAD_UNSAFE|BUFFER_PUSH_OVERWRITE)) == 0); \
M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_THREAD_UNSAFE|M_BUFFER_PUSH_OVERWRITE)) == 0); \
atomic_init(&buffer->ProdIdx, (unsigned int) size); \
atomic_init(&buffer->ConsoIdx, (unsigned int) size); \
buffer->size = (unsigned int) size; \
@@ -890,7 +896,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
} \
for(unsigned int j = 0; j < (unsigned int) size; j++) { \
atomic_init(&buffer->Tab[j].seq, 2*j+1U); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_INIT(oplist, buffer->Tab[j].x); \
} \
} \
@@ -901,7 +907,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_C(name, _clear)(buffer_t buffer) \
{ \
M_QU3UE_MPMC_CONTRACT(buffer); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
for(unsigned int j = 0; j < buffer->size; j++) { \
M_CALL_CLEAR(oplist, buffer->Tab[j].x); \
} \
@@ -974,7 +980,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
/* Deferred evaluation for the definition,
so that all arguments are evaluated before further expansion */
#define M_QU3UE_SPSC_DEF_P1(arg) M_QU3UE_SPSC_DEF_P2 arg
#define M_QU3UE_SPSC_DEF_P1(arg) M_ID( M_QU3UE_SPSC_DEF_P2 arg )
/* Validate the value oplist before going further */
#define M_QU3UE_SPSC_DEF_P2(name, type, policy, oplist, buffer_t) \
@@ -1037,7 +1043,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
if (w-r >= table->size) \
return false; \
unsigned int i = w & (table->size -1); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, table->Tab[i].x, x); \
} else { \
M_CALL_INIT_SET(oplist, table->Tab[i].x, x); \
@@ -1058,7 +1064,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
if (w-r >= table->size) \
return false; \
unsigned int i = w & (table->size -1); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_DO_MOVE(oplist, table->Tab[i].x, *x); \
} else { \
M_DO_INIT_MOVE(oplist, table->Tab[i].x, *x); \
@@ -1080,7 +1086,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
if (w-r == 0) \
return false; \
unsigned int i = r & (table->size -1); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, *ptr , table->Tab[i].x); \
} else { \
M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \
@@ -1105,7 +1111,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
return 0; \
for(unsigned int k = 0; k < max; k++) { \
unsigned int i = (w+k) & (table->size -1); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, table->Tab[i].x, x[k]); \
} else { \
M_CALL_INIT_SET(oplist, table->Tab[i].x, x[k]); \
@@ -1131,7 +1137,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
unsigned int max = M_MIN(w-r, n); \
for(unsigned int k = 0; k < max; k++) { \
unsigned int i = (r+k) & (table->size -1); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, ptr[k], table->Tab[i].x); \
} else { \
M_DO_INIT_MOVE (oplist, ptr[k], table->Tab[i].x); \
@@ -1156,7 +1162,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
r += b; \
} \
unsigned int i = w & (table->size -1); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, table->Tab[i].x, x); \
} else { \
M_CALL_INIT_SET(oplist, table->Tab[i].x, x); \
@@ -1210,7 +1216,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_ASSERT (buffer != NULL); \
M_ASSERT( M_POWEROF2_P(size)); \
M_ASSERT (0 < size && size <= UINT_MAX); \
M_ASSERT(((policy) & (BUFFER_STACK|BUFFER_THREAD_UNSAFE|BUFFER_PUSH_OVERWRITE)) == 0); \
M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_THREAD_UNSAFE|M_BUFFER_PUSH_OVERWRITE)) == 0); \
atomic_init(&buffer->prodIdx, (unsigned int) size); \
atomic_init(&buffer->consoIdx, (unsigned int) size); \
buffer->size = (unsigned int) size; \
@@ -1219,7 +1225,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_MEMORY_FULL (size*sizeof(M_C(name, _el_ct) )); \
return; \
} \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
for(unsigned int j = 0; j < (unsigned int) size; j++) { \
M_CALL_INIT(oplist, buffer->Tab[j].x); \
} \
@@ -1231,7 +1237,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_C(name, _clear)(buffer_t buffer) \
{ \
M_QU3UE_SPSC_CONTRACT(buffer); \
if (!M_BUFF3R_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
for(unsigned int j = 0; j < buffer->size; j++) { \
M_CALL_CLEAR(oplist, buffer->Tab[j].x); \
} \
@@ -1282,5 +1288,30 @@ M_C(name, _init)(buffer_t v, size_t size) \
,GET_SIZE(M_C(name, _size)) \
)
#if M_USE_SMALL_NAME
#define BUFFER_DEF M_BUFFER_DEF
#define BUFFER_DEF_AS M_BUFFER_DEF_AS
#define BUFFER_OPLIST M_BUFFER_OPLIST
#define QUEUE_MPMC_DEF M_QUEUE_MPMC_DEF
#define QUEUE_MPMC_DEF_AS M_QUEUE_MPMC_DEF_AS
#define QUEUE_SPSC_DEF M_QUEUE_SPSC_DEF
#define QUEUE_SPSC_DEF_AS M_QUEUE_SPSC_DEF_AS
#define buffer_policy_e m_buffer_policy_e
#define BUFFER_QUEUE M_BUFFER_QUEUE
#define BUFFER_STACK M_BUFFER_STACK
#define BUFFER_BLOCKING_PUSH M_BUFFER_BLOCKING_PUSH
#define BUFFER_UNBLOCKING_PUSH M_BUFFER_UNBLOCKING_PUSH
#define BUFFER_BLOCKING_POP M_BUFFER_BLOCKING_POP
#define BUFFER_UNBLOCKING_POP M_BUFFER_UNBLOCKING_POP
#define BUFFER_BLOCKING M_BUFFER_BLOCKING
#define BUFFER_UNBLOCKING M_BUFFER_UNBLOCKING
#define BUFFER_THREAD_SAFE M_BUFFER_THREAD_SAFE
#define BUFFER_THREAD_UNSAFE M_BUFFER_THREAD_UNSAFE
#define BUFFER_PUSH_INIT_POP_MOVE M_BUFFER_PUSH_INIT_POP_MOVE
#define BUFFER_PUSH_OVERWRITE M_BUFFER_PUSH_OVERWRITE
#define BUFFER_DEFERRED_POP M_BUFFER_DEFERRED_POP
#endif
#endif
+23 -19
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Concurrent memory pool allocator
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,7 +34,7 @@ M_BEGIN_PROTECTED_CODE
/* Minimum number of nodes per group of nodes */
#define M_CMEMP00L_MIN_NODE_PER_GROUP 16
#define C_MEMPOOL_DEF(name, type_t) \
#define M_C_MEMPOOL_DEF(name, type_t) \
M_BEGIN_PROTECTED_CODE \
M_CMEMP00L_DEF_SINGLY_LIST(name, type_t) \
M_CMEMP00L_DEF_LF_QUEUE(name, type_t) \
@@ -418,18 +418,18 @@ M_BEGIN_PROTECTED_CODE
M_C(name, _lflist_ct) free; \
M_C(name, _lflist_ct) to_be_reclaimed; \
M_C(name, _lflist_ct) empty; \
m_gM_CMEMP00L_list_ct mempool_node; \
m_cmemp00l_list_ct mempool_node; \
struct m_gc_s *gc_mem; \
} M_C(name, _t)[1]; \
\
/* Garbage collect of the nodes of the mempool on sleep */ \
static inline void \
M_C3(m_cmemp00l_,name,_gc_on_sleep)(m_gc_t gc_mem, m_gM_CMEMP00L_list_ct *data, \
M_C3(m_cmemp00l_,name,_gc_on_sleep)(m_gc_t gc_mem, m_cmemp00l_list_ct *data, \
m_gc_tid_t id, m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket) \
{ \
/* Get back the mempool from the node */ \
struct M_C(name, _s) *mempool = \
M_TYPE_FROM_FIELD(struct M_C(name, _s), data, m_gM_CMEMP00L_list_ct, mempool_node); \
M_TYPE_FROM_FIELD(struct M_C(name, _s), data, m_cmemp00l_list_ct, mempool_node); \
\
/* Move the local nodes of the mempool to be reclaimed to the thread into the global pool */ \
if (!M_C(name, _slist_empty_p)(mempool->thread_data[id].to_be_reclaimed)) { \
@@ -555,13 +555,13 @@ typedef atomic_ulong m_gc_atomic_ticket_ct;
/* Define the Linked List of mempools that are registered in the GC */
struct m_gc_s;
typedef struct m_gM_CMEMP00L_list_s {
struct m_gM_CMEMP00L_list_s *next;
typedef struct m_cmemp00l_list_s {
struct m_cmemp00l_list_s *next;
void (*gc_on_sleep)(struct m_gc_s *gc_mem,
struct m_gM_CMEMP00L_list_s *data, m_gc_tid_t id,
struct m_cmemp00l_list_s *data, m_gc_tid_t id,
m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket);
void *data;
} m_gM_CMEMP00L_list_ct;
} m_cmemp00l_list_ct;
/* Define the Garbage collector thread data */
typedef struct m_gc_lfmp_thread_s {
@@ -574,9 +574,9 @@ typedef struct m_gc_lfmp_thread_s {
typedef struct m_gc_s {
m_gc_atomic_ticket_ct ticket;
m_gc_tid_t max_thread;
genint_t thread_alloc;
m_genint_t thread_alloc;
m_gc_lfmp_thread_ct *thread_data;
m_gM_CMEMP00L_list_ct *mempool_list;
m_cmemp00l_list_ct *mempool_list;
} m_gc_t[1];
static inline void
@@ -586,7 +586,7 @@ m_gc_init(m_gc_t gc_mem, size_t max_thread)
M_ASSERT(max_thread > 0 && max_thread < INT_MAX);
atomic_init(&gc_mem->ticket, 0UL);
genint_init(gc_mem->thread_alloc, (unsigned int) max_thread);
m_genint_init(gc_mem->thread_alloc, (unsigned int) max_thread);
gc_mem->thread_data = M_MEMORY_REALLOC(m_gc_lfmp_thread_ct, NULL, max_thread);
if (gc_mem->thread_data == NULL) {
M_MEMORY_FULL(max_thread * sizeof(m_gc_lfmp_thread_ct));
@@ -610,7 +610,7 @@ m_gc_clear(m_gc_t gc_mem)
}
M_MEMORY_FREE(gc_mem->thread_data);
gc_mem->thread_data = NULL;
genint_clear(gc_mem->thread_alloc);
m_genint_clear(gc_mem->thread_alloc);
}
static inline m_gc_tid_t
@@ -618,7 +618,7 @@ m_gc_attach_thread(m_gc_t gc_mem)
{
M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0);
unsigned id = genint_pop(gc_mem->thread_alloc);
unsigned id = m_genint_pop(gc_mem->thread_alloc);
return M_ASSIGN_CAST(m_gc_tid_t, id);
}
@@ -629,7 +629,7 @@ m_gc_detach_thread(m_gc_t gc_mem, m_gc_tid_t id)
M_ASSERT(id < gc_mem->max_thread);
M_ASSERT(atomic_load(&gc_mem->thread_data[id].ticket) == ULONG_MAX);
genint_push(gc_mem->thread_alloc, id);
m_genint_push(gc_mem->thread_alloc, id);
}
static inline void
@@ -662,7 +662,7 @@ m_gc_sleep(m_gc_t gc_mem, m_gc_tid_t id)
atomic_store(&gc_mem->thread_data[id].ticket, t+1);
const m_gc_ticket_ct min_ticket = m_cmemp00l_gc_min_ticket(gc_mem);
/* Iterate over all registered mempools */
m_gM_CMEMP00L_list_ct *it = gc_mem->mempool_list;
m_cmemp00l_list_ct *it = gc_mem->mempool_list;
while (it) {
/* Perform a garbage collect of the mempool */
@@ -707,18 +707,18 @@ typedef struct m_vlapool_s {
m_vlapool_lflist_ct to_be_reclaimed;
m_vlapool_lflist_ct empty;
m_vlapool_lfmp_thread_ct *thread_data;
m_gM_CMEMP00L_list_ct mvla_node;
m_cmemp00l_list_ct mvla_node;
struct m_gc_s *gc_mem;
} m_vlapool_t[1];
/* Garbage collect of the nodes of the vla mempool on sleep */
static inline void
m_cmemp00l_vlapool_on_sleep(m_gc_t gc_mem, m_gM_CMEMP00L_list_ct *data,
m_cmemp00l_vlapool_on_sleep(m_gc_t gc_mem, m_cmemp00l_list_ct *data,
m_gc_tid_t id, m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket)
{
/* Get back the mempool from the node */
struct m_vlapool_s *vlapool =
M_TYPE_FROM_FIELD(struct m_vlapool_s, data, m_gM_CMEMP00L_list_ct, mvla_node);
M_TYPE_FROM_FIELD(struct m_vlapool_s, data, m_cmemp00l_list_ct, mvla_node);
/* Move the local nodes of the vlapool to be reclaimed to the thread into the global pool */
if (!m_vlapool_slist_empty_p(vlapool->thread_data[id].to_be_reclaimed)) {
@@ -828,4 +828,8 @@ m_vlapool_del(m_vlapool_t mem, void *d, m_gc_tid_t id)
M_END_PROTECTED_CODE
#if M_USE_SMALL_NAME
#define C_MEMPOOL_DEF M_C_MEMPOOL_DEF
#endif
#endif
+21 -22
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Basic Protected Concurrent module over container.
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,14 +32,14 @@
/* Define a protected concurrent container and its associated functions
based on the given container.
USAGE: CONCURRENT_DEF(name, type [, oplist_of_the_type]) */
#define CONCURRENT_DEF(name, ...) \
CONCURRENT_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
#define M_CONCURRENT_DEF(name, ...) \
M_CONCURRENT_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
/* Define a protected concurrent container and its associated functions
based on the given container as the given name name_t
USAGE: CONCURRENT_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
#define CONCURRENT_DEF_AS(name, name_t, ...) \
#define M_CONCURRENT_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_C0NCURRENT_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
@@ -51,8 +51,8 @@
based on its given container. Operations that perform only read of the container
can be done in parallel.
USAGE: CONCURRENT_RP_DEF(name, type [, oplist_of_the_type]) */
#define CONCURRENT_RP_DEF(name, ...) \
CONCURRENT_RP_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
#define M_CONCURRENT_RP_DEF(name, ...) \
M_CONCURRENT_RP_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
/* Define a protected concurrent container and its associated functions
@@ -60,7 +60,7 @@
based on its given container. Operations that perform only read of the container
can be done in parallel.
USAGE: CONCURRENT_RP_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
#define CONCURRENT_RP_DEF_AS(name, name_t, ...) \
#define M_CONCURRENT_RP_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_C0NCURRENT_RP_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
@@ -70,9 +70,9 @@
/* Define the oplist of a protected concurrent container given its name and its oplist.
USAGE: CONCURRENT_OPLIST(name[, oplist of the type]) */
#define CONCURRENT_OPLIST(...) \
#define M_CONCURRENT_OPLIST(...) \
M_C0NCURRENT_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
((__VA_ARGS__, M_BASIC_OPLIST), \
(__VA_ARGS__ )))
@@ -143,7 +143,7 @@
/* Deferred evaluation for the concurrent definition,
so that all arguments are evaluated before further expansion */
#define M_C0NCURRENT_DEF_P1(arg) M_C0NCURRENT_DEF_P2 arg
#define M_C0NCURRENT_DEF_P1(arg) M_ID( M_C0NCURRENT_DEF_P2 arg )
/* Validate the value oplist before going further */
#define M_C0NCURRENT_DEF_P2(name, type, oplist, concurrent_t) \
@@ -423,11 +423,6 @@
M_CALL_RESET(oplist, out->data); \
M_C(name, _write_unlock)(out); \
} \
static inline void M_ATTR_DEPRECATED \
M_C(name, _clean)(concurrent_t out) \
{ \
M_C(name,_reset)(out); \
} \
,) \
\
M_IF_METHOD(EMPTY_P, oplist)( \
@@ -494,11 +489,6 @@
M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \
M_C(name, _write_unlock)(out); \
} \
static inline M_ATTR_DEPRECATED void \
M_C(name, _get_at_copy)(M_GET_VALUE_TYPE oplist *out_data, concurrent_t out, M_GET_KEY_TYPE oplist const key) \
{ \
M_C(name, _safe_get_copy)(out_data, out, key); \
} \
,) \
\
M_IF_METHOD(ERASE_KEY, oplist)( \
@@ -525,6 +515,8 @@
M_C(name, _write_signal)(out); \
M_C(name, _write_unlock)(out); \
} \
\
M_EMPLACE_QUEUE_DEF(name, concurrent_t, M_C(name, _emplace), M_GET_OPLIST oplist, M_EMPLACE_QUEUE_GENE) \
,) \
\
M_IF_METHOD(POP, oplist)( \
@@ -565,7 +557,7 @@
\
M_IF_METHOD(GET_STR, oplist)( \
static inline void \
M_C(name, _get_str)(string_t str, concurrent_t const out, bool a) \
M_C(name, _get_str)(m_string_t str, concurrent_t const out, bool a) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_C(name, _read_lock)(out); \
@@ -750,7 +742,7 @@
/* Deferred evaluation for the RP concurrent definition,
so that all arguments are evaluated before further expansion */
#define M_C0NCURRENT_RP_DEF_P1(arg) M_C0NCURRENT_RP_DEF_P2 arg
#define M_C0NCURRENT_RP_DEF_P1(arg) M_ID( M_C0NCURRENT_RP_DEF_P2 arg )
/* Validate the value oplist before going further */
#define M_C0NCURRENT_RP_DEF_P2(name, type, oplist, concurrent_t) \
@@ -905,5 +897,12 @@
\
M_C0NCURRENT_DEF_FUNC_P3(name, type, oplist, concurrent_t)
#if M_USE_SMALL_NAME
#define CONCURRENT_DEF M_CONCURRENT_DEF
#define CONCURRENT_DEF_AS M_CONCURRENT_DEF_AS
#define CONCURRENT_RP_DEF M_CONCURRENT_RP_DEF
#define CONCURRENT_RP_DEF_AS M_CONCURRENT_RP_DEF_AS
#define CONCURRENT_OPLIST M_CONCURRENT_OPLIST
#endif
#endif
+1397 -404
View File
File diff suppressed because it is too large. Load diff
+46 -17
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - DEQUE module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -29,14 +29,14 @@
/* Define a deque of a given type and its associated functions.
USAGE: DEQUE_DEF(name, type [, oplist_of_the_type]) */
#define DEQUE_DEF(name, ...) \
DEQUE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
#define M_DEQUE_DEF(name, ...) \
M_DEQUE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
/* Define a deque of a given type and its associated functions.
as the provided type name_t with the iterator named it_t.
USAGE: DEQUE_DEF(name, name_t, it_t, type [, oplist_of_the_type]) */
#define DEQUE_DEF_AS(name, name_t, it_t, ...) \
#define M_DEQUE_DEF_AS(name, name_t, it_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_D3QU3_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t, M_C(name, _node_ct) ), \
@@ -46,9 +46,9 @@
/* Define the oplist of a deque of a type.
USAGE: DEQUE_OPLIST(name[, oplist of the type]) */
#define DEQUE_OPLIST(...) \
#define M_DEQUE_OPLIST(...) \
M_D3QU3_OPLIST_P1 (M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
((__VA_ARGS__, M_BASIC_OPLIST), \
(__VA_ARGS__ )))
/* Default initial size of a bucket of items */
@@ -74,7 +74,7 @@
/* Deferred evaluation for the deque definition,
so that all arguments are evaluated before further expansion */
#define M_D3QU3_DEF_P1(arg) M_D3QU3_DEF_P2 arg
#define M_D3QU3_DEF_P1(arg) M_ID( M_D3QU3_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_D3QU3_DEF_P2(name, type, oplist, deque_t, it_t, node_t) \
@@ -226,12 +226,6 @@
M_D3QU3_CONTRACT(d); \
} \
\
static inline void M_ATTR_DEPRECATED \
M_C(name, _clean)(deque_t d) \
{ \
M_C(name, _reset)(d); \
} \
\
static inline void \
M_C(name, _clear)(deque_t d) \
{ \
@@ -902,10 +896,10 @@
\
M_IF_METHOD(GET_STR, oplist)( \
static inline void \
M_C(name, _get_str)(string_t str, deque_t const deque, bool append) \
M_C(name, _get_str)(m_string_t str, deque_t const deque, bool append) \
{ \
M_D3QU3_CONTRACT(deque); \
(append ? string_cat_str : string_set_str) (str, "["); \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
it_t it; \
for (M_C(name, _it)(it, deque) ; \
!M_C(name, _end_p)(it); \
@@ -913,9 +907,9 @@
type const *item = M_C(name, _cref)(it); \
M_CALL_GET_STR(oplist, str, *item, true); \
if (!M_C(name, _last_p)(it)) \
string_push_back (str, M_GET_SEPARATOR oplist); \
m_string_push_back (str, M_GET_SEPARATOR oplist); \
} \
string_push_back (str, ']'); \
m_string_push_back (str, ']'); \
} \
, /* no GET_STR */ ) \
\
@@ -1048,6 +1042,35 @@
} \
, /* no IN_SERIAL & INIT */ ) \
\
M_EMPLACE_QUEUE_DEF(name, deque_t, M_C(name, _emplace_back), oplist, M_D3QUE_EMPLACE_BACK_DEF) \
M_EMPLACE_QUEUE_DEF(name, deque_t, M_C(name, _emplace_front), oplist, M_D3QUE_EMPLACE_FRONT_DEF)
/* Definition of the emplace_back function for deque */
#define M_D3QUE_EMPLACE_BACK_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
static inline void \
function_name(name_t v \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
M_C(name, _subtype_ct) *data = M_C(name, _push_back_raw)(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
}
/* Definition of the emplace_front function for deque */
#define M_D3QUE_EMPLACE_FRONT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
static inline void \
function_name(name_t v \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
M_C(name, _subtype_ct) *data = M_C(name, _push_front_raw)(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
}
/* Deferred evaluation for the oplist definition,
so that all arguments are evaluated before further expansion */
@@ -1106,4 +1129,10 @@
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
)
#if M_USE_SMALL_NAME
#define DEQUE_DEF M_DEQUE_DEF
#define DEQUE_DEF_AS M_DEQUE_DEF_AS
#define DEQUE_OPLIST M_DEQUE_OPLIST
#endif
#endif
+82 -69
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - DICTIONARY Module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,8 +36,8 @@
OR
DICT_DEF2(name, key_type, value_type)
*/
#define DICT_DEF2(name, key_type, ...) \
DICT_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), key_type, __VA_ARGS__)
#define M_DICT_DEF2(name, key_type, ...) \
M_DICT_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), key_type, __VA_ARGS__)
/* Define a dictionary associating the key key_type to the value value_type and its associated functions.
@@ -47,7 +47,7 @@
OR
DICT_DEF2_AS(name, name_t, it_t, itref_t, key_type, value_type)
*/
#define DICT_DEF2_AS(name, name_t, it_t, itref_t, key_type, ...) \
#define M_DICT_DEF2_AS(name, name_t, it_t, itref_t, key_type, ...) \
M_BEGIN_PROTECTED_CODE \
M_D1CT_DEF2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t, itref_t ), \
@@ -63,8 +63,8 @@
OR
DICT_STOREHASH_DEF2(name, key_type[, key_oplist], value_type[, value_oplist])
*/
#define DICT_STOREHASH_DEF2(name, key_type, ...) \
DICT_STOREHASH_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), key_type, __VA_ARGS__)
#define M_DICT_STOREHASH_DEF2(name, key_type, ...) \
M_DICT_STOREHASH_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), key_type, __VA_ARGS__)
/* Define a dictionary asssociating the key key_type to the value value_type and its associated functions.
@@ -76,7 +76,7 @@
OR
DICT_STOREHASH_DEF2_AS(name, name_t, it_t, itref_t, key_type[, key_oplist], value_type[, value_oplist])
*/
#define DICT_STOREHASH_DEF2_AS(name, name_t, it_t, itref_t, key_type, ...) \
#define M_DICT_STOREHASH_DEF2_AS(name, name_t, it_t, itref_t, key_type, ...) \
M_BEGIN_PROTECTED_CODE \
M_D1CT_SHASH_DEF2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t, itref_t ), \
@@ -92,8 +92,8 @@
OR
DICT_OA_DEF2(name, key_type, value_type)
*/
#define DICT_OA_DEF2(name, key_type, ...) \
DICT_OA_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), key_type, __VA_ARGS__)
#define M_DICT_OA_DEF2(name, key_type, ...) \
M_DICT_OA_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), key_type, __VA_ARGS__)
/* Define a dictionary associating the key key_type to the value value_type
@@ -105,7 +105,7 @@
OR
DICT_OA_DEF2_AS(name, name_t, it_t, itref_t, key_type, value_type)
*/
#define DICT_OA_DEF2_AS(name, name_t, it_t, itref_t, key_type, ...) \
#define M_DICT_OA_DEF2_AS(name, name_t, it_t, itref_t, key_type, ...) \
M_BEGIN_PROTECTED_CODE \
M_D1CT_OA_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t, itref_t ), \
@@ -117,8 +117,8 @@
The set is unordered.
USAGE: DICT_SET_DEF(name, key_type[, key_oplist])
*/
#define DICT_SET_DEF(name, ...) \
DICT_SET_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
#define M_DICT_SET_DEF(name, ...) \
M_DICT_SET_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
/* Define a set of the key key_type and its associated functions.
@@ -126,7 +126,7 @@
The set is unordered.
USAGE: DICT_SET_DEF_AS(name, name_t, it_t, key_type[, key_oplist])
*/
#define DICT_SET_DEF_AS(name, name_t, it_t, ...) \
#define M_DICT_SET_DEF_AS(name, name_t, it_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_D1CT_SET_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t, M_C(name, _itref_ct) ), \
@@ -139,8 +139,8 @@
The set is unordered.
USAGE: DICT_OASET_DEF(name, key_type[, key_oplist])
*/
#define DICT_OASET_DEF(name, ...) \
DICT_OASET_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
#define M_DICT_OASET_DEF(name, ...) \
M_DICT_OASET_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
/* Define a set of the key key_type
@@ -149,7 +149,7 @@
The set is unordered.
USAGE: DICT_OASET_DEF_AS(name, name_t, it_t, key_type[, key_oplist])
*/
#define DICT_OASET_DEF_AS(name, name_t, it_t, ...) \
#define M_DICT_OASET_DEF_AS(name, name_t, it_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_D1CT_OASET_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t, M_C(name, _itref_ct) ), \
@@ -163,17 +163,17 @@
OR
DICT_OPLIST(name)
*/
#define DICT_OPLIST(...) \
#define M_DICT_OPLIST(...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(M_D1CT_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST )), \
(M_D1CT_OPLIST_P1((__VA_ARGS__, M_BASIC_OPLIST, M_BASIC_OPLIST )), \
M_D1CT_OPLIST_P1((__VA_ARGS__ )))
/* Define the oplist of a dictionnary (DICT_SET_DEF).
USAGE: DICT_SET_OPLIST(name[, oplist of the key type]) */
#define DICT_SET_OPLIST(...) \
#define M_DICT_SET_OPLIST(...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(M_D1CT_SET_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST)), \
(M_D1CT_SET_OPLIST_P1((__VA_ARGS__, M_BASIC_OPLIST)), \
M_D1CT_SET_OPLIST_P1((__VA_ARGS__ )))
@@ -186,7 +186,7 @@
current array size).
*/
/* Deferred evaluation for arg */
#define M_D1CT_DEF2_P1(arg) M_D1CT_DEF2_P2 arg
#define M_D1CT_DEF2_P1(arg) M_ID( M_D1CT_DEF2_P2 arg )
/* Validate the key oplist before going further */
#define M_D1CT_DEF2_P2(name, key_type, key_oplist, value_type, value_oplist, dict_t, dict_it_t, it_deref_t) \
@@ -218,7 +218,7 @@
representing a bucket).
*/
/* Defered evaluation for arg */
#define M_D1CT_SHASH_DEF2_P1(arg) M_D1CT_SHASH_DEF2_P2 arg
#define M_D1CT_SHASH_DEF2_P1(arg) M_ID( M_D1CT_SHASH_DEF2_P2 arg )
/* Validate the key oplist before going further */
#define M_D1CT_SHASH_DEF2_P2(name, key_type, key_oplist, value_type, value_oplist, dict_t, dict_it_t, it_deref_t) \
@@ -237,10 +237,10 @@
M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \
M_CHECK_COMPATIBLE_OPLIST(name, 2, value_type, value_oplist) \
\
TUPLE_DEF2(M_C(name, _pair), (hash, size_t, M_DEFAULT_OPLIST), (key, key_type, key_oplist), (value, value_type, value_oplist)) \
TUPLE_DEF2(M_C(name, _pair), (hash, size_t, M_BASIC_OPLIST), (key, key_type, key_oplist), (value, value_type, value_oplist)) \
\
M_D1CT_FUNC_DEF2_P5(name, key_type, key_oplist, value_type, value_oplist, \
M_C(name, _pair_ct), TUPLE_OPLIST(M_C(name, _pair), M_DEFAULT_OPLIST, key_oplist, value_oplist), 0, 1, \
M_C(name, _pair_ct), TUPLE_OPLIST(M_C(name, _pair), M_BASIC_OPLIST, key_oplist, value_oplist), 0, 1, \
dict_t, dict_it_t, it_deref_t )
@@ -248,7 +248,7 @@
It is defined as an array of singly linked list (each list
representing a bucket).
*/
#define M_D1CT_SET_DEF_P1(arg) M_D1CT_SET_DEF_P2 arg
#define M_D1CT_SET_DEF_P1(arg) M_ID( M_D1CT_SET_DEF_P2 arg )
/* Validate the key oplist before going further */
#define M_D1CT_SET_DEF_P2(name, key_type, key_oplist, dict_t, dict_it_t, it_deref_t) \
@@ -270,7 +270,7 @@
/* Define the structure of a chained dictionnary for all kind of dictionnaries
/* Define the structure of a chained dictionnary for all kind of dictionaries
* name: prefix of the container,
* key_type: type of the key
* key_oplist: oplist of the key
@@ -421,12 +421,6 @@
M_D1CT_CONTRACT(name, map); \
} \
\
static inline void M_ATTR_DEPRECATED \
M_C(name,_clean)(dict_t map) \
{ \
M_C(name, _reset)(map); \
} \
\
static inline value_type * \
M_C(name, _get)(const dict_t map, key_type const key) \
{ \
@@ -456,7 +450,7 @@
static inline void \
M_C3(m_d1ct_,name,_resize_up)(dict_t map) \
{ \
/* NOTE: Contract may not be fullfilled here */ \
/* NOTE: Contract may not be fulfilled here */ \
size_t old_size = M_C(name, _array_list_pair_size)(map->table); \
size_t new_size = old_size * 2; \
if (M_UNLIKELY (new_size <= old_size)) { \
@@ -496,7 +490,7 @@
static inline void \
M_C3(m_d1ct_,name,_resize_down)(dict_t map) \
{ \
/* NOTE: Contract may not be fullfilled here */ \
/* NOTE: Contract may not be fulfilled here */ \
size_t old_size = M_C(name, _array_list_pair_size)(map->table); \
M_ASSERT ((old_size % 2) == 0); \
size_t new_size = old_size / 2; \
@@ -581,11 +575,6 @@
} \
M_D1CT_CONTRACT(name, map); \
return &(*ref)->M_IF(isSet)(key, value); \
} \
static inline M_ATTR_DEPRECATED value_type * \
M_C(name, _get_at)(dict_t map, key_type const key) \
{ \
return M_C(name, _safe_get)(map, key); \
} \
\
static inline bool \
@@ -719,7 +708,7 @@
/* Define additional functions for dictionnary (Common for all kinds of dictionnary).
Do not used any specific fields of the dictionnary but the public API
It is not possible to define the _remove method: we could easily define it
It is not possible to define a method for IT_REMOVE: we could easily define it
by performing an _erase of the key get by the _cref method. However,
computing the next element is way harder. We could easily compute the next
element of the iteration (using _next). However with the _erase method, the
@@ -728,7 +717,18 @@
'next' element impossible as the order of the elements in the dict
has fundamentaly changed in this case. We could detect this and restart
the iteration from the first element, but it wouldn't fit the contract
of the IT\_REMOVE operator.
of the IT_REMOVE operator.
HASH method for dictionnary itself seems hard to implement:
we have to handle the case where two dictionaries are structuraly
different, but functionnaly identical (seems they have the same
members, but put in a different order).
We cannot iterator over the dictionary to compute a hash, as the
order of the items in the dictionnary is not specified: they more
or less follow the hash of the keys, but if the low bits of the
hash of the key is equal, they order may be different.
Or if the table of the dictionnary has different values (this may
be avoided).
*/
#define M_D1CT_FUNC_ADDITIONAL_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, dict_t, dict_it_t, it_deref_t) \
\
@@ -759,7 +759,7 @@
return true; \
/* Otherwise this is the slow path : \
both dictionary may not have arrays with the same size, but \
still the dictionnaries shall be equal as they contain the same \
still the dictionaries shall be equal as they contain the same \
items. */ \
dict_it_t it; \
for(M_C(name, _it)(it, dict1) ; \
@@ -778,27 +778,27 @@
\
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \
static inline void \
M_C(name, _get_str)(string_t str, const dict_t dict, const bool append) \
M_C(name, _get_str)(m_string_t str, const dict_t dict, const bool append) \
{ \
(append ? string_cat_str : string_set_str) (str, "{"); \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "{"); \
dict_it_t it; \
bool print_comma = false; \
for (M_C(name, _it)(it, dict) ; \
!M_C(name, _end_p)(it); \
M_C(name, _next)(it)){ \
if (print_comma) \
string_push_back (str, ','); \
m_string_push_back (str, ','); \
const it_deref_t *item = M_C(name, _cref)(it); \
M_IF(isSet)( \
M_CALL_GET_STR(key_oplist, str, *item, true); \
, \
M_CALL_GET_STR(key_oplist, str, item->key, true); \
string_push_back (str, ':'); \
m_string_push_back (str, ':'); \
M_CALL_GET_STR(value_oplist, str, item->value, true); \
) \
print_comma = true; \
} \
string_push_back (str, '}'); \
m_string_push_back (str, '}'); \
} \
, /* no GET_STR */ ) \
\
@@ -1035,18 +1035,7 @@
} \
, /* NO UPDATE */) ) \
\
/* HASH method for dictionnary itself seems hard to implement: \
we have to handle the case where two dictionnaries are structuraly \
different, but functionnaly identical (seems they have the same \
members, but put in a different order). \
We cannot iterator over the dictionary to compute a hash, as the \
order of the items in the dictionnary is not specified: they more \
or less follow the hash of the keys, but if the low bits of the \
hash of the key is equal, they order may be different. \
Or if the table of the dictionnary has different values (this may \
be avoided). */
M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF(isSet, name, dict_t, key_oplist, value_oplist)
/* Deferred evaluation for the definition,
so that all arguments are evaluated before further expansion */
@@ -1226,7 +1215,7 @@ enum m_d1ct_oa_element_e {
M_ASSERT( (dict)->upper_limit <= (dict)->mask+1); \
} while (0)
#define M_D1CT_OA_DEF_P1(args) M_D1CT_OA_DEF_P2 args
#define M_D1CT_OA_DEF_P1(args) M_ID( M_D1CT_OA_DEF_P2 args )
/* Validate the key oplist before going further */
#define M_D1CT_OA_DEF_P2(name, key_type, key_oplist, value_type, value_oplist, dict_t, dict_it_t, it_deref_t) \
@@ -1245,7 +1234,7 @@ enum m_d1ct_oa_element_e {
M_D1CT_OA_LOWER_BOUND, M_D1CT_OA_UPPER_BOUND, \
dict_t, dict_it_t, it_deref_t)
#define M_D1CT_OASET_DEF_P1(args) M_D1CT_OASET_DEF_P2 args
#define M_D1CT_OASET_DEF_P1(args) M_ID( M_D1CT_OASET_DEF_P2 args )
/* Validate the value oplist before going further */
#define M_D1CT_OASET_DEF_P2(name, key_type, key_oplist, dict_t, dict_it_t, it_deref_t) \
@@ -1339,7 +1328,7 @@ enum m_d1ct_oa_element_e {
M_D1CT_OA_CONTRACT(dict); \
for(size_t i = 0; i <= dict->mask; i++) { \
if (!M_CALL_OOR_EQUAL(key_oplist, dict->data[i].key, M_D1CT_OA_EMPTY) \
& !M_CALL_OOR_EQUAL(key_oplist, dict->data[i].key, M_D1CT_OA_DELETED)) { \
&& !M_CALL_OOR_EQUAL(key_oplist, dict->data[i].key, M_D1CT_OA_DELETED)) { \
M_CALL_CLEAR(key_oplist, dict->data[i].key); \
M_CALL_CLEAR(value_oplist, dict->data[i].value); \
} \
@@ -1372,6 +1361,7 @@ enum m_d1ct_oa_element_e {
size_t s = 1; \
do { \
p = (p + M_D1CT_OA_PROBING(s)) & mask; \
/* data[p].key may be OA_DELETED or OA_EMPTY */ \
if (M_CALL_EQUAL(key_oplist, data[p].key, key)) \
return &data[p].M_IF(isSet)(key, value); \
M_ASSERT (s <= dict->mask); \
@@ -1435,10 +1425,12 @@ enum m_d1ct_oa_element_e {
const size_t mask = (newSize -1); \
\
for(size_t i = 0 ; i < oldSize; i++) { \
if (!M_CALL_OOR_EQUAL(key_oplist, data[i].key, M_D1CT_OA_DELETED) & !M_CALL_OOR_EQUAL(key_oplist, data[i].key, M_D1CT_OA_EMPTY)) { \
if (!M_CALL_OOR_EQUAL(key_oplist, data[i].key, M_D1CT_OA_DELETED) \
&& !M_CALL_OOR_EQUAL(key_oplist, data[i].key, M_D1CT_OA_EMPTY)) { \
size_t p = M_CALL_HASH(key_oplist, data[i].key) & mask; \
if (p != i) { \
if (M_LIKELY (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) | M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED))) { \
if (M_LIKELY (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) \
|| M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED))) { \
M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \
M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \
} else { \
@@ -1512,7 +1504,10 @@ enum m_d1ct_oa_element_e {
return; \
} \
M_ASSERT (s <= dict->mask); \
if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED) & (delPos == (size_t)-1)) delPos = p; \
if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED) \
&& (delPos == (size_t)-1)) { \
delPos = p; \
} \
} while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) ); \
if (delPos != SIZE_MAX) { \
p = delPos; \
@@ -1563,7 +1558,10 @@ enum m_d1ct_oa_element_e {
return &data[p].M_IF(isSet)(key, value); \
} \
M_ASSERT (s <= dict->mask); \
if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED) & (delPos == (size_t)-1)) delPos = p; \
if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED) \
&& (delPos == (size_t)-1)) { \
delPos = p; \
} \
} while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) ); \
if (delPos != SIZE_MAX) { \
p = delPos; \
@@ -1619,7 +1617,8 @@ enum m_d1ct_oa_element_e {
} \
size_t p = M_CALL_HASH(key_oplist, data[i].key) & mask; \
if (p != i) { \
if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) || M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED)) { \
if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) \
|| M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED)) { \
M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \
M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \
} else { \
@@ -1833,7 +1832,7 @@ enum m_d1ct_oa_element_e {
size_t i = 0; \
while (i <= d->mask \
&& (M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, M_D1CT_OA_EMPTY) \
|| M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, M_D1CT_OA_DELETED))) { \
|| M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, M_D1CT_OA_DELETED))) { \
i++; \
} \
it->index = i; \
@@ -1858,7 +1857,7 @@ enum m_d1ct_oa_element_e {
size_t i = d->mask; \
while (i <= d->mask \
&& (M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, M_D1CT_OA_EMPTY) \
|| M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, M_D1CT_OA_DELETED))) { \
|| M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, M_D1CT_OA_DELETED))) { \
i--; \
} \
it->index = i; \
@@ -1970,5 +1969,19 @@ enum m_d1ct_oa_element_e {
\
M_D1CT_FUNC_ADDITIONAL_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, dict_t, dict_it_t, it_deref_t)
#if M_USE_SMALL_NAME
#define DICT_DEF2 M_DICT_DEF2
#define DICT_DEF2_AS M_DICT_DEF2_AS
#define DICT_STOREHASH_DEF2 M_DICT_STOREHASH_DEF2
#define DICT_STOREHASH_DEF2_AS M_DICT_STOREHASH_DEF2_AS
#define DICT_OA_DEF2 M_DICT_OA_DEF2
#define DICT_OA_DEF2_AS M_DICT_OA_DEF2_AS
#define DICT_SET_DEF M_DICT_SET_DEF
#define DICT_SET_DEF_AS M_DICT_SET_DEF_AS
#define DICT_OASET_DEF M_DICT_OASET_DEF
#define DICT_OASET_DEF_AS M_DICT_OASET_DEF_AS
#define DICT_OPLIST M_DICT_OPLIST
#define DICT_SET_OPLIST M_DICT_SET_OPLIST
#endif
#endif
+20 -11
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Function Object module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,8 +32,8 @@
* USAGE:
* FUNC_OBJ_ITF_DEF(name, retcode type, type of param1, type of param 2, ...)
*/
#define FUNC_OBJ_ITF_DEF(name, ...) \
FUNC_OBJ_ITF_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
#define M_FUNC_OBJ_ITF_DEF(name, ...) \
M_FUNC_OBJ_ITF_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
/* Define a function object interface of name 'name'
@@ -41,7 +41,7 @@
* USAGE:
* FUNC_OBJ_ITF_DEF_AS(name, name_t, retcode type, type of param1, type of param 2, ...)
*/
#define FUNC_OBJ_ITF_DEF_AS(name, name_t, ...) \
#define M_FUNC_OBJ_ITF_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_IF_NARGS_EQ1(__VA_ARGS__)(M_FUNC0BJ_ITF_NO_PARAM_DEF, M_FUNC0BJ_ITF_PARAM_DEF)(name, name_t, __VA_ARGS__) \
M_END_PROTECTED_CODE
@@ -65,8 +65,8 @@
* USAGE/EXAMPLE:
* FUNC_OBJ_INS_DEF(name, base_name, (param1, ...), { return param1 * self->member1 }, (member1, int), ...)
*/
#define FUNC_OBJ_INS_DEF(name, base_name, param_list, ...) \
FUNC_OBJ_INS_DEF_AS(name, M_C(name,_t), base_name, param_list, __VA_ARGS__)
#define M_FUNC_OBJ_INS_DEF(name, base_name, param_list, ...) \
M_FUNC_OBJ_INS_DEF_AS(name, M_C(name,_t), base_name, param_list, __VA_ARGS__)
/* Define a function object instance of name 'name' based on the interface 'base_name'
@@ -76,7 +76,7 @@
* USAGE/EXAMPLE:
* FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, (param1, ...), { return param1 * self->member1 }, (member1, int), ...)
*/
#define FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, param_list, ...) \
#define M_FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, param_list, ...) \
M_BEGIN_PROTECTED_CODE \
M_IF_NARGS_EQ1(__VA_ARGS__)(M_FUNC0BJ_INS_NO_ATTR_DEF, M_FUNC0BJ_INS_ATTR_DEF)(name, name_t, base_name, param_list, __VA_ARGS__) \
M_END_PROTECTED_CODE
@@ -86,7 +86,7 @@
* USAGE:
* FUNC_OBJ_INS_OPLIST(name, oplist of the attr1, ...)
*/
#define FUNC_OBJ_INS_OPLIST(...) \
#define M_FUNC_OBJ_INS_OPLIST(...) \
M_IF_NARGS_EQ1(__VA_ARGS__)(M_FUNC0BJ_INS_NO_ATTR_OPLIST, M_FUNC0BJ_INS_ATTR_OPLIST_P1)( __VA_ARGS__)
@@ -98,7 +98,7 @@
/* To be used by M_IF_FUNCOBJ macro defined in m-core.
NOTE: It is reversed (0 instead of 1) so that it can be used in M_IF reliabely.
*/
#define M_FUNCOBJ_IS_NOT_DEFINED 0
#define M_FUNC0BJ_IS_NOT_DEFINED 0
/* Design Constraints:
* callback SHALL be the first member of the structures in all the definitions.
@@ -266,7 +266,7 @@
M_MAP_C(M_FUNC0BJ_INJECT_OPLIST_A, __VA_ARGS__)
/* Transform (x, type) into (x, type, oplist) if there is global registered oplist
or (x, type, M_DEFAULT_OPLIST) if there is no global one,
or (x, type, M_BASIC_OPLIST) if there is no global one,
or keep (x, type, oplist) if oplist was already present */
#define M_FUNC0BJ_INJECT_OPLIST_A( duo_or_trio ) \
M_FUNC0BJ_INJECT_OPLIST_B duo_or_trio
@@ -310,7 +310,9 @@
) \
) \
{ \
struct M_C(name, _s) *self = (struct M_C(name, _s) *)(void*)_self; \
/* Let's go through an uintptr_t to avoid [broken] aliasing detection by compiler */ \
uintptr_t __self = (uintptr_t) _self; \
struct M_C(name, _s) *self = (struct M_C(name, _s) *)(void*)__self; \
(void) self; /* maybe unused */ \
callback_core; \
} \
@@ -395,5 +397,12 @@
#define M_FUNC0BJ_CONTROL_OPLIST(name, a) \
M_CHECK_COMPATIBLE_OPLIST(name, M_RET_ARG1 a, M_RET_ARG2 a, M_RET_ARG3 a)
#if M_USE_SMALL_NAME
#define FUNC_OBJ_ITF_DEF M_FUNC_OBJ_ITF_DEF
#define FUNC_OBJ_ITF_DEF_AS M_FUNC_OBJ_ITF_DEF_AS
#define FUNC_OBJ_INS_DEF M_FUNC_OBJ_INS_DEF
#define FUNC_OBJ_INS_DEF_AS M_FUNC_OBJ_INS_DEF_AS
#define FUNC_OBJ_INS_OPLIST M_FUNC_OBJ_INS_OPLIST
#endif
#endif
+32 -34
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Integer Generator (GENINT) module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -45,42 +45,40 @@ M_BEGIN_PROTECTED_CODE
enough.
*/
// TO DO: We may want a specialization with constant N value.
// Define the limb size used by genint
typedef unsigned long long genint_limb_ct;
typedef unsigned long long m_genint_limb_ct;
/* Define a generator of unique integer (Lock Free) */
typedef struct genint_s {
unsigned int n; // size of the container
unsigned int max; // number of allocated limb - 1
genint_limb_ct mask0; // mask of the last limb (constant)
genint_limb_ct mask_master; // mask of the master limb that controls others (constant)
atomic_ullong master; // master bitfield (which informs if a limb is full or not)
atomic_ullong *data; // the bitfield which informs if an integer is used or not
} genint_t[1];
typedef struct m_genint_s {
unsigned int n; // size of the container
unsigned int max; // number of allocated limb - 1
m_genint_limb_ct mask0; // mask of the last limb (constant)
m_genint_limb_ct mask_master; // mask of the master limb that controls others (constant)
atomic_ullong master; // master bitfield (which informs if a limb is full or not)
atomic_ullong *data; // the bitfield which informs if an integer is used or not
} m_genint_t[1];
// Define the max absolute supported value. It should be 2048 on most implementations.
#define GENINT_MAX_ALLOC (M_GEN1NT_LIMBSIZE * (M_GEN1NT_LIMBSIZE - M_GEN1NT_ABA_CPT))
#define M_GENINT_MAX_ALLOC (M_GEN1NT_LIMBSIZE * (M_GEN1NT_LIMBSIZE - M_GEN1NT_ABA_CPT))
// Define the size of a limb in bits.
#define M_GEN1NT_LIMBSIZE ((unsigned)(sizeof(genint_limb_ct) * CHAR_BIT))
#define M_GEN1NT_LIMBSIZE ((unsigned)(sizeof(m_genint_limb_ct) * CHAR_BIT))
// Define the contract of a genint
#define M_GEN1NT_CONTRACT(s) do { \
M_ASSERT (s != NULL); \
M_ASSERT (s->n > 0 && s->n <= GENINT_MAX_ALLOC); \
M_ASSERT (s->n > 0 && s->n <= M_GENINT_MAX_ALLOC); \
M_ASSERT ((s->max+1) * M_GEN1NT_LIMBSIZE >= s->n); \
M_ASSERT (s->data != NULL); \
} while (0)
// Define the limb one
#define M_GEN1NT_ONE ((genint_limb_ct)1)
#define M_GEN1NT_ONE ((m_genint_limb_ct)1)
#define M_GEN1NT_FULL_MASK ULLONG_MAX
// Value returned in case of error (not integer available).
#define GENINT_ERROR (UINT_MAX)
#define M_GENINT_ERROR (UINT_MAX)
/* 32 bits of the master mask are kept for handling the ABA problem.
* NOTE: May be too much. 16 bits should be more than enough. TBC
@@ -106,9 +104,9 @@ typedef struct genint_s {
* for all threads.
*/
static inline void
genint_init(genint_t s, unsigned int n)
m_genint_init(m_genint_t s, unsigned int n)
{
M_ASSERT (s != NULL && n > 0 && n <= GENINT_MAX_ALLOC);
M_ASSERT (s != NULL && n > 0 && n <= M_GENINT_MAX_ALLOC);
const size_t alloc = (n + M_GEN1NT_LIMBSIZE - 1) / M_GEN1NT_LIMBSIZE;
const unsigned int index = n % M_GEN1NT_LIMBSIZE;
atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, alloc);
@@ -121,15 +119,15 @@ genint_init(genint_t s, unsigned int n)
s->max = (unsigned int) (alloc-1);
s->mask0 = (index == 0) ? M_GEN1NT_FULL_MASK : ~((M_GEN1NT_ONE<<(M_GEN1NT_LIMBSIZE-index))-1);
s->mask_master = (((M_GEN1NT_ONE << alloc) - 1) << (M_GEN1NT_LIMBSIZE-alloc)) >> M_GEN1NT_ABA_CPT;
atomic_init (&s->master, (genint_limb_ct)0);
atomic_init (&s->master, (m_genint_limb_ct)0);
for(unsigned int i = 0; i < alloc; i++)
atomic_init(&s->data[i], (genint_limb_ct)0);
atomic_init(&s->data[i], (m_genint_limb_ct)0);
M_GEN1NT_CONTRACT(s);
}
/* Clear an integer generator (Destructor) */
static inline void
genint_clear(genint_t s)
m_genint_clear(m_genint_t s)
{
M_GEN1NT_CONTRACT(s);
M_MEMORY_FREE(s->data);
@@ -138,7 +136,7 @@ genint_clear(genint_t s)
/* Return the maximum integer that the generator will provide */
static inline size_t
genint_size(genint_t s)
m_genint_size(m_genint_t s)
{
M_GEN1NT_CONTRACT(s);
return s->n;
@@ -147,22 +145,22 @@ genint_size(genint_t s)
/* Get an unique integer from the integer generator.
* NOTE: For a typical case, the amortized cost is one CAS per pop. */
static inline unsigned int
genint_pop(genint_t s)
m_genint_pop(m_genint_t s)
{
M_GEN1NT_CONTRACT(s);
// First read master to see which limb is not full.
genint_limb_ct master = atomic_load(&s->master);
m_genint_limb_ct master = atomic_load(&s->master);
// While master is not full
while ((master >> M_GEN1NT_ABA_CPT) != s->mask_master) {
// Let's get the index i of the first not full limb according to master.
unsigned int i = m_core_clz64(~master);
M_ASSERT (i < M_GEN1NT_LIMBSIZE);
// Let's compute the mask of this limb representing the limb as being full
genint_limb_ct mask = s->mask0;
m_genint_limb_ct mask = s->mask0;
mask = (i == s->max) ? mask : M_GEN1NT_FULL_MASK;
unsigned int bit;
// Let's load this limb,
genint_limb_ct next, org = atomic_load(&s->data[i]);
m_genint_limb_ct next, org = atomic_load(&s->data[i]);
do {
// If it is now full, we have been preempted by another.
if (M_UNLIKELY (org == mask))
@@ -181,7 +179,7 @@ genint_pop(genint_t s)
// If the limb is now full, try to update master
if (M_UNLIKELY(next == mask)) {
while (true) {
genint_limb_ct newMaster;
m_genint_limb_ct newMaster;
if (next == mask) {
newMaster = M_GEN1NT_MASTER_SET(master, i);
} else {
@@ -201,21 +199,21 @@ genint_pop(genint_t s)
master = atomic_load(&s->master);
}
M_GEN1NT_CONTRACT(s);
return GENINT_ERROR; // No more resource available
return M_GENINT_ERROR; // No more resource available
}
/* Restore a used integer in the integer generator.
* NOTE: For a typical case, the amortized cost is one CAS per pop */
static inline void
genint_push(genint_t s, unsigned int n)
m_genint_push(m_genint_t s, unsigned int n)
{
M_GEN1NT_CONTRACT(s);
M_ASSERT (n < s->n);
const unsigned int i = n / M_GEN1NT_LIMBSIZE;
const unsigned int bit = M_GEN1NT_LIMBSIZE - 1 - (n % M_GEN1NT_LIMBSIZE);
genint_limb_ct master = atomic_load(&s->master);
m_genint_limb_ct master = atomic_load(&s->master);
// Load the limb
genint_limb_ct next, org = atomic_load(&s->data[i]);
m_genint_limb_ct next, org = atomic_load(&s->data[i]);
do {
M_ASSERT ((org & (M_GEN1NT_ONE << bit)) != 0);
// Reset it
@@ -223,13 +221,13 @@ genint_push(genint_t s, unsigned int n)
// Try to unreserve it.
} while (!atomic_compare_exchange_weak (&s->data[i], &org, next));
// if the limb was marked as full by master
genint_limb_ct mask = s->mask0;
m_genint_limb_ct mask = s->mask0;
mask = (i == s->max) ? mask : M_GEN1NT_FULL_MASK;
if (M_UNLIKELY (next != mask)) {
// Let's compute the mask of this limb representing the limb as being full
// Let's try to update master to say that this limb is not full
while (true) {
genint_limb_ct newMaster;
m_genint_limb_ct newMaster;
if (next == mask) {
newMaster = M_GEN1NT_MASTER_SET(master, i);
} else {
+49 -48
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Intrusive List module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -38,16 +38,16 @@
...
} tmp_str_t;
*/
#define ILIST_INTERFACE(name, type) \
struct m_ilist_head_s name
#define M_ILIST_INTERFACE(name, type) \
struct m_il1st_head_s name
/* Define a doubly-linked intrusive list of a given type.
The type needs to have ILIST_INTERFACE().
USAGE:
ILIST_DEF(name, type [, oplist_of_the_type]) */
#define ILIST_DEF(name, ...) \
ILIST_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
#define M_ILIST_DEF(name, ...) \
M_ILIST_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
/* Define a doubly-linked intrusive list of a given type
@@ -55,7 +55,7 @@
The type needs to have ILIST_INTERFACE().
USAGE:
ILIST_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
#define ILIST_DEF_AS(name, name_t, it_t, ...) \
#define M_ILIST_DEF_AS(name, name_t, it_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_IL1ST_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
@@ -66,19 +66,19 @@
/* Define the oplist of a doubly-linked instrusive list of type.
USAGE:
ILIST_OPLIST(name [, oplist_of_the_type]) */
#define ILIST_OPLIST(...) \
#define M_ILIST_OPLIST(...) \
M_IL1ST_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
((__VA_ARGS__, M_BASIC_OPLIST), \
(__VA_ARGS__ )))
/********************************** INTERNAL ************************************/
/* Define the basic structure to be added in all objects. */
typedef struct m_ilist_head_s {
struct m_ilist_head_s *next;
struct m_ilist_head_s *prev;
} m_ilist_head_ct;
typedef struct m_il1st_head_s {
struct m_il1st_head_s *next;
struct m_il1st_head_s *prev;
} m_il1st_head_ct;
/* Indirection call to allow expanding all arguments */
#define M_IL1ST_OPLIST_P1(arg) M_IL1ST_OPLIST_P2 arg
@@ -140,8 +140,8 @@ typedef struct m_ilist_head_s {
M_ASSERT((node)->prev->next == node); \
} while (0)
/* Indirection call to allow expanding all arguments (TBC) */
#define M_IL1ST_DEF_P1(arg) M_IL1ST_DEF_P2 arg
/* Indirection call to allow expanding all arguments */
#define M_IL1ST_DEF_P1(arg) M_ID( M_IL1ST_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_IL1ST_DEF_P2(name, type, oplist, list_t, it_t) \
@@ -164,7 +164,7 @@ typedef struct m_ilist_head_s {
/* Define the list as a structure containing pointers \
* to the front & back nodes */ \
typedef struct M_C(name, _s) { \
struct m_ilist_head_s name; \
struct m_il1st_head_s name; \
} list_t[1]; \
\
/* Define internal types pointers to such a list */ \
@@ -173,10 +173,10 @@ typedef struct m_ilist_head_s {
\
/* Define iterator of such a list */ \
typedef struct M_C(name, _it_s) { \
struct m_ilist_head_s *head; \
struct m_ilist_head_s *previous; \
struct m_ilist_head_s *current; \
struct m_ilist_head_s *next; \
struct m_il1st_head_s *head; \
struct m_il1st_head_s *previous; \
struct m_il1st_head_s *current; \
struct m_il1st_head_s *next; \
} it_t[1]; \
\
/* Define types used by oplist */ \
@@ -199,11 +199,11 @@ typedef struct m_ilist_head_s {
M_C(name, _reset)(list_t list) \
{ \
M_IL1ST_CONTRACT(name, list); \
for(struct m_ilist_head_s *it = list->name.next, *next ; \
for(struct m_il1st_head_s *it = list->name.next, *next ; \
it != &list->name; it = next) { \
/* Cannot check node contract as previous node may be deleted */ \
type *obj = M_TYPE_FROM_FIELD(type, it, \
struct m_ilist_head_s, name); \
struct m_il1st_head_s, name); \
/* Read next now before the object is destroyed */ \
next = it->next; \
M_ASSERT (next != NULL); \
@@ -217,12 +217,6 @@ typedef struct m_ilist_head_s {
M_IL1ST_CONTRACT(name, list); \
} \
\
static inline void M_ATTR_DEPRECATED \
M_C(name, _clean)(list_t list) \
{ \
M_C(name,_reset)(list); \
} \
\
static inline void \
M_C(name, _clear)(list_t list) \
{ \
@@ -271,7 +265,7 @@ typedef struct m_ilist_head_s {
M_IL1ST_CONTRACT(name, list); \
size_t s = 0; \
/* Scan the full list to count the number of elements */ \
for(const struct m_ilist_head_s *it = list->name.next ; \
for(const struct m_il1st_head_s *it = list->name.next ; \
it != &list->name; it = it->next) { \
M_IL1ST_NODE_CONTRACT(it); \
s++; \
@@ -284,7 +278,7 @@ typedef struct m_ilist_head_s {
{ \
M_IL1ST_CONTRACT(name, list); \
M_ASSERT (obj != NULL); \
struct m_ilist_head_s *prev = list->name.prev; \
struct m_il1st_head_s *prev = list->name.prev; \
list->name.prev = &obj->name; \
obj->name.prev = prev; \
obj->name.next = &list->name; \
@@ -297,7 +291,7 @@ typedef struct m_ilist_head_s {
{ \
M_IL1ST_CONTRACT(name, list); \
M_ASSERT (obj != NULL); \
struct m_ilist_head_s *next = list->name.next; \
struct m_il1st_head_s *next = list->name.next; \
list->name.next = &obj->name; \
obj->name.next = next; \
obj->name.prev = &list->name; \
@@ -311,7 +305,7 @@ typedef struct m_ilist_head_s {
M_ASSERT (obj_pos != NULL && obj != NULL); \
/* We don't have the list, so we have no contract at list level */ \
M_IL1ST_NODE_CONTRACT(&obj_pos->name); \
struct m_ilist_head_s *next = obj_pos->name.next; \
struct m_il1st_head_s *next = obj_pos->name.next; \
obj_pos->name.next = &obj->name; \
obj->name.next = next; \
obj->name.prev = &obj_pos->name; \
@@ -333,8 +327,8 @@ typedef struct m_ilist_head_s {
M_ASSERT (obj != NULL); \
/* We don't have the list, so we have no contract at list level */ \
M_IL1ST_NODE_CONTRACT(&obj->name); \
struct m_ilist_head_s *next = obj->name.next; \
struct m_ilist_head_s *prev = obj->name.prev; \
struct m_il1st_head_s *next = obj->name.next; \
struct m_il1st_head_s *prev = obj->name.prev; \
next->prev = prev; \
prev->next = next; \
/* Note: not really needed, but safer */ \
@@ -348,7 +342,7 @@ typedef struct m_ilist_head_s {
M_IL1ST_CONTRACT(name, list); \
M_ASSERT(!M_C(name, _empty_p)(list)); \
return M_TYPE_FROM_FIELD(type, list->name.prev, \
struct m_ilist_head_s, name); \
struct m_il1st_head_s, name); \
} \
\
static inline type * \
@@ -357,7 +351,7 @@ typedef struct m_ilist_head_s {
M_IL1ST_CONTRACT(name, list); \
M_ASSERT(!M_C(name, _empty_p)(list)); \
return M_TYPE_FROM_FIELD(type, list->name.next, \
struct m_ilist_head_s, name); \
struct m_il1st_head_s, name); \
} \
\
static inline type * \
@@ -368,7 +362,7 @@ typedef struct m_ilist_head_s {
M_IL1ST_NODE_CONTRACT(&obj->name); \
return obj->name.next == &list->name ? NULL : \
M_TYPE_FROM_FIELD(type, obj->name.next, \
struct m_ilist_head_s, name); \
struct m_il1st_head_s, name); \
} \
\
static inline type * \
@@ -379,7 +373,7 @@ typedef struct m_ilist_head_s {
M_IL1ST_NODE_CONTRACT(&obj->name); \
return obj->name.prev == &list->name ? NULL : \
M_TYPE_FROM_FIELD(type, obj->name.prev, \
struct m_ilist_head_s, name); \
struct m_il1st_head_s, name); \
} \
\
static inline void \
@@ -492,7 +486,7 @@ typedef struct m_ilist_head_s {
M_ASSERT (it->current->prev == it->previous); \
M_ASSERT (!M_C(name, _end_p)(it)); \
return M_TYPE_FROM_FIELD(type, it->current, \
struct m_ilist_head_s, name); \
struct m_il1st_head_s, name); \
} \
\
static inline type const * \
@@ -509,14 +503,14 @@ typedef struct m_ilist_head_s {
M_IL1ST_NODE_CONTRACT(it->current); \
(void)list; /* list param is not used */ \
type *obj = M_TYPE_FROM_FIELD(type, it->current, \
struct m_ilist_head_s, name); \
struct m_il1st_head_s, name); \
M_C(name, _unlink)(obj); \
M_CALL_CLEAR(oplist, obj); \
M_IF_METHOD(DEL, oplist)(M_CALL_DEL(oplist, obj), (void) 0); \
M_C(name, _next)(it); \
} \
\
M_IF_METHOD(NEW, oplist)( \
M_IF_METHOD2(NEW, INIT_SET, oplist)( \
static inline void \
M_C(name, _insert)(list_t list, it_t it, type x) \
{ \
@@ -534,7 +528,7 @@ typedef struct m_ilist_head_s {
(void) list; \
M_IL1ST_CONTRACT(name, list); \
} \
, /* NEW not defined */) \
, /* NEW & INIT_SET not defined */) \
\
static inline type * \
M_C(name, _pop_back)(list_t list) \
@@ -563,8 +557,8 @@ typedef struct m_ilist_head_s {
{ \
M_IL1ST_CONTRACT(name, list1); \
M_IL1ST_CONTRACT(name, list2); \
struct m_ilist_head_s *midle1 = list1->name.prev; \
struct m_ilist_head_s *midle2 = list2->name.next; \
struct m_il1st_head_s *midle1 = list1->name.prev; \
struct m_il1st_head_s *midle2 = list2->name.next; \
midle1->next = midle2; \
midle2->prev = midle1; \
list1->name.prev = list2->name.prev; \
@@ -602,11 +596,11 @@ typedef struct m_ilist_head_s {
/* npos may be end */ \
(void) olist, (void) nlist; \
type *obj = M_C(name, _ref)(opos); \
struct m_ilist_head_s *ref = npos->current; \
struct m_il1st_head_s *ref = npos->current; \
/* Remove object */ \
M_C(name, _unlink)(obj); \
/* Push 'obj' after 'ref' */ \
struct m_ilist_head_s *next = ref->next; \
struct m_il1st_head_s *next = ref->next; \
ref->next = &obj->name; \
obj->name.next = next; \
obj->name.prev = ref; \
@@ -626,8 +620,8 @@ typedef struct m_ilist_head_s {
{ \
M_IL1ST_CONTRACT(name, d); \
M_IL1ST_CONTRACT(name, e); \
struct m_ilist_head_s *d_item = d->name.next; \
struct m_ilist_head_s *e_item = e->name.next; \
struct m_il1st_head_s *d_item = d->name.next; \
struct m_il1st_head_s *e_item = e->name.next; \
/* it is more complicated than other swap functions since \
we need to detect "cyclic" loop */ \
d->name.next = e_item == &e->name ? &d->name : e_item; \
@@ -648,7 +642,7 @@ typedef struct m_ilist_head_s {
M_C(name, _reverse)(list_t list) \
{ \
M_IL1ST_CONTRACT(name, list); \
struct m_ilist_head_s *next, *it; \
struct m_il1st_head_s *next, *it; \
for(it = list->name.next ; it != &list->name; it = next) { \
next = it->next; \
it->next = it->prev; \
@@ -664,4 +658,11 @@ typedef struct m_ilist_head_s {
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
#if M_USE_SMALL_NAME
#define ILIST_INTERFACE M_ILIST_INTERFACE
#define ILIST_DEF M_ILIST_DEF
#define ILIST_DEF_AS M_ILIST_DEF_AS
#define ILIST_OPLIST M_ILIST_OPLIST
#endif
#endif
+19 -16
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - INTRUSIVE SHARED PTR Module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,9 +32,9 @@ M_BEGIN_PROTECTED_CODE
/* Define the oplist of a intrusive shared pointer.
USAGE: ISHARED_OPLIST(name [, oplist_of_the_type]) */
#define ISHARED_PTR_OPLIST(...) \
#define M_ISHARED_PTR_OPLIST(...) \
M_ISHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
((__VA_ARGS__, M_BASIC_OPLIST), \
(__VA_ARGS__ )))
@@ -42,29 +42,29 @@ M_BEGIN_PROTECTED_CODE
name: name of the intrusive shared pointer.
type: name of the type of the structure (aka. struct test_s) - not used currently.
NOTE: There can be only one interface of this kind in a type! */
#define ISHARED_PTR_INTERFACE(name, type) \
#define M_ISHARED_PTR_INTERFACE(name, type) \
atomic_int M_C(name, _cpt)
/* Value of the interface field for static intialization (Uses C99 designated element). */
#define ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
#define M_ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
.M_C(name, _cpt) = ATOMIC_VAR_INIT(0)
/* Value of the interface field for static intialization (Uses C89 designated element). */
#define ISHARED_PTR_STATIC_INIT(name, type) \
#define M_ISHARED_PTR_STATIC_INIT(name, type) \
ATOMIC_VAR_INIT(0)
/* Define the intrusive shared pointer type and its static inline functions.
USAGE: ISHARED_PTR_DEF(name, type, [, oplist]) */
#define ISHARED_PTR_DEF(name, ...) \
ISHARED_PTR_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
#define M_ISHARED_PTR_DEF(name, ...) \
M_ISHARED_PTR_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
/* Define the intrusive shared pointer type and its static inline functions
as the name name_t
USAGE: ISHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
#define ISHARED_PTR_DEF_AS(name, name_t, ...) \
#define M_ISHARED_PTR_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_ISHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
@@ -102,7 +102,7 @@ M_BEGIN_PROTECTED_CODE
)
// Deferred evaluatioin
#define M_ISHAR3D_PTR_DEF_P1(arg) M_ISHAR3D_PTR_DEF_P2 arg
#define M_ISHAR3D_PTR_DEF_P1(arg) M_ID( M_ISHAR3D_PTR_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_ISHAR3D_PTR_DEF_P2(name, type, oplist, shared_t) \
@@ -219,12 +219,6 @@ M_BEGIN_PROTECTED_CODE
*shared = NULL; \
} \
\
static inline void M_ATTR_DEPRECATED \
M_C(name, _clean)(shared_t *shared) \
{ \
M_C(name, _reset)(shared); \
} \
\
static inline void \
M_C(name, _set)(shared_t *ptr, shared_t shared) \
{ \
@@ -238,4 +232,13 @@ M_BEGIN_PROTECTED_CODE
M_END_PROTECTED_CODE
#if M_USE_SMALL_NAME
#define ISHARED_PTR_OPLIST M_ISHARED_PTR_OPLIST
#define ISHARED_PTR_INTERFACE M_ISHARED_PTR_INTERFACE
#define ISHARED_PTR_STATIC_DESIGNATED_INIT M_ISHARED_PTR_STATIC_DESIGNATED_INIT
#define ISHARED_PTR_STATIC_INIT M_ISHARED_PTR_STATIC_INIT
#define ISHARED_PTR_DEF M_ISHARED_PTR_DEF
#define ISHARED_PTR_DEF_AS M_ISHARED_PTR_DEF_AS
#endif
#endif
+71 -29
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - LIST module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -29,14 +29,14 @@
/* Define a singly linked list of a given type.
USAGE: LIST_DEF(name, type [, oplist_of_the_type]) */
#define LIST_DEF(name, ...) \
LIST_DEF_AS(name, M_C(name, _t), M_C(name, _it_t), __VA_ARGS__)
#define M_LIST_DEF(name, ...) \
M_LIST_DEF_AS(name, M_C(name, _t), M_C(name, _it_t), __VA_ARGS__)
/* Define a singly linked list of a given type
as the provided type name_t with the iterator named it_t
USAGE: LIST_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
#define LIST_DEF_AS(name, name_t, it_t, ...) \
#define M_LIST_DEF_AS(name, name_t, it_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_L1ST_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
@@ -46,14 +46,14 @@
/* Define a singly linked list of a given type allowing both push.
USAGE: LIST_DUAL_PUSH_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
#define LIST_DUAL_PUSH_DEF(name, ...) \
LIST_DUAL_PUSH_DEF_AS(name, M_C(name,_t), M_C(name, _it_t), __VA_ARGS__)
#define M_LIST_DUAL_PUSH_DEF(name, ...) \
M_LIST_DUAL_PUSH_DEF_AS(name, M_C(name,_t), M_C(name, _it_t), __VA_ARGS__)
/* Define a singly linked list of a given type allowing both push.
as the provided type name_t with the iterator named it_t
USAGE: LIST_DUAL_PUSH_DEF(name, type [, oplist_of_the_type]) */
#define LIST_DUAL_PUSH_DEF_AS(name, name_t, it_t, ...) \
#define M_LIST_DUAL_PUSH_DEF_AS(name, name_t, it_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_L1ST_DUAL_PUSH_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
@@ -63,16 +63,16 @@
/* Define the oplist of a list of the given type.
USAGE: LIST_OPLIST(name [, oplist_of_the_type]) */
#define LIST_OPLIST(...) \
#define M_LIST_OPLIST(...) \
M_L1ST_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
((__VA_ARGS__, M_BASIC_OPLIST ), \
(__VA_ARGS__ )))
/* Define an init value to init global variables of type list.
USAGE:
list_t global_variable = LIST_INIT_VALUE();
*/
#define LIST_INIT_VALUE() \
#define M_LIST_INIT_VALUE() \
{ NULL }
@@ -80,7 +80,7 @@
USAGE:
list_t global_variable = LIST_DUAL_PUSH_INIT_VALUE();
*/
#define LIST_DUAL_PUSH_INIT_VALUE() \
#define M_LIST_DUAL_PUSH_INIT_VALUE() \
{ { NULL, NULL } }
@@ -148,7 +148,7 @@
/* Deferred evaluation for the list definition,
so that all arguments are evaluated before further expansion */
#define M_L1ST_DEF_P1(arg) M_L1ST_DEF_P2 arg
#define M_L1ST_DEF_P1(arg) M_ID( M_L1ST_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_L1ST_DEF_P2(name, type, oplist, list_t, it_t) \
@@ -256,12 +256,6 @@
M_L1ST_CONTRACT(v); \
} \
\
static inline void M_ATTR_DEPRECATED \
M_C(name, _clean)(list_t v) \
{ \
M_C(name, _reset)(v); \
} \
\
static inline void \
M_C(name, _clear)(list_t v) \
{ \
@@ -672,6 +666,8 @@
} \
*list = previous; \
} \
\
M_EMPLACE_QUEUE_DEF(name, list_t, M_C(name, _emplace_back), oplist, M_L1ST_EMPLACE_DEF)
/* Internal list function definition using only iterator functions
@@ -688,11 +684,11 @@
\
M_IF_METHOD(GET_STR, oplist)( \
static inline void \
M_C(name, _get_str)(string_t str, const list_t list, \
M_C(name, _get_str)(m_string_t str, const list_t list, \
bool append) \
{ \
M_ASSERT (str != NULL && list != NULL); \
(append ? string_cat_str : string_set_str) (str, "["); \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
it_t it; \
for (M_C(name, _it)(it, list) ; \
!M_C(name, _end_p)(it); \
@@ -700,9 +696,9 @@
type const *item = M_C(name, _cref)(it); \
M_CALL_GET_STR(oplist, str, *item, true); \
if (!M_C(name, _last_p)(it)) \
string_push_back (str, M_GET_SEPARATOR oplist); \
m_string_push_back (str, M_GET_SEPARATOR oplist); \
} \
string_push_back (str, ']'); \
m_string_push_back (str, ']'); \
} \
, /* no str */ ) \
\
@@ -876,9 +872,48 @@
, /* no hash */ ) \
/* Definition of the emplace_back function for single list */
#define M_L1ST_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
static inline void \
function_name(name_t v \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
M_C(name, _subtype_ct) *data = M_C(name, _push_raw)(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
}
/* Definition of the emplace_back function for dual push list */
#define M_L1ST_EMPLACE_BACK_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
static inline void \
function_name(name_t v \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
M_C(name, _subtype_ct) *data = M_C(name, _push_back_raw)(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
}
/* Definition of the emplace_front function for dual push list */
#define M_L1ST_EMPLACE_FRONT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
static inline void \
function_name(name_t v \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
M_C(name, _subtype_ct) *data = M_C(name, _push_front_raw)(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
}
/* Deferred evaluation for the dual-push list definition,
so that all arguments are evaluated before further expansion */
#define M_L1ST_DUAL_PUSH_DEF_P1(arg) M_L1ST_DUAL_PUSH_DEF_P2 arg
#define M_L1ST_DUAL_PUSH_DEF_P1(arg) M_ID( M_L1ST_DUAL_PUSH_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_L1ST_DUAL_PUSH_DEF_P2(name, type, oplist, list_t, it_t) \
@@ -974,12 +1009,6 @@
M_L1ST_DUAL_PUSH_CONTRACT(v); \
} \
\
static inline void M_ATTR_DEPRECATED \
M_C(name, _clean)(list_t v) \
{ \
M_C(name, _reset)(v); \
} \
\
static inline void \
M_C(name, _clear)(list_t v) \
{ \
@@ -1475,5 +1504,18 @@
list->back = previous; \
M_L1ST_DUAL_PUSH_CONTRACT(list); \
} \
\
M_EMPLACE_QUEUE_DEF(name, list_t, M_C(name, _emplace_back), oplist, M_L1ST_EMPLACE_BACK_DEF) \
M_EMPLACE_QUEUE_DEF(name, list_t, M_C(name, _emplace_front), oplist, M_L1ST_EMPLACE_FRONT_DEF)
#if M_USE_SMALL_NAME
#define LIST_DEF M_LIST_DEF
#define LIST_DEF_AS M_LIST_DEF_AS
#define LIST_DUAL_PUSH_DEF M_LIST_DUAL_PUSH_DEF
#define LIST_DUAL_PUSH_DEF_AS M_LIST_DUAL_PUSH_DEF_AS
#define LIST_OPLIST M_LIST_OPLIST
#define LIST_INIT_VALUE M_LIST_INIT_VALUE
#define LIST_DUAL_PUSH_INIT_VALUE M_LIST_DUAL_PUSH_INIT_VALUE
#endif
#endif
+26 -13
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - MEMPOOL module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -27,35 +27,42 @@
#include "m-core.h"
/* Fast Fixed Size thread unsafe allocator based on memory region.
/* Fast, fixed size, thread unsafe allocator based on memory regions.
No oplist is needed.
USAGE:
MEMPOOL_DEF(memppol_uint, unsigned int)
MEMPOOL_DEF(name, type)
Example:
MEMPOOL_DEF(mempool_uint, unsigned int)
...
memppol_uint_t m;
mempool_uint_t m;
mempool_uint_init(m);
unsigned int *ptr = mempool_uint_alloc(m);
*ptr = 17;
mempool_uint_free(m, ptr);
mempool_uint_clear(m); // Give back memory to system
NOTE: Can not use m-list since it may be expanded from LIST_DEF
Technically, it uses a list of memory regions, where multiple
allocations are performed in each region. However, it
can not use m-list since it may be expanded from LIST_DEF
(recursive dependency problem).
*/
#define MEMPOOL_DEF(name, type) \
MEMPOOL_DEF_AS(name, M_C(name,_t), type)
#define M_MEMPOOL_DEF(name, type) \
M_MEMPOOL_DEF_AS(name, M_C(name,_t), type)
/* Fast Fixed Size thread unsafe allocator based on memory region.
/* Fast, fixed Size, thread unsafe allocator based on memory region.
USAGE:
MEMPOOL_DEF_AS(memppol_uint, name_t, unsigned int)
MEMPOOL_DEF_AS(name, name_t, type)
*/
#define MEMPOOL_DEF_AS(name, name_t, type) \
#define M_MEMPOOL_DEF_AS(name, name_t, type) \
M_BEGIN_PROTECTED_CODE \
M_M3MPOOL_DEF_P2(name, type, name_t ) \
M_END_PROTECTED_CODE
/* User shall be able to cutomize the size of the segment and/or
/* User shall be able to cutomize the size of the region segment and/or
the minimun number of elements.
The default is the number of elements that fits in 16KB.
The default is the number of elements that fits in 16KB, or 256
is the size of the type is too big.
*/
#ifndef M_USE_MEMPOOL_MAX_PER_SEGMENT
#define M_USE_MEMPOOL_MAX_PER_SEGMENT(type) \
@@ -169,11 +176,17 @@
M_M3MPOOL_CONTRACT(mem, type); \
} \
/* MEMPOOL contract */
/* MEMPOOL contract. We only control the current segment. */
#define M_M3MPOOL_CONTRACT(mempool, type) do { \
M_ASSERT((mempool) != NULL); \
M_ASSERT((mempool)->current_segment != NULL); \
M_ASSERT((mempool)->current_segment->count <= M_USE_MEMPOOL_MAX_PER_SEGMENT(type)); \
} while (0)
#if M_USE_SMALL_NAME
#define MEMPOOL_DEF M_MEMPOOL_DEF
#define MEMPOOL_DEF_AS M_MEMPOOL_DEF_AS
#endif
#endif
+16 -18
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Thin Mutex & Thread wrapper
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -152,14 +152,14 @@ static inline bool m_thread_sleep(unsigned long long usec)
return retval == 0;
}
// Internal type, not exported.
typedef once_flag m_once_ct[1];
// a helper structure for m_once_call
typedef once_flag m_once_t[1];
// Initial value for m_once_ct
#define M_ONCEI_INIT_VALUE { ONCE_FLAG_INIT }
// Initial value for m_once_t
#define M_ONCE_INIT_VALUE { ONCE_FLAG_INIT }
// Call the function exactly once
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
static inline void m_once_call(m_once_t o, void (*func)(void))
{
call_once(o,func);
}
@@ -315,10 +315,9 @@ static inline bool m_thread_sleep(unsigned long long usec)
}
// Internal type, not exported.
typedef INIT_ONCE m_once_ct[1];
#define M_ONCEI_INIT_VALUE { INIT_ONCE_STATIC_INIT }
static inline BOOL CALLBACK m_oncei_callback( PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext)
typedef INIT_ONCE m_once_t[1];
#define M_ONCE_INIT_VALUE { INIT_ONCE_STATIC_INIT }
static inline BOOL CALLBACK m_once_callback( PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext)
{
void (*func)(void);
(void) InitOnce;
@@ -327,9 +326,9 @@ static inline BOOL CALLBACK m_oncei_callback( PINIT_ONCE InitOnce, PVOID Paramet
(*func)();
return TRUE;
}
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
static inline void m_once_call(m_once_t o, void (*func)(void))
{
InitOnceExecuteOnce(o, m_oncei_callback, (void*)(intptr_t)func, NULL);
InitOnceExecuteOnce(o, m_once_callback, (void*)(intptr_t)func, NULL);
}
#if defined(_MSC_VER)
@@ -474,10 +473,9 @@ static inline bool m_thread_sleep(unsigned long long usec)
return retval == 0;
}
// Internal type, not exported.
typedef pthread_once_t m_once_ct[1];
#define M_ONCEI_INIT_VALUE { PTHREAD_ONCE_INIT }
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
typedef pthread_once_t m_once_t[1];
#define M_ONCE_INIT_VALUE { PTHREAD_ONCE_INIT }
static inline void m_once_call(m_once_t o, void (*func)(void))
{
pthread_once(o,func);
}
@@ -511,9 +509,9 @@ M_END_PROTECTED_CODE
static void M_C(m_mutex_init_, name)(void) { \
m_mutex_init(name); \
} \
m_once_ct M_C(m_once_, name) = M_ONCEI_INIT_VALUE
m_once_t M_C(m_once_, name) = M_ONCE_INIT_VALUE
# define M_LOCKI_BY_ONCE(name) \
(m_oncei_call(M_C(m_once_, name), M_C(m_mutex_init_, name)), \
(m_once_call(M_C(m_once_, name), M_C(m_mutex_init_, name)), \
m_mutex_lock(name), (void) 0 )
# define M_LOCK(name) \
M_LOCKI_DO(name, M_C(local_cont_, __LINE__), M_LOCKI_BY_ONCE, m_mutex_unlock)
+79 -23
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - dynamic priority queue module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,14 +32,14 @@
/* Define a prioqueue of a given type and its associated functions.
USAGE: PRIOQUEUE_DEF(name, type [, oplist_of_the_type]) */
#define PRIOQUEUE_DEF(name, ...) \
PRIOQUEUE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
#define M_PRIOQUEUE_DEF(name, ...) \
M_PRIOQUEUE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
/* Define a prioqueue of a given type and its associated functions.
as the name name_t with an iterator named it_t
USAGE: PRIOQUEUE_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
#define PRIOQUEUE_DEF_AS(name, name_t, it_t, ...) \
#define M_PRIOQUEUE_DEF_AS(name, name_t, it_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_PR1OQUEUE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
@@ -49,9 +49,9 @@
/* Define the oplist of a prioqueue of type.
USAGE: PRIOQUEUE_OPLIST(name[, oplist of the type]) */
#define PRIOQUEUE_OPLIST(...) \
#define M_PRIOQUEUE_OPLIST(...) \
M_PR1OQUEUE_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
((__VA_ARGS__, M_BASIC_OPLIST), \
(__VA_ARGS__ )))
@@ -87,23 +87,29 @@
,PUSH(M_C(name,_push)) \
,POP(M_C(name,_pop)) \
,OPLIST(oplist) \
,EMPTY_P(M_C(name, _empty_p)), \
,EMPTY_P(M_C(name, _empty_p)) \
,GET_SIZE(M_C(name, _size)) \
,IT_TYPE(M_C(name, _it_ct)), \
IT_FIRST(M_C(name,_it)), \
IT_END(M_C(name,_it_end)), \
IT_SET(M_C(name,_it_set)), \
IT_END_P(M_C(name,_end_p)), \
IT_EQUAL_P(M_C(name,_it_equal_p)), \
IT_LAST_P(M_C(name,_last_p)), \
IT_NEXT(M_C(name,_next)), \
IT_CREF(M_C(name,_cref)), \
,IT_TYPE(M_C(name, _it_ct)) \
,IT_FIRST(M_C(name,_it)) \
,IT_END(M_C(name,_it_end)) \
,IT_SET(M_C(name,_it_set)) \
,IT_END_P(M_C(name,_end_p)) \
,IT_EQUAL_P(M_C(name,_it_equal_p)) \
,IT_LAST_P(M_C(name,_last_p)) \
,IT_NEXT(M_C(name,_next)) \
,IT_CREF(M_C(name,_cref)) \
,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),) \
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),) \
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),) \
,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),) \
,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),) \
,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),) \
)
/* Deferred evaluation for the definition,
so that all arguments are evaluated before further expansion */
#define M_PR1OQUEUE_DEF_P1(arg) M_PR1OQUEUE_DEF_P2 arg
#define M_PR1OQUEUE_DEF_P1(arg) M_ID( M_PR1OQUEUE_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_PR1OQUEUE_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
@@ -191,12 +197,6 @@
M_C(name, _array_reset)(p->array); \
} \
\
static inline void M_ATTR_DEPRECATED \
M_C(name, _clean)(prioqueue_t p) \
{ \
M_C(name,_reset)(p); \
} \
\
static inline size_t \
M_C(name, _i_parent)(size_t i) \
{ \
@@ -435,8 +435,64 @@
} \
} \
, /* No EQUAL */ ) \
\
M_IF_METHOD(OUT_STR, oplist)( \
static inline void \
M_C(name, _out_str)(FILE *file, const prioqueue_t p) \
{ \
M_C(name, _array_out_str)(file, p->array); \
} \
,/* No OUT_STR */) \
\
M_IF_METHOD(IN_STR, oplist)( \
static inline bool \
M_C(name, _in_str)(prioqueue_t p, FILE *file) \
{ \
return M_C(name, _array_in_str)(p->array, file); \
} \
,/* No IN_STR */) \
\
M_IF_METHOD(GET_STR, oplist)( \
static inline void \
M_C(name, _get_str)(string_t str, const prioqueue_t p, bool append) \
{ \
M_C(name, _array_get_str)(str, p->array, append); \
} \
,/* No GET_STR */) \
\
M_IF_METHOD(PARSE_STR, oplist)( \
static inline bool \
M_C(name, _parse_str)(prioqueue_t p, const char str[], const char **endp) \
{ \
return M_C(name, _array_parse_str)(p->array, str, endp); \
} \
,/* No PARSE_STR */) \
\
M_IF_METHOD(OUT_SERIAL, oplist)( \
static inline m_serial_return_code_t \
M_C(name, _out_serial)(m_serial_write_t f, const prioqueue_t p) \
{ \
return M_C(name, _array_out_serial)(f, p->array); \
} \
,/* No OUT_SERIAL */) \
\
M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \
static inline m_serial_return_code_t \
M_C(name, _in_serial)(prioqueue_t p, m_serial_read_t f) \
{ \
return M_C(name, _array_in_serial)(p->array, f); \
} \
,/* No in_SERIAL */) \
\
M_EMPLACE_QUEUE_DEF(name, prioqueue_t, M_C(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
// TODO: set all & remove all function
#if M_USE_SMALL_NAME
#define PRIOQUEUE_DEF M_PRIOQUEUE_DEF
#define PRIOQUEUE_DEF_AS M_PRIOQUEUE_DEF_AS
#define PRIOQUEUE_OPLIST M_PRIOQUEUE_OPLIST
#endif
#endif
+30 -30
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - RED BLACK TREE module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -29,14 +29,14 @@
/* Define a Red/Black binary tree of a given type.
USAGE: RBTREE_DEF(name, type [, oplist_of_the_type]) */
#define RBTREE_DEF(name, ...) \
RBTREE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
#define M_RBTREE_DEF(name, ...) \
M_RBTREE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
/* Define a Red/Black binary tree of a given type
as the name name_t and the iterator it_t.
USAGE: RBTREE_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
#define RBTREE_DEF_AS(name, name_t, it_t, ...) \
#define M_RBTREE_DEF_AS(name, name_t, it_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_RBTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, M_C(name, _node_ct), it_t ), \
@@ -46,9 +46,9 @@
/* Define the oplist of a rbtree of type.
USAGE: RBTREE_OPLIST(name [, oplist_of_the_type]) */
#define RBTREE_OPLIST(...) \
#define M_RBTREE_OPLIST(...) \
M_RBTR33_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
((__VA_ARGS__, M_BASIC_OPLIST), \
(__VA_ARGS__ )))
@@ -74,7 +74,7 @@
#define M_RBTR33_OPLIST_P3(name, oplist) \
(INIT(M_C(name, _init)), \
INIT_SET(M_C(name, _init_set)), \
INIT_WITH(API_1(M_INIT_VAI)), \
INIT_WITH(API_1(M_INIT_EMPLACE_VAI)), \
SET(M_C(name, _set)), \
CLEAR(M_C(name, _clear)), \
INIT_MOVE(M_C(name, _init_move)), \
@@ -122,10 +122,10 @@
#define M_RBTR33_MAX_STACK (2*CHAR_BIT*sizeof (size_t))
/* Encapsulation of the color of the nodes. */
#define M_RBTR33_SET_RED(x) ((x)->color = RBTREE_RED)
#define M_RBTR33_SET_BLACK(x) ((x)->color = RBTREE_BLACK)
#define M_RBTR33_IS_RED(x) ((x)->color == RBTREE_RED)
#define M_RBTR33_IS_BLACK(x) ((x)->color == RBTREE_BLACK)
#define M_RBTR33_SET_RED(x) ((x)->color = M_RBTR33_RED)
#define M_RBTR33_SET_BLACK(x) ((x)->color = M_RBTR33_BLACK)
#define M_RBTR33_IS_RED(x) ((x)->color == M_RBTR33_RED)
#define M_RBTR33_IS_BLACK(x) ((x)->color == M_RBTR33_BLACK)
#define M_RBTR33_COPY_COLOR(x,y) ((x)->color = (y)->color)
#define M_RBTR33_GET_COLOR(x) (true ? (x)->color : (x)->color)
#define M_RBTR33_SET_COLOR(x, c) ((x)->color = (c))
@@ -134,8 +134,8 @@
// Color of a node of a Red/Black tree
typedef enum {
RBTREE_BLACK = 0, RBTREE_RED
} rbtreei_color_e;
M_RBTR33_BLACK = 0, M_RBTR33_RED
} m_rbtr33_color_e;
// General contact of a Read/Black tree
#define M_RBTR33_CONTRACT(tree) do { \
@@ -156,7 +156,7 @@ typedef enum {
/* Deferred evaluation for the rbtree definition,
so that all arguments are evaluated before further expansion */
#define M_RBTR33_DEF_P1(arg) M_RBTR33_DEF_P2 arg
#define M_RBTR33_DEF_P1(arg) M_ID( M_RBTR33_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_RBTR33_DEF_P2(name, type, oplist, tree_t, node_t, it_t) \
@@ -182,7 +182,7 @@ typedef enum {
typedef struct M_C(name, _node_s) { \
struct M_C(name, _node_s) *child[2]; \
type data; \
rbtreei_color_e color; \
m_rbtr33_color_e color; \
} node_t; \
\
/* Define the Red/Black tree */ \
@@ -294,12 +294,6 @@ typedef enum {
tree->size = 0; \
} \
\
static inline void M_ATTR_DEPRECATED \
M_C(name, _clean)(tree_t tree) \
{ \
M_C(name,_reset)(tree); \
} \
\
static inline void \
M_C(name, _clear)(tree_t tree) \
{ \
@@ -480,6 +474,7 @@ typedef enum {
{ \
M_RBTR33_CONTRACT (tree); \
M_ASSERT (it != NULL); \
(void) tree; /* parameter not used */ \
it->cpt = 0; \
} \
\
@@ -837,7 +832,7 @@ typedef enum {
unsigned int cpt_n = cpt; \
node_t *v = n; /* the replacement node */ \
node_t *u; /* the deleted node */ \
rbtreei_color_e v_color = M_RBTR33_GET_COLOR(v); \
m_rbtr33_color_e v_color = M_RBTR33_GET_COLOR(v); \
/* Classical removal of a node from a binary tree */ \
if (v->child[0] != NULL && v->child[1] != NULL) { \
/* node has 2 child. */ \
@@ -883,7 +878,7 @@ typedef enum {
} \
\
/* Rebalance from child to root */ \
if (v_color == RBTREE_BLACK \
if (v_color == M_RBTR33_BLACK \
&& M_C3(m_rbtr33_,name,_black_p)(u)) { \
/* tab[0] is NULL, tab[1] is root, u is double black */ \
node_t *p = u, *s; \
@@ -924,7 +919,7 @@ typedef enum {
/* at least one child of 's' is red */ \
/* perform rotation(s) */ \
bool childIsRight = !M_C3(m_rbtr33_,name,_black_p)(s->child[1]); \
rbtreei_color_e p_color = M_RBTR33_GET_COLOR (p); \
m_rbtr33_color_e p_color = M_RBTR33_GET_COLOR (p); \
if (childIsRight != nbChild) { \
/* left-left or right-right case */ \
p = M_C3(m_rbtr33_,name,_rotate) (p, tab[cpt-1], childIsRight); \
@@ -1020,24 +1015,24 @@ typedef enum {
, /* NO HASH METHOD */ ) \
\
M_IF_METHOD(GET_STR, oplist)( \
static inline void M_C(name, _get_str)(string_t str, \
static inline void M_C(name, _get_str)(m_string_t str, \
tree_t const t1, bool append) { \
M_RBTR33_CONTRACT(t1); \
M_ASSERT(str != NULL); \
(append ? string_cat_str : string_set_str) (str, "["); \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
/* NOTE: The print is really naive, and not really efficient */ \
bool commaToPrint = false; \
it_t it1; \
M_C(name, _it)(it1, t1); \
while (!M_C(name, _end_p)(it1)) { \
if (commaToPrint) \
string_push_back (str, M_GET_SEPARATOR oplist); \
m_string_push_back (str, M_GET_SEPARATOR oplist); \
commaToPrint = true; \
type const *ref1 = M_C(name, _cref)(it1); \
M_CALL_GET_STR(oplist, str, *ref1, true); \
M_C(name, _next)(it1); \
} \
string_push_back (str, ']'); \
m_string_push_back (str, ']'); \
} \
, /* NO GET_STR */ ) \
\
@@ -1170,9 +1165,14 @@ typedef enum {
} \
, /* no in_serial */ ) \
\
\
M_EMPLACE_QUEUE_DEF(name, tree_t, M_C(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
// TODO: specialized _sort shall do nothing, but shall check the requested order. How ?
#if M_USE_SMALL_NAME
#define RBTREE_DEF M_RBTREE_DEF
#define RBTREE_DEF_AS M_RBTREE_DEF_AS
#define RBTREE_OPLIST M_RBTREE_OPLIST
#endif
#endif
+74 -63
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Serial BIN
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,12 +32,17 @@
M_BEGIN_PROTECTED_CODE
/********************************************************************************/
/************************** FILE / WRITE / BIN *******************************/
/********************************************************************************/
/* Internal service:
* Write size_t in the stream in a compact form to reduce consumption
* (and I/O bandwidth)
*/
static inline bool
m_serial_bin_write_size(FILE *f, const size_t size)
m_ser1al_bin_write_size(FILE *f, const size_t size)
{
bool b;
if (M_LIKELY(size < 253))
@@ -84,7 +89,7 @@ m_serial_bin_write_size(FILE *f, const size_t size)
* (and I/O bandwidth)
*/
static inline bool
m_serial_bin_read_size(FILE *f, size_t *size)
m_ser1al_bin_read_size(FILE *f, size_t *size)
{
int c;
c = fgetc(f);
@@ -94,7 +99,7 @@ m_serial_bin_read_size(FILE *f, size_t *size)
return true;
}
size_t s = 0;
int l = (c = 255) ? 8 : (c == 254) ? 4 : 2;
int l = (c == 255) ? 8 : (c == 254) ? 4 : 2;
for(int i = 0; i < l; i++) {
c = fgetc(f);
if (M_UNLIKELY(c == EOF)) return false;
@@ -107,7 +112,7 @@ m_serial_bin_read_size(FILE *f, size_t *size)
/* Write the boolean 'data' into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_boolean(m_serial_write_t serial, const bool data)
m_ser1al_bin_write_boolean(m_serial_write_t serial, const bool data)
{
FILE *f = (FILE *)serial->data[0].p;
size_t n = fwrite (M_ASSIGN_CAST(const void*, &data), sizeof (bool), 1, f);
@@ -117,7 +122,7 @@ m_serial_bin_write_boolean(m_serial_write_t serial, const bool data)
/* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
m_ser1al_bin_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
{
int8_t i8;
int16_t i16;
@@ -153,7 +158,7 @@ m_serial_bin_write_integer(m_serial_write_t serial,const long long data, const s
/* Write the float 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
m_ser1al_bin_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
{
float f1;
double f2;
@@ -179,13 +184,13 @@ m_serial_bin_write_float(m_serial_write_t serial, const long double data, const
/* Write the null-terminated string 'data'into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_string(m_serial_write_t serial, const char data[], size_t length)
m_ser1al_bin_write_string(m_serial_write_t serial, const char data[], size_t length)
{
M_ASSERT_SLOW(length == strlen(data) );
FILE *f = (FILE *)serial->data[0].p;
M_ASSERT(f != NULL && data != NULL);
// Write first the number of (non null) characters
if (m_serial_bin_write_size(f, length) != true) return m_core_serial_fail();
if (m_ser1al_bin_write_size(f, length) != true) return m_core_serial_fail();
// Write the characters (excluding the final null char)
// NOTE: fwrite supports length == 0.
size_t n = fwrite (M_ASSIGN_CAST(const void*, data), 1, length, f);
@@ -199,7 +204,7 @@ m_serial_bin_write_string(m_serial_write_t serial, const char data[], size_t len
(local is an unique serialization object of the array).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
m_ser1al_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
{
FILE *f = (FILE *)serial->data[0].p;
size_t n = fwrite (M_ASSIGN_CAST(const void*, &number_of_elements), sizeof number_of_elements, 1, f);
@@ -210,7 +215,7 @@ m_serial_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial,
/* Write an array separator between elements of an array into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial)
{
FILE *f = (FILE *)serial->data[0].p;
// Need separator if we don't know the real size
@@ -226,7 +231,7 @@ m_serial_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial)
/* End the writing of an array into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial)
{
FILE *f = (FILE *)serial->data[0].p;
// Need mark if we don't know the real size
@@ -242,7 +247,7 @@ m_serial_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial)
/* Write a value separator between element of the same pair of a map into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
(void) serial;
@@ -254,7 +259,7 @@ m_serial_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
(local is an unique serialization object of the tuple).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
(void) serial;
@@ -264,7 +269,7 @@ m_serial_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
/* Start writing the field named field_name[index] of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
m_ser1al_bin_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
{
(void) local; // argument not used
(void) serial;
@@ -277,7 +282,7 @@ m_serial_bin_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, con
/* End the write of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
(void) serial;
@@ -290,7 +295,7 @@ m_serial_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
Otherwise, the field 'field_name[index]' will be filled.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
m_ser1al_bin_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
{
(void) field_name;
(void) max;
@@ -303,7 +308,7 @@ m_serial_bin_write_variant_start(m_serial_local_t local, m_serial_write_t serial
/* End Writing a variant into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_bin_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
(void) serial;
@@ -311,28 +316,28 @@ m_serial_bin_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
}
/* The exported interface. */
static const m_serial_write_interface_t m_serial_write_bin_interface = {
m_serial_bin_write_boolean,
m_serial_bin_write_integer,
m_serial_bin_write_float,
m_serial_bin_write_string,
m_serial_bin_write_array_start,
m_serial_bin_write_array_next,
m_serial_bin_write_array_end,
m_serial_bin_write_array_start,
m_serial_bin_write_map_value,
m_serial_bin_write_array_next,
m_serial_bin_write_array_end,
m_serial_bin_write_tuple_start,
m_serial_bin_write_tuple_id,
m_serial_bin_write_tuple_end,
m_serial_bin_write_variant_start,
m_serial_bin_write_variant_end
static const m_serial_write_interface_t m_ser1al_bin_write_interface = {
m_ser1al_bin_write_boolean,
m_ser1al_bin_write_integer,
m_ser1al_bin_write_float,
m_ser1al_bin_write_string,
m_ser1al_bin_write_array_start,
m_ser1al_bin_write_array_next,
m_ser1al_bin_write_array_end,
m_ser1al_bin_write_array_start,
m_ser1al_bin_write_map_value,
m_ser1al_bin_write_array_next,
m_ser1al_bin_write_array_end,
m_ser1al_bin_write_tuple_start,
m_ser1al_bin_write_tuple_id,
m_ser1al_bin_write_tuple_end,
m_ser1al_bin_write_variant_start,
m_ser1al_bin_write_variant_end
};
static inline void m_serial_bin_write_init(m_serial_write_t serial, FILE *f)
{
serial->m_interface = &m_serial_write_bin_interface;
serial->m_interface = &m_ser1al_bin_write_interface;
serial->data[0].p = M_ASSIGN_CAST(void*, f);
}
@@ -344,16 +349,22 @@ static inline void m_serial_bin_write_clear(m_serial_write_t serial)
/* Define a synonym of m_serial_read_t to the BIN serializer with its proper OPLIST */
typedef m_serial_write_t m_serial_bin_write_t;
#define M_OPL_m_serial_bin_write_t() \
(INIT_WITH(m_serial_bin_write_init), CLEAR(m_serial_bin_write_clear), \
TYPE(m_serial_bin_write_t), PROPERTIES(( LET_AS_INIT_WITH(1) )) )
/********************************************************************************/
/************************** FILE / READ / BIN *******************************/
/********************************************************************************/
/* Read from the stream 'serial' a boolean.
Set '*b' with the boolean value if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_boolean(m_serial_read_t serial, bool *b){
m_ser1al_bin_read_boolean(m_serial_read_t serial, bool *b){
FILE *f = (FILE*) serial->data[0].p;
size_t n = fread (M_ASSIGN_CAST(void*, b), sizeof (bool), 1, f);
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
@@ -363,7 +374,7 @@ m_serial_bin_read_boolean(m_serial_read_t serial, bool *b){
Set '*i' with the integer value if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
m_ser1al_bin_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
int8_t i8;
int16_t i16;
int32_t i32;
@@ -398,7 +409,7 @@ m_serial_bin_read_integer(m_serial_read_t serial, long long *i, const size_t siz
Set '*r' with the boolean value if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
m_ser1al_bin_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
float f1;
double f2;
long double f3;
@@ -423,12 +434,12 @@ m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
Set 's' with the string if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_string(m_serial_read_t serial, struct string_s *s){
m_ser1al_bin_read_string(m_serial_read_t serial, struct string_s *s){
FILE *f = (FILE*) serial->data[0].p;
M_ASSERT(f != NULL && s != NULL);
// First read the number of non null characters
size_t length;
if (m_serial_bin_read_size(f, &length) != true) return m_core_serial_fail();
if (m_ser1al_bin_read_size(f, &length) != true) return m_core_serial_fail();
// Use of internal string interface to dimension the string
char *p = m_str1ng_fit2size(s, length + 1);
m_str1ng_set_size(s, length);
@@ -448,7 +459,7 @@ m_serial_bin_read_string(m_serial_read_t serial, struct string_s *s){
M_SERIAL_OK_DONE if it succeeds and the array ends (the array is empty),
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
m_ser1al_bin_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
{
FILE *f = (FILE*) serial->data[0].p;
size_t n = fread (M_ASSIGN_CAST(void*, num), sizeof *num, 1, f);
@@ -472,7 +483,7 @@ m_serial_bin_read_array_start(m_serial_local_t local, m_serial_read_t serial, si
M_SERIAL_OK_DONE if it succeeds and the array ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_array_next(m_serial_local_t local, m_serial_read_t serial)
m_ser1al_bin_read_array_next(m_serial_local_t local, m_serial_read_t serial)
{
FILE *f = (FILE*) serial->data[0].p;
if (local->data[0].b) {
@@ -494,7 +505,7 @@ m_serial_bin_read_array_next(m_serial_local_t local, m_serial_read_t serial)
Return M_SERIAL_OK_CONTINUE if it succeeds and the map continue,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_map_value(m_serial_local_t local, m_serial_read_t serial)
m_ser1al_bin_read_map_value(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
(void) serial;
@@ -505,7 +516,7 @@ m_serial_bin_read_map_value(m_serial_local_t local, m_serial_read_t serial)
Return M_SERIAL_OK_CONTINUE if it succeeds and the tuple continues,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
m_ser1al_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
{
(void) serial;
local->data[1].i = 0;
@@ -519,7 +530,7 @@ m_serial_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
Return M_SERIAL_OK_DONE if it succeeds and the tuple ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const char *const field_name [], const int max, int *id)
m_ser1al_bin_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const char *const field_name [], const int max, int *id)
{
(void) serial;
(void) field_name;
@@ -536,7 +547,7 @@ m_serial_bin_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const
Return M_SERIAL_OK_DONE if it succeeds and the variant ends(variant is empty),
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_variant_start(m_serial_local_t local, m_serial_read_t serial, const char *const field_name[], const int max, int*id)
m_ser1al_bin_read_variant_start(m_serial_local_t local, m_serial_read_t serial, const char *const field_name[], const int max, int*id)
{
(void) field_name;
(void) max;
@@ -550,32 +561,32 @@ m_serial_bin_read_variant_start(m_serial_local_t local, m_serial_read_t serial,
Return M_SERIAL_OK_DONE if it succeeds and the variant ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
m_ser1al_bin_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
(void) serial;
return M_SERIAL_OK_DONE;
}
static const m_serial_read_interface_t m_serial_bin_read_interface = {
m_serial_bin_read_boolean,
m_serial_bin_read_integer,
m_serial_bin_read_float,
m_serial_bin_read_string,
m_serial_bin_read_array_start,
m_serial_bin_read_array_next,
m_serial_bin_read_array_start,
m_serial_bin_read_map_value,
m_serial_bin_read_array_next,
m_serial_bin_read_tuple_start,
m_serial_bin_read_tuple_id,
m_serial_bin_read_variant_start,
m_serial_bin_read_variant_end
static const m_serial_read_interface_t m_ser1al_bin_read_interface = {
m_ser1al_bin_read_boolean,
m_ser1al_bin_read_integer,
m_ser1al_bin_read_float,
m_ser1al_bin_read_string,
m_ser1al_bin_read_array_start,
m_ser1al_bin_read_array_next,
m_ser1al_bin_read_array_start,
m_ser1al_bin_read_map_value,
m_ser1al_bin_read_array_next,
m_ser1al_bin_read_tuple_start,
m_ser1al_bin_read_tuple_id,
m_ser1al_bin_read_variant_start,
m_ser1al_bin_read_variant_end
};
static inline void m_serial_bin_read_init(m_serial_read_t serial, FILE *f)
{
serial->m_interface = &m_serial_bin_read_interface;
serial->m_interface = &m_ser1al_bin_read_interface;
serial->data[0].p = M_ASSIGN_CAST(void*, f);
}
+215 -215
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Serial JSON
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,7 +37,7 @@ M_BEGIN_PROTECTED_CODE
/* Write the boolean 'data' into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_boolean(m_serial_write_t serial, const bool data)
m_ser1al_json_write_boolean(m_serial_write_t serial, const bool data)
{
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "%s", data ? "true" : "false");
@@ -47,7 +47,7 @@ m_serial_json_write_boolean(m_serial_write_t serial, const bool data)
/* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
m_ser1al_json_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
{
(void) size_of_type; // Ignored
FILE *f = (FILE *)serial->data[0].p;
@@ -58,7 +58,7 @@ m_serial_json_write_integer(m_serial_write_t serial,const long long data, const
/* Write the float 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
m_ser1al_json_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
{
(void) size_of_type; // Ignored
FILE *f = (FILE *)serial->data[0].p;
@@ -69,18 +69,18 @@ m_serial_json_write_float(m_serial_write_t serial, const long double data, const
/* Write the null-terminated string 'data'into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_string(m_serial_write_t serial, const char data[], size_t length)
m_ser1al_json_write_string(m_serial_write_t serial, const char data[], size_t length)
{
M_ASSERT_SLOW(length == strlen(data) );
FILE *f = (FILE *)serial->data[0].p;
M_ASSERT(f != NULL && data != NULL);
/* HACK: Build dummy string to reuse string_out_str */
string_t v2;
/* HACK: Build dummy string to reuse m_string_out_str */
m_string_t v2;
uintptr_t ptr = (uintptr_t) data;
v2->u.heap.size = length;
v2->u.heap.alloc = length + 1;
v2->ptr = (char*)ptr;
string_out_str(f, v2);
m_string_out_str(f, v2);
return M_SERIAL_OK_DONE;
}
@@ -91,7 +91,7 @@ m_serial_json_write_string(m_serial_write_t serial, const char data[], size_t le
(local is an unique serialization object of the array).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
m_ser1al_json_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
{
(void) local; // argument not used
(void) number_of_elements; // Ignored
@@ -103,7 +103,7 @@ m_serial_json_write_array_start(m_serial_local_t local, m_serial_write_t serial,
/* Write an array separator between elements of an array into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_array_next(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_json_write_array_next(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
@@ -114,7 +114,7 @@ m_serial_json_write_array_next(m_serial_local_t local, m_serial_write_t serial)
/* End the writing of an array into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_array_end(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_json_write_array_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
@@ -129,7 +129,7 @@ m_serial_json_write_array_end(m_serial_local_t local, m_serial_write_t serial)
(local is an unique serialization object of the map).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
m_ser1al_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
{
(void) local; // argument not used
(void) number_of_elements; // Ignored
@@ -141,7 +141,7 @@ m_serial_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, c
/* Write a value separator between element of the same pair of a map into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_map_value(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_json_write_map_value(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
@@ -152,7 +152,7 @@ m_serial_json_write_map_value(m_serial_local_t local, m_serial_write_t serial)
/* Write a map separator between elements of a map into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_map_next(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_json_write_map_next(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
@@ -163,7 +163,7 @@ m_serial_json_write_map_next(m_serial_local_t local, m_serial_write_t serial)
/* End the writing of a map into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
@@ -176,7 +176,7 @@ m_serial_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
(local is an unique serialization object of the tuple).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
@@ -187,7 +187,7 @@ m_serial_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
/* Start writing the field named field_name[index] of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
m_ser1al_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
{
(void) local; // argument not used
(void) max; // Ignored
@@ -199,7 +199,7 @@ m_serial_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, co
/* End the write of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
@@ -213,7 +213,7 @@ m_serial_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
Otherwise, the field 'field_name[index]' will be filled.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
m_ser1al_json_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
{
(void) local; // argument not used
(void) max; // argument not used
@@ -232,7 +232,7 @@ m_serial_json_write_variant_start(m_serial_local_t local, m_serial_write_t seria
/* End Writing a variant into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
@@ -242,29 +242,29 @@ m_serial_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
/* The internal exported interface of m_serial_write_json
If it is not used, it will be optimized away by the compiler. */
static const m_serial_write_interface_t m_serial_write_json_interface = {
m_serial_json_write_boolean,
m_serial_json_write_integer,
m_serial_json_write_float,
m_serial_json_write_string,
m_serial_json_write_array_start,
m_serial_json_write_array_next,
m_serial_json_write_array_end,
m_serial_json_write_map_start,
m_serial_json_write_map_value,
m_serial_json_write_map_next,
m_serial_json_write_map_end,
m_serial_json_write_tuple_start,
m_serial_json_write_tuple_id,
m_serial_json_write_tuple_end,
m_serial_json_write_variant_start,
m_serial_json_write_variant_end
static const m_serial_write_interface_t m_ser1al_json_write_interface = {
m_ser1al_json_write_boolean,
m_ser1al_json_write_integer,
m_ser1al_json_write_float,
m_ser1al_json_write_string,
m_ser1al_json_write_array_start,
m_ser1al_json_write_array_next,
m_ser1al_json_write_array_end,
m_ser1al_json_write_map_start,
m_ser1al_json_write_map_value,
m_ser1al_json_write_map_next,
m_ser1al_json_write_map_end,
m_ser1al_json_write_tuple_start,
m_ser1al_json_write_tuple_id,
m_ser1al_json_write_tuple_end,
m_ser1al_json_write_variant_start,
m_ser1al_json_write_variant_end
};
/* Initialize the JSON serial object for writing any object to JSON format in the given FILE */
static inline void m_serial_json_write_init(m_serial_write_t serial, FILE *f)
{
serial->m_interface = &m_serial_write_json_interface;
serial->m_interface = &m_ser1al_json_write_interface;
serial->data[0].p = M_ASSIGN_CAST(void*, f);
}
@@ -289,7 +289,7 @@ typedef m_serial_write_t m_serial_json_write_t;
/* Helper function to skip a space */
static inline int
m_serial_json_read_skip (FILE *f)
m_ser1al_json_read_skip (FILE *f)
{
int c;
do {
@@ -302,9 +302,9 @@ m_serial_json_read_skip (FILE *f)
Set '*b' with the boolean value if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_read_boolean(m_serial_read_t serial, bool *b){
m_ser1al_json_read_boolean(m_serial_read_t serial, bool *b){
FILE *f = (FILE*) serial->data[0].p;
int c = m_serial_json_read_skip(f);
int c = m_ser1al_json_read_skip(f);
if (c == 't') {
*b = true;
c = fgetc(f);
@@ -334,7 +334,7 @@ m_serial_json_read_boolean(m_serial_read_t serial, bool *b){
Set '*i' with the integer value if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
m_ser1al_json_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
(void) size_of_type; // Ignored
FILE *f = (FILE*) serial->data[0].p;
return m_core_fscanf(f, " %lld", i) == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
@@ -344,7 +344,7 @@ m_serial_json_read_integer(m_serial_read_t serial, long long *i, const size_t si
Set '*r' with the boolean value if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
m_ser1al_json_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
(void) size_of_type; // Ignored
FILE *f = (FILE*) serial->data[0].p;
return m_core_fscanf(f, " %Lf", r) == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
@@ -354,11 +354,11 @@ m_serial_json_read_float(m_serial_read_t serial, long double *r, const size_t si
Set 's' with the string if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_read_string(m_serial_read_t serial, struct string_s *s){
m_ser1al_json_read_string(m_serial_read_t serial, struct m_string_s *s){
FILE *f = (FILE*) serial->data[0].p;
int n = m_core_fscanf(f, " "); // Skip any leading spaces.
(void) n; // Unused return value.
return string_in_str(s, f) ? M_SERIAL_OK_DONE : m_core_serial_fail();
return m_string_in_str(s, f) ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Start reading from the stream 'serial' an array.
@@ -369,7 +369,7 @@ m_serial_json_read_string(m_serial_read_t serial, struct string_s *s){
M_SERIAL_OK_DONE if it succeeds and the array ends (the array is empty),
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
m_ser1al_json_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
@@ -387,7 +387,7 @@ m_serial_json_read_array_start(m_serial_local_t local, m_serial_read_t serial, s
M_SERIAL_OK_DONE if it succeeds and the array ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_read_array_next(m_serial_local_t local, m_serial_read_t serial)
m_ser1al_json_read_array_next(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
@@ -405,7 +405,7 @@ m_serial_json_read_array_next(m_serial_local_t local, m_serial_read_t serial)
M_SERIAL_OK_DONE if it succeeds and the map ends (the map is empty),
m_core_serial_fail() otherwise */
static inline m_serial_return_code_t
m_serial_json_read_map_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
m_ser1al_json_read_map_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
@@ -422,7 +422,7 @@ m_serial_json_read_map_start(m_serial_local_t local, m_serial_read_t serial, siz
Return M_SERIAL_OK_CONTINUE if it succeeds and the map continue,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_read_map_value(m_serial_local_t local, m_serial_read_t serial)
m_ser1al_json_read_map_value(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
@@ -437,7 +437,7 @@ m_serial_json_read_map_value(m_serial_local_t local, m_serial_read_t serial)
M_SERIAL_OK_DONE if it succeeds and the map ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_read_map_next(m_serial_local_t local, m_serial_read_t serial)
m_ser1al_json_read_map_next(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
@@ -451,7 +451,7 @@ m_serial_json_read_map_next(m_serial_local_t local, m_serial_read_t serial)
Return M_SERIAL_OK_CONTINUE if it succeeds and the tuple continues,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
m_ser1al_json_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
@@ -468,11 +468,11 @@ m_serial_json_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
Return M_SERIAL_OK_DONE if it succeeds and the tuple ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const char *const field_name [], const int max, int *id)
m_ser1al_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const char *const field_name [], const int max, int *id)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
int c = m_serial_json_read_skip(f);
int c = m_ser1al_json_read_skip(f);
if (c == EOF) return m_core_serial_fail();
if (c == '}') return M_SERIAL_OK_DONE;
if (c == ',') {
@@ -507,7 +507,7 @@ m_serial_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, cons
Return M_SERIAL_OK_DONE if it succeeds and the variant ends(variant is empty),
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_read_variant_start(m_serial_local_t local, m_serial_read_t serial, const char *const field_name[], const int max, int*id)
m_ser1al_json_read_variant_start(m_serial_local_t local, m_serial_read_t serial, const char *const field_name[], const int max, int*id)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
@@ -542,7 +542,7 @@ m_serial_json_read_variant_start(m_serial_local_t local, m_serial_read_t serial,
Return M_SERIAL_OK_DONE if it succeeds and the variant ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
m_ser1al_json_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
@@ -552,26 +552,26 @@ m_serial_json_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
return final > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
static const m_serial_read_interface_t m_serial_json_read_interface = {
m_serial_json_read_boolean,
m_serial_json_read_integer,
m_serial_json_read_float,
m_serial_json_read_string,
m_serial_json_read_array_start,
m_serial_json_read_array_next,
m_serial_json_read_map_start,
m_serial_json_read_map_value,
m_serial_json_read_map_next,
m_serial_json_read_tuple_start,
m_serial_json_read_tuple_id,
m_serial_json_read_variant_start,
m_serial_json_read_variant_end
static const m_serial_read_interface_t m_ser1al_json_read_interface = {
m_ser1al_json_read_boolean,
m_ser1al_json_read_integer,
m_ser1al_json_read_float,
m_ser1al_json_read_string,
m_ser1al_json_read_array_start,
m_ser1al_json_read_array_next,
m_ser1al_json_read_map_start,
m_ser1al_json_read_map_value,
m_ser1al_json_read_map_next,
m_ser1al_json_read_tuple_start,
m_ser1al_json_read_tuple_id,
m_ser1al_json_read_variant_start,
m_ser1al_json_read_variant_end
};
/* Initialize the JSON serial object for reading any object from JSON format in the given FILE */
static inline void m_serial_json_read_init(m_serial_read_t serial, FILE *f)
{
serial->m_interface = &m_serial_json_read_interface;
serial->m_interface = &m_ser1al_json_read_interface;
serial->data[0].p = M_ASSIGN_CAST(void*, f);
}
@@ -597,50 +597,50 @@ typedef m_serial_read_t m_serial_json_read_t;
/* Write the boolean 'data' into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_boolean(m_serial_write_t serial, const bool data)
m_ser1al_str_json_write_boolean(m_serial_write_t serial, const bool data)
{
struct string_s *f = (struct string_s *)serial->data[0].p;
int n = string_cat_printf(f, "%s", data ? "true" : "false");
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
int n = m_string_cat_printf(f, "%s", data ? "true" : "false");
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
m_ser1al_str_json_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
{
(void) size_of_type; // Ignored
struct string_s *f = (struct string_s *)serial->data[0].p;
int n = string_cat_printf(f, "%lld", data);
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
int n = m_string_cat_printf(f, "%lld", data);
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Write the float 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
m_ser1al_str_json_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
{
(void) size_of_type; // Ignored
struct string_s *f = (struct string_s *)serial->data[0].p;
int n = string_cat_printf(f, "%Lf", data);
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
int n = m_string_cat_printf(f, "%Lf", data);
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Write the null-terminated string 'data'into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_string(m_serial_write_t serial, const char data[], size_t length)
m_ser1al_str_json_write_string(m_serial_write_t serial, const char data[], size_t length)
{
M_ASSERT_SLOW(length == strlen(data) );
struct string_s *f = (struct string_s *)serial->data[0].p;
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
M_ASSERT(f != NULL && data != NULL);
/* HACK: Build dummy string to reuse string_get_str */
string_t v2;
/* HACK: Build dummy string to reuse m_string_get_str */
m_string_t v2;
uintptr_t ptr = (uintptr_t) data;
v2->u.heap.size = length;
v2->u.heap.alloc = length + 1;
v2->ptr = (char*)ptr;
string_get_str(f, v2, true);
m_string_get_str(f, v2, true);
return M_SERIAL_OK_DONE;
}
@@ -651,34 +651,34 @@ m_serial_str_json_write_string(m_serial_write_t serial, const char data[], size_
(local is an unique serialization object of the array).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
m_ser1al_str_json_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
{
(void) local; // argument not used
(void) number_of_elements; // Ignored
struct string_s *f = (struct string_s *)serial->data[0].p;
string_push_back(f, '[');
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, '[');
return M_SERIAL_OK_CONTINUE;
}
/* Write an array separator between elements of an array into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_array_next(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_str_json_write_array_next(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct string_s *f = (struct string_s *)serial->data[0].p;
string_push_back(f, ',');
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, ',');
return M_SERIAL_OK_CONTINUE;
}
/* End the writing of an array into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_array_end(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_str_json_write_array_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct string_s *f = (struct string_s *)serial->data[0].p;
string_push_back(f, ']');
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, ']');
return M_SERIAL_OK_CONTINUE;
}
@@ -689,45 +689,45 @@ m_serial_str_json_write_array_end(m_serial_local_t local, m_serial_write_t seria
(local is an unique serialization object of the map).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
m_ser1al_str_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
{
(void) local; // argument not used
(void) number_of_elements; // Ignored
struct string_s *f = (struct string_s *)serial->data[0].p;
string_push_back(f, '{');
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, '{');
return M_SERIAL_OK_CONTINUE;
}
/* Write a value separator between element of the same pair of a map into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_map_value(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_str_json_write_map_value(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct string_s *f = (struct string_s *)serial->data[0].p;
string_push_back(f, ':');
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, ':');
return M_SERIAL_OK_CONTINUE;
}
/* Write a map separator between elements of a map into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_map_next(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_str_json_write_map_next(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct string_s *f = (struct string_s *)serial->data[0].p;
string_push_back(f, ',');
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, ',');
return M_SERIAL_OK_CONTINUE;
}
/* End the writing of a map into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_str_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct string_s *f = (struct string_s *)serial->data[0].p;
string_push_back(f, '}');
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, '}');
return M_SERIAL_OK_CONTINUE;
}
@@ -736,34 +736,34 @@ m_serial_str_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
(local is an unique serialization object of the tuple).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_str_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct string_s *f = (struct string_s *)serial->data[0].p;
string_push_back(f, '{');
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, '{');
return M_SERIAL_OK_CONTINUE;
}
/* Start writing the field named field_name[index] of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
m_ser1al_str_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
{
(void) local; // argument not used
(void) max; // Ignored
struct string_s *f = (struct string_s *)serial->data[0].p;
int n = string_cat_printf(f, "%c\"%s\":", index == 0 ? ' ' : ',', field_name[index]);
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
int n = m_string_cat_printf(f, "%c\"%s\":", index == 0 ? ' ' : ',', field_name[index]);
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
/* End the write of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_str_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct string_s *f = (struct string_s *)serial->data[0].p;
string_push_back(f, '}');
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, '}');
return M_SERIAL_OK_CONTINUE;
}
@@ -773,18 +773,18 @@ m_serial_str_json_write_tuple_end(m_serial_local_t local, m_serial_write_t seria
Otherwise, the field 'field_name[index]' will be filled.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
m_ser1al_str_json_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
{
(void) local; // argument not used
(void) max; // argument not used
struct string_s *f = (struct string_s *)serial->data[0].p;
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
int n;
if (index >= 0) {
M_ASSERT (index < max);
n = string_cat_printf(f, "{\"%s\":", field_name[index]);
n = m_string_cat_printf(f, "{\"%s\":", field_name[index]);
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
} else {
n = string_cat_printf(f, "{}");
n = m_string_cat_printf(f, "{}");
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
}
@@ -792,39 +792,39 @@ m_serial_str_json_write_variant_start(m_serial_local_t local, m_serial_write_t s
/* End Writing a variant into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
m_ser1al_str_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct string_s *f = (struct string_s *)serial->data[0].p;
string_push_back(f, '}');
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, '}');
return M_SERIAL_OK_CONTINUE;
}
/* The internal exported interface of m_serial_write_json. */
static const m_serial_write_interface_t m_serial_str_json_write_interface = {
m_serial_str_json_write_boolean,
m_serial_str_json_write_integer,
m_serial_str_json_write_float,
m_serial_str_json_write_string,
m_serial_str_json_write_array_start,
m_serial_str_json_write_array_next,
m_serial_str_json_write_array_end,
m_serial_str_json_write_map_start,
m_serial_str_json_write_map_value,
m_serial_str_json_write_map_next,
m_serial_str_json_write_map_end,
m_serial_str_json_write_tuple_start,
m_serial_str_json_write_tuple_id,
m_serial_str_json_write_tuple_end,
m_serial_str_json_write_variant_start,
m_serial_str_json_write_variant_end
static const m_serial_write_interface_t m_ser1al_str_json_write_interface = {
m_ser1al_str_json_write_boolean,
m_ser1al_str_json_write_integer,
m_ser1al_str_json_write_float,
m_ser1al_str_json_write_string,
m_ser1al_str_json_write_array_start,
m_ser1al_str_json_write_array_next,
m_ser1al_str_json_write_array_end,
m_ser1al_str_json_write_map_start,
m_ser1al_str_json_write_map_value,
m_ser1al_str_json_write_map_next,
m_ser1al_str_json_write_map_end,
m_ser1al_str_json_write_tuple_start,
m_ser1al_str_json_write_tuple_id,
m_ser1al_str_json_write_tuple_end,
m_ser1al_str_json_write_variant_start,
m_ser1al_str_json_write_variant_end
};
/* Initialize the JSON serial object for writing any object to JSON format in the given FILE */
static inline void m_serial_str_json_write_init(m_serial_write_t serial, string_t s)
static inline void m_serial_str_json_write_init(m_serial_write_t serial, m_string_t s)
{
serial->m_interface = &m_serial_str_json_write_interface;
serial->data[0].p = M_ASSIGN_CAST(struct string_s *, s);
serial->m_interface = &m_ser1al_str_json_write_interface;
serial->data[0].p = M_ASSIGN_CAST(struct m_string_s *, s);
}
/* CLear the JSON serial object for writing*/
@@ -847,7 +847,7 @@ typedef m_serial_write_t m_serial_str_json_write_t;
/* Helper function to read a character and advance the stream */
static inline char
m_serial_str_json_getc(const char **p)
m_ser1al_str_json_getc(const char **p)
{
char c = **p;
// Once it reaches the end of string character (== 0), stop advancing the stream.
@@ -857,7 +857,7 @@ m_serial_str_json_getc(const char **p)
/* Helper function to skip space(s) */
static inline void
m_serial_str_json_skip (const char **p)
m_ser1al_str_json_skip (const char **p)
{
while (isspace (**p)) {
(*p)++;
@@ -866,7 +866,7 @@ m_serial_str_json_skip (const char **p)
/* Helper function to read a string with characters not present in reject */
static inline void
m_serial_str_json_gets(size_t alloc, char field[], const char reject[], const char **s)
m_ser1al_str_json_gets(size_t alloc, char field[], const char reject[], const char **s)
{
M_ASSERT (alloc > 0);
size_t length = strcspn(*s, reject);
@@ -881,28 +881,28 @@ m_serial_str_json_gets(size_t alloc, char field[], const char reject[], const ch
Set '*b' with the boolean value if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_read_boolean(m_serial_read_t serial, bool *b){
m_ser1al_str_json_read_boolean(m_serial_read_t serial, bool *b){
const char **f = &serial->data[0].cstr;
m_serial_str_json_skip(f);
char c = m_serial_str_json_getc(f);
m_ser1al_str_json_skip(f);
char c = m_ser1al_str_json_getc(f);
if (c == 't') {
*b = true;
c = m_serial_str_json_getc(f);
c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY(c != 'r')) return m_core_serial_fail();
c = m_serial_str_json_getc(f);
c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY(c != 'u')) return m_core_serial_fail();
c = m_serial_str_json_getc(f);
c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY(c != 'e')) return m_core_serial_fail();
return M_SERIAL_OK_DONE;
} else if (M_LIKELY(c == 'f')) {
*b = false;
c = m_serial_str_json_getc(f);
c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY(c != 'a')) return m_core_serial_fail();
c = m_serial_str_json_getc(f);
c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY(c != 'l')) return m_core_serial_fail();
c = m_serial_str_json_getc(f);
c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY(c != 's')) return m_core_serial_fail();
c = m_serial_str_json_getc(f);
c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY(c != 'e')) return m_core_serial_fail();
return M_SERIAL_OK_DONE;
} else {
@@ -914,7 +914,7 @@ m_serial_str_json_read_boolean(m_serial_read_t serial, bool *b){
Set '*i' with the integer value if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
m_ser1al_str_json_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
(void) size_of_type; // Ignored
const char **f = &serial->data[0].cstr;
char *e;
@@ -928,7 +928,7 @@ m_serial_str_json_read_integer(m_serial_read_t serial, long long *i, const size_
Set '*r' with the boolean value if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
m_ser1al_str_json_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
(void) size_of_type; // Ignored
const char **f = &serial->data[0].cstr;
char *e;
@@ -942,11 +942,11 @@ m_serial_str_json_read_float(m_serial_read_t serial, long double *r, const size_
Set 's' with the string if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_read_string(m_serial_read_t serial, struct string_s *s){
m_ser1al_str_json_read_string(m_serial_read_t serial, struct m_string_s *s){
const char **f = &serial->data[0].cstr;
m_serial_str_json_skip(f);
m_ser1al_str_json_skip(f);
const char *e;
bool b = string_parse_str(s, *f, &e);
bool b = m_string_parse_str(s, *f, &e);
serial->data[0].cstr = e;
return b ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
@@ -959,19 +959,19 @@ m_serial_str_json_read_string(m_serial_read_t serial, struct string_s *s){
M_SERIAL_OK_DONE if it succeeds and the array ends (the array is empty),
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
m_ser1al_str_json_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
{
(void) local; // argument not used
const char **f = &serial->data[0].cstr;
m_serial_str_json_skip(f);
char c = m_serial_str_json_getc(f);
m_ser1al_str_json_skip(f);
char c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY(c != '[')) {
return m_core_serial_fail();
}
*num = 0; // Don't know the size of the array.
m_serial_str_json_skip(f);
m_ser1al_str_json_skip(f);
if (M_UNLIKELY (**f == ']')) {
c = m_serial_str_json_getc(f);
c = m_ser1al_str_json_getc(f);
return M_SERIAL_OK_DONE;
} else {
return M_SERIAL_OK_CONTINUE;
@@ -983,12 +983,12 @@ m_serial_str_json_read_array_start(m_serial_local_t local, m_serial_read_t seria
M_SERIAL_OK_DONE if it succeeds and the array ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_read_array_next(m_serial_local_t local, m_serial_read_t serial)
m_ser1al_str_json_read_array_next(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
const char **f = &serial->data[0].cstr;
m_serial_str_json_skip(f);
char c = m_serial_str_json_getc(f);
m_ser1al_str_json_skip(f);
char c = m_ser1al_str_json_getc(f);
return c == ',' ? M_SERIAL_OK_CONTINUE : c == ']' ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
@@ -1000,19 +1000,19 @@ m_serial_str_json_read_array_next(m_serial_local_t local, m_serial_read_t serial
M_SERIAL_OK_DONE if it succeeds and the map ends (the map is empty),
m_core_serial_fail() otherwise */
static inline m_serial_return_code_t
m_serial_str_json_read_map_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
m_ser1al_str_json_read_map_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
{
(void) local; // argument not used
const char **f = &serial->data[0].cstr;
m_serial_str_json_skip(f);
char c = m_serial_str_json_getc(f);
m_ser1al_str_json_skip(f);
char c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY(c != '{')) {
return m_core_serial_fail();
}
*num = 0; // Don't know the size of the map
m_serial_str_json_skip(f);
m_ser1al_str_json_skip(f);
if (M_UNLIKELY (**f == '}')) {
c = m_serial_str_json_getc(f);
c = m_ser1al_str_json_getc(f);
return M_SERIAL_OK_DONE;
} else {
return M_SERIAL_OK_CONTINUE;
@@ -1023,12 +1023,12 @@ m_serial_str_json_read_map_start(m_serial_local_t local, m_serial_read_t serial,
Return M_SERIAL_OK_CONTINUE if it succeeds and the map continue,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_read_map_value(m_serial_local_t local, m_serial_read_t serial)
m_ser1al_str_json_read_map_value(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
const char **f = &serial->data[0].cstr;
m_serial_str_json_skip(f);
char c = m_serial_str_json_getc(f);
m_ser1al_str_json_skip(f);
char c = m_ser1al_str_json_getc(f);
return c ==':' ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
@@ -1037,12 +1037,12 @@ m_serial_str_json_read_map_value(m_serial_local_t local, m_serial_read_t serial)
M_SERIAL_OK_DONE if it succeeds and the map ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_read_map_next(m_serial_local_t local, m_serial_read_t serial)
m_ser1al_str_json_read_map_next(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
const char **f = &serial->data[0].cstr;
m_serial_str_json_skip(f);
char c = m_serial_str_json_getc(f);
m_ser1al_str_json_skip(f);
char c = m_ser1al_str_json_getc(f);
return c == ',' ? M_SERIAL_OK_CONTINUE : c == '}' ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
@@ -1050,12 +1050,12 @@ m_serial_str_json_read_map_next(m_serial_local_t local, m_serial_read_t serial)
Return M_SERIAL_OK_CONTINUE if it succeeds and the tuple continues,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
m_ser1al_str_json_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
const char **f = &serial->data[0].cstr;
m_serial_str_json_skip(f);
char c = m_serial_str_json_getc(f);
m_ser1al_str_json_skip(f);
char c = m_ser1al_str_json_getc(f);
return c == '{' ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
@@ -1066,28 +1066,28 @@ m_serial_str_json_read_tuple_start(m_serial_local_t local, m_serial_read_t seria
Return M_SERIAL_OK_DONE if it succeeds and the tuple ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const char *const field_name [], const int max, int *id)
m_ser1al_str_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const char *const field_name [], const int max, int *id)
{
(void) local; // argument not used
const char **f = &serial->data[0].cstr;
m_serial_str_json_skip(f);
char c = m_serial_str_json_getc(f);
m_ser1al_str_json_skip(f);
char c = m_ser1al_str_json_getc(f);
if (c == 0) return m_core_serial_fail();
if (c == '}') return M_SERIAL_OK_DONE;
if (c == ',') {
// If first call of read_tuple_id, it is a failure
if (M_UNLIKELY (*id == -1)) return m_core_serial_fail();
m_serial_str_json_skip(f);
c = m_serial_str_json_getc(f);
m_ser1al_str_json_skip(f);
c = m_ser1al_str_json_getc(f);
}
/* Read the field in the JSON */
char field[M_USE_IDENTIFIER_ALLOC+1];
if (M_UNLIKELY(c != '"')) return m_core_serial_fail();
m_serial_str_json_gets(M_USE_IDENTIFIER_ALLOC+1, field, " \t\n\"", f);
c = m_serial_str_json_getc(f);
m_ser1al_str_json_gets(M_USE_IDENTIFIER_ALLOC+1, field, " \t\n\"", f);
c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY (c != '"')) return m_core_serial_fail();
c = m_serial_str_json_getc(f);
c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY (c != ':')) return m_core_serial_fail();
/* Search for field in field_name */
@@ -1107,26 +1107,26 @@ m_serial_str_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial,
Return M_SERIAL_OK_DONE if it succeeds and the variant ends(variant is empty),
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_read_variant_start(m_serial_local_t local, m_serial_read_t serial, const char *const field_name[], const int max, int*id)
m_ser1al_str_json_read_variant_start(m_serial_local_t local, m_serial_read_t serial, const char *const field_name[], const int max, int*id)
{
(void) local; // argument not used
const char **f = &serial->data[0].cstr;
m_serial_str_json_skip(f);
int c = m_serial_str_json_getc(f);
m_ser1al_str_json_skip(f);
int c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY (c != '{'))
// TODO: Accept 'null' as empty variant?
return m_core_serial_fail();
m_serial_str_json_skip(f);
c = m_serial_str_json_getc(f);
m_ser1al_str_json_skip(f);
c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY (c == '}')) return M_SERIAL_OK_DONE; // Empty variant
/* Read the field in the JSON */
char field[M_USE_IDENTIFIER_ALLOC+1];
if (M_UNLIKELY(c != '"')) return m_core_serial_fail();
m_serial_str_json_gets(M_USE_IDENTIFIER_ALLOC+1, field, " \t\n\"", f);
c = m_serial_str_json_getc(f);
m_ser1al_str_json_gets(M_USE_IDENTIFIER_ALLOC+1, field, " \t\n\"", f);
c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY (c != '"')) return m_core_serial_fail();
c = m_serial_str_json_getc(f);
c = m_ser1al_str_json_getc(f);
if (M_UNLIKELY (c != ':')) return m_core_serial_fail();
/* Linear Search for field in field_name */
@@ -1144,35 +1144,35 @@ m_serial_str_json_read_variant_start(m_serial_local_t local, m_serial_read_t ser
Return M_SERIAL_OK_DONE if it succeeds and the variant ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_str_json_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
m_ser1al_str_json_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
const char **f = &serial->data[0].cstr;
m_serial_str_json_skip(f);
int c = m_serial_str_json_getc(f);
m_ser1al_str_json_skip(f);
int c = m_ser1al_str_json_getc(f);
return (M_UNLIKELY (c != '}')) ? m_core_serial_fail() : M_SERIAL_OK_DONE;
}
static const m_serial_read_interface_t m_serial_str_json_read_interface = {
m_serial_str_json_read_boolean,
m_serial_str_json_read_integer,
m_serial_str_json_read_float,
m_serial_str_json_read_string,
m_serial_str_json_read_array_start,
m_serial_str_json_read_array_next,
m_serial_str_json_read_map_start,
m_serial_str_json_read_map_value,
m_serial_str_json_read_map_next,
m_serial_str_json_read_tuple_start,
m_serial_str_json_read_tuple_id,
m_serial_str_json_read_variant_start,
m_serial_str_json_read_variant_end
static const m_serial_read_interface_t m_ser1al_str_json_read_interface = {
m_ser1al_str_json_read_boolean,
m_ser1al_str_json_read_integer,
m_ser1al_str_json_read_float,
m_ser1al_str_json_read_string,
m_ser1al_str_json_read_array_start,
m_ser1al_str_json_read_array_next,
m_ser1al_str_json_read_map_start,
m_ser1al_str_json_read_map_value,
m_ser1al_str_json_read_map_next,
m_ser1al_str_json_read_tuple_start,
m_ser1al_str_json_read_tuple_id,
m_ser1al_str_json_read_variant_start,
m_ser1al_str_json_read_variant_end
};
/* Initialize the JSON serial object for reading any object from JSON format in the given const string */
static inline void m_serial_str_json_read_init(m_serial_read_t serial, const char str[])
{
serial->m_interface = &m_serial_str_json_read_interface;
serial->m_interface = &m_ser1al_str_json_read_interface;
serial->data[0].cstr = str;
}
+39 -33
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - SHARED Module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,22 +33,22 @@ M_BEGIN_PROTECTED_CODE
/* Define the oplist of a shared pointer.
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
#define SHARED_PTR_OPLIST(...) \
#define M_SHARED_PTR_OPLIST(...) \
M_SHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
((__VA_ARGS__, M_BASIC_OPLIST ), \
(__VA_ARGS__ )))
/* Define shared pointer and its function.
USAGE: SHARED_PTR_DEF(name, type, [, oplist]) */
#define SHARED_PTR_DEF(name, ...) \
SHARED_PTR_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
#define M_SHARED_PTR_DEF(name, ...) \
M_SHARED_PTR_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
/* Define shared pointer and its function
as the given name name_t
USAGE: SHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
#define SHARED_PTR_DEF_AS(name, name_t, ...) \
#define M_SHARED_PTR_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_SHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_SHAR3D_ATOMIC_OPLIST, name_t ), \
@@ -58,14 +58,14 @@ M_BEGIN_PROTECTED_CODE
/* Define relaxed shared pointer and its function (thread unsafe).
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
#define SHARED_PTR_RELAXED_DEF(name, ...) \
SHARED_PTR_RELAXED_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
#define M_SHARED_PTR_RELAXED_DEF(name, ...) \
M_SHARED_PTR_RELAXED_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
/* Define relaxed shared pointer and its function (thread unsafe)
as the given name name_t
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
#define SHARED_PTR_RELAXED_DEF_AS(name, name_t, ...) \
#define M_SHARED_PTR_RELAXED_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_SHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_SHAR3D_INTEGER_OPLIST, name_t ), \
@@ -76,15 +76,15 @@ M_BEGIN_PROTECTED_CODE
/* Define shared resource and its function.
This is a bounded pool of resource shared by multiple owners.
USAGE: SHARED_RESOURCE_DEF(name, type, [, oplist]) */
#define SHARED_RESOURCE_DEF(name, ...) \
SHARED_RESOURCE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
#define M_SHARED_RESOURCE_DEF(name, ...) \
M_SHARED_RESOURCE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
/* Define shared resource and its function
as the given name named_t and the iterator it_t
This is a bounded pool of resource shared by multiple owners.
USAGE: SHARED_RESOURCE_DEF_AS(name, name_t, it_t, type, [, oplist]) */
#define SHARED_RESOURCE_DEF_AS(name, name_t, it_t, ...) \
#define M_SHARED_RESOURCE_DEF_AS(name, name_t, it_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_SHAR3D_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
@@ -149,7 +149,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
} while (0)
// deferred evaluation
#define M_SHAR3D_PTR_DEF_P1(arg) M_SHAR3D_PTR_DEF_P2 arg
#define M_SHAR3D_PTR_DEF_P1(arg) M_ID( M_SHAR3D_PTR_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_SHAR3D_PTR_DEF_P2(name, type, oplist, cpt_oplist, shared_t) \
@@ -208,6 +208,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
} \
\
M_IF_METHOD(INIT, oplist)( \
static inline void \
M_C(name, _init_new)(shared_t shared) \
{ \
@@ -227,6 +228,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
*shared = ptr; \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
} \
, /* No INIT */ ) \
\
static inline bool \
M_C(name, _NULL_p)(const shared_t shared) \
@@ -277,12 +279,6 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_C(name, _clear)(dest); \
} \
\
static inline void M_ATTR_DEPRECATED \
M_C(name, _clean)(shared_t dest) \
{ \
M_C(name, _reset)(dest); \
} \
\
static inline void \
M_C(name, _set)(shared_t dest, \
const shared_t shared) \
@@ -366,7 +362,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
} while (0)
// deferred
#define M_SHAR3D_RESOURCE_DEF_P1(arg) M_SHAR3D_RESOURCE_DEF_P2 arg
#define M_SHAR3D_RESOURCE_DEF_P1(arg) M_ID( M_SHAR3D_RESOURCE_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_SHAR3D_RESOURCE_DEF_P2(name, type, oplist, shared_t, it_t) \
@@ -386,7 +382,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
} M_C(name, _atype_ct); \
\
typedef struct M_C(name, _s) { \
genint_t core; \
m_genint_t core; \
M_C(name, _atype_ct) *buffer; \
} shared_t[1]; \
\
@@ -412,7 +408,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_CALL_INIT(oplist, s->buffer[i].x); \
atomic_init (&s->buffer[i].cpt, 0U); \
} \
genint_init(s->core, (unsigned int) n); \
m_genint_init(s->core, (unsigned int) n); \
M_SHAR3D_RESOURCE_CONTRACT(s); \
} \
\
@@ -420,13 +416,13 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_C(name, _clear)(shared_t s) \
{ \
M_SHAR3D_RESOURCE_CONTRACT(s); \
size_t n = genint_size(s->core); \
size_t n = m_genint_size(s->core); \
for(size_t i = 0; i < n; i++) { \
M_CALL_CLEAR(oplist, s->buffer[i].x); \
} \
M_CALL_FREE(oplist, s->buffer); \
s->buffer = NULL; \
genint_clear(s->core); \
m_genint_clear(s->core); \
} \
\
static inline void \
@@ -434,10 +430,10 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
{ \
M_SHAR3D_RESOURCE_CONTRACT(s); \
M_ASSERT (it != NULL); \
unsigned int idx = genint_pop(s->core); \
unsigned int idx = m_genint_pop(s->core); \
it->idx = idx; \
it->ref = s; \
if (M_LIKELY (idx != GENINT_ERROR)) { \
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
M_ASSERT(atomic_load(&s->buffer[idx].cpt) == 0); \
atomic_store(&s->buffer[idx].cpt, 1U); \
} \
@@ -447,13 +443,13 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_C(name, _end_p)(it_t it) \
{ \
M_ASSERT (it != NULL); \
return it->idx == GENINT_ERROR; \
return it->idx == M_GENINT_ERROR; \
} \
\
static inline type * \
M_C(name, _ref)(it_t it) \
{ \
M_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
M_ASSERT (it != NULL && it->ref != NULL && it->idx != M_GENINT_ERROR); \
M_SHAR3D_RESOURCE_CONTRACT(it->ref); \
return &it->ref->buffer[it->idx].x; \
} \
@@ -461,7 +457,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
static inline type const * \
M_C(name, _cref)(it_t it) \
{ \
M_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
M_ASSERT (it != NULL && it->ref != NULL && it->idx != M_GENINT_ERROR); \
M_SHAR3D_RESOURCE_CONTRACT(it->ref); \
return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \
} \
@@ -473,12 +469,12 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_ASSERT (it != NULL); \
M_ASSERT (it->ref == s); \
unsigned int idx = it->idx; \
if (M_LIKELY (idx != GENINT_ERROR)) { \
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \
if (c == 1) { \
genint_push(it->ref->core, idx); \
m_genint_push(it->ref->core, idx); \
} \
it->idx = GENINT_ERROR; \
it->idx = M_GENINT_ERROR; \
} \
} \
\
@@ -490,7 +486,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
itd->ref = its->ref; \
unsigned int idx = its->idx; \
itd->idx = idx; \
if (M_LIKELY (idx != GENINT_ERROR)) { \
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \
M_ASSERT (c >= 1); \
} \
@@ -498,4 +494,14 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_END_PROTECTED_CODE
#if M_USE_SMALL_NAME
#define SHARED_PTR_OPLIST M_SHARED_PTR_OPLIST
#define SHARED_PTR_DEF M_SHARED_PTR_DEF
#define SHARED_PTR_DEF_AS M_SHARED_PTR_DEF_AS
#define SHARED_PTR_RELAXED_DEF M_SHARED_PTR_RELAXED_DEF
#define SHARED_PTR_RELAXED_DEF_AS M_SHARED_PTR_RELAXED_DEF_AS
#define SHARED_RESOURCE_DEF M_SHARED_RESOURCE_DEF
#define SHARED_RESOURCE_DEF_AS M_SHARED_RESOURCE_DEF_AS
#endif
#endif
+55 -45
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - SNAPSHOT Module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,14 +33,14 @@ M_BEGIN_PROTECTED_CODE
/* Define a Single Producer Single Consummer snapshot and its functions
USAGE: SNAPSHOT_SPSC_DEF(name, type[, oplist]) */
#define SNAPSHOT_SPSC_DEF(name, ...) \
SNAPSHOT_SPSC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
#define M_SNAPSHOT_SPSC_DEF(name, ...) \
M_SNAPSHOT_SPSC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
/* Define a Single Producer Single Consummer snapshot and its functions
as the given name name_t
USAGE: SNAPSHOT_SPSC_DEF_AS(name, name_t, type[, oplist]) */
#define SNAPSHOT_SPSC_DEF_AS(name, name_t, ...) \
#define M_SNAPSHOT_SPSC_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_SNAPSH0T_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
@@ -50,14 +50,14 @@ M_BEGIN_PROTECTED_CODE
/* Define a Single Producer Multiple Consummer snapshot and its functions
USAGE: SNAPSHOT_SPMC_DEF(name, type[, oplist]) */
#define SNAPSHOT_SPMC_DEF(name, ...) \
SNAPSHOT_SPMC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
#define M_SNAPSHOT_SPMC_DEF(name, ...) \
M_SNAPSHOT_SPMC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
/* Define a Single Producer Multiple Consummer snapshot and its functions
as the given name name_t
USAGE: SNAPSHOT_SPMC_DEF_AS(name, type[, oplist]) */
#define SNAPSHOT_SPMC_DEF_AS(name, name_t, ...) \
#define M_SNAPSHOT_SPMC_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_SNAPSH0T_SPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
@@ -67,14 +67,14 @@ M_BEGIN_PROTECTED_CODE
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
USAGE: SNAPSHOT_MPMC_DEF(name, type[, oplist]) */
#define SNAPSHOT_MPMC_DEF(name, ...) \
SNAPSHOT_MPMC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
#define M_SNAPSHOT_MPMC_DEF(name, ...) \
M_SNAPSHOT_MPMC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
as the given name name_t
USAGE: SNAPSHOT_MPMC_DEF_AS(name, name_t, type[, oplist]) */
#define SNAPSHOT_MPMC_DEF_AS(name, name_t, ...) \
#define M_SNAPSHOT_MPMC_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_SNAPSH0T_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
@@ -84,7 +84,7 @@ M_BEGIN_PROTECTED_CODE
/* Define the oplist of a snapshot (SPSC, SPMC or MPMC).
USAGE: SNAPSHOT_OPLIST(name[, oplist]) */
#define SNAPSHOT_OPLIST(...) \
#define M_SNAPSHOT_OPLIST(...) \
M_SNAPSH0T_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
(__VA_ARGS__ )))
@@ -156,7 +156,7 @@ M_BEGIN_PROTECTED_CODE
#define M_SNAPSH0T_SPSC_MAX_BUFFER 3
// Defered evaluation of the arguments.
#define M_SNAPSH0T_SPSC_DEF_P1(arg) M_SNAPSH0T_SPSC_DEF_P2 arg
#define M_SNAPSH0T_SPSC_DEF_P1(arg) M_ID( M_SNAPSH0T_SPSC_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_SNAPSH0T_SPSC_DEF_P2(name, type, oplist, snapshot_t) \
@@ -347,7 +347,7 @@ M_BEGIN_PROTECTED_CODE
// 2 more buffer than the number of readers are needed
#define M_SNAPSH0T_SPMC_EXTRA_BUFFER 2
#define M_SNAPSH0T_SPMC_MAX_READER (GENINT_MAX_ALLOC-M_SNAPSH0T_SPMC_EXTRA_BUFFER)
#define M_SNAPSH0T_SPMC_MAX_READER (M_GENINT_MAX_ALLOC-M_SNAPSH0T_SPMC_EXTRA_BUFFER)
/* Internal structure to handle SPMC snapshot but return an unique index in the buffer array.
- lastNext: last published written index + next flag (format M_SNAPSH0T_SPMC_INT_FLAG)
@@ -356,13 +356,13 @@ M_BEGIN_PROTECTED_CODE
- cptTab: ref counter array to keep track of how many readers use the corresponding buffer.
- freeList: a pool of free integers.
*/
typedef struct m_snapshot_mrsw_s {
typedef struct m_snapsh0t_mrsw_s {
atomic_uint lastNext;
unsigned int currentWrite;
size_t n_reader;
atomic_uint *cptTab;
genint_t freeList;
} m_snapshot_mrsw_ct[1];
m_genint_t freeList;
} m_snapsh0t_mrsw_ct[1];
// can't check currentWrite due to potential data race on it
#define M_SNAPSH0T_SPMC_INT_CONTRACT(s) do { \
@@ -373,9 +373,9 @@ typedef struct m_snapshot_mrsw_s {
M_ASSERT (s->cptTab != NULL); \
} while (0)
/* Initialize m_snapshot_mrsw_ct for n readers (constructor) */
/* Initialize m_snapsh0t_mrsw_ct for n readers (constructor) */
static inline void
m_snapsh0t_mrsw_init(m_snapshot_mrsw_ct s, size_t n)
m_snapsh0t_mrsw_init(m_snapsh0t_mrsw_ct s, size_t n)
{
M_ASSERT (s != NULL);
M_ASSERT (n >= 1 && n <= M_SNAPSH0T_SPMC_MAX_READER);
@@ -391,35 +391,35 @@ m_snapsh0t_mrsw_init(m_snapshot_mrsw_ct s, size_t n)
s->cptTab = ptr;
for(size_t i = 0; i < n; i++)
atomic_init(&s->cptTab[i], 0U);
genint_init (s->freeList, (unsigned int) n);
m_genint_init (s->freeList, (unsigned int) n);
// Get a free buffer and set it as available for readers
unsigned int w = genint_pop(s->freeList);
M_ASSERT (w != GENINT_ERROR);
unsigned int w = m_genint_pop(s->freeList);
M_ASSERT (w != M_GENINT_ERROR);
atomic_store(&s->cptTab[w], 1U);
atomic_init(&s->lastNext, M_SNAPSH0T_SPMC_INT_FLAG(w, true));
// Get working buffer
s->currentWrite = genint_pop(s->freeList);
M_ASSERT (s->currentWrite != GENINT_ERROR);
s->currentWrite = m_genint_pop(s->freeList);
M_ASSERT (s->currentWrite != M_GENINT_ERROR);
atomic_store(&s->cptTab[s->currentWrite], 1U);
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
}
/* Clear m_snapshot_mrsw_ct (destructor) */
/* Clear m_snapsh0t_mrsw_ct (destructor) */
static inline void
m_snapsh0t_mrsw_clear(m_snapshot_mrsw_ct s)
m_snapsh0t_mrsw_clear(m_snapsh0t_mrsw_ct s)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
M_MEMORY_FREE (s->cptTab);
genint_clear(s->freeList);
m_genint_clear(s->freeList);
s->cptTab = NULL;
s->n_reader = 0;
}
/* Return the current index that is written in the buffer */
static inline unsigned int
m_snapsh0t_mrsw_get_write_idx(m_snapshot_mrsw_ct s)
m_snapsh0t_mrsw_get_write_idx(m_snapsh0t_mrsw_ct s)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
return s->currentWrite;
@@ -427,7 +427,7 @@ m_snapsh0t_mrsw_get_write_idx(m_snapshot_mrsw_ct s)
/* Return the number of readers */
static inline unsigned int
m_snapsh0t_mrsw_size(m_snapshot_mrsw_ct s)
m_snapsh0t_mrsw_size(m_snapsh0t_mrsw_ct s)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
return (unsigned int) s->n_reader;
@@ -436,7 +436,7 @@ m_snapsh0t_mrsw_size(m_snapshot_mrsw_ct s)
/* Give the current index that is written to the readers,
and return new available index for the writer thread */
static inline unsigned int
m_snapsh0t_mrsw_write_idx(m_snapshot_mrsw_ct s, unsigned int idx)
m_snapsh0t_mrsw_write_idx(m_snapsh0t_mrsw_ct s, unsigned int idx)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
@@ -462,8 +462,8 @@ m_snapsh0t_mrsw_write_idx(m_snapshot_mrsw_ct s, unsigned int idx)
if (c != 1) {
// If someone else keeps a ref on the buffer, we can't reuse it
// get another free one.
idx = genint_pop(s->freeList);
M_ASSERT(idx != GENINT_ERROR);
idx = m_genint_pop(s->freeList);
M_ASSERT(idx != M_GENINT_ERROR);
} else {
// No other thread keep track of this buffer.
// Reuse it.
@@ -478,7 +478,7 @@ m_snapsh0t_mrsw_write_idx(m_snapshot_mrsw_ct s, unsigned int idx)
/* Perform a swap of the current write buffer and return a new one */
static inline unsigned int
m_snapsh0t_mrsw_write(m_snapshot_mrsw_ct s)
m_snapsh0t_mrsw_write(m_snapsh0t_mrsw_ct s)
{
s->currentWrite = m_snapsh0t_mrsw_write_idx(s, s->currentWrite);
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
@@ -487,12 +487,12 @@ m_snapsh0t_mrsw_write(m_snapshot_mrsw_ct s)
/* Start writing to the write buffer and return its index */
static inline unsigned int
m_snapsh0t_mrsw_write_start(m_snapshot_mrsw_ct s)
m_snapsh0t_mrsw_write_start(m_snapsh0t_mrsw_ct s)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
// Get a new buffer.
unsigned int idx = genint_pop(s->freeList);
M_ASSERT (idx != GENINT_ERROR);
unsigned int idx = m_genint_pop(s->freeList);
M_ASSERT (idx != M_GENINT_ERROR);
M_ASSERT (idx < s->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER);
M_ASSERT (atomic_load(&s->cptTab[idx]) == 0);
atomic_store(&s->cptTab[idx], 1U);
@@ -502,7 +502,7 @@ m_snapsh0t_mrsw_write_start(m_snapshot_mrsw_ct s)
/* End writing to the given write buffer */
static inline void
m_snapsh0t_mrsw_write_end(m_snapshot_mrsw_ct s, unsigned int idx)
m_snapsh0t_mrsw_write_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
@@ -517,14 +517,14 @@ m_snapsh0t_mrsw_write_end(m_snapshot_mrsw_ct s, unsigned int idx)
unsigned int c = atomic_fetch_sub(&s->cptTab[idx], 1U);
M_ASSERT (c != 0 && c <= s->n_reader + 1);
if (c == 1) {
genint_push(s->freeList, idx);
m_genint_push(s->freeList, idx);
}
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
}
/* Start reading the latest written buffer and return the index to it */
static inline unsigned int
m_snapsh0t_mrsw_read_start(m_snapshot_mrsw_ct s)
m_snapsh0t_mrsw_read_start(m_snapsh0t_mrsw_ct s)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
unsigned int idx, previous;
@@ -558,7 +558,7 @@ m_snapsh0t_mrsw_read_start(m_snapshot_mrsw_ct s)
c = atomic_fetch_sub(&s->cptTab[idx], 1U);
M_ASSERT (c != 0 && c <= s->n_reader + 1);
if (c == 1) {
genint_push(s->freeList, idx);
m_genint_push(s->freeList, idx);
}
}
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
@@ -567,7 +567,7 @@ m_snapsh0t_mrsw_read_start(m_snapshot_mrsw_ct s)
/* End the reading the given buffer */
static inline void
m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
M_ASSERT (idx < s->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER);
@@ -577,7 +577,7 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
if (c == 1) {
// Buffer no longer used by any reader thread.
// Push back index in free list
genint_push(s->freeList, idx);
m_genint_push(s->freeList, idx);
}
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
}
@@ -591,7 +591,7 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
// Defered evaluation
#define M_SNAPSH0T_SPMC_DEF_P1(arg) M_SNAPSH0T_SPMC_DEF_P2 arg
#define M_SNAPSH0T_SPMC_DEF_P1(arg) M_ID( M_SNAPSH0T_SPMC_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_SNAPSH0T_SPMC_DEF_P2(name, type, oplist, snapshot_t) \
@@ -612,7 +612,7 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
\
typedef struct M_C(name, _s) { \
M_C(name, _aligned_type_ct) *data; \
m_snapshot_mrsw_ct core; \
m_snapsh0t_mrsw_ct core; \
} snapshot_t[1]; \
\
/* Define internal types for oplist */ \
@@ -700,7 +700,7 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
// MPMC is built upon SPMC
// Defered evaluation
#define M_SNAPSH0T_MPMC_DEF_P1(arg) M_SNAPSH0T_MPMC_DEF_P2 arg
#define M_SNAPSH0T_MPMC_DEF_P1(arg) M_ID( M_SNAPSH0T_MPMC_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_SNAPSH0T_MPMC_DEF_P2(name, type, oplist, snapshot_t) \
@@ -730,7 +730,7 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
{ \
M_C(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \
unsigned int idx = snap->core->core->currentWrite; \
snap->core->core->currentWrite = GENINT_ERROR; \
snap->core->core->currentWrite = M_GENINT_ERROR; \
m_snapsh0t_mrsw_write_end(snap->core->core, idx); \
} \
\
@@ -778,4 +778,14 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
M_END_PROTECTED_CODE
#if M_USE_SMALL_NAME
#define SNAPSHOT_SPSC_DEF M_SNAPSHOT_SPSC_DEF
#define SNAPSHOT_SPSC_DEF_AS M_SNAPSHOT_SPSC_DEF_AS
#define SNAPSHOT_SPMC_DEF M_SNAPSHOT_SPMC_DEF
#define SNAPSHOT_SPMC_DEF_AS M_SNAPSHOT_SPMC_DEF_AS
#define SNAPSHOT_MPMC_DEF M_SNAPSHOT_MPMC_DEF
#define SNAPSHOT_MPMC_DEF_AS M_SNAPSHOT_MPMC_DEF_AS
#define SNAPSHOT_OPLIST M_SNAPSHOT_OPLIST
#endif
#endif
+809 -513
View File
File diff suppressed because it is too large. Load diff
+1483
View File
File diff suppressed because it is too large. Load diff
+35 -23
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - TUPLE module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -32,15 +32,15 @@
/* Define the tuple type and functions.
USAGE:
TUPLE_DEF2(name, [(field1, type1[, oplist1]), (field2, type2[, oplist2]), ...] ) */
#define TUPLE_DEF2(name, ...) \
TUPLE_DEF2_AS(name, M_C(name,_t), __VA_ARGS__)
#define M_TUPLE_DEF2(name, ...) \
M_TUPLE_DEF2_AS(name, M_C(name,_t), __VA_ARGS__)
/* Define the tuple type and functions
as the given name.
USAGE:
TUPLE_DEF2_AS(name, name_t, [(field1, type1[, oplist1]), (field2, type2[, oplist2]), ...] ) */
#define TUPLE_DEF2_AS(name, name_t, ...) \
#define M_TUPLE_DEF2_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_TUPL3_DEF2_P1( (name, name_t M_TUPL3_INJECT_GLOBAL(__VA_ARGS__)) ) \
M_END_PROTECTED_CODE
@@ -48,9 +48,9 @@
/* Define the oplist of a tuple.
USAGE: TUPLE_OPLIST(name[, oplist of the first type, ...]) */
#define TUPLE_OPLIST(...) \
#define M_TUPLE_OPLIST(...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(M_TUPL3_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST )), \
(M_TUPL3_OPLIST_P1((__VA_ARGS__, M_BASIC_OPLIST )), \
M_TUPL3_OPLIST_P1((__VA_ARGS__ )))
@@ -60,7 +60,7 @@
(shall be constexpr, but only supported in C++14).
*/
#ifndef __cplusplus
#define TUPLE_ORDER(name, ...) \
#define M_TUPLE_ORDER(name, ...) \
( (const int[]) {M_MAP2_C(M_TUPL3_ORDER_CONVERT, name, __VA_ARGS__), 0})
#else
#include <initializer_list>
@@ -76,7 +76,7 @@ namespace m_lib {
}
};
}
#define TUPLE_ORDER(name, ...) \
#define M_TUPLE_ORDER(name, ...) \
(m_lib::m_tupl3_integer_va<M_NARGS(__VA_ARGS__,0)>({M_MAP2_C(M_TUPL3_ORDER_CONVERT, name, __VA_ARGS__), 0}).data)
#endif
@@ -93,7 +93,7 @@ namespace m_lib {
M_MAP(M_TUPL3_INJECT_OPLIST_A, __VA_ARGS__)
/* Transform (x, type) into (x, type, oplist) if there is global registered oplist
or (x, type, M_DEFAULT_OPLIST) if there is no global one,
or (x, type, M_BASIC_OPLIST) if there is no global one,
or keep (x, type, oplist) if oplist was already present */
#define M_TUPL3_INJECT_OPLIST_A( duo_or_trio ) \
M_TUPL3_INJECT_OPLIST_B duo_or_trio
@@ -103,7 +103,7 @@ namespace m_lib {
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
// Deferred evaluation
#define M_TUPL3_DEF2_P1(...) M_TUPL3_DEF2_P2 __VA_ARGS__
#define M_TUPL3_DEF2_P1(...) M_ID( M_TUPL3_DEF2_P2 __VA_ARGS__ )
// Test if all third argument of all arguments is an oplist
#define M_TUPL3_IF_ALL_OPLIST(...) \
@@ -212,7 +212,12 @@ namespace m_lib {
/* Save constant as the number of arguments (internal) */ \
typedef enum { \
M_C3(m_tupl3_, name, _num_args) = M_NARGS(__VA_ARGS__) \
} M_C3(m_tupl3_, name, _num_args_ct);
} M_C3(m_tupl3_, name, _num_args_ct); \
/* Save alias for the types of arguments */ \
M_MAP3(M_TUPL3_DEFINE_TYPE_ELE, name, __VA_ARGS__)
#define M_TUPL3_DEFINE_TYPE_ELE(name, num, a) \
typedef M_TUPL3_GET_TYPE a M_C4(name, _type_, num, _ct);
#define M_TUPL3_DEFINE_RECUR_TYPE_ELE(a) \
M_TUPL3_GET_TYPE a M_TUPL3_GET_FIELD a ;
@@ -394,15 +399,15 @@ namespace m_lib {
#define M_TUPL3_MAP_CMP_FIELD(name, a) \
M_IF_METHOD(CMP, M_TUPL3_GET_OPLIST a)( \
M_TUPL3_DEFINE_CMP_FIELD_FUNC(name, M_TUPL3_GET_FIELD a, M_TUPL3_GET_CMP a), \
M_TUPL3_DEFINE_CMP_FIELD_FUNC(name, M_TUPL3_GET_FIELD a, M_TUPL3_GET_CMP a, M_TUPL3_GET_OPLIST a), \
)
#define M_TUPL3_DEFINE_CMP_FIELD_FUNC(name, field, func_cmp) \
#define M_TUPL3_DEFINE_CMP_FIELD_FUNC(name, field, func_cmp, oplist) \
static inline int M_C3(name, _cmp_, field)(M_C(name,_ct) const e1 , \
M_C(name,_ct) const e2) { \
M_TUPL3_CONTRACT(e1); \
M_TUPL3_CONTRACT(e2); \
return func_cmp ( e1 -> field , e2 -> field ); \
return M_APPLY_API(func_cmp, oplist, e1 -> field , e2 -> field ); \
}
@@ -441,19 +446,19 @@ namespace m_lib {
/* Define a GET_STR method by calling the GET_STR methods for all params */
#define M_TUPL3_DEFINE_GET_STR(name, ...) \
static inline void M_C(name, _get_str)(string_t str, \
static inline void M_C(name, _get_str)(m_string_t str, \
M_C(name,_ct) const el, \
bool append) { \
bool comma = false; \
M_TUPL3_CONTRACT(el); \
M_ASSERT (str != NULL); \
(append ? string_cat_str : string_set_str) (str, "("); \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "("); \
M_MAP(M_TUPL3_DEFINE_GET_STR_FUNC , __VA_ARGS__) \
string_push_back (str, ')'); \
m_string_push_back (str, ')'); \
}
#define M_TUPL3_DEFINE_GET_STR_FUNC(a) \
if (comma) string_push_back (str, ','); \
if (comma) m_string_push_back (str, ','); \
comma = true; \
M_TUPL3_CALL_GET_STR(a, str, el -> M_TUPL3_GET_FIELD a, true); \
@@ -633,17 +638,13 @@ namespace m_lib {
M_TUPL3_CONTRACT(el1); \
M_MAP(M_TUPL3_DEFINE_RESET_FUNC , __VA_ARGS__) \
} \
static inline void M_ATTR_DEPRECATED \
M_C(name, _clean)(M_C(name,_ct) el1) { \
M_C(name, _reset)(el1); \
}
#define M_TUPL3_DEFINE_RESET_FUNC(a) \
M_TUPL3_CALL_RESET(a, el1 -> M_TUPL3_GET_FIELD a);
/* INIT_WITH macro enabling recursive INIT_WITH initialization
tuple = { int, string_t, array<string_t> }
tuple = { int, m_string_t, array<m_string_t> }
USAGE:
M_LET( (x, 2, ("John"), ( ("Bear"), ("Rabbit") )), tuple_t)
@@ -740,7 +741,18 @@ namespace m_lib {
M_IF_METHOD(NEW, M_RET_ARG1(__VA_ARGS__,))(NEW(M_DELAY2(M_GET_NEW) M_RET_ARG1(__VA_ARGS__,)),), \
M_IF_METHOD(REALLOC, M_RET_ARG1(__VA_ARGS__,))(REALLOC(M_DELAY2(M_GET_REALLOC) M_RET_ARG1(__VA_ARGS__,)),), \
M_IF_METHOD(DEL, M_RET_ARG1(__VA_ARGS__,))(DEL(M_DELAY2(M_GET_DEL) M_RET_ARG1(__VA_ARGS__,)),), \
EMPLACE_TYPE( ( M_REDUCE2(M_TUPL3_OPLIST_SUBTYPE, M_ID, name, M_SEQ(1, M_NARGS(__VA_ARGS__))) ) ) \
)
/* Support for EMPLACE_TYPE in OPLIST. It refers the created internal type alias */
#define M_TUPL3_OPLIST_SUBTYPE(name, num) \
M_C4(name, _type_, num, _ct)
#if M_USE_SMALL_NAME
#define TUPLE_DEF2 M_TUPLE_DEF2
#define TUPLE_DEF2_AS M_TUPLE_DEF2_AS
#define TUPLE_OPLIST M_TUPLE_OPLIST
#define TUPLE_ORDER M_TUPLE_ORDER
#endif
#endif
+52 -17
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - VARIANT module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -33,15 +33,15 @@
/* Define the variant type and functions.
USAGE:
VARIANT_DEF2(name, [(field1, type1, oplist1), (field2, type2, oplist2), ...] ) */
#define VARIANT_DEF2(name, ...) \
VARIANT_DEF2_AS(name, M_C(name,_t), __VA_ARGS__)
#define M_VARIANT_DEF2(name, ...) \
M_VARIANT_DEF2_AS(name, M_C(name,_t), __VA_ARGS__)
/* Define the variant type and functions
as the given name_t
USAGE:
VARIANT_DEF2_AS(name, name_t, [(field1, type1, oplist1), (field2, type2, oplist2), ...] ) */
#define VARIANT_DEF2_AS(name, name_t, ...) \
#define M_VARIANT_DEF2_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_VAR1ANT_DEF2_P1( (name, name_t M_VAR1ANT_INJECT_GLOBAL(__VA_ARGS__)) ) \
M_END_PROTECTED_CODE
@@ -49,9 +49,9 @@
/* Define the oplist of a variant.
USAGE: VARIANT_OPLIST(name[, oplist of the first type, ...]) */
#define VARIANT_OPLIST(...) \
#define M_VARIANT_OPLIST(...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(M_VAR1ANT_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST)), \
(M_VAR1ANT_OPLIST_P1((__VA_ARGS__, M_BASIC_OPLIST)), \
M_VAR1ANT_OPLIST_P1((__VA_ARGS__ )))
@@ -69,7 +69,7 @@
M_MAP(M_VAR1ANT_INJECT_OPLIST_A, __VA_ARGS__)
/* Transform (x, type) into (x, type, oplist) if there is global registered oplist
or (x, type, M_DEFAULT_OPLIST) if there is no global one,
or (x, type, M_BASIC_OPLIST) if there is no global one,
or keep (x, type, oplist) if oplist was already present */
#define M_VAR1ANT_INJECT_OPLIST_A( duo_or_trio ) \
M_VAR1ANT_INJECT_OPLIST_B duo_or_trio
@@ -79,7 +79,7 @@
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
// Deferred evaluation
#define M_VAR1ANT_DEF2_P1(...) M_VAR1ANT_DEF2_P2 __VA_ARGS__
#define M_VAR1ANT_DEF2_P1(...) M_ID( M_VAR1ANT_DEF2_P2 __VA_ARGS__ )
// Test if all third argument of all arguments is an oplist
#define M_VAR1ANT_IF_ALL_OPLIST(...) \
@@ -105,6 +105,7 @@
M_VAR1ANT_DEFINE_CLEAR(name, __VA_ARGS__) \
M_VAR1ANT_DEFINE_INIT_SET(name, __VA_ARGS__) \
M_VAR1ANT_DEFINE_SET(name, __VA_ARGS__) \
M_VAR1ANT_DEFINE_EMPLACE(name, __VA_ARGS__) \
M_VAR1ANT_DEFINE_TEST_P(name, __VA_ARGS__) \
M_VAR1ANT_IF_ALL(INIT, __VA_ARGS__) \
(M_VAR1ANT_DEFINE_INIT_FIELD(name, __VA_ARGS__),) \
@@ -383,6 +384,39 @@
}
/* Define the EMPLACE of a given type function.
NOTE: Use of a variant of MAP3 because of recursive use of MAP2/MAP3/REDUCE2 !
*/
#define M_VAR1ANT_DEFINE_EMPLACE(name, ...) \
M_VAR1ANT_MAP3_ALT(M_VAR1ANT_DEFINE_EMPLACE_FUNC, name, __VA_ARGS__)
// Variant of M_MAP3 using M_REDUCE3
#define M_VAR1ANT_MAP3_ALT(f, d, ...) M_REDUCE3(f, M_VAR1ANT_MAP3_ALT_ID, d, __VA_ARGS__)
#define M_VAR1ANT_MAP3_ALT_ID(a, b) a b
#define M_VAR1ANT_DEFINE_EMPLACE_FUNC(name, num, a) \
M_EMPLACE_QUEUE_DEF( (name, M_VAR1ANT_GET_FIELD a), M_C(name,_ct), M_C3(name, _init_emplace_, M_VAR1ANT_GET_FIELD a), M_VAR1ANT_GET_OPLIST a, M_VAR1ANT_DEFINE_INIT_EMPLACE_DEF) \
M_EMPLACE_QUEUE_DEF( (name, M_VAR1ANT_GET_FIELD a), M_C(name,_ct), M_C3(name, _emplace_, M_VAR1ANT_GET_FIELD a), M_VAR1ANT_GET_OPLIST a, M_VAR1ANT_DEFINE_EMPLACE_DEF)
#define M_VAR1ANT_DEFINE_INIT_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
static inline void \
function_name(name_t my \
M_EMPLACE_LIST_TYPE_VAR(ab, exp_emplace_type) ) \
{ \
my->type = M_C4(M_PAIR_1 name, _, M_PAIR_2 name, _value); \
M_EMPLACE_CALL_FUNC(ab, init_func, oplist, my -> value. M_PAIR_2 name, exp_emplace_type); \
} \
#define M_VAR1ANT_DEFINE_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
static inline void \
function_name(name_t my \
M_EMPLACE_LIST_TYPE_VAR(ab, exp_emplace_type) ) \
{ \
/* No optimization done */ \
M_C(M_PAIR_1 name, _clear)(my); \
my->type = M_C4(M_PAIR_1 name, _, M_PAIR_2 name, _value); \
M_EMPLACE_CALL_FUNC(ab, init_func, oplist, my -> value. M_PAIR_2 name, exp_emplace_type); \
} \
/* Define the EQUAL_P function. */
#define M_VAR1ANT_DEFINE_EQUAL(name, ...) \
static inline bool M_C(name, _equal_p)(M_C(name,_ct) const e1 , \
@@ -517,19 +551,19 @@
/* Define the GET_STR function */
#define M_VAR1ANT_DEFINE_GET_STR(name, ...) \
static inline void M_C(name, _get_str)(string_t str, \
static inline void M_C(name, _get_str)(m_string_t str, \
M_C(name,_ct) const el, \
bool append) { \
M_VAR1ANT_CONTRACT(name, el); \
M_ASSERT (str != NULL); \
void (*func)(string_t, const char *); \
func = append ? string_cat_str : string_set_str; \
void (*func)(m_string_t, const char *); \
func = append ? m_string_cat_cstr : m_string_set_cstr; \
switch (el->type) { \
case M_C(name, _EMPTY): func(str, "@EMPTY@"); break; \
M_MAP2(M_VAR1ANT_DEFINE_GET_STR_FUNC , name, __VA_ARGS__) \
default: M_ASSERT(false); break; \
} \
string_push_back (str, '@'); \
m_string_push_back (str, '@'); \
}
#define M_VAR1ANT_DEFINE_GET_STR_FUNC(name, a) \
@@ -718,11 +752,6 @@
M_C(name, _clear)(my); \
M_C(name, _init)(my); \
} \
static inline void M_ATTR_DEPRECATED \
M_C(name, _clean)(M_C(name,_ct) my) \
{ \
M_C(name, _reset)(my); \
}
/* deferred evaluation of the oplist */
#define M_VAR1ANT_OPLIST_P1(arg) M_VAR1ANT_OPLIST_P2 arg
@@ -776,4 +805,10 @@
#define M_VAR1ANT_IF_ALL2(method1, method2, ...) \
M_IF(M_REDUCE2(M_VAR1ANT_TEST_METHOD2_P, M_AND, (method1, method2), __VA_ARGS__))
#if M_USE_SMALL_NAME
#define VARIANT_DEF2 M_VARIANT_DEF2
#define VARIANT_DEF2_AS M_VARIANT_DEF2_AS
#define VARIANT_OPLIST M_VARIANT_OPLIST
#endif
#endif
+108 -90
View File
@@ -1,7 +1,7 @@
/*
* M*LIB / WORKER - Extra worker interface
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -40,7 +40,7 @@
#include "m-buffer.h"
#include "m-mutex.h"
/* Include needed system header for detection of how many core on the system */
/* Include needed system header for detection of how many cores are available in the system */
#if defined(_WIN32)
# include <windows.h>
#elif (defined(__APPLE__) && defined(__MACH__)) \
@@ -96,8 +96,8 @@
M_BEGIN_PROTECTED_CODE
/* Definition of a work order */
typedef struct work_order_s {
struct worker_sync_s *block; // Reference to the shared Synchronization block
typedef struct m_work3r_order_s {
struct m_worker_sync_s *block; // Reference to the shared Synchronization block
void * data; // The work order data
void (*func) (void *data); // The work order function (for GCC)
#if M_USE_WORKER_CLANG_BLOCK
@@ -106,7 +106,7 @@ typedef struct work_order_s {
#if M_USE_WORKER_CPP_FUNCTION
std::function<void(void*)> function; // The work order function (for C++)
#endif
} worker_order_ct;
} m_work3r_order_ct;
/* Define the macros needed to initialize an order.
* * MACRO to be used to send an empty order to stop the thread
@@ -120,38 +120,38 @@ typedef struct work_order_s {
# define M_WORK3R_EXTRA_ORDER
#endif
/* As in C++, it uses std::function, M_POD_OPLIST
/* As it is C++, it uses std::function, M_POD_OPLIST
is not sufficient for initialization of the structure.
So let's use C++ constructor, destructor and copy constructor */
#if M_USE_WORKER_CPP_FUNCTION
# define M_WORK3R_CPP_INIT(x) (new (&(x)) worker_order_ct())
# define M_WORK3R_CPP_INIT_SET(x, y) (new (&(x)) worker_order_ct(y))
# define M_WORK3R_CPP_SET(x, y) ((x) = (y))
# define M_WORK3R_CPP_CLEAR(x) ((&(x))->~worker_order_ct())
# define M_WORK3R_CPP_INIT_MOVE(x,y) (new (&(x)) worker_order_ct(y), ((&(y))->~worker_order_ct()))
# define WORKER_OPLIST \
# define M_WORK3R_CPP_INIT(x) (new (&(x)) m_work3r_order_ct())
# define M_WORK3R_CPP_INIT_SET(x, y) (new (&(x)) m_work3r_order_ct(y))
# define M_WORK3R_CPP_SET(x, y) ((x) = (y))
# define M_WORK3R_CPP_CLEAR(x) ((&(x))->~m_work3r_order_ct())
# define M_WORK3R_CPP_INIT_MOVE(x,y) (new (&(x)) m_work3r_order_ct(y), ((&(y))->~m_work3r_order_ct()))
# define M_WORK3R_OPLIST \
(INIT(M_WORK3R_CPP_INIT), INIT_SET(M_WORK3R_CPP_INIT_SET), \
SET(M_WORK3R_CPP_SET), CLEAR(M_WORK3R_CPP_CLEAR), INIT_MOVE(M_WORK3R_CPP_INIT_MOVE) )
#else
# define WORKER_OPLIST M_POD_OPLIST
# define M_WORK3R_OPLIST M_POD_OPLIST
#endif
/* Definition of a worker (implemented by a thread) */
typedef struct worker_thread_s {
/* Definition of the identity of a worker thread */
typedef struct m_work3r_thread_s {
m_thread_t id;
} worker_thread_ct;
} m_work3r_thread_ct;
/* Definition of the queue that will record the work orders */
BUFFER_DEF_AS(worker_queue, m_worker_queue_ct, worker_order_ct, 0,
BUFFER_QUEUE|BUFFER_UNBLOCKING_PUSH|BUFFER_BLOCKING_POP|BUFFER_THREAD_SAFE|BUFFER_DEFERRED_POP, WORKER_OPLIST)
BUFFER_DEF(m_work3r_queue, m_work3r_order_ct, 0,
BUFFER_QUEUE|BUFFER_UNBLOCKING_PUSH|BUFFER_BLOCKING_POP|BUFFER_THREAD_SAFE|BUFFER_DEFERRED_POP, M_WORK3R_OPLIST)
/* Definition the global pool of workers */
typedef struct worker_s {
typedef struct m_worker_s {
/* The work order queue */
m_worker_queue_ct queue_g;
m_work3r_queue_t queue_g;
/* The table of available workers */
worker_thread_ct *worker;
m_work3r_thread_ct *worker;
/* Number of workers in the table */
unsigned int numWorker_g;
@@ -165,18 +165,18 @@ typedef struct worker_s {
m_mutex_t lock;
m_cond_t a_thread_ends; // EVENT: A worker has ended
} worker_t[1];
} m_worker_t[1];
/* Definition of the synchronization point for workers */
typedef struct worker_sync_s {
typedef struct m_worker_sync_s {
atomic_int num_spawn; // Number of spawned workers accord this synchronization point
atomic_int num_terminated_spawn; // Number of terminated spawned workers
struct worker_s *worker; // Reference to the pool of workers
} worker_sync_t[1];
struct m_worker_s *worker; // Reference to the pool of workers
} m_worker_sync_t[1];
/* Return the number of CPU of the system */
/* Return the number of cores available in the system */
static inline int
workeri_get_cpu_count(void)
m_work3r_get_cpu_count(void)
{
#if defined(_WIN32)
SYSTEM_INFO sysinfo;
@@ -207,7 +207,7 @@ workeri_get_cpu_count(void)
/* Execute the registered work order **synchronously** */
static inline void
workeri_exec(worker_order_ct *w)
m_work3r_exec(m_work3r_order_ct *w)
{
M_ASSERT (w!= NULL && w->block != NULL);
M_WORK3R_DEBUG ("Starting thread with data %p\n", w->data);
@@ -231,28 +231,28 @@ workeri_exec(worker_order_ct *w)
/* The worker thread main loop*/
static inline void
workeri_thread(void *arg)
m_work3r_thread(void *arg)
{
// Get back the given argument
struct worker_s *g = M_ASSIGN_CAST(struct worker_s *, arg);
struct m_worker_s *g = M_ASSIGN_CAST(struct m_worker_s *, arg);
while (true) {
worker_order_ct w;
m_work3r_order_ct w;
// If needed, reset the global state of the worker
if (g->resetFunc_g != NULL) {
g->resetFunc_g();
}
// Waiting for data
M_WORK3R_DEBUG ("Waiting for data (queue: %lu / %lu)\n", worker_queue_size(g->queue_g), worker_queue_capacity(g->queue_g));
worker_queue_pop(&w, g->queue_g);
M_WORK3R_DEBUG ("Waiting for data (queue: %lu / %lu)\n", m_work3r_queue_size(g->queue_g), m_work3r_queue_capacity(g->queue_g));
m_work3r_queue_pop(&w, g->queue_g);
// We received a work order
// Note: that the work order is still present in the queue
// preventing further work order to be pushed in the queue until it finishes doing the work
// If a stop request is received, terminate the thread
if (w.block == NULL) break;
// Execute the work order
workeri_exec(&w);
m_work3r_exec(&w);
// Consumme fully the work order in the queue
worker_queue_pop_release(g->queue_g);
m_work3r_queue_pop_release(g->queue_g);
// Signal that a worker has finished.
m_mutex_lock(g->lock);
m_cond_broadcast(g->a_thread_ends);
@@ -272,23 +272,23 @@ workeri_thread(void *arg)
@clearFunc: function to clear the state of a worker before terminaning (or NULL if none)
*/
static inline void
worker_init(worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
{
M_ASSERT (numWorker >= -1);
// Auto compute number of workers if the argument is 0
if (numWorker <= 0)
numWorker = (1 + (numWorker == -1))*workeri_get_cpu_count()-1;
numWorker = (1 + (numWorker == -1))*m_work3r_get_cpu_count()-1;
M_WORK3R_DEBUG ("Starting queue with: %d\n", numWorker + extraQueue);
// Initialization
// numWorker can still be 0 if it is a single core cpu (no worker available)
M_ASSERT(numWorker >= 0);
size_t numWorker_st = (size_t) numWorker;
g->worker = M_MEMORY_REALLOC(worker_thread_ct, NULL, numWorker_st);
g->worker = M_MEMORY_REALLOC(m_work3r_thread_ct, NULL, numWorker_st);
if (g->worker == NULL) {
M_MEMORY_FULL(sizeof (worker_thread_ct) * numWorker_st);
M_MEMORY_FULL(sizeof (m_work3r_thread_ct) * numWorker_st);
return;
}
worker_queue_init(g->queue_g, numWorker_st + extraQueue);
m_work3r_queue_init(g->queue_g, numWorker_st + extraQueue);
g->numWorker_g = (unsigned int) numWorker_st;
g->resetFunc_g = resetFunc;
g->clearFunc_g = clearFunc;
@@ -297,30 +297,31 @@ worker_init(worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc
// Create & start the workers
for(size_t i = 0; i < numWorker_st; i++) {
m_thread_create(g->worker[i].id, workeri_thread, M_ASSIGN_CAST(void*, g));
m_thread_create(g->worker[i].id, m_work3r_thread, M_ASSIGN_CAST(void*, g));
}
}
/* Initialization of the worker module (constructor)
Provide default values for the arguments.
Input:
@numWorker: number of worker to create (0=autodetect, -1=2*autodetect)
@extraQueue: number of extra work order we can get if all workers are full
@resetFunc: function to reset the state of a worker between work orders (optional)
@clearFunc: function to clear the state of a worker before terminaning (optional)
*/
#define worker_init(...) worker_init(M_DEFAULT_ARGS(5, (0, 0, NULL, NULL), __VA_ARGS__))
#define m_worker_init(...) m_worker_init(M_DEFAULT_ARGS(5, (0, 0, NULL, NULL), __VA_ARGS__))
/* Clear of the worker module (destructor) */
static inline void
worker_clear(worker_t g)
m_worker_clear(m_worker_t g)
{
M_ASSERT (worker_queue_empty_p (g->queue_g));
M_ASSERT (m_work3r_queue_empty_p (g->queue_g));
// Push the terminate order on the queue
for(unsigned int i = 0; i < g->numWorker_g; i++) {
worker_order_ct w = M_WORK3R_EMPTY_ORDER;
m_work3r_order_ct w = M_WORK3R_EMPTY_ORDER;
// Normaly all worker threads shall be waiting at this
// stage, so all push won't block as the queue is empty.
// But for robustness, let's wait.
worker_queue_push_blocking (g->queue_g, w, true);
m_work3r_queue_push_blocking (g->queue_g, w, true);
}
// Wait for thread terminanison
for(unsigned int i = 0; i < g->numWorker_g; i++) {
@@ -330,13 +331,13 @@ worker_clear(worker_t g)
M_MEMORY_FREE(g->worker);
m_mutex_clear(g->lock);
m_cond_clear(g->a_thread_ends);
worker_queue_clear(g->queue_g);
m_work3r_queue_clear(g->queue_g);
}
/* Start a new collaboration between workers of pool 'g'
by defining the synchronization point 'block' */
static inline void
worker_start(worker_sync_t block, worker_t g)
m_worker_start(m_worker_sync_t block, m_worker_t g)
{
atomic_init (&block->num_spawn, 0);
atomic_init (&block->num_terminated_spawn, 0);
@@ -349,11 +350,11 @@ worker_start(worker_sync_t block, worker_t g)
The work order if composed of the function 'func' and its 'data'
*/
static inline void
worker_spawn(worker_sync_t block, void (*func)(void *data), void *data)
m_worker_spawn(m_worker_sync_t block, void (*func)(void *data), void *data)
{
const worker_order_ct w = { block, data, func M_WORK3R_EXTRA_ORDER };
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
&& worker_queue_push (block->worker->queue_g, w) == true) {
const m_work3r_order_ct w = { block, data, func M_WORK3R_EXTRA_ORDER };
if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g))
&& m_work3r_queue_push (block->worker->queue_g, w) == true) {
M_WORK3R_DEBUG ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
atomic_fetch_add (&block->num_spawn, 1);
return;
@@ -367,11 +368,11 @@ worker_spawn(worker_sync_t block, void (*func)(void *data), void *data)
/* Spawn or not the given work order to workers,
or do it ourself if no worker is available */
static inline void
worker_spawn_block(worker_sync_t block, void (^func)(void *data), void *data)
m_work3r_spawn_block(m_worker_sync_t block, void (^func)(void *data), void *data)
{
const worker_order_ct w = { block, data, NULL, func };
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
&& worker_queue_push (block->worker->queue_g, w) == true) {
const m_work3r_order_ct w = { block, data, NULL, func };
if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g))
&& m_work3r_queue_push (block->worker->queue_g, w) == true) {
M_WORK3R_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
atomic_fetch_add (&block->num_spawn, 1);
return;
@@ -386,11 +387,11 @@ worker_spawn_block(worker_sync_t block, void (^func)(void *data), void *data)
/* Spawn or not the given work order to workers,
or do it ourself if no worker is available */
static inline void
worker_spawn_function(worker_sync_t block, std::function<void(void *data)> func, void *data)
m_work3r_spawn_function(m_worker_sync_t block, std::function<void(void *data)> func, void *data)
{
const worker_order_ct w = { block, data, NULL, func };
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
&& worker_queue_push (block->worker->queue_g, w) == true) {
const m_work3r_order_ct w = { block, data, NULL, func };
if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g))
&& m_work3r_queue_push (block->worker->queue_g, w) == true) {
M_WORK3R_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
atomic_fetch_add (&block->num_spawn, 1);
return;
@@ -403,7 +404,7 @@ worker_spawn_function(worker_sync_t block, std::function<void(void *data)> func,
/* Test if all work orders of the given synchronization point are finished */
static inline bool
worker_sync_p(worker_sync_t block)
m_worker_sync_p(m_worker_sync_t block)
{
/* If the number of spawns is greated than the number
of terminated spawns, some spawns are still working.
@@ -413,14 +414,14 @@ worker_sync_p(worker_sync_t block)
/* Wait for all work orders of the given synchronization point to be finished */
static inline void
worker_sync(worker_sync_t block)
m_worker_sync(m_worker_sync_t block)
{
M_WORK3R_DEBUG ("Waiting for thread terminasion.\n");
// Fast case: all workers have finished
if (worker_sync_p(block)) return;
if (m_worker_sync_p(block)) return;
// Slow case: perform a locked wait to put this thread to waiting state
m_mutex_lock(block->worker->lock);
while (!worker_sync_p(block)) {
while (!m_worker_sync_p(block)) {
m_cond_wait(block->worker->a_thread_ends, block->worker->lock);
}
m_mutex_unlock(block->worker->lock);
@@ -428,19 +429,19 @@ worker_sync(worker_sync_t block)
/* Flush any work order in the queue ourself if some remains.*/
static inline void
worker_flush(worker_t g)
m_worker_flush(m_worker_t g)
{
worker_order_ct w;
while (worker_queue_pop_blocking (&w, g->queue_g, false) == true) {
workeri_exec(&w);
worker_queue_pop_release(g->queue_g);
m_work3r_order_ct w;
while (m_work3r_queue_pop_blocking (&w, g->queue_g, false) == true) {
m_work3r_exec(&w);
m_work3r_queue_pop_release(g->queue_g);
}
}
/* Return the number of workers */
static inline size_t
worker_count(worker_t g)
m_worker_count(m_worker_t g)
{
return g->numWorker_g + 1;
}
@@ -454,24 +455,24 @@ worker_count(worker_t g)
TODO: Support oplist for input & outputs parameters
*/
#if M_USE_WORKER_CLANG_BLOCK
#define WORKER_SPAWN(_block, _input, _core, _output) \
#define M_WORKER_SPAWN(_block, _input, _core, _output) \
M_WORK3R_DEF_DATA(_input, _output) \
M_WORK3R_DEF_SUBBLOCK(_input, _output, _core) \
worker_spawn_block ((_block), M_WORK3R_SPAWN_SUBFUNC_NAME, &M_WORK3R_SPAWN_DATA_NAME)
m_work3r_spawn_block ((_block), M_WORK3R_SPAWN_SUBFUNC_NAME, &M_WORK3R_SPAWN_DATA_NAME)
#elif M_USE_WORKER_CPP_FUNCTION
// TODO: Explicit pass all arguments by reference.
#define WORKER_SPAWN(_block, _input, _core, _output) \
worker_spawn_function ((_block), [&](void *param) {(void)param ; _core } , NULL)
#define M_WORKER_SPAWN(_block, _input, _core, _output) \
m_work3r_spawn_function ((_block), [&](void *param) {(void)param ; _core } , NULL)
#else
#define WORKER_SPAWN(_block, _input, _core, _output) \
#define M_WORKER_SPAWN(_block, _input, _core, _output) \
M_WORK3R_DEF_DATA(_input, _output) \
M_WORK3R_DEF_SUBFUNC(_input, _output, _core) \
worker_spawn ((_block), M_WORK3R_SPAWN_SUBFUNC_NAME, &M_WORK3R_SPAWN_DATA_NAME)
m_worker_spawn ((_block), M_WORK3R_SPAWN_SUBFUNC_NAME, &M_WORK3R_SPAWN_DATA_NAME)
#endif
#define M_WORK3R_SPAWN_STRUCT_NAME M_C(worker_data_s_, __LINE__)
#define M_WORK3R_SPAWN_DATA_NAME M_C(worker_data_, __LINE__)
#define M_WORK3R_SPAWN_SUBFUNC_NAME M_C(worker_subfunc_, __LINE__)
#define M_WORK3R_SPAWN_STRUCT_NAME M_C(m_work3r_data_s_, __LINE__)
#define M_WORK3R_SPAWN_DATA_NAME M_C(m_work3r_data_, __LINE__)
#define M_WORK3R_SPAWN_SUBFUNC_NAME M_C(m_work3r_subfunc_, __LINE__)
#define M_WORK3R_DEF_DATA(_input, _output) \
struct M_WORK3R_SPAWN_STRUCT_NAME { \
M_WORK3R_DEF_DATA_INPUT _input \
@@ -533,22 +534,39 @@ M_END_PROTECTED_CODE
/* Define empty types and empty functions to not use any worker */
typedef struct worker_block_s {
typedef struct m_worker_block_s {
int x;
} worker_sync_t[1];
} m_worker_sync_t[1];
typedef struct worker_s {
typedef struct m_worker_s {
int x;
} worker_t[1];
} m_worker_t[1];
#define worker_init(g, numWorker, extraQueue, resetFunc) do { (void) g; } while (0)
#define worker_clear(g) do { (void) g; } while (0)
#define worker_start(b, w) do { (void) b; } while (0)
#define worker_spawn(b, f, d) do { f(d); } while (0)
#define worker_sync(b) do { (void) b; } while (0)
#define worker_count(w) 1
#define WORKER_SPAWN(b, i, c, o) do { c } while (0)
#define m_worker_init(g, numWorker, extraQueue, resetFunc) do { (void) g; } while (0)
#define m_worker_clear(g) do { (void) g; } while (0)
#define m_worker_start(b, w) do { (void) b; } while (0)
#define m_worker_spawn(b, f, d) do { f(d); } while (0)
#define m_worker_sync_p(b) true
#define m_worker_sync(b) do { (void) b; } while (0)
#define m_worker_count(w) 1
#define m_worker_flush(w) do { (void) w; } while (0)
#define M_WORKER_SPAWN(b, i, c, o) do { c } while (0)
#endif /* M_USE_WORKER */
#if M_USE_SMALL_NAME
#define worker_t m_worker_t
#define worker_sync_t m_worker_sync_t
#define worker_init m_worker_init
#define worker_clear m_worker_clear
#define worker_start m_worker_start
#define worker_spawn m_worker_spawn
#define worker_sync_p m_worker_sync_p
#define worker_sync m_worker_sync
#define worker_count m_worker_count
#define worker_flush m_worker_flush
#define WORKER_SPAWN M_WORKER_SPAWN
#endif
#endif
+9 -2
View File
@@ -1,4 +1,4 @@
REM Copyright (c) 2017-2021, Patrick Pelissier
REM Copyright (c) 2017-2022, Patrick Pelissier
REM All rights reserved.
REM
REM Redistribution and use in source and binary forms, with or without
@@ -22,7 +22,7 @@ REM SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REM Execute the test suite for Microsoft Visual Studio
REM
REM Load Micosoft Visual Studio environement file.
REM Load Micosoft Visual Studio environement file (2019 or 2022)
IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" (
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
)
@@ -30,6 +30,13 @@ IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxi
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
)
IF EXIST "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" (
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
)
IF EXIST "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" (
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
)
REM Add clang-cl in the PATH. It is the default install of clang for MSVC:
REM %VCINSTALLDIR%\Tools\Llvm\bin;%VCINSTALLDIR%\Tools\Llvm\x64\bin
REM Adding x64 version
+25 -10
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2017-2021, Patrick Pelissier
# Copyright (c) 2017-2022, Patrick Pelissier
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,7 @@ all:
.POSIX:
.PHONY: scan-build sanitize check clean *.log coverage synthesis
.SUFFIXES:
.SUFFIXES: .c .exe .log .depend .gcov .analyzer .cpp
.SUFFIXES: .c .exe .log .depend .gcov .analyzer .cpp .fuzz
.SECONDARY:
.c.exe:
@@ -68,13 +68,19 @@ all:
awk ' printit { print } /END_COVERAGE/ { printit=1}' $< > $<.end.c
$(CC) $(CPPFLAGS) -E -DNDEBUG -DWITHIN_COVERAGE $< |grep -v '^#' |awk ' /END_COVERAGE/ { printit=0} printit { print } /START_COVERAGE/ { printit=1 }' |perl -p -e "s/;(?![\"'])/;\n/g ; s/}(?![\"'])/}\n/g ; s/{(?![\"'])/{\n/g" > $<.middle.c
cat $<.first.c $<.middle.c $<.end.c > $<.c
$(CC) $(CPPFLAGS) $(LDFLAGS) -ftest-coverage -fprofile-arcs -g $<.c -o $<.exe
$(CC) $(CPPFLAGS) $(LDFLAGS) -ftest-coverage -fprofile-arcs -O -g $<.c -o $<.exe
$(LOG_COMPILER) ./$<.exe
LANG=C gcov $<.gcno > `basename $< .c`.synt
cat `basename $< .c`.synt
mv $<.c.gcov `basename $< .c`.gcov
$(RM) $<.first.c $<.end.c $<.middle.c $<.c $<.exe
.cpp.fuzz:
afl-g++ $(WCFLAGS_CPP) $(CPPFLAGS) -Wno-sign-conversion -Wno-inline -Wno-conversion -O2 -fsanitize=address,undefined,leak -m32 $< -o $@.exe
mkdir -p fuzzer-testsuite
for i in $$(seq 1 1000) ; do printf "%d " $$RANDOM ; done > fuzzer-testsuite/t1
afl-fuzz -i fuzzer-testsuite/ -o fuzzer-findings -m 800 ./$@.exe -1
-include depend
depend:
@@ -87,7 +93,7 @@ depend:
#####################################################################################################
# Clean
# Main target
#####################################################################################################
# This target generates all executable to be tested by CodeQL
@@ -107,6 +113,7 @@ clean:
$(RM) *.exe *.s *~ *.o *.log a*.dat
$(RM) *.gcda *.gcno *.gcov all.info test.tar *.synt clang_output_* *.c.c *.end.c *.first.c *.middle.c *.analyzer
$(RMDIR) coverage coverage-dir mlib-report
$(RMDIR) fuzzer-testsuite fuzzer-findings
distclean: clean
$(RM) *.depend depend
@@ -166,8 +173,8 @@ gene-serial:
#####################################################################################################
coverage:
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.gcov/g'`
$(MAKE) synthesis
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.gcov/g'` CC="cc -std=c11"
$(MAKE) synthesis.synt check-synthesis
SYNTHESIS_DATA= M-ALGO test-malgo.c.c test-malgo.synt \
M-ARRAY test-marray.c.c test-marray.synt \
@@ -192,11 +199,12 @@ SYNTHESIS_DATA= M-ALGO test-malgo.c.c test-malgo.synt \
M-SHARED test-mshared.c.c test-mshared.synt \
M-SNAPSHOT test-msnapshot.c.c test-msnapshot.synt \
M-STRING ../m-string.h test-mstring.synt \
M-TREE test-mtree.c.c test-mtree.synt \
M-TUPLE test-mtuple.c.c test-mtuple.synt \
M-VARIANT test-mvariant.c.c test-mvariant.synt \
M-WORKER ../m-worker.h test-mworker.synt
synthesis:
synthesis.synt:
@printf "+-------------------------------+-------------------------------+\n"
@for i in $(SYNTHESIS_DATA) ; do \
if test "$$j" = "" ; then j=$$i ; continue ; fi; \
@@ -204,9 +212,14 @@ synthesis:
printf "|\t%16.16s\t|\t%16.16s\t|\n" "$$j" "`grep -v Creating $$i|grep $$k -F -A1 |tail -1|cut -f2 -d':'`"; \
j=""; \
k=""; \
done
done > synthesis.synt
@cat synthesis.synt
@printf "+-------------------------------+-------------------------------+\n"
# Compare the computed coverage against the reference coverage (synthesis.ref), allowing only increase of coverage
check-synthesis: synthesis.synt
@paste synthesis.ref synthesis.synt |awk '($$2 != $$9) {err=1} { n1=$$4*$$6/100 ; n2=$$11*$$13/100; if (n1 > n2) { printf "ERROR for %s: new coverage (%d) is lower than reference (%d)\n",$$2,n2,n1 ; err=2 } } END {exit err}'
#####################################################################################################
# Code analyzer tools
@@ -219,8 +232,10 @@ scan-build: clean
# Relaunch the test suite with the sanitizer.
sanitize:
$(MAKE) clean check XCFLAGS="-fsanitize=address,undefined,leak"
$(MAKE) clean check XCFLAGS="-fsanitize=thread -pie -fPIE"
$(MAKE) clean
$(MAKE) check XCFLAGS="-fsanitize=address,undefined,leak"
$(MAKE) clean
$(MAKE) check XCFLAGS="-fsanitize=thread -pie -fPIE"
# Static analysis of the code using GCC "-fanalyzer" option
+2 -11
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Patrick Pelissier
* Copyright (c) 2021-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -25,27 +25,18 @@
ARRAY_DEF(array_int, int)
// Transform an integer 'i' into a M*LIB base item 'a'
#define TYPE_SET_INT(a, i) (a) = (i)
// Container OPLIST
#define CONT_OPL ARRAY_OPLIST(array_int, M_OPL_int())
// C++ Base class of the item in the container
#define BASE_CLASS int
// Transform an integer 'i' into a C++ base item 'a'
#define CLASS_SET_INT(a, i) (a) = (i)
// C++ Container class
#define CONT_CLASS std::vector<int>
// Compare the M*LIB container a to the C++ container b
#define CMP_CONT(a, b) cmp_cont(a, b)
// Compate the M*LIB base object to the C++ base object
#define CMP_BASE(a, b) assert( (a) == (b) )
void cmp_cont(array_int_t a, std::vector<int> b)
{
size_t s = array_int_size(a);
@@ -53,7 +44,7 @@ void cmp_cont(array_int_t a, std::vector<int> b)
for(size_t i = 0; i < s; i++) {
int *b0 = array_int_get(a, i);
int &b1 = b.at(i);
CMP_BASE(*b0, b1);
assert(*b0 == b1);
}
}
+69
View File
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2021-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <map>
#include "m-bptree.h"
BPTREE_DEF2(tree_int, 5, int, int)
// Container OPLIST
#define CONT_OPL BPTREE_OPLIST2(tree_int, M_OPL_int(), M_OPL_int() )
// C++ Base class of the item in the container
#define BASE_CLASS int
// C++ Container class
#define CONT_CLASS std::map<int,int>
// Compare the M*LIB container a to the C++ container b
#define CMP_CONT(a, b) cmp_cont(a, b)
#define CLASS_IT_TO_INT(it) (it)->second
#define TYPE_IT_TO_INT(it) (it)->value
void cmp_cont(const tree_int_t a, const std::map<int,int> &b)
{
tree_int_it_t ita;
tree_int_it(ita, a);
auto itb = b.begin();
while (itb != b.end()) {
assert(!tree_int_end_p(ita));
const int *k0 = tree_int_cref(ita)->key_ptr;
const int &k1 = itb->first;
assert(*k0 == k1);
const int *v0 = tree_int_cref(ita)->value_ptr;
const int &v1 = itb->second;
assert(*v0 == v1);
itb++;
tree_int_next(ita);
}
assert(tree_int_end_p(ita));
}
#define DEFAULT_NUMBER 1000000
#define HAVE_GET_KEY_THROUGH_FIND
#define HAVE_SET_KEY
#define HAVE_KEY_PTR
#define push_back insert
#include "check-generic.hpp"
+59
View File
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2021-2022-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <set>
#include "m-bptree.h"
BPTREE_DEF(tree_int, 5, int)
// Container OPLIST
#define CONT_OPL BPTREE_OPLIST(tree_int, M_OPL_int())
// C++ Base class of the item in the container
#define BASE_CLASS int
// C++ Container class
#define CONT_CLASS std::set<int>
// Compare the M*LIB container a to the C++ container b
#define CMP_CONT(a, b) cmp_cont(a, b)
void cmp_cont(const tree_int_t a, const std::set<int> &b)
{
tree_int_it_t ita;
tree_int_it(ita, a);
auto itb = b.begin();
while (itb != b.end()) {
assert(!tree_int_end_p(ita));
const int *b0 = tree_int_cref(ita);
const int &b1 = *itb;
assert(*b0 == b1);
itb++;
tree_int_next(ita);
}
assert(tree_int_end_p(ita));
}
#define DEFAULT_NUMBER 1000000
#define push_back insert
#include "check-generic.hpp"
+2 -11
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Patrick Pelissier
* Copyright (c) 2021-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -25,27 +25,18 @@
DEQUE_DEF(deque_float, float)
// Transform an integer 'i' into a M*LIB base item 'a'
#define TYPE_SET_INT(a, i) (a) = (i)
// Container OPLIST
#define CONT_OPL DEQUE_OPLIST(deque_float, M_OPL_float())
// C++ Base class of the item in the container
#define BASE_CLASS float
// Transform an integer 'i' into a C++ base item 'a'
#define CLASS_SET_INT(a, i) (a) = (i)
// C++ Container class
#define CONT_CLASS std::deque<float>
// Compare the M*LIB container a to the C++ container b
#define CMP_CONT(a, b) cmp_cont(a, b)
// Compate the M*LIB base object to the C++ base object
#define CMP_BASE(a, b) assert( (a) == (b) )
void cmp_cont(deque_float_t a, std::deque<float> b)
{
deque_float_it_t ita;
@@ -55,7 +46,7 @@ void cmp_cont(deque_float_t a, std::deque<float> b)
assert(!deque_float_end_p(ita));
const float *b0 = deque_float_cref(ita);
float &b1 = *itb;
CMP_BASE(*b0, b1);
assert(*b0 == b1);
itb++;
deque_float_next(ita);
}
+2 -12
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Patrick Pelissier
* Copyright (c) 2021-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -25,27 +25,18 @@
LIST_DUAL_PUSH_DEF(list_int, int)
// Transform an integer 'i' into a M*LIB base item 'a'
#define TYPE_SET_INT(a, i) (a) = (i)
// Container OPLIST
#define CONT_OPL LIST_OPLIST(list_int, M_OPL_int())
// C++ Base class of the item in the container
#define BASE_CLASS int
// Transform an integer 'i' into a C++ base item 'a'
#define CLASS_SET_INT(a, i) (a) = (i)
// C++ Container class
#define CONT_CLASS std::list<int>
// Compare the M*LIB container a to the C++ container b
#define CMP_CONT(a, b) cmp_cont(a, b)
// Compate the M*LIB base object to the C++ base object
#define CMP_BASE(a, b) assert( (a) == (b) )
void cmp_cont(const list_int_t a, const std::list<int> &b)
{
list_int_it_t ita;
@@ -55,8 +46,7 @@ void cmp_cont(const list_int_t a, const std::list<int> &b)
assert(!list_int_end_p(ita));
const int *b0 = list_int_cref(ita);
const int &b1 = *itb;
//printf("%d VS %d\n", *b0, b1);
CMP_BASE(*b0, b1);
assert(*b0 == b1);
itb++;
list_int_next(ita);
}
+149 -32
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Patrick Pelissier
* Copyright (c) 2021-2022 Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,14 +37,54 @@
# define CONT_TYPE_(CONT_OPL) M_GET_TYPE CONT_OPL
# define CONT_TYPE CONT_TYPE_(CONT_OPL)
#endif
// Type used for M*LIB container. Default is the same as C++
#ifndef BASE_TYPE
# define BASE_TYPE_(CONT_OPL) M_GET_SUBTYPE CONT_OPL
# define BASE_TYPE BASE_TYPE_(CONT_OPL)
# define BASE_TYPE BASE_CLASS
#endif
// Compare the M*LIB base object to the C++ base object
#ifndef CMP_BASE
# define CMP_BASE(a, b) assert( (a) == (b) )
#endif
/* Get the affectation if needed to transform an integer into C++ class (resp. M*LIB type) */
#ifndef CLASS_SET_INT
# define CLASS_SET_INT(a, i) (a) = (i)
#endif
#ifndef TYPE_SET_INT
# define TYPE_SET_INT(a, i) (a) = (i)
#endif
/* Get the affectation if needed to transform a C++ iterator (resp. M*LIB) to an int */
#ifndef CLASS_IT_TO_INT
# define CLASS_IT_TO_INT(it) *(it)
#endif
#ifndef TYPE_IT_TO_INT
# define TYPE_IT_TO_INT(it) *(it)
#endif
/* Global properties of the container */
// Use find to perform GET_KEY for C++
//#define HAVE_GET_KEY_THROUGH_FIND
// Container are nor ordered
//#define DONT_HAVE_SEQUENCE_IT
// associative array container
//#define HAVE_SET_KEY
// Container is in reverse
//#define HAVE_REVERSE_IT
// Have PUSH_FRONT operator
//#define HAVE_PUSH_FRONT
// Have POP_FRONT operator
//#define HAVE_POP_FRONT
/*********************************************************************************/
// Define the container name, extracting it from its oplist
#define CONT_NAME_(CONT_OPL) M_GET_NAME CONT_OPL
#define CONT_NAME CONT_NAME_(CONT_OPL)
// Define the maximum number of tests
#define MAX_TEST 28
#ifdef HAVE_REVERSE_IT
@@ -128,37 +168,76 @@ void test(int select_test, int index,
#if M_TEST_METHOD_P(GET_KEY, CONT_OPL)
case 6:
if (!c1.empty()) {
// To rework for dict
index = index % c1.size();
#ifndef HAVE_GET_KEY_THROUGH_FIND
// GET_KEY takes an index which shall be within the range of the container
index = index % c1.size();
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_GET_KEY(CONT_OPL, c0, index));
b1 = c1[index];
#else
// GET_KEY takes a key
index = index % (DEFAULT_NUMBER/4);
BASE_TYPE *p = M_CALL_GET_KEY(CONT_OPL, c0, index);
if (p!= NULL) {
// Key found
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *p);
auto i = c1.find(index);
assert(i != c1.end());
b1 = *i;
b1 = CLASS_IT_TO_INT(i);
} else {
// Key not found
auto i = c1.find(index);
assert(i == c1.end());
TYPE_SET_INT(b0, 0);
CLASS_SET_INT(b1, 0);
}
#endif
} else {
assert( M_CALL_EMPTY_P(CONT_OPL, c0) == true);
}
break;
#endif
#if M_TEST_METHOD_P(SET_KEY, CONT_OPL)
case 7:
if (!c1.empty()) {
TYPE_SET_INT(b0, index);
CLASS_SET_INT(b1, index);
index = index % c1.size();
M_CALL_SET_KEY(CONT_OPL, c0, index, b0);
c1[index] = b1;
TYPE_SET_INT(b0, index);
CLASS_SET_INT(b1, index);
#ifndef HAVE_SET_KEY
if (!c1.empty())
{
index = index % c1.size();
M_CALL_SET_KEY(CONT_OPL, c0, index, b0);
c1[index] = b1;
}
#else
index = index % (DEFAULT_NUMBER/4);
M_CALL_SET_KEY(CONT_OPL, c0, index, b0);
c1[index] = b1;
#endif
break;
case 21:
{
unsigned n = index % 1000;
unsigned offset = (index / 1027) % 1000;
#ifndef HAVE_SET_KEY
// If it is a sequence container, check it it fits, otherwise resize
// without resize which may not be available, but push is assumed to be.
if ((size_t) n+offset > c1.size() ) {
TYPE_SET_INT(b0, 0);
CLASS_SET_INT(b1, 0);
for(unsigned i = c1.size() ; i < (size_t) n+offset; i++) {
M_CALL_PUSH(CONT_OPL, c0, b0);
c1.push_back(b1);
}
assert(c1.size() == (size_t) n+offset);
}
#endif
for(unsigned i = 0; i < n; i++) {
TYPE_SET_INT(b0, 3*i);
CLASS_SET_INT(b1, 3*i);
M_CALL_SET_KEY(CONT_OPL, c0, offset + i, b0);
c1[offset + i] = b1;
}
}
break;
#endif
@@ -228,7 +307,6 @@ void test(int select_test, int index,
#if M_TEST_METHOD_P(SAFE_GET_KEY, CONT_OPL)
case 14:
// To rework for dict
index = (1 + (c1.size() < 1000000)) * (index % ( c1.size() + 1) );
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_SAFE_GET_KEY(CONT_OPL, c0, index));
#ifndef HAVE_GET_KEY_THROUGH_FIND
@@ -240,10 +318,15 @@ void test(int select_test, int index,
{
auto i = c1.find(index);
if (i == c1.end()) {
#ifdef HAVE_SET_KEY
c1[index] = 0;
#else
c1.insert(index);
#endif
i = c1.find(index);
assert(i != c1.end());
}
b1 = *i;
b1 = CLASS_IT_TO_INT(i);
}
#endif
break;
@@ -254,15 +337,29 @@ void test(int select_test, int index,
M_CALL_IT_FIRST(CONT_OPL, it0, c0);
it1 = c1.begin();
while (!M_CALL_IT_END_P(CONT_OPL, it0)) {
#ifdef HAVE_KEY_PTR
// Containers are key / value (through ptr)
index = *M_CALL_IT_CREF(CONT_OPL, it0)->key_ptr;
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_IT_CREF(CONT_OPL, it0)->value_ptr);
#elif defined(HAVE_SET_KEY)
// Containers are key / value
index = M_CALL_IT_CREF(CONT_OPL, it0)->key;
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, M_CALL_IT_CREF(CONT_OPL, it0)->value);
#else
// Containers are single key
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_IT_CREF(CONT_OPL, it0));
index = b0;
#endif
#ifndef DONT_HAVE_SEQUENCE_IT
// Container are ordered
assert(it1 != c1.end());
b1 = *it1;
b1 = CLASS_IT_TO_INT(it1);
it1++;
#else
it1 = c1.find(b0);
// Containers are not ordered.
it1 = c1.find(index);
assert(it1 != c1.end());
b1 = *it1;
b1 = CLASS_IT_TO_INT(it1);
#endif
CMP_BASE(b0, b1);
M_CALL_IT_NEXT(CONT_OPL, it0);
@@ -281,7 +378,7 @@ void test(int select_test, int index,
assert( !M_CALL_IT_END_P(CONT_OPL, it0));
TYPE_SET_INT(b0, index);
CLASS_SET_INT(b1, index);
M_CALL_SET(M_GET_OPLIST CONT_OPL, *M_CALL_IT_REF(CONT_OPL, it0), b0);
M_CALL_SET(M_GET_OPLIST CONT_OPL, TYPE_IT_TO_INT(M_CALL_IT_REF(CONT_OPL, it0)), b0);
*it1 = b1;
M_CALL_IT_NEXT(CONT_OPL, it0);
it1++;
@@ -298,8 +395,8 @@ void test(int select_test, int index,
auto it1b = c1.rbegin();
while (it1b != c1.rend()) {
assert( !M_CALL_IT_END_P(CONT_OPL, it0));
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_IT_CREF(CONT_OPL, it0));
b1 = *it1b;
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, TYPE_IT_TO_INT(M_CALL_IT_CREF(CONT_OPL, it0)));
b1 = CLASS_IT_TO_INT(it1b);
CMP_BASE(b0, b1);
M_CALL_IT_PREVIOUS(CONT_OPL, it0);
it1b++;
@@ -387,13 +484,7 @@ void test(int select_test, int index,
M_CALL_REVERSE(CONT_OPL, c0);
c1.reverse();
break;
#endif
#if M_TEST_METHOD_P(SPLICE_BACK, CONT_OPL)
case 21:
M_CALL_REVERSE(CONT_OPL, c0);
c1.reverse();
break;
// 21 is above
#endif
#ifdef HAVE_PUSH_FRONT
@@ -451,6 +542,7 @@ void test(int select_test, int index,
// Needs SPLICE ?
default:
M_STATIC_ASSERT( 28 == MAX_TEST, MLIB_INTERNAL_ERROR, "Constant MAX_TEST is no coherent with the effective number of tests");
// Nothing to do
break;
}
@@ -482,6 +574,22 @@ static void init_rand(void)
}
}
static int read_int(FILE *f)
{
int c = 0;
while (true) {
int n = fscanf(f, " %d", &c);
if (n == 1) {
return c;
}
if (feof(f)) {
return 0;
}
// Skip next character
c = fgetc(f);
}
}
int main(int argc, const char *argv[])
{
int loop = argc >= 2 ? atoi(argv[1]) : DEFAULT_NUMBER;
@@ -496,11 +604,20 @@ int main(int argc, const char *argv[])
M_CALL_INIT(M_GET_OPLIST CONT_OPL, b0);
TYPE_SET_INT(b0, 0);
CLASS_SET_INT(b1, 0);
for(int i = 0; i < loop; i++) {
int t = rand();
int s = rand();
test(t, s, b0, b1, c0, c1);
if (loop < 0) {
/* test input is provided from stdin */
while (!feof(stdin)) {
int t = read_int(stdin);
int s = read_int(stdin);
test(t, s, b0, b1, c0, c1);
}
} else {
for(int i = 0; i < loop; i++) {
int t = rand();
int s = rand();
test(t, s, b0, b1, c0, c1);
}
}
M_CALL_CLEAR(M_GET_OPLIST CONT_OPL, b0);
+2 -11
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Patrick Pelissier
* Copyright (c) 2021-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -25,27 +25,18 @@
LIST_DEF(list_int, int)
// Transform an integer 'i' into a M*LIB base item 'a'
#define TYPE_SET_INT(a, i) (a) = (i)
// Container OPLIST
#define CONT_OPL LIST_OPLIST(list_int, M_OPL_int())
// C++ Base class of the item in the container
#define BASE_CLASS int
// Transform an integer 'i' into a C++ base item 'a'
#define CLASS_SET_INT(a, i) (a) = (i)
// C++ Container class
#define CONT_CLASS std::forward_list<int>
// Compare the M*LIB container a to the C++ container b
#define CMP_CONT(a, b) cmp_cont(a, b)
// Compate the M*LIB base object to the C++ base object
#define CMP_BASE(a, b) assert( (a) == (b) )
void cmp_cont(list_int_t a, std::forward_list<int> b)
{
list_int_it_t ita;
@@ -55,7 +46,7 @@ void cmp_cont(list_int_t a, std::forward_list<int> b)
assert(!list_int_end_p(ita));
const int *b0 = list_int_cref(ita);
int &b1 = *itb;
CMP_BASE(*b0, b1);
assert(*b0 == b1);
itb++;
list_int_next(ita);
}
+74
View File
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2021-2022-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <queue>
#include "m-prioqueue.h"
// Invert the order of priority for the integers to match the C++ one
#define CMP_REVERT(a,b) ((a) > (b) ? -1 : (a) < (b))
PRIOQUEUE_DEF(prio_int, int, M_OPEXTEND(M_BASIC_OPLIST, CMP(CMP_REVERT) ))
// Container OPLIST (disable iterators & reset)
#define CONT_OPL \
M_OPEXTEND( PRIOQUEUE_OPLIST(prio_int, M_OPL_int()), \
RESET(0), \
IT_TYPE(0), \
IT_FIRST(0), \
IT_END(0), \
IT_SET(0), \
IT_END_P(0), \
IT_EQUAL_P(0), \
IT_LAST_P(0), \
IT_NEXT(0), \
IT_CREF(0) )
// C++ Base class of the item in the container
#define BASE_CLASS int
// C++ Container class
#define CONT_CLASS std::priority_queue<int>
// Compare the M*LIB container a to the C++ container b
#define CMP_CONT(a, b) cmp_cont(a, b)
void cmp_cont(const prio_int_t a, const std::priority_queue<int> &b)
{
std::priority_queue<int> cb = b;
prio_int_t ca;
prio_int_init_set(ca, a);
while (!cb.empty()) {
int n;
prio_int_pop(&n, ca);
assert(n == cb.top());
cb.pop();
}
assert(prio_int_empty_p(ca));
prio_int_clear(ca);
}
// There is no reset, so the prioqueue keeps increasing ==> Limit the number of operation.
#define DEFAULT_NUMBER 1500
#define push_back push
#define pop_back pop
#define back top
#include "check-generic.hpp"
+2 -12
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Patrick Pelissier
* Copyright (c) 2021-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -25,27 +25,18 @@
RBTREE_DEF(tree_int, int)
// Transform an integer 'i' into a M*LIB base item 'a'
#define TYPE_SET_INT(a, i) (a) = (i)
// Container OPLIST
#define CONT_OPL RBTREE_OPLIST(tree_int, M_OPL_int())
// C++ Base class of the item in the container
#define BASE_CLASS int
// Transform an integer 'i' into a C++ base item 'a'
#define CLASS_SET_INT(a, i) (a) = (i)
// C++ Container class
#define CONT_CLASS std::set<int>
// Compare the M*LIB container a to the C++ container b
#define CMP_CONT(a, b) cmp_cont(a, b)
// Compate the M*LIB base object to the C++ base object
#define CMP_BASE(a, b) assert( (a) == (b) )
void cmp_cont(const tree_int_t a, const std::set<int> &b)
{
tree_int_it_t ita;
@@ -55,8 +46,7 @@ void cmp_cont(const tree_int_t a, const std::set<int> &b)
assert(!tree_int_end_p(ita));
const int *b0 = tree_int_cref(ita);
const int &b1 = *itb;
//printf("%d VS %d\n", *b0, b1);
CMP_BASE(*b0, b1);
assert(*b0 == b1);
itb++;
tree_int_next(ita);
}
+68
View File
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2021-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <unordered_map>
#include "m-dict.h"
DICT_DEF2(dict_int, int, int)
// Container OPLIST
#define CONT_OPL DICT_OPLIST(dict_int, M_OPL_int(), M_OPL_int() )
// C++ Base class of the item in the container
#define BASE_CLASS int
// C++ Container class
#define CONT_CLASS std::unordered_map<int,int>
// Compare the M*LIB container a to the C++ container b
#define CMP_CONT(a, b) cmp_cont(a, b)
// Get the value from the iterator
#define CLASS_IT_TO_INT(it) (it)->second
#define TYPE_IT_TO_INT(it) (it)->value
void cmp_cont(const dict_int_t a, const std::unordered_map<int,int> &b)
{
size_t n = 0;
auto itb = b.begin();
while (itb != b.end()) {
const int *b0 = dict_int_get(a, itb->first);
assert(b0 != nullptr);
assert(*b0 == itb->second);
itb++;
n++;
}
assert(dict_int_size(a) == n);
}
#define DEFAULT_NUMBER 1000000
// Use find to perform GET_KEY for C++
#define HAVE_GET_KEY_THROUGH_FIND
// Container are nor ordered
#define DONT_HAVE_SEQUENCE_IT
// associative array container
#define HAVE_SET_KEY
#define push_back insert
#include "check-generic.hpp"
+2 -11
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Patrick Pelissier
* Copyright (c) 2021-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -25,27 +25,18 @@
DICT_SET_DEF(dict_int, int)
// Transform an integer 'i' into a M*LIB base item 'a'
#define TYPE_SET_INT(a, i) (a) = (i)
// Container OPLIST
#define CONT_OPL DICT_SET_OPLIST(dict_int, M_OPL_int())
// C++ Base class of the item in the container
#define BASE_CLASS int
// Transform an integer 'i' into a C++ base item 'a'
#define CLASS_SET_INT(a, i) (a) = (i)
// C++ Container class
#define CONT_CLASS std::unordered_set<int>
// Compare the M*LIB container a to the C++ container b
#define CMP_CONT(a, b) cmp_cont(a, b)
// Compate the M*LIB base object to the C++ base object
#define CMP_BASE(a, b) assert( (a) == (b) )
void cmp_cont(const dict_int_t a, const std::unordered_set<int> &b)
{
size_t n = 0;
@@ -54,7 +45,7 @@ void cmp_cont(const dict_int_t a, const std::unordered_set<int> &b)
const int &b1 = *itb;
const int *b0 = dict_int_get(a, b1);
assert(b0 != nullptr);
CMP_BASE(*b0, b1);
assert(*b0 == b1);
itb++;
n++;
}
+4 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -101,6 +101,9 @@
#undef M_ASSIGN_CAST
#undef M_CHECK_DEFAULT_TYPE
#undef M_CHECK_SAME
#undef M_TR33_NODE_CONTRACT
#undef M_TR33_CONTRACT
#undef M_TR33_IT_CONTRACT
#else
/* For normal builds, empty macros which does nothing */
#define START_COVERAGE
+18 -18
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -64,14 +64,14 @@ BPTREE_DEF(bptree2, 5, bptree_t, BPTREE_OPLIST(bptree, DEFAULT_OPLIST))
#include "m-bptree.h"
BPTREE_DEF2(bptree, 4, int, int)
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, DEFAULT_OPLIST, M_BASIC_OPLIST), int, M_BASIC_OPLIST)
#elif TEST == 6
#include "m-bptree.h"
BPTREE_DEF2(bptree, 4, int, int)
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, M_DEFAULT_OPLIST, DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, M_BASIC_OPLIST, DEFAULT_OPLIST), int, M_BASIC_OPLIST)
#elif TEST == 7
@@ -86,7 +86,7 @@ BUFFER_DEF(buffer2, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer, DEFAULT_OPL
#include "m-concurrent.h"
ARRAY_DEF(array, int)
CONCURRENT_DEF(array2, array_t, ARRAY_OPLIST(array, M_DEFAULT_OPLIST))
CONCURRENT_DEF(array2, array_t, ARRAY_OPLIST(array, M_BASIC_OPLIST))
ARRAY_DEF(array3, array2_t, CONCURRENT_OPLIST(array2, ARRAY_OPLIST(array, DEFAULT_OPLIST)))
#elif TEST == 9
@@ -94,14 +94,14 @@ ARRAY_DEF(array3, array2_t, CONCURRENT_OPLIST(array2, ARRAY_OPLIST(array, DEFAUL
#include "m-dict.h"
DICT_DEF2(dict, int, int)
DICT_DEF2(dict2, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict, DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
DICT_DEF2(dict2, int, M_BASIC_OPLIST, dict_t, DICT_OPLIST(dict, DEFAULT_OPLIST, M_BASIC_OPLIST) )
#elif TEST == 10
#include "m-dict.h"
DICT_DEF2(dict, int, int)
DICT_DEF2(dict2, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict, M_DEFAULT_OPLIST, DEFAULT_OPLIST) )
DICT_DEF2(dict2, int, M_BASIC_OPLIST, dict_t, DICT_OPLIST(dict, M_BASIC_OPLIST, DEFAULT_OPLIST) )
#elif TEST == 11
@@ -140,64 +140,64 @@ CONCURRENT_DEF(array, tmpstr_t, ISHARED_PTR_OPLIST(tmpstr, X()))
#include "m-prioqueue.h"
PRIOQUEUE_DEF(prioqueue, int)
PRIOQUEUE_DEF(prioqueue2, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue, M_DEFAULT_OPLIST()))
PRIOQUEUE_DEF(prioqueue2, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue, M_BASIC_OPLIST()))
#elif TEST == 15
#include "m-rbtree.h"
RBTREE_DEF(rbtree, int)
RBTREE_DEF(rbtree2, rbtree_t, RBTREE_OPLIST(rbtree, M_DEFAULT_OPLIST2))
RBTREE_DEF(rbtree2, rbtree_t, RBTREE_OPLIST(rbtree, M_BASIC_OPLIST2))
#elif TEST == 16
#include "m-shared.h"
SHARED_PTR_DEF(shared, int)
SHARED_PTR_DEF(shared2, shared_t, SHARED_PTR_OPLIST(shared, M_DEFAULT_OPLISTop))
SHARED_PTR_DEF(shared2, shared_t, SHARED_PTR_OPLIST(shared, M_BASIC_OPLISTop))
#elif TEST == 17
#include "m-snapshot.h"
SNAPSHOT_SPSC_DEF(shared, int)
SNAPSHOT_SPSC_DEF(shared2, shared_t, SNAPSHOT_OPLIST(shared, M_DEFAULT_OPLIST x))
SNAPSHOT_SPSC_DEF(shared2, shared_t, SNAPSHOT_OPLIST(shared, M_BASIC_OPLIST x))
#elif TEST == 18
#include "m-tuple.h"
TUPLE_DEF2(aggregate, (x, int), (z, float))
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, DEFAULT_OPLIST, M_DEFAULT_OPLIST)))
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, DEFAULT_OPLIST, M_BASIC_OPLIST)))
#elif TEST == 19
#include "m-tuple.h"
TUPLE_DEF2(aggregate, (x, int), (z, float))
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST() )))
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST() )))
#elif TEST == 20
#include "m-variant.h"
VARIANT_DEF2(aggregate, (x, int), (z, float))
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, DEFAULT_OPLIST, M_DEFAULT_OPLIST)))
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, DEFAULT_OPLIST, M_BASIC_OPLIST)))
#elif TEST == 21
#include "m-variant.h"
VARIANT_DEF2(aggregate, (x, int), (z, float))
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, DEFAULT_OPLIST)))
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, M_BASIC_OPLIST, DEFAULT_OPLIST)))
#elif TEST == 22
#include "m-funcobj.h"
FUNC_OBJ_ITF_DEF(itf, int, int)
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_DEFAULT_OPLIST), (b, int, M_DEFAULT_OPLIST))
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, M_DEFAULT_OPLIST, DEFAULT_OPLIST)
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_BASIC_OPLIST), (b, int, M_BASIC_OPLIST))
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, M_BASIC_OPLIST, DEFAULT_OPLIST)
int f(void) {
int r;
@@ -211,8 +211,8 @@ int f(void) {
#include "m-funcobj.h"
FUNC_OBJ_ITF_DEF(itf, int, int)
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_DEFAULT_OPLIST), (b, int, M_DEFAULT_OPLIST))
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, DEFAULT_OPLIST, M_DEFAULT_OPLIST)
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_BASIC_OPLIST), (b, int, M_BASIC_OPLIST))
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, DEFAULT_OPLIST, M_BASIC_OPLIST)
int f(void) {
int r;
+26 -26
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -40,7 +40,7 @@
ARRAY_DEF(array, int)
ARRAY_DEF(array2, int)
ARRAY_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
ARRAY_DEF(array3, array_t, ARRAY_OPLIST(array2, M_BASIC_OPLIST))
#elif TEST == 2
@@ -48,7 +48,7 @@ ARRAY_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
LIST_DEF(list, int)
LIST_DEF(list2, int)
LIST_DEF(list3, list_t, LIST_OPLIST(list2, M_DEFAULT_OPLIST))
LIST_DEF(list3, list_t, LIST_OPLIST(list2, M_BASIC_OPLIST))
#elif TEST == 3
@@ -56,7 +56,7 @@ LIST_DEF(list3, list_t, LIST_OPLIST(list2, M_DEFAULT_OPLIST))
DEQUE_DEF(deque, int)
DEQUE_DEF(deque2, int)
DEQUE_DEF(deque3, deque_t, DEQUE_OPLIST(deque2, M_DEFAULT_OPLIST))
DEQUE_DEF(deque3, deque_t, DEQUE_OPLIST(deque2, M_BASIC_OPLIST))
#elif TEST == 4
@@ -64,7 +64,7 @@ DEQUE_DEF(deque3, deque_t, DEQUE_OPLIST(deque2, M_DEFAULT_OPLIST))
BPTREE_DEF(bptree, 4, int)
BPTREE_DEF(bptree2, 4, int)
BPTREE_DEF(bptree3, 5, bptree_t, BPTREE_OPLIST(bptree2, M_DEFAULT_OPLIST))
BPTREE_DEF(bptree3, 5, bptree_t, BPTREE_OPLIST(bptree2, M_BASIC_OPLIST))
#elif TEST == 5
@@ -72,7 +72,7 @@ BPTREE_DEF(bptree3, 5, bptree_t, BPTREE_OPLIST(bptree2, M_DEFAULT_OPLIST))
BPTREE_DEF2(bptree, 4, int, int)
BPTREE_DEF2(bptree2, 4, int, int)
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_BASIC_OPLIST, M_BASIC_OPLIST), int, M_BASIC_OPLIST)
#elif TEST == 6
@@ -80,7 +80,7 @@ BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DE
BPTREE_DEF2(bptree, 4, int, int)
BPTREE_DEF2(bptree2, 4, int, int)
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_BASIC_OPLIST, M_BASIC_OPLIST), int, M_BASIC_OPLIST)
#elif TEST == 7
@@ -88,7 +88,7 @@ BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DE
BUFFER_DEF(buffer, int, 4, BUFFER_THREAD_UNSAFE)
BUFFER_DEF(buffer2, int, 4, BUFFER_THREAD_UNSAFE)
BUFFER_DEF(buffer3, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer2, M_DEFAULT_OPLIST))
BUFFER_DEF(buffer3, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer2, M_BASIC_OPLIST))
#elif TEST == 8
@@ -97,7 +97,7 @@ BUFFER_DEF(buffer3, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer2, M_DEFAULT_
ARRAY_DEF(array, int)
ARRAY_DEF(array2, int)
CONCURRENT_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
CONCURRENT_DEF(array3, array_t, ARRAY_OPLIST(array2, M_BASIC_OPLIST))
#elif TEST == 9
@@ -105,7 +105,7 @@ CONCURRENT_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
DICT_DEF2(dict, int, int)
DICT_DEF2(dict2, int, int)
DICT_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
DICT_DEF2(dict3, int, M_BASIC_OPLIST, dict_t, DICT_OPLIST(dict2, M_BASIC_OPLIST, M_BASIC_OPLIST) )
#elif TEST == 10
@@ -113,7 +113,7 @@ DICT_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_DEFAULT_OPL
DICT_STOREHASH_DEF2(dict, int, int)
DICT_STOREHASH_DEF2(dict2, int, int)
DICT_STOREHASH_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
DICT_STOREHASH_DEF2(dict3, int, M_BASIC_OPLIST, dict_t, DICT_OPLIST(dict2, M_BASIC_OPLIST, M_BASIC_OPLIST) )
#elif TEST == 11
@@ -122,7 +122,7 @@ DICT_STOREHASH_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_D
ARRAY_DEF(array, int)
ARRAY_DEF(array2, int)
DICT_SET_DEF(dict, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST) )
DICT_SET_DEF(dict, array_t, ARRAY_OPLIST(array2, M_BASIC_OPLIST) )
#elif TEST == 12
@@ -152,7 +152,7 @@ ISHARED_PTR_DEF(tmpstr, tmp_str_t, (TYPE(struct toto), CLEAR(M_NOTHING_DEFAULT))
PRIOQUEUE_DEF(prioqueue, int)
PRIOQUEUE_DEF(prioqueue2, int)
PRIOQUEUE_DEF(prioqueue3, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue2, M_DEFAULT_OPLIST ))
PRIOQUEUE_DEF(prioqueue3, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue2, M_BASIC_OPLIST ))
#elif TEST == 15
@@ -160,7 +160,7 @@ PRIOQUEUE_DEF(prioqueue3, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue2, M_DEFAULT_OP
RBTREE_DEF(rbtree, int)
RBTREE_DEF(rbtree2, int)
RBTREE_DEF(rbtree3, rbtree_t, RBTREE_OPLIST(rbtree2, M_DEFAULT_OPLIST))
RBTREE_DEF(rbtree3, rbtree_t, RBTREE_OPLIST(rbtree2, M_BASIC_OPLIST))
#elif TEST == 16
@@ -168,7 +168,7 @@ RBTREE_DEF(rbtree3, rbtree_t, RBTREE_OPLIST(rbtree2, M_DEFAULT_OPLIST))
SHARED_PTR_DEF(shared, int)
SHARED_PTR_DEF(shared2, int)
SHARED_PTR_DEF(shared3, shared_t, SHARED_PTR_OPLIST(shared2, M_DEFAULT_OPLIST))
SHARED_PTR_DEF(shared3, shared_t, SHARED_PTR_OPLIST(shared2, M_BASIC_OPLIST))
#elif TEST == 17
@@ -176,7 +176,7 @@ SHARED_PTR_DEF(shared3, shared_t, SHARED_PTR_OPLIST(shared2, M_DEFAULT_OPLIST))
SNAPSHOT_SPSC_DEF(shared, int)
SNAPSHOT_SPSC_DEF(shared2, int)
SNAPSHOT_SPSC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
SNAPSHOT_SPSC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_BASIC_OPLIST))
#elif TEST == 18
@@ -184,7 +184,7 @@ SNAPSHOT_SPSC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
SNAPSHOT_SPMC_DEF(shared, int)
SNAPSHOT_SPMC_DEF(shared2, int)
SNAPSHOT_SPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
SNAPSHOT_SPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_BASIC_OPLIST))
#elif TEST == 19
@@ -192,7 +192,7 @@ SNAPSHOT_SPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
SNAPSHOT_MPMC_DEF(shared, int)
SNAPSHOT_MPMC_DEF(shared2, int)
SNAPSHOT_MPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
SNAPSHOT_MPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_BASIC_OPLIST))
#elif TEST == 20
@@ -201,8 +201,8 @@ SNAPSHOT_MPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
TUPLE_DEF2(aggregate, (x, int), (z, float))
TUPLE_DEF2(aggregate2, (x, int), (z, float))
TUPLE_DEF2(struct2,
(a, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
(b, aggregate_t, TUPLE_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
(a, aggregate_t, TUPLE_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST)),
(b, aggregate_t, TUPLE_OPLIST(aggregate2, M_BASIC_OPLIST, M_BASIC_OPLIST))
)
#elif TEST == 21
@@ -212,8 +212,8 @@ TUPLE_DEF2(struct2,
TUPLE_DEF2(aggregate, (x, int), (z, float))
TUPLE_DEF2(aggregate2, (x, int), (z, float))
TUPLE_DEF2(struct2,
(a, aggregate_t, TUPLE_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
(b, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
(a, aggregate_t, TUPLE_OPLIST(aggregate2, M_BASIC_OPLIST, M_BASIC_OPLIST)),
(b, aggregate_t, TUPLE_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST))
)
#elif TEST == 22
@@ -223,8 +223,8 @@ TUPLE_DEF2(struct2,
VARIANT_DEF2(aggregate, (x, int), (z, float))
VARIANT_DEF2(aggregate2, (x, int), (z, float))
VARIANT_DEF2(struct2,
(a, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
(b, aggregate_t, VARIANT_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
(a, aggregate_t, VARIANT_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST)),
(b, aggregate_t, VARIANT_OPLIST(aggregate2, M_BASIC_OPLIST, M_BASIC_OPLIST))
)
#elif TEST == 23
@@ -234,8 +234,8 @@ VARIANT_DEF2(struct2,
VARIANT_DEF2(aggregate, (x, int), (z, float))
VARIANT_DEF2(aggregate2, (x, int), (z, float))
VARIANT_DEF2(struct2,
(a, aggregate_t, VARIANT_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
(b, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
(a, aggregate_t, VARIANT_OPLIST(aggregate2, M_BASIC_OPLIST, M_BASIC_OPLIST)),
(b, aggregate_t, VARIANT_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST))
)
#elif TEST == 24
+23 -23
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -80,7 +80,7 @@ ILIST_DEF(tmpstr, tmp_str_t, DEFAULT_OPLIST)
#include "m-string.h"
void f(void)
{
M_LET(x, M_STRING_OPLIST) {
M_LET(x, M_M_STRING_OPLIST) {
}
}
@@ -109,7 +109,7 @@ void f(void)
#include "m-array.h"
ARRAY_DEF(array, int)
ALGO_DEF(array, M_ARRAY_OPLIST(array))
ALGO_DEF(array, M_M_ARRAY_OPLIST(array))
#elif TEST == 12
@@ -123,13 +123,13 @@ ALGO_DEF(array, (OPLIST(array)))
#include "m-bptree.h"
BPTREE_DEF2(tree, 4, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
BPTREE_DEF2(tree, 4, int, M_BASIC_OPLIST, int, DEFAULT_OPLIST)
#elif TEST == 14
#include "m-bptree.h"
BPTREE_DEF2(tree, 4, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
BPTREE_DEF2(tree, 4, int, DEFAULT_OPLIST, int, M_BASIC_OPLIST)
#elif TEST == 15
@@ -141,7 +141,7 @@ BPTREE_DEF(tree, 4, int, DEFAULT_OPLIST)
#include "m-bptree.h"
BPTREE_MULTI_DEF2(tree, 4, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
BPTREE_MULTI_DEF2(tree, 4, int, DEFAULT_OPLIST, int, M_BASIC_OPLIST)
#elif TEST == 17
@@ -173,7 +173,7 @@ QUEUE_SPSC_DEF(buffer, int, BUFFER_QUEUE, DEFAULT_OPLIST)
#include "m-concurrent.h"
ARRAY_DEF(array, int)
CONCURRENT_DEF(lock_array, array_t, M_ARRAY_OPLIST(array))
CONCURRENT_DEF(lock_array, array_t, M_M_ARRAY_OPLIST(array))
#elif TEST == 22
@@ -187,37 +187,37 @@ CONCURRENT_RP_DEF(lock_array, array_t, MARRAY_OPLIST(array))
#include "m-dict.h"
DICT_DEF2(array, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
DICT_DEF2(array, int, M_BASIC_OPLIST, int, DEFAULT_OPLIST)
#elif TEST == 24
#include "m-dict.h"
DICT_DEF2(array, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
DICT_DEF2(array, int, DEFAULT_OPLIST, int, M_BASIC_OPLIST)
#elif TEST == 25
#include "m-dict.h"
DICT_STOREHASH_DEF2(array, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
DICT_STOREHASH_DEF2(array, int, DEFAULT_OPLIST, int, M_BASIC_OPLIST)
#elif TEST == 26
#include "m-dict.h"
DICT_STOREHASH_DEF2(array, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
DICT_STOREHASH_DEF2(array, int, M_BASIC_OPLIST, int, DEFAULT_OPLIST)
#elif TEST == 27
#include "m-dict.h"
DICT_OA_DEF2(array, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
DICT_OA_DEF2(array, int, DEFAULT_OPLIST, int, M_BASIC_OPLIST)
#elif TEST == 28
#include "m-dict.h"
DICT_OA_DEF2(array, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
DICT_OA_DEF2(array, int, M_BASIC_OPLIST, int, DEFAULT_OPLIST)
#elif TEST == 29
@@ -252,43 +252,43 @@ PRIOQUEUE_DEF(prio, int, DEFAULT_OPLIST)
#include "m-rbtree.h"
RBTREE_DEF(tree, int, M_DEFAULT_OPLIST() )
RBTREE_DEF(tree, int, M_BASIC_OPLIST() )
#elif TEST == 34
#include "m-shared.h"
SHARED_PTR_DEF(shared, int, M_DEFAULT_OPLIST2 )
SHARED_PTR_DEF(shared, int, M_BASIC_OPLIST2 )
#elif TEST == 35
#include "m-shared.h"
SHARED_RESOURCE_DEF(shared, int, M_DEFAULT_OPLIST3 )
SHARED_RESOURCE_DEF(shared, int, M_BASIC_OPLIST3 )
#elif TEST == 36
#include "m-snapshot.h"
SNAPSHOT_SPSC_DEF(snap, int, M_DEFAULT_OPLIST2 )
SNAPSHOT_SPSC_DEF(snap, int, M_BASIC_OPLIST2 )
#elif TEST == 37
#include "m-snapshot.h"
SNAPSHOT_SPMC_DEF(snap, int, M_DEFAULT_OPLIST2 )
SNAPSHOT_SPMC_DEF(snap, int, M_BASIC_OPLIST2 )
#elif TEST == 38
#include "m-snapshot.h"
SNAPSHOT_MPMC_DEF(snap, int, M_DEFAULT_OPLIST8 )
SNAPSHOT_MPMC_DEF(snap, int, M_BASIC_OPLIST8 )
#elif TEST == 39
#include "m-tuple.h"
TUPLE_DEF2(agregate, (x, int, M_DEFAULT_OPLIST), (y, float, DEFAULT_OPLIST) )
TUPLE_DEF2(agregate, (x, int, M_BASIC_OPLIST), (y, float, DEFAULT_OPLIST) )
#elif TEST == 40
@@ -300,7 +300,7 @@ TUPLE_DEF2(agregate, (x, int, DEFAULT_OPLIST), (y, float) )
#include "m-variant.h"
VARIANT_DEF2(agregate, (x, int, M_DEFAULT_OPLIST), (y, float, DEFAULT_OPLIST) )
VARIANT_DEF2(agregate, (x, int, M_BASIC_OPLIST), (y, float, DEFAULT_OPLIST) )
#elif TEST == 42
@@ -314,7 +314,7 @@ VARIANT_DEF2(agregate, (x, int, DEFAULT_OPLIST), (y, float) )
FUNC_OBJ_ITF_DEF(itf, int, int)
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, DEFAULT_OPLIST), (b, int, M_DEFAULT_OPLIST))
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, DEFAULT_OPLIST), (b, int, M_BASIC_OPLIST))
#elif TEST == 44
@@ -322,7 +322,7 @@ FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, DEFA
FUNC_OBJ_ITF_DEF(itf, int, int)
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int), (b, int, M_DEFAULT_OPLIST() ))
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int), (b, int, M_BASIC_OPLIST() ))
#else
+27
View File
@@ -0,0 +1,27 @@
| M-ALGO | 100.00% of 1160 |
| M-ARRAY | 98.24% of 908 |
| M-BITSET | 98.31% of 413 |
| M-BBPTREE | 99.60% of 998 |
| M-BUFFER | 98.86% of 877 |
| M-CONCURRENT | 100.00% of 102 |
| M-CORE | 100.00% of 268 |
| M-DEQUE | 99.47% of 943 |
| M-DICT | 93.00% of 1528 |
| M-FUNCOBJ | 100.00% of 108 |
| M-GENINT | 97.40% of 77 |
| M-I-LIST | 98.10% of 474 |
| M-I-SHARED | 100.00% of 112 |
| M-LIST | 99.12% of 1368 |
| M-MEMPOOL | 97.98% of 99 |
| M-MUTEX | 100.00% of 19 |
| M-PRIOQUEUE | 99.17% of 600 |
| M-RBTREE | 99.04% of 937 |
| M-SERIAL-BIN | 70.87% of 254 |
| M-SERIAL-JSON | 100.00% of 494 |
| M-SHARED | 99.07% of 324 |
| M-SNAPSHOT | 99.54% of 439 |
| M-STRING | 99.40% of 831 |
| M-TREE | 98.46% of 1232 |
| M-TUPLE | 100.00% of 186 |
| M-VARIANT | 99.25% of 266 |
| M-WORKER | 98.73% of 79 |
+13 -13
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -48,12 +48,12 @@ DEQUE_DEF(deque_obj, testobj_t, TESTOBJ_CMP_OPLIST)
DICT_DEF2(dict_obj, string_t, STRING_OPLIST, testobj_t, TESTOBJ_OPLIST)
LIST_DUAL_PUSH_DEF(dlist_int, int)
DICT_DEF2(dict_int, string_t, int)
#define M_OPL_dict_int_t() DICT_OPLIST(dict_int, STRING_OPLIST, M_DEFAULT_OPLIST)
#define M_OPL_dict_int_t() DICT_OPLIST(dict_int, STRING_OPLIST, M_BASIC_OPLIST)
ARRAY_DEF(array_uint, unsigned int)
#define M_OPL_array_uint_t() ARRAY_OPLIST(array_uint)
TUPLE_DEF2(person, (age, int), (name, string_t) )
#define M_OPL_person_t() TUPLE_OPLIST(person, M_DEFAULT_OPLIST, STRING_OPLIST)
#define M_OPL_person_t() TUPLE_OPLIST(person, M_BASIC_OPLIST, STRING_OPLIST)
ARRAY_DEF(array_person, person_t)
#define M_OPL_array_person_t() ARRAY_OPLIST(array_person, M_OPL_person_t() )
@@ -225,32 +225,32 @@ static void test_list(void)
list_int_clear(l);
M_LET( (l1, 1, 3, 5), (l2, 1, 2, 4), (l3, 1, 2, 3, 4, 5), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
M_LET( (l1, 1, 3, 5), (l2, 1, 2, 4), (l3, 1, 2, 3, 4, 5), LIST_OPLIST(list_int, M_BASIC_OPLIST)) {
algo_list_sort_union(l1, l2);
assert(list_int_equal_p (l1, l3));
}
M_LET( (l1, 1, 30, 31), (l2, 2, 4, 31, 32), (l3, 1, 2, 4, 30, 31, 32), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
M_LET( (l1, 1, 30, 31), (l2, 2, 4, 31, 32), (l3, 1, 2, 4, 30, 31, 32), LIST_OPLIST(list_int, M_BASIC_OPLIST)) {
algo_list_sort_union(l1, l2);
assert(list_int_equal_p (l1, l3));
}
M_LET( (l1, 4, 28, 29, 30, 34), (l2, 1, 3, 31, 32, 33), (l3, 1, 3, 4, 28, 29, 30, 31, 32, 33, 34), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
M_LET( (l1, 4, 28, 29, 30, 34), (l2, 1, 3, 31, 32, 33), (l3, 1, 3, 4, 28, 29, 30, 31, 32, 33, 34), LIST_OPLIST(list_int, M_BASIC_OPLIST)) {
algo_list_sort_union(l1, l2);
assert(list_int_equal_p (l1, l3));
}
M_LET( (l1, 1, 4, 28, 29, 31, 34), (l2, 1, 3, 31, 32, 33), (l3, 1, 31), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
M_LET( (l1, 1, 4, 28, 29, 31, 34), (l2, 1, 3, 31, 32, 33), (l3, 1, 31), LIST_OPLIST(list_int, M_BASIC_OPLIST)) {
algo_list_sort_intersect(l1, l2);
assert(list_int_equal_p (l1, l3));
}
M_LET( (l1, 4, 28, 29, 31, 34), (l2, 1, 3, 31, 32, 33), (l3, (31)), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
M_LET( (l1, 4, 28, 29, 31, 34), (l2, 1, 3, 31, 32, 33), (l3, (31)), LIST_OPLIST(list_int, M_BASIC_OPLIST)) {
algo_list_sort_intersect(l1, l2);
assert(list_int_equal_p (l1, l3));
}
M_LET( (l1, 1, 4, 28, 29, 31, 34), (l2, 3, 32, 33), l3, LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
M_LET( (l1, 1, 4, 28, 29, 31, 34), (l2, 3, 32, 33), l3, LIST_OPLIST(list_int, M_BASIC_OPLIST)) {
algo_list_sort_intersect(l1, l2);
assert(list_int_equal_p (l1, l3));
}
@@ -646,25 +646,25 @@ FUNC_OBJ_INS_DEF(fo_test, algo_array_fo_test_obj,
(a), {
return a == self->x;
}, (x, int))
#define M_OPL_fo_test_t() FUNC_OBJ_INS_OPLIST(fo_test, M_DEFAULT_OPLIST)
#define M_OPL_fo_test_t() FUNC_OBJ_INS_OPLIST(fo_test, M_BASIC_OPLIST)
FUNC_OBJ_INS_DEF(fo_eq, algo_array_fo_eq_obj,
(a, b), {
return a == b && self->x != a;
}, (x, int))
#define M_OPL_fo_eq_t() FUNC_OBJ_INS_OPLIST(fo_eq, M_DEFAULT_OPLIST)
#define M_OPL_fo_eq_t() FUNC_OBJ_INS_OPLIST(fo_eq, M_BASIC_OPLIST)
FUNC_OBJ_INS_DEF(fo_cmp, algo_array_fo_cmp_obj,
(a, b), {
return a < b ? -self->x : a > b ? self->x : 0;
}, (x, int))
#define M_OPL_fo_cmp_t() FUNC_OBJ_INS_OPLIST(fo_cmp, M_DEFAULT_OPLIST)
#define M_OPL_fo_cmp_t() FUNC_OBJ_INS_OPLIST(fo_cmp, M_BASIC_OPLIST)
FUNC_OBJ_INS_DEF(fol_cmp, algo_list_fo_cmp_obj,
(a, b), {
return a < b ? -self->x : a > b ? self->x : 0;
}, (x, int))
#define M_OPL_fol_cmp_t() FUNC_OBJ_INS_OPLIST(fol_cmp, M_DEFAULT_OPLIST)
#define M_OPL_fol_cmp_t() FUNC_OBJ_INS_OPLIST(fol_cmp, M_BASIC_OPLIST)
static void test_fo(void)
{
+140 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -23,6 +23,7 @@
#include <stdio.h>
#include "test-obj.h"
#include "m-array.h"
#include "m-string.h"
#include "coverage.h"
START_COVERAGE
@@ -37,9 +38,9 @@ ARRAY_DEF(array_min2_z, testobj_t, (INIT(testobj_init), CLEAR(testobj_clear)))
ARRAY_DEF(array_min3_z, testobj_t, (CLEAR(testobj_clear)))
ARRAY_DEF(array_ulong, uint64_t)
ARRAY_DEF(array_string, string_t)
ARRAY_DEF_AS(array_double, ArrayDouble, ArrayDoubleIt, double)
#define M_OPL_ArrayDouble() ARRAY_OPLIST(array_double, M_DEFAULT_OPLIST)
#define M_OPL_ArrayDouble() ARRAY_OPLIST(array_double, M_BASIC_OPLIST)
ArrayDouble g_array = ARRAY_INIT_VALUE();
@@ -279,11 +280,61 @@ static void test_mpz(void)
// NOTE: Not the same order than list...
}
testobj_clear (z);
array_mpz_clear(array2);
array_mpz_reset(array1);
/* Test of the emplace functions.
* 3 functions have been generated for testobj:
* one from unsigned int (suffix _ui)
* one from C string (suffix _str)
* one from testobj_t itself (no suffix)
*/
array_mpz_emplace_back_ui(array1, 42);
assert(testobj_cmp_ui(*array_mpz_back(array1), 42) == 0);
array_mpz_emplace_back_ui(array1, 426);
assert(testobj_cmp_ui(*array_mpz_back(array1), 426) == 0);
array_mpz_emplace_back_str(array1, "458");
assert(testobj_cmp_ui(*array_mpz_back(array1), 458) == 0);
testobj_set_ui(z, 789);
array_mpz_emplace_back(array1, z);
assert(testobj_cmp_ui(*array_mpz_back(array1), 789) == 0);
testobj_clear (z);
array_mpz_clear(array1);
}
static void test_str(void)
{
array_string_t a;
array_string_init(a);
// Test of emplace with const char * ==> string_t
array_string_emplace_back(a, "Hello");
assert(string_equal_str_p(*array_string_back(a), "Hello"));
array_string_emplace_back(a, "world");
assert(string_equal_str_p(*array_string_back(a), "world"));
array_string_emplace_back(a, "How");
assert(string_equal_str_p(*array_string_back(a), "How"));
array_string_emplace_back(a, "are");
assert(string_equal_str_p(*array_string_back(a), "are"));
array_string_emplace_back(a, "you");
assert(string_equal_str_p(*array_string_back(a), "you"));
// Test stable sort with string_t
array_string_special_stable_sort(a);
// Test INIT_WITH of array of string_t wihtin M_LET
M_LET( (b, ("Hello"), ("How"), ("are"), ("world"), ("you")), ARRAY_OPLIST(array_string, STRING_OPLIST)){
assert( array_string_equal_p(a, b));
}
array_string_clear(a);
}
static void test_d(void)
{
array_uint_t a1, a2;
@@ -393,11 +444,96 @@ static void test_double(void)
array_double_clear(g_array);
}
// Test support of M*LIB for C++ class
#if defined(__cplusplus)
/* For this, we need new placement support */
#include <new>
/* For std::move */
#include <utility>
/* Some Simple Oplist for a C++ class (using new placement feature)
Some features may not be always available (like comparison or I/O).
It isn't exported, since there is no meaning to support for M*LIB
C++ class officialy (use the STL instead!)
*/
#define M_CLASS_CPP_INIT(opl,x) (new (&(x)) (M_GET_NAME opl))
#define M_CLASS_CPP_INIT_SET(opl,x, y) (new (&(x)) M_GET_NAME opl(y))
#define M_CLASS_CPP_SET(opl, x, y) ((x) = (y))
#define M_CLASS_CPP_CLEAR(opl, x) ((&(x))->~M_GET_NAME opl())
#define M_CLASS_CPP_CLEAR2(x) ((&(x))->~opl())
#define M_CLASS_CPP_INIT_MOVE(opl,x,y) (new (&(x)) M_GET_NAME opl(std::move(y)), ((&(y))->~M_GET_NAME opl()))
#define M_CLASS_CPP_CMP(opl, x, y) ((x) < (y) ? -1 : (y) < (x) ? 1 : 0)
#define M_CLASS_CPP_HASH(opl, x) (std::hash(x))
#define M_CLASS_OPLIST(_class) \
(NAME(_class), \
TYPE(_class), \
INIT(API_1(M_CLASS_CPP_INIT)), \
INIT_SET(API_1(M_CLASS_CPP_INIT_SET)), \
SET(API_1(M_CLASS_CPP_SET)), \
CLEAR(API_1(M_CLASS_CPP_CLEAR)), \
INIT_MOVE(API_1(M_CLASS_CPP_INIT_MOVE)) )
// Define a basic C++ class
class Foo {
int *x;
public:
Foo() { x = new (int); };
Foo(int n) { x = new (int) ; *x = n; }
Foo(const Foo &y) {x = new (int) ; *x = *y.x;};
~Foo() { delete x; }
void operator=(const Foo &y) { *x = *y.x; };
void operator=(int n) { *x = n; }
bool operator<(const Foo &y) const { return *x < *y.x; }
bool operator==(int n) const { return *x == n; }
};
// Disable the warning due to using memcpy/memmove with this C++ class
#if defined(__GNUC__) && __GNUC__ >= 8
_Pragma("GCC diagnostic push")
_Pragma("GCC diagnostic ignored \"-Wclass-memaccess\"")
#endif
// Define a M*LIB array of such class
ARRAY_DEF_AS(array_foo, array_foo_t, array_foo_it_t, Foo, M_CLASS_OPLIST(Foo))
#define M_OPL_array_foo_t() ARRAY_OPLIST(array_foo, M_CLASS_OPLIST(Foo))
#if defined(__GNUC__) && __GNUC__ >= 8
_Pragma("GCC diagnostic pop")
#endif
static void test_cplusplus(void)
{
int n = 100;
M_LET(a, array_foo_t) {
Foo b;
for(int i = 0; i < n; i++) {
b = i;
array_foo_push_back(a, b);
}
array_foo_it_t it;
int j = 0;
for(array_foo_it(it, a); !array_foo_end_p(it); array_foo_next(it)) {
assert( *array_foo_cref(it) == j);
j++;
}
assert(j == n);
}
}
#else
static void test_cplusplus(void)
{
// Nothing to do
}
#endif
int main(void)
{
test_uint();
test_mpz();
test_d();
test_str();
test_double();
test_cplusplus();
exit(0);
}
+66 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -377,6 +377,70 @@ static void test_clz(void)
bitset_set_str(s1, "[10000011100000110010101010110000011111111111111110000001110001110001110001110000]");
assert(bitset_popcount(s1) == 40);
}
M_LET(s1, bitset_t) {
bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]");
assert(bitset_ctz(s1) == 116);
bitset_set_str(s1, "[10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]");
assert(bitset_ctz(s1) == 0);
bitset_set_str(s1, "[01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]");
assert(bitset_ctz(s1) == 1);
bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]");
assert(bitset_ctz(s1) == 115);
bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010]");
assert(bitset_ctz(s1) == 114);
bitset_set_str(s1, "[000001]");
assert(bitset_ctz(s1) == 5);
bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000001]");
assert(bitset_ctz(s1) == 64);
bitset_set_str(s1, "[000000000000000000000000000000000000000000000000000000000000000010000]");
assert(bitset_ctz(s1) == 64);
bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000001]");
assert(bitset_ctz(s1) == 63);
bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000001000]");
assert(bitset_ctz(s1) == 63);
bitset_set_str(s1, "[000000000000000000000000000000000000000000000000000000000000000001]");
assert(bitset_ctz(s1) == 65);
bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000000010000]");
assert(bitset_ctz(s1) == 65);
bitset_set_str(s1, "[00001000001110000011001010101011000001111111111111111000000111000111000111000111000]");
assert(bitset_ctz(s1) == 4);
bitset_set_str(s1, "[000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]");
assert(bitset_ctz(s1) == 128);
bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]");
assert(bitset_ctz(s1) == 127);
bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]");
assert(bitset_ctz(s1) == 129);
bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000100000000000000000001]");
assert(bitset_ctz(s1) == 128);
bitset_set_str(s1, "[000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000010000000000000000001000]");
assert(bitset_ctz(s1) == 127);
bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000011000000000000000000000000]");
assert(bitset_ctz(s1) == 129);
}
}
// Detect bug on bitset_resize function in case of increase of size.
// the first limb may not be cleared properly in some cases
static void test_resize(void)
{
M_LET(set, bitset_t) {
for(size_t i = 1; i < 257; i++) {
bitset_resize(set, i);
assert( bitset_get(set, i-1) == false);
bitset_set_at(set, 0, true);
bitset_set_at(set, i-1, true);
bitset_reset(set);
bitset_resize(set, i);
assert( bitset_get(set, 0) == false);
assert( bitset_get(set, i-1) == false);
bitset_set_at(set, 0, true);
bitset_set_at(set, i-1, true);
bitset_resize(set, i-1);
bitset_resize(set, i);
assert( bitset_get(set, i-1) == false);
}
}
}
int main(void)
@@ -387,5 +451,6 @@ int main(void)
test_logic();
test_let();
test_clz();
test_resize();
exit(0);
}
+59 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -28,27 +28,28 @@
#include "coverage.h"
START_COVERAGE
BPTREE_DEF2(btree, 3, int, M_DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
BPTREE_DEF2(btree, 3, int, M_BASIC_OPLIST, int, M_BASIC_OPLIST)
END_COVERAGE
BPTREE_DEF2(btree_my, 3, testobj_t, TESTOBJ_CMP_OPLIST, testobj_t, TESTOBJ_CMP_OPLIST)
BPTREE_DEF2(btree_string, 5, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
BPTREE_DEF2(btree_int, 17, int, int)
BPTREE_DEF2(btree_mpz, 9, string_t, STRING_OPLIST, testobj_t, TESTOBJ_CMP_OPLIST)
BPTREE_DEF(btree_intset, 13, int)
BPTREE_DEF(btree_myset, 15, testobj_t, TESTOBJ_CMP_OPLIST)
BPTREE_MULTI_DEF2(multimap, 3, int, M_DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
BPTREE_MULTI_DEF(multiset, 6, int, M_DEFAULT_OPLIST)
BPTREE_MULTI_DEF2(multimap, 3, int, M_BASIC_OPLIST, int, M_BASIC_OPLIST)
BPTREE_MULTI_DEF(multiset, 6, int, M_BASIC_OPLIST)
BPTREE_DEF2_AS(MapDouble, MapDouble, MapDoubleIt, MapDoubleItRef, 4, double, double)
#define M_OPL_MapDouble() BPTREE_OPLIST2(MapDouble, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
#define M_OPL_MapDouble() BPTREE_OPLIST2(MapDouble, M_BASIC_OPLIST, M_BASIC_OPLIST)
BPTREE_DEF_AS(SetDouble, SetDouble, SetDoubleIt, 7, double)
#define M_OPL_SetDouble() BPTREE_OPLIST(SetDouble, M_DEFAULT_OPLIST)
#define M_OPL_SetDouble() BPTREE_OPLIST(SetDouble, M_BASIC_OPLIST)
BPTREE_MULTI_DEF2_AS(MultiMapDouble, MultiMapDouble, MultiMapDoubleIt, MultiMapDoubleItRef, 8, double, double)
#define M_OPL_MultiMapDouble() BPTREE_OPLIST2(MultiMapDouble, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
#define M_OPL_MultiMapDouble() BPTREE_OPLIST2(MultiMapDouble, M_BASIC_OPLIST, M_BASIC_OPLIST)
BPTREE_MULTI_DEF_AS(MultiSetDouble, MultiSetDouble, MultiSetDoubleIt, 9, double)
#define M_OPL_MultiSetDouble() BPTREE_OPLIST(MultiSetDouble, M_DEFAULT_OPLIST)
#define M_OPL_MultiSetDouble() BPTREE_OPLIST(MultiSetDouble, M_BASIC_OPLIST)
static void test1(void)
{
@@ -641,6 +642,55 @@ static void test_double(void)
}
}
static void test_emplace (void)
{
btree_mpz_t d;
btree_mpz_init(d);
string_t s;
string_init(s);
testobj_t o;
testobj_init(o);
btree_mpz_emplace_key_val_str(d, "HELLO", "14");
string_set_str(s, "HELLO");
testobj_t *ptr = btree_mpz_get(d, s);
assert(ptr != NULL);
assert(testobj_cmp_ui(*ptr, 14) == 0);
btree_mpz_emplace_key_val_ui(d, "HE", 145);
string_set_str(s, "HE");
ptr = btree_mpz_get(d, s);
assert(ptr != NULL);
assert(testobj_cmp_ui(*ptr, 145) == 0);
testobj_set(o, *ptr);
btree_mpz_emplace_key_val(d, "SHE", o);
string_set_str(s, "SHE");
ptr = btree_mpz_get(d, s);
assert(ptr != NULL);
assert(testobj_cmp_ui(*ptr, 145) == 0);
btree_mpz_emplace_key(d, "IT", o);
string_set_str(s, "IT");
ptr = btree_mpz_get(d, s);
assert(ptr != NULL);
assert(testobj_cmp_ui(*ptr, 145) == 0);
btree_mpz_emplace_val_ui(d, s, 19);
ptr = btree_mpz_get(d, s);
assert(ptr != NULL);
assert(testobj_cmp_ui(*ptr, 19) == 0);
btree_mpz_emplace_val_str(d, s, "190");
ptr = btree_mpz_get(d, s);
assert(ptr != NULL);
assert(testobj_cmp_ui(*ptr, 190) == 0);
testobj_clear(o);
string_clear(s);
btree_mpz_clear(d);
}
int main(void)
{
test1();
@@ -654,5 +704,6 @@ int main(void)
test_multimap();
test_multiset();
test_double();
test_emplace();
exit(0);
}
+22 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -49,9 +49,14 @@ QUEUE_SPSC_DEF(squeue_a, testobj_t, BUFFER_QUEUE, TESTOBJ_OPLIST)
BUFFER_DEF_AS(BufferDouble1, BufferDouble1, double, 4, BUFFER_QUEUE)
QUEUE_MPMC_DEF_AS(BufferDouble2, BufferDouble2, double, BUFFER_QUEUE)
QUEUE_SPSC_DEF_AS(BufferDouble3, BufferDouble3, double, BUFFER_QUEUE)
#define M_OPL_BufferDouble1() BUFFER_OPLIST(BufferDouble1, M_DEFAULT_OPLIST)
#define M_OPL_BufferDouble2() BUFFER_OPLIST(BufferDouble2, M_DEFAULT_OPLIST)
#define M_OPL_BufferDouble3() BUFFER_OPLIST(BufferDouble3, M_DEFAULT_OPLIST)
#define M_OPL_BufferDouble1() BUFFER_OPLIST(BufferDouble1, M_BASIC_OPLIST)
#define M_OPL_BufferDouble2() BUFFER_OPLIST(BufferDouble2, M_BASIC_OPLIST)
#define M_OPL_BufferDouble3() BUFFER_OPLIST(BufferDouble3, M_BASIC_OPLIST)
// Define buffer with ENUM oplist (with API_1 usage)
typedef enum { OK, KO } state_t;
#define M_OPL_state_t() M_ENUM_OPLIST(state_t, OK)
BUFFER_DEF(array_state, state_t, 0, M_BUFFER_QUEUE)
buffer_uint_t g_buff;
buffer_uint_t g_buffB;
@@ -266,6 +271,18 @@ static void test_no_thread(void)
buffer_llong_clear(buff);
}
static void test_emplace(void)
{
buffer_mpz_t b;
buffer_mpz_init(b, 32);
buffer_mpz_emplace_str(b, "56");
testobj_t o;
testobj_init(o);
buffer_mpz_pop(&o, b);
assert( testobj_cmp_ui(o, 56) == 0 );
testobj_clear(o);
buffer_mpz_clear(b);
}
/********************************************************************************************/
/* Test intrusive shared pointer + buffer */
@@ -637,6 +654,7 @@ int main(void)
test_stack();
test_stack2();
test_no_thread();
test_emplace();
test_global_ishared();
test_queue(1000000, 2, 2148371710223136ULL);
test_spsc();
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Test for Concurrent memory pool allocator
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
+19 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,13 +37,13 @@
#include "m-concurrent.h"
TUPLE_DEF2(point, (x, int), (y, int))
#define M_OPL_point_t() TUPLE_OPLIST(point, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
#define M_OPL_point_t() TUPLE_OPLIST(point, M_BASIC_OPLIST, M_BASIC_OPLIST)
START_COVERAGE
CONCURRENT_DEF(ppoint, point_t)
END_COVERAGE
VARIANT_DEF2(dimension, (x, int), (y, float))
#define M_OPL_dimension_t() VARIANT_OPLIST(dimension, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
#define M_OPL_dimension_t() VARIANT_OPLIST(dimension, M_BASIC_OPLIST, M_BASIC_OPLIST)
CONCURRENT_DEF(pdimension, dimension_t)
ARRAY_DEF(array1, int)
@@ -68,7 +68,7 @@ PRIOQUEUE_DEF(prio1, int)
CONCURRENT_DEF(pprio1, prio1_t, PRIOQUEUE_OPLIST(prio1))
BPTREE_DEF2(bptree1, 10, int, int)
CONCURRENT_DEF(pbtree1, bptree1_t, BPTREE_OPLIST2(bptree1, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
CONCURRENT_DEF(pbtree1, bptree1_t, BPTREE_OPLIST2(bptree1, M_BASIC_OPLIST, M_BASIC_OPLIST))
BPTREE_DEF(bptree2, 10, int)
CONCURRENT_DEF(pbtree2, bptree2_t, BPTREE_OPLIST(bptree2))
@@ -110,8 +110,8 @@ static inline void int_oor_set(int *s, unsigned char n)
*s = -n;
}
#define INT_OA_OPLIST \
M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(int_oor_equal_p), OOR_SET(API_2(int_oor_set)))
DICT_OA_DEF2(dict3, int, INT_OA_OPLIST, int, M_DEFAULT_OPLIST)
M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(int_oor_equal_p), OOR_SET(API_2(int_oor_set)))
DICT_OA_DEF2(dict3, int, INT_OA_OPLIST, int, M_BASIC_OPLIST)
CONCURRENT_DEF(pdict3, dict3_t, DICT_OPLIST(dict3))
/********************************/
@@ -226,6 +226,18 @@ static void test_double(void)
ConcurrentRpDouble_clear(r);
}
static void test_emplace(void)
{
key_list_ts_t ts;
key_list_ts_init(ts);
key_list_ts_emplace(ts, "HELLO");
M_LET(s, string_t) {
key_list_ts_pop(&s, ts);
assert(string_equal_str_p(s, "HELLO"));
}
key_list_ts_clear(ts);
}
int main(void)
{
test_basic();
@@ -233,5 +245,6 @@ int main(void)
test_thread();
test_rp_thread();
test_double();
test_emplace();
exit(0);
}
+155 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,6 +34,13 @@ static void test_cat(void)
assert (M_C(A,andB));
assert (M_C3(A,and,B));
assert (M_C4(A,and,B,andC));
assert (M_C3_EMPTY(A,and,B));
assert (M_C3_EMPTY(Aand,,B));
assert (M_C3_EMPTY(AandB,,));
assert (M_C5_EMPTY(A,a,n,d,B));
assert (M_C5_EMPTY(Aand,,,,B));
}
static void test_power2(void)
@@ -156,6 +163,37 @@ static void test_incdec(void)
assert(!M_KEYWORD_P(M_OVERFLOW, M_ADD(M_MAX_NB_ARGUMENT, 1)));
assert(M_KEYWORD_P(M_OVERFLOW, M_ADD(M_MAX_NB_ARGUMENT, 2)));
assert(M_KEYWORD_P(M_OVERFLOW, M_ADD(M_MAX_NB_ARGUMENT, 3)));
// Test if the initial error is not lost in translation
assert(M_KEYWORD_P(M_UNDERFLOW, M_INC(M_UNDERFLOW)));
assert(M_KEYWORD_P(M_OVERFLOW, M_DEC(M_OVERFLOW)));
assert(M_AND(0, 0) == 0);
assert(M_AND(0, 1) == 0);
assert(M_AND(1, 0) == 0);
assert(M_AND(1, 1) == 1);
assert(M_OR(0, 0) == 0);
assert(M_OR(0, 1) == 1);
assert(M_OR(1, 0) == 1);
assert(M_OR(1, 1) == 1);
assert(M_AND3(0, 0, 0) == 0);
assert(M_AND3(0, 0, 1) == 0);
assert(M_AND3(0, 1, 0) == 0);
assert(M_AND3(0, 1, 1) == 0);
assert(M_AND3(1, 0, 0) == 0);
assert(M_AND3(1, 0, 1) == 0);
assert(M_AND3(1, 1, 0) == 0);
assert(M_AND3(1, 1, 1) == 1);
assert(M_OR3(0, 0, 0) == 0);
assert(M_OR3(0, 0, 1) == 1);
assert(M_OR3(0, 1, 0) == 1);
assert(M_OR3(0, 1, 1) == 1);
assert(M_OR3(1, 0, 0) == 1);
assert(M_OR3(1, 0, 1) == 1);
assert(M_OR3(1, 1, 0) == 1);
assert(M_OR3(1, 1, 1) == 1);
}
static void test_return(void)
@@ -230,6 +268,7 @@ static void test_map(void)
assert (M_MAP (f, 1) 0 == 1);
assert (M_MAP (f, 1, 2) 0 == 5);
assert (M_MAP (f, 1, 2, 3) 0 == 14);
assert (M_MAP (f, M_SEQ(1, 4)) 0 == 1+4+9+16);
assert (M_MAP2 (f2, 2, 1) 0 == 2);
assert (M_MAP2 (f2, 3, 1, 2) 0 == 9);
@@ -238,6 +277,19 @@ static void test_map(void)
assert (M_MAP3 (f3, 2, 2) 0 == 4);
assert (M_MAP3 (f3, 3, 2, 4) 0 == 30);
assert (M_MAP3 (f3, 4, 2, 4, 6) 0 == 8+32+12*6);
assert (M_CROSS_MAP(f2, (1), (2)) 0 == 1*2);
assert (M_CROSS_MAP(f2, (1), (2, 3)) 0 == 1*2+1*3);
assert (M_CROSS_MAP(f2, (1, 3), (2)) 0 == 1*2+3*2);
assert (M_CROSS_MAP(f2, (1, 3), (2,4)) 0 == 1*2 + 1*4 + 3*2 + 3*4);
assert (M_CROSS_MAP(f2, (1, 3, 5), (2,4)) 0 == 1*2 + 1*4 + 3*2 + 3*4 + 5*2 + 5*4);
assert (M_CROSS_MAP2(f3, 2, (1), (2)) 0 == (1*2) * 2);
assert (M_CROSS_MAP2(f3, 2, (1), (2, 3)) 0 == (1*2+1*3) * 2);
assert (M_CROSS_MAP2(f3, 2, (1, 3), (2)) 0 == (1*2+3*2) * 2);
assert (M_CROSS_MAP2(f3, 2, (1, 3), (2,4)) 0 == (1*2 + 1*4 + 3*2 + 3*4) * 2);
assert (M_CROSS_MAP2(f3, 2, (1, 3, 5), (2,4)) 0 == (1*2 + 1*4 + 3*2 + 3*4 + 5*2 + 5*4)*2);
}
static void test_let(void)
@@ -290,6 +342,7 @@ static void test_let(void)
M_LET( (x, 4590) , OPL6)
assert (x == 4590);
// Test of M_LET_IF
int c = 0;
M_LET_IF( assert(c++ == 0), (assert(c++ == 1), true), assert(c++ == 3)) {
assert(c++ == 2);
@@ -351,12 +404,14 @@ static void test_if(void)
static void test_test(void)
{
assert(M_COMMA_P(,));
assert(M_COMMA_P(1,2));
assert(M_COMMA_P(1,2,aa));
assert(!M_COMMA_P(1));
assert(!M_COMMA_P(()));
assert(!M_COMMA_P("aa"));
assert(!M_COMMA_P(""));
assert(!M_COMMA_P((,)));
assert(M_PARENTHESIS_P(()));
assert(M_PARENTHESIS_P((aa)));
@@ -369,6 +424,26 @@ static void test_test(void)
assert(!M_PARENTHESIS_P(,));
assert(!M_PARENTHESIS_P((),));
assert(!M_PARENTHESIS_P(()x));
assert(!M_KEYWORD_P(sum, sul));
assert(M_KEYWORD_P(sum, sum));
assert(M_KEYWORD_P(sum, add));
assert(M_KEYWORD_P(product, product));
assert(M_KEYWORD_P(product, mul));
assert(!M_KEYWORD_P(product, mul2));
assert(M_KEYWORD_P(_, _));
assert(M_KEYWORD_P(_, _() ));
assert(M_KEYWORD_P(LIST, LIST));
assert(M_KEYWORD_P(LIST, LIST(1,23,4) ));
assert(!M_KEYWORD_P(LIST, SEQ(1,23,4) ));
assert(M_KEYWORD_TO_VA_ARGS(LIST, LIST(16)) == 16);
assert(M_KEYWORD_TO_VA_ARGS(LIST, LIST(14)) == 14);
assert(M_GET_AT( ( M_KEYWORD_TO_VA_ARGS(LIST, LIST(11, 22, 33)) ), 0) == 11);
assert(M_GET_AT( ( M_KEYWORD_TO_VA_ARGS(LIST, LIST(11, 22, 33)) ), 1) == 22);
assert(M_GET_AT( ( M_KEYWORD_TO_VA_ARGS(LIST, LIST(11, 22, 33)) ), 2) == 33);
assert(M_KEYWORD_TO_VA_ARGS(_, _(10)) == 10);
}
static void test_list(void)
@@ -439,11 +514,11 @@ static void test_oplist(void)
#define CHECK_OPLIST(op, oplist) \
M_IF_METHOD(op, oplist) (true, false)
assert (CHECK_OPLIST (INIT, M_DEFAULT_OPLIST));
assert (CHECK_OPLIST (INIT_SET, M_DEFAULT_OPLIST));
assert (CHECK_OPLIST (SET, M_DEFAULT_OPLIST));
assert (CHECK_OPLIST (CLEAR, M_DEFAULT_OPLIST));
assert (!CHECK_OPLIST (CLEAR_TOOT, M_DEFAULT_OPLIST));
assert (CHECK_OPLIST (INIT, M_BASIC_OPLIST));
assert (CHECK_OPLIST (INIT_SET, M_BASIC_OPLIST));
assert (CHECK_OPLIST (SET, M_BASIC_OPLIST));
assert (CHECK_OPLIST (CLEAR, M_BASIC_OPLIST));
assert (!CHECK_OPLIST (CLEAR_TOOT, M_BASIC_OPLIST));
assert (M_OPLIST_P(()));
assert (M_OPLIST_P((INIT(init))));
@@ -504,6 +579,9 @@ static void test_reduce(void)
assert ( M_REDUCE2(id, add, d, M_SEQ(1, 5)) == 5 * 6 /2);
assert ( M_REDUCE2(id, add, d, M_SEQ(1, 10)) == 10 * 11 /2);
assert ( M_REDUCE2(id, add, d, M_SEQ(1, 1)) == 1);
assert ( M_REDUCE2(id, add, d, M_SEQ(1, 2)) == 1+2);
assert ( M_REDUCE(M_ID, add, M_SEQ(1, 5))
+ M_REDUCE(M_ID, add, M_SEQ(6, 10))
== M_REDUCE(M_ID, add, M_SEQ(1, 10)));
@@ -694,6 +772,18 @@ static void test_builtin(void)
assert(m_core_clz64((uint64_t) ((1ULL<<i) | 1)) == 63U - i);
}
assert(m_core_ctz32(0) == 32);
for(unsigned i = 0; i < 31; i++) {
assert(m_core_ctz32((uint32_t) (1UL<<i)) == i);
assert(m_core_ctz32((uint32_t) ((1UL<<i) | 1UL<<31)) == i);
}
assert(m_core_ctz64(0) == 64);
for(unsigned i = 0; i < 63; i++) {
assert(m_core_ctz64((uint64_t) (1ULL<<i)) == i);
assert(m_core_ctz64((uint64_t) ((1ULL<<i) | 1ULL<<63)) == i);
}
assert ( m_core_roundpow2(0) == 0);
for(unsigned i = 0; i < 62; i++) {
assert ( m_core_roundpow2(1ULL<<i) == 1ULL<<i);
@@ -758,6 +848,64 @@ static void test_properties(void)
assert( M_GET_PROPERTY (OP_PROP(), IT_TYPE ) == 2);
assert( M_KEYWORD_P( M_GET_PROPERTY (OP_PROP(), INIT_WITH ), priority));
}
static int init3(int *p, int a, int b)
{
*p = b;
return a;
}
static int cmp1(int a, int b)
{
return a < b ? -1 : a > b;
}
static int cmp2(int *a, int *b)
{
return *a < *b ? -1 : *a > *b;
}
#define cmp3(a, b) \
(a < b ? -1 : a > b)
static void test_generic_api(void)
{
assert( M_HEAD(17, 0) == 17);
assert( M_TAIL(18, 19) == 19);
assert( M_HEAD_2(18, 17, 0) == 17);
assert( M_TAIL_2(18, 17, 8) == 8);
#define GO1 (INIT(API( init3, ARG1, ARGPTR2, 17, 43 )))
#define GO2 (INIT(API( init3, NONE, ARGPTR2, 0, ARG1 )))
#define GO3 (EQUAL(API( cmp2, EQ(0), ARGPTR1, ARGPTR2 )))
#define GO4 (EQUAL(API( cmp1, EQ(0), ARG1, ARG2 )))
#define GO5 (EQUAL(API( cmp3, EQ(0), ARG1, ARG2 )))
int x = 0, y = 0;
M_CALL_INIT(GO1, x, y);
assert(x == 17);
assert(y == 43);
x = 89;
M_CALL_INIT(GO2, x, y);
assert( y == 89);
assert( x == 89);
x = y = 78;
bool b = M_CALL_EQUAL(GO3, x, y);
assert(b);
x = 77;
b = M_CALL_EQUAL(GO4, x, y);
assert(!b);
x = y = 78;
b = M_CALL_EQUAL(GO5, x, y);
assert(b);
x = 77;
b = M_CALL_EQUAL(GO5, x, y);
assert(!b);
}
int main(void)
{
test_cat();
@@ -783,5 +931,6 @@ int main(void)
test_str_hash();
test_M_CSTR();
test_properties();
test_generic_api();
exit(0);
}
+8 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2022, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -46,7 +46,7 @@ DEQUE_DEF(deque_retcode, ReturnCode_t, M_ENUM_OPLIST(ReturnCode_t, SUCCESS))
#define OPL DEQUE_OPLIST(deque)
DEQUE_DEF_AS(DequeDouble, DequeDouble, DequeDoubleIt, double)
#define M_OPL_DequeDouble() DEQUE_OPLIST(DequeDouble, M_DEFAULT_OPLIST)
#define M_OPL_DequeDouble() DEQUE_OPLIST(DequeDouble, M_BASIC_OPLIST)
ARRAY_DEF(array, int)
@@ -323,8 +323,13 @@ static void test_z(void)
testobj_clear(z);
deque_mpz_pop_front_move(&z, d);
assert (testobj_cmp_ui (z, 4217) == 0);
}
deque_mpz_emplace_back_ui(d, 45);
assert(testobj_cmp_ui(*deque_mpz_back(d), 45) == 0);
deque_mpz_emplace_front_str(d, "450");
assert(testobj_cmp_ui(*deque_mpz_front(d), 450) == 0);
assert(testobj_cmp_ui(*deque_mpz_back(d), 45) == 0);
}
}
static void test_io(void)
Loaded 100 of 126 files, more files were not shown because too many files have changed in this diff. Show more