669 Commits
Author SHA1 Message Date
Patrick Pelissier 8902a752f5 Migrate to V0.7.2 2023-12-31 13:02:42 +01:00
PpHd 3445da13f3 Merge generic interface (WIP) 2023-12-31 12:53:10 +01:00
Patrick Pelissier 127530abaa Fix format 2023-12-30 16:27:25 +01:00
Patrick Pelissier ed0f538fb7 Add documentation of generic interface 2023-12-30 16:23:02 +01:00
Patrick Pelissier 76ef061dec Add basic example of generic interface 2023-12-30 16:23:02 +01:00
Patrick Pelissier c98786a3b3 Update TODO items 2023-12-30 16:23:02 +01:00
Patrick Pelissier 422f3c2c04 Add GENTYPE operator to all oplists 2023-12-30 16:23:02 +01:00
Patrick Pelissier 5ceb34d980 Cosmetics changes 2023-12-30 16:23:02 +01:00
Patrick Pelissier 73e3d1d1bd Register string_t globally 2023-12-30 16:23:02 +01:00
Patrick Pelissier 044a085fb6 Fix support for pop generic macro function 2023-12-30 16:23:02 +01:00
Patrick Pelissier 5344423ad9 Reorder header / comment 2023-12-30 16:23:02 +01:00
Patrick Pelissier 76ea989865 Fix warnings 2023-12-30 16:23:02 +01:00
Patrick Pelissier 29c4ba3dcc Add support for M_PRINT 2023-12-30 16:23:02 +01:00
Patrick Pelissier 42184f69db Disable generic tests for TCC 2023-12-30 16:23:02 +01:00
Patrick Pelissier fb8bf65233 Worlaround for warning with clang 2023-12-30 16:23:02 +01:00
Patrick Pelissier 1d86e51f4a Improve test suite 2023-12-30 16:23:02 +01:00
Patrick Pelissier 53c35a22d7 First version of Generic header 2023-12-30 16:23:02 +01:00
Patrick Pelissier 722737d60c Add M_QUAD internal macros 2023-12-30 16:23:02 +01:00
Patrick Pelissier f951a947ec Adding a try catch example 2023-12-30 13:42:47 +01:00
Patrick Pelissier d9401371a6 Fix warnings reported by CLANG,
the C warning generator.
2023-12-23 13:16:42 +01:00
Patrick Pelissier 690fd72c8b Fix documentation 2023-12-23 11:24:25 +01:00
Patrick Pelissier d318493c6c Remove M_PRINT_ARG macro to simplify maintenance
(M_FPRINT_MACRO with stdout can be used instead)
2023-12-22 23:46:07 +01:00
Patrick Pelissier fecece19cb Add retry for TCC due the random segfault it generates 2023-12-22 23:45:39 +01:00
Patrick Pelissier ea640482a7 Add new examples with custom allocation 2023-12-20 19:25:27 +01:00
Patrick Pelissier 3e558af559 Remove unused function 2023-12-20 19:24:57 +01:00
Patrick Pelissier 91a602f774 Add bench of boost unordered flat hashmap 2023-12-19 20:58:02 +01:00
Patrick Pelissier 6a5c136c72 Complete bench-verstable with bench on big structure 2023-12-13 19:35:08 +01:00
Patrick Pelissier e50fdc82ef Add benchmark for verstable 2023-12-12 23:59:17 +01:00
Patrick Pelissier ec0a082701 Update ISSUE 2023-12-12 22:57:13 +01:00
Patrick Pelissier 7bf3ea3a87 Update Function Object interface
to make interface trivially copiable

There is no need to perform a copy-protected type as there is no init/clear for this type.
It is always created through an instance.
2023-12-09 12:40:45 +01:00
Patrick Pelissier 15492394ad Update list of exported files 2023-12-08 20:58:47 +01:00
Patrick Pelissier 09f40b5695 Fix format 2023-12-08 20:58:33 +01:00
Patrick Pelissier eabfcd1d49 Update list of ignored files 2023-12-08 00:25:53 +01:00
Patrick Pelissier 00aeafc616 Update comments 2023-12-06 23:55:11 +01:00
Patrick Pelissier f512051807 Migrate to actions/checkout@v4 2023-12-06 23:52:04 +01:00
Patrick Pelissier 4e8b929da9 Migrate to vmactions/freebsd-vm v1 2023-12-06 23:51:40 +01:00
Patrick Pelissier 5841f936e6 Work around static analyzer
that raise an issue on freeing non heap pointer
2023-12-02 13:48:21 +01:00
Patrick Pelissier 2ee40339b0 Using emplace to generate init_with for shared_ptr:
Equivalent to C++ make_shared)
2023-12-02 13:21:45 +01:00
Patrick Pelissier 0c8eca893d Add example of REST client
by using libcurl for HTTP connection
and M*LIB for JSON formating.
2023-11-25 13:33:27 +01:00
Patrick Pelissier b16048a55b Add test cases for tuple emplace 2023-11-25 13:32:57 +01:00
Patrick Pelissier 9dc582c6bc Add emplace set functions for tuple 2023-11-25 13:30:08 +01:00
Patrick Pelissier 1df8bf84fb Fix oplist definition for tuple.
The oplist didn't include as many sub-oplists as the number of variables.
2023-11-25 13:29:48 +01:00
Patrick Pelissier e017a90e5c Fix format 2023-11-04 19:28:32 +01:00
Patrick Pelissier 58b317b759 Add timeout for run in VM 2023-11-04 18:50:43 +01:00
Patrick Pelissier 3a057fc319 M_STATIC_ASSERT: provide expression compatible
macro even in pure C11 mode
(Remove GCC extension)

Add M_OPL_AS_STR to display the oplist conditionnaly as the generated string may be too big for some compilers.

Translate some M_STATIC_FAILURE into M_STATIC_ASSERT
as M_STATIC_FAILURE is not an expression whereas M_STATIC_ASSERT is an expression.
2023-11-04 18:48:13 +01:00
Patrick Pelissier 703ab6ff9c Update examples 2023-11-04 18:48:13 +01:00
Patrick Pelissier f7f5db61d3 Fix formatting 2023-11-01 11:13:54 +01:00
Patrick Pelissier 32b00eb433 Add new operator GENTYPE 2023-10-21 19:05:08 +02:00
Patrick Pelissier 796f2619e5 Change M_BY_NARGS semantics:
simplify suffix by __ # NARGS
instead of __NARGS_ # NARGS

Driver: reduce macro name length.
2023-10-20 00:02:38 +02:00
Patrick Pelissier 268192138a WIP M_ON_EXCEPTION 2023-10-19 22:54:51 +02:00
Patrick Pelissier 0671a2ea41 Update doc 2023-10-15 22:21:12 +02:00
Patrick Pelissier 07dce84e51 Tuple init: handle case of exception
during construction of tuple
2023-10-14 20:15:14 +02:00
Patrick Pelissier 5f4303624f Adding macro M_CHAIN_OBJ 2023-10-14 15:55:59 +02:00
Patrick Pelissier 19e61467d5 Adding tuple generation
for analysis of generated code.
2023-10-14 15:31:37 +02:00
Patrick Pelissier 1454bcebe4 Add unique name identifier
in order to avoid Wshadow warning
in generated code.
2023-10-14 15:30:57 +02:00
Patrick Pelissier d48f2ff84d Update comment 2023-10-06 22:38:36 +02:00
Patrick Pelissier 269636b4d8 Update doc with new macro M_CHAIN_INIT 2023-09-09 18:40:59 +02:00
Patrick Pelissier bf68340106 Add macro M_CHAIN_INIT for support of partially constructed object. 2023-09-09 18:40:32 +02:00
Patrick Pelissier 5dba526e29 Update ISSUES 2023-09-08 22:12:16 +02:00
Patrick Pelissier 469239adcd Update comments 2023-08-24 23:32:47 +02:00
Patrick Pelissier 589abda0c2 Fix bug in list insertion:
The output iterator has its previous field incorrect.
2023-08-13 23:27:12 +02:00
Patrick Pelissier 8f141896ba Clarify operators for memory allocation 2023-08-02 23:20:02 +02:00
Patrick Pelissier a0cbec4329 Support of output failure for serialization of strings 2023-08-02 23:20:02 +02:00
Patrick Pelissier df66db562d Add comments 2023-08-01 00:33:43 +02:00
Patrick Pelissier 1829a70601 Update documentation 2023-07-20 23:42:15 +02:00
Patrick Pelissier e9b25f2414 Rename internal field size to capacity
to match what it is used for.
2023-07-13 21:48:33 +02:00
Patrick Pelissier c9bb739f24 Fix format 2023-07-10 00:59:18 +02:00
Patrick Pelissier e049b83a9e Rename M_SUFFIX_FUNCTION_BY_NARGS in M_BY_NARGS
and updates suffix with __NARGS_
in order to be more explicit.
2023-07-10 00:58:31 +02:00
Patrick Pelissier 31ac3999a1 Add new operators 2023-07-07 22:17:39 +02:00
Patrick Pelissier a0818419ab Fix format 2023-07-04 01:08:40 +02:00
Patrick Pelissier 496f885a84 Add threads backend for FreeRTOS tasks. 2023-07-04 01:07:59 +02:00
Patrick Pelissier d5d9a4bd5c Update documentation of threads 2023-07-04 00:46:32 +02:00
Patrick Pelissier ca9571a110 Fix no stdio:
M_CSTR macro cannot be available if there is no stdio
2023-06-29 21:26:22 +02:00
Patrick Pelissier 4497214b9c Fix spelling 2023-06-29 00:32:23 +02:00
PpHd ccb1658afd Provide way of avoiding code duplication for multiple source C files
Use of compiler extension for that, only compatible for GCC /CLANG.
This provides easy and total customization (for example non template functions like strings can also avoid code duplication).
2023-06-13 23:46:58 +02:00
Patrick Pelissier eaf2783f1a Synchro with master branch 2023-06-11 23:32:42 +02:00
Patrick Pelissier 5705819814 Update doc 2023-06-11 23:32:02 +02:00
Patrick Pelissier 91f5f513c4 Update macro names
Make global logic easier.
2023-06-11 23:32:02 +02:00
Patrick Pelissier 3dec4e2cbe Fix example 2023-06-11 23:32:02 +02:00
Patrick Pelissier e70766beaa Update list of ignored file 2023-06-11 23:32:02 +02:00
Patrick Pelissier d7639f0ae0 Update example to match new semantic 2023-06-11 23:32:02 +02:00
Patrick Pelissier c63ce84e45 Update logic to select which linkage to use
so that user code can be written easily
M_USE_EXTERN_DECL / M_USE_DECL activates functions that are not inlined.
If M_USE_EXTERN_DEF / M_USE_DEF is also defined, then the definition is emitted instead of the declaration.
2023-06-11 23:32:02 +02:00
Patrick Pelissier a043c379c0 Update user code as per new liberty 2023-06-11 23:32:02 +02:00
Patrick Pelissier 92bb380117 Rewrite order in preprocessing if to simplify user code 2023-06-11 23:32:02 +02:00
Patrick Pelissier 6bb7a184db Fix compil rules 2023-06-11 23:32:02 +02:00
Patrick Pelissier fa9163be9d Make linker options optional 2023-06-11 23:32:02 +02:00
Patrick Pelissier 0bade1563c Also build exn.exe by default 2023-06-11 23:32:02 +02:00
Patrick Pelissier 1278d2f8a0 Implement noinline another way 2023-06-11 23:32:02 +02:00
Patrick Pelissier 53af2aae68 Add example of separating inline & function code 2023-06-11 23:32:02 +02:00
Patrick Pelissier 17ded6fcc8 Update M_USE_EXTERN_FINE_GRAINED to avoid warnings 2023-06-11 23:32:02 +02:00
Patrick Pelissier 19ce371533 Add support for M_USE_EXTERN_FINE_GRAINED to enable / disable inline semantics alongside the translation unit by redefining it when needed 2023-06-11 23:32:02 +02:00
Patrick Pelissier 0bd1bcb68e Another way to request the desired semantics, compatible with clang 2023-06-11 23:32:02 +02:00
Patrick Pelissier b50813713a Define internal M_INLINE:
it is used to control the inline semantics.
By combining it with optimize option "-fno-inline"
for the internal M*LIB function (using _Pragma optimize)
we can control easily if we want to use an inline version
or call of an external function.

Define new user API:
* M_USE_EXTERN_DECL : define it before including any MLIB header to requests to call the M*LIB functions and don't inline then.
* M_USE_EXTERN_DEF  : define it once in a translation unit to define the M*LIB functions. This translation unit shall contain all templated macro too.
If you use one option, you need to use the other one too for another translation unit.
2023-06-11 23:32:02 +02:00
Patrick Pelissier 2628536d20 Add +m_string_it_set_ref 2023-06-10 01:50:14 +02:00
Patrick Pelissier ecfa4a9152 Add new function string_pop_u
to pop the last unicode code point
of a string.
2023-06-03 00:59:34 +02:00
Patrick Pelissier dafe4bcec5 Add basic test for M_DEFAULT_ARGS
Print hint to developper in case of incorrect usage
2023-06-03 00:56:13 +02:00
Patrick Pelissier 8544a7f289 Update example 2023-05-30 14:01:30 +02:00
Patrick Pelissier aa18915d61 Fix overflow computation 2023-05-21 00:15:58 +02:00
Patrick Pelissier df4bc0a56c Remove alloc warning for analyzer:
it is not able to track allocations correctly and only give false warnings.
valgraind or memory sanitizer are much more reliable to track memory errors.
2023-05-13 00:52:06 +02:00
Patrick Pelissier b6046e5e23 Fix new warnings with GCC13 2023-05-13 00:52:06 +02:00
Patrick Pelissier b487bfe5ad Adding missing inline 2023-05-08 23:54:16 +02:00
PpHd 408272c810 Merge pull request
Add m_string_cat_vprintf
2023-05-08 23:35:54 +02:00
kitterion 6a9ee17eca Add tests 2023-05-08 23:17:19 +03:00
kitterion 05c5a94634 Add m_string_cat_vprintf 2023-05-08 20:52:47 +03:00
Patrick Pelissier b1b0927e9f Update examples 2023-05-06 21:54:08 +02:00
Patrick Pelissier 37770365a1 Fix several bugs:
* in case of some invalid format starting with ']' directly it wrongly assume that the parsing was valid.
* incase of exception handling, and an exception was raised during the internal parsing, some destructors wern't called.
2023-05-05 22:16:39 +02:00
Patrick Pelissier 82bdcc685a Add internal macro MQLET for internal M_LET use 2023-05-05 22:15:13 +02:00
Patrick Pelissier 26fa733f70 Fix format 2023-05-05 22:14:41 +02:00
Patrick Pelissier cd2fc05573 Add FIXED_SIZE property 2023-05-05 21:41:05 +02:00
Patrick Pelissier 33430d4359 Update 2023-04-29 18:46:09 +02:00
Patrick Pelissier dc95b49f05 Update 2023-04-29 12:07:10 +02:00
Patrick Pelissier 3ec24cfa40 Update 2023-04-29 11:41:08 +02:00
Patrick Pelissier 12b099dcf8 Update 2023-04-29 11:25:56 +02:00
Patrick Pelissier b885d6136c Update 2023-04-29 11:20:00 +02:00
Patrick Pelissier b51c4bea2b Update 2023-04-29 11:19:54 +02:00
Patrick Pelissier 302c5eb300 Remove export passthrough of NEW/DEL/REALLOC/FREE interface
from the container oplist.
It has no real practical purpose.
NEW/DEL/REALLOC/FREE shall be a property of the container
to be defined, and not a property for an already defined container.
2023-04-29 10:50:04 +02:00
Patrick Pelissier 6d2900a2bd Improve coverage of test suite. 2023-04-27 00:04:44 +02:00
Patrick Pelissier 573e09c56e Remove variable number of elements support which was not working.
Request an explicit number of elements.
2023-04-27 00:04:03 +02:00
Patrick Pelissier 0a39a17d36 The undefined number of element value of serial _array_start
is now (size_t)-1 and no longer 0.
Moreoever, a serialization interface may refuse outputting data
if it doesn't know the number of elements.
In which case, the container shall explictly compute the number
of elements and recall the serial object _array_start method.
2023-04-27 00:01:50 +02:00
Patrick Pelissier a913d0947c Rewrite code to fix coverage 2023-04-26 23:34:13 +02:00
Patrick Pelissier abbd8ad6ce Update 2023-04-26 22:56:23 +02:00
Patrick Pelissier a09c9fe1c3 Update 2023-04-26 22:56:23 +02:00
Patrick Pelissier 219c62ff5d Provide a way to alter the standard naming convention for the functions
Close #72
2023-04-22 09:33:08 +02:00
Patrick Pelissier 272a326375 Fix warning issue for coverage 2023-04-22 09:23:18 +02:00
Patrick Pelissier eca79f2c80 Improve coverage of test suite 2023-04-21 22:44:34 +02:00
Patrick Pelissier 2feda4059f Fix issue in case of invalid IO 2023-04-21 22:44:23 +02:00
Patrick Pelissier de0ef67cf2 Fix build issue with VC++ 2023-04-19 23:06:23 +02:00
Patrick Pelissier 95762a058c Fix const attribute of _get_emplace 2023-04-19 22:42:21 +02:00
Patrick Pelissier acd8671017 Fix test case according to contract. 2023-04-19 22:37:54 +02:00
Patrick Pelissier a6c1688f23 Fix issue in remove root node for tree (part 2) 2023-04-19 22:37:40 +02:00
Patrick Pelissier f6ed549ce5 Fix issue in tree_remove for root node index (Part 2)
Enable support of removing root node
In this case, it considers the first child of the root as the new root (breaking symetry)
2023-04-18 23:24:48 +02:00
Patrick Pelissier 8639fdbd98 Fix issue in tree_remove when it is root node (part 1) 2023-04-18 22:56:56 +02:00
Patrick Pelissier 693b09387f Improve coverage of test suite. 2023-04-18 22:19:41 +02:00
Patrick Pelissier 4052d3794b Tree: Transform runtime tests into assertion
as it is proven that it cannot happen.
2023-04-18 22:19:28 +02:00
Patrick Pelissier 044e9c3bf7 Fix benchmark 2023-04-17 16:56:57 +02:00
Patrick Pelissier 45a2a1afb2 Add bench for CC 2023-04-16 21:16:04 +02:00
Patrick Pelissier b44e4e09dd Don't use builtin for clang as they are not properly supported. 2023-04-16 20:11:56 +02:00
Patrick Pelissier 5158059ec4 Make m_throw a classic "cold" function rather than a static inline function.
Since the function shall be rarely called, there is no point in inlining/duplicating it
in several units.
2023-04-16 19:26:15 +02:00
Patrick Pelissier 7279011f0a Use of the builtin versions of setjmp /longjmp for GCC / CLANG
They are more than twice faster on extreme bench of M\_LET / M\_TRY scenario
(and still twice slower than C++).
They also use less stack usage.
2023-04-16 19:18:04 +02:00
Patrick Pelissier 79369e9b05 Update README 2023-04-16 19:16:08 +02:00
Patrick Pelissier 58a7a7c214 Add gene TRY 2023-04-16 19:15:54 +02:00
Patrick Pelissier e3e94ca238 Add M_ATTR_COLD_FUNCTION attribute 2023-04-16 19:15:22 +02:00
Patrick Pelissier ae81271b2a Fix name of internal variable for M_DEFER 2023-04-16 08:33:45 +02:00
Patrick Pelissier d9c3724cff Compatiblity with C++ 2023-04-15 23:18:45 +02:00
Patrick Pelissier 1ff9848384 Update test so that it tests also the case of throwing without any try section (override M_RAISE_FATAL) 2023-04-15 22:51:57 +02:00
Patrick Pelissier 83e7f2a641 Use of new M_ATTR_NO_RETURN attribute 2023-04-15 22:50:47 +02:00
Patrick Pelissier 6580601969 Add M_ATTR_NO_RETURN attribute support (not C23 compatible yet) 2023-04-15 22:50:27 +02:00
Patrick Pelissier ad023bb09d Improve coverage of the test suite 2023-04-13 23:27:01 +02:00
Patrick Pelissier b5df21f9c5 Simplify function: for LCA both iterators shall be in the same tree 2023-04-13 23:26:12 +02:00
Patrick Pelissier d2dccbf514 Add table of contents 2023-04-12 20:35:22 +02:00
Patrick Pelissier a8075cbb05 Transform runtime test into assertion
as it is proven that it cannot happen.
2023-04-11 21:57:56 +02:00
Patrick Pelissier 1322afc4c9 Improve coverage of test suite 2023-04-11 21:53:14 +02:00
Patrick Pelissier 0f885fb158 Fix coverage source for m-core 2023-04-11 21:32:57 +02:00
Patrick Pelissier 25a2eb0875 Correct syntax 2023-04-11 21:32:38 +02:00
Patrick Pelissier 6bcd51f10f Complete coverage synthesis
with branch coverage information
2023-04-11 21:09:40 +02:00
Patrick Pelissier 9c1cb9c835 Update doc 2023-04-11 00:07:33 +02:00
Patrick Pelissier 19cb329ae6 Simplfy example 2023-04-11 00:05:41 +02:00
Patrick Pelissier 8099e6a94f Update doc 2023-04-11 00:04:46 +02:00
Patrick Pelissier ce6cc080d6 Improve coverage of test suite 2023-04-10 23:09:18 +02:00
Patrick Pelissier a27b0b4014 Fix wrong parsing of malformed dict. 2023-04-10 23:08:51 +02:00
Patrick Pelissier e74f80cc59 Update doc 2023-04-08 11:32:15 +02:00
Patrick Pelissier bafd307247 Update performance chapter 2023-04-08 11:27:37 +02:00
Patrick Pelissier 6bed3ac697 Print time with 2 digits after the decimal 2023-04-08 11:25:59 +02:00
Patrick Pelissier b8a9073fc9 Fix issue to generate graph without any repetition 2023-04-08 11:25:05 +02:00
Patrick Pelissier da3e71c676 Fix introduced warning in release mode 2023-04-08 11:23:32 +02:00
Patrick Pelissier 4ea83e129e Improve coverage of test suite 2023-04-08 00:17:33 +02:00
Patrick Pelissier fc34fa80b5 Properly mark condition for entering memory failure. 2023-04-07 23:50:03 +02:00
Patrick Pelissier 4f608ec266 Fix target of run 2023-04-06 22:02:49 +02:00
Patrick Pelissier ccaa54d2a5 Improve coverage of the tet suite 2023-04-06 21:55:21 +02:00
Patrick Pelissier 095bf7070d Rewrite loop to avoid final assert(0) 2023-04-06 21:55:06 +02:00
Patrick Pelissier 676b12d5d2 Fix warnings 2023-04-05 23:15:39 +02:00
Patrick Pelissier f858aa2cb5 Improve coverage of the test suite. 2023-04-05 23:07:52 +02:00
Patrick Pelissier 9d77448a25 Reduce optimization level to 0
Otherwise the coverage results are not reliable:
* some uncovered lines are not reported as uncovered
* some covered lines are reported as uncovered (!)
2023-04-05 23:04:22 +02:00
Patrick Pelissier 8babc33b91 Rewrite code differently to be more robust
and improve coverage of the test suite
2023-04-05 22:41:33 +02:00
Patrick Pelissier 352d7cf725 Improve coverage of the test suite 2023-04-05 22:22:49 +02:00
Patrick Pelissier a6993ab758 Overload assert in coverage mode
to avoid polluting the report with untaken branch by the assert macro.
2023-04-05 22:22:01 +02:00
Patrick Pelissier 48260ac2a6 Ignore temporary coverage files 2023-04-05 22:21:23 +02:00
Patrick Pelissier e4afb024b9 Improve coverage of test suite 2023-04-05 00:38:44 +02:00
Patrick Pelissier 63008af30f Add assertions 2023-04-05 00:38:32 +02:00
Patrick Pelissier 1828aca65e Fix preprocessing 2023-04-05 00:38:16 +02:00
Patrick Pelissier 9354e9717d Remove unused test function 2023-04-04 01:06:32 +02:00
Patrick Pelissier 100c0f22fe Improve test coverage 2023-04-04 00:48:03 +02:00
Patrick Pelissier ff778528f8 Improve coverage of the test suite 2023-04-04 00:22:49 +02:00
Patrick Pelissier 8f1a1df617 Improve coverage of test suite 2023-04-03 16:38:54 +02:00
Patrick Pelissier 28faf815d7 Improve robustness against broken I/O file 2023-04-03 14:09:34 +02:00
Patrick Pelissier fe3b703d0a Don't expand isspace for coverage tests 2023-04-03 14:09:07 +02:00
Patrick Pelissier 0aa6a9f0cf Update comments 2023-04-03 13:19:50 +02:00
Patrick Pelissier 67832ac918 Add more tests case for IO parsing 2023-04-03 13:18:28 +02:00
Patrick Pelissier 669a3297c7 Fix issue in ispace usage and allow more space in formating (to be more uniform. The allowed spaces before were in strange place only) 2023-04-03 13:18:10 +02:00
Patrick Pelissier 25d4829d7b Add utilities function for parsing FILE or char* while skipping space character 2023-04-03 13:17:25 +02:00
Patrick Pelissier ebab05a789 Improve coverage of test suite 2023-04-03 12:36:35 +02:00
Patrick Pelissier 727df5b7bf Fix coverage 2023-04-03 00:36:18 +02:00
Patrick Pelissier aebe1308fc Improve coverage computation 2023-04-03 00:23:05 +02:00
Patrick Pelissier 1d163a396e Replace assert by M_ASSERT 2023-04-03 00:12:00 +02:00
Patrick Pelissier 7534aa0d61 Add internal M_UNLIKELY_NOMEM to help coverage computation 2023-04-03 00:05:29 +02:00
Patrick Pelissier 6976d4e23d Remove (broken) auto check of coverage 2023-04-02 23:02:48 +02:00
Patrick Pelissier 6b7954e141 Fix coverage for new files 2023-04-02 22:52:40 +02:00
Patrick Pelissier c27d76a83b Remove assert & contract from coverage to avoid polluting reports 2023-04-02 22:45:56 +02:00
Patrick Pelissier 0e3081bfc6 Include branch probabilities in report 2023-04-02 22:45:35 +02:00
Patrick Pelissier d754e9a15f Update doc for _get_emplace functions for associative array 2023-03-29 22:59:54 +02:00
Patrick Pelissier 4e4e21793c Add _get_emplace functions for associative array 2023-03-29 22:59:43 +02:00
Patrick Pelissier c515da9f37 Update documentation 2023-03-29 22:50:51 +02:00
Patrick Pelissier 961b93bd4c Add test for M_LET + associative array 2023-03-28 23:43:49 +02:00
Patrick Pelissier 39a719c3f0 Fix warnings 2023-03-28 23:43:21 +02:00
Patrick Pelissier 8b643b4878 Add support for emplace detection in associative array + M_LET 2023-03-28 23:43:08 +02:00
Patrick Pelissier 876c394fba Fix format 2023-03-28 23:42:25 +02:00
Patrick Pelissier 81439c9437 Fix grammar 2023-03-27 01:05:53 +02:00
Patrick Pelissier 191ef7d09e Fix grammar 2023-03-27 00:55:08 +02:00
Patrick Pelissier bd4131dd8f Fix typo 2023-03-27 00:53:31 +02:00
Patrick Pelissier cfe8293c64 Cleanup documentation 2023-03-25 10:25:52 +01:00
Patrick Pelissier ea2715aa75 Remove static assert. Some old compilers failed to simplify into a constant expression, resulting in build failure 2023-03-24 23:54:49 +01:00
Patrick Pelissier f69cec6820 Fix warning with clang+const char * type 2023-03-24 21:53:23 +01:00
Patrick Pelissier 085f371693 Update doc 2023-03-24 21:12:28 +01:00
Patrick Pelissier 16a0a5c1a3 Add new examples 2023-03-24 21:11:15 +01:00
Patrick Pelissier 3953f81884 Update 2023-03-24 21:10:59 +01:00
Patrick Pelissier 8365888e6e Add Oplist inheritanc chapter 2023-03-24 20:38:51 +01:00
Patrick Pelissier c3f6e3c5f0 Add trivial script to separate preproc of compilation for debug 2023-03-19 00:29:51 +01:00
Patrick Pelissier 4cafe4dce1 Fix steps to debug 2023-03-19 00:29:06 +01:00
Patrick Pelissier 9f8b97ae46 Rename fields of m_exception_t:
data->context
n->num
2023-03-18 18:11:23 +01:00
Patrick Pelissier 030bea9c11 Add test for M_DEFER & M_LET_IF in exceptions 2023-03-18 17:57:46 +01:00
Patrick Pelissier e33894f1b3 Finish support for M_DEFER / M_LET_IF & exceptions 2023-03-18 17:57:15 +01:00
Patrick Pelissier 66f5e6c67d Support for more than one expression in M_DEFER 2023-03-18 17:56:44 +01:00
Patrick Pelissier 78c6dce068 Update doc 2023-03-18 17:56:11 +01:00
Patrick Pelissier 0798480ad5 Refactoring & implement support for RAII with M_DEFER 2023-03-18 17:39:56 +01:00
Patrick Pelissier e8322215fd Update doc about clang 2023-03-18 17:39:20 +01:00
Patrick Pelissier 42d3042c15 Add NOCLEAR property to M_BASIC_OPLIST and prepare injection for M_DEFER 2023-03-18 17:25:08 +01:00
Patrick Pelissier b7214ad11d Adding test of NOCLEAR property 2023-03-18 17:20:30 +01:00
Patrick Pelissier 08b4bc9052 M_LET_IF reuses clear mechanism provided by M_DEFER 2023-03-18 15:14:31 +01:00
Patrick Pelissier d813171e8a Add new test generation 2023-03-18 09:15:39 +01:00
Patrick Pelissier d1094999f5 Update M_ASSERT to separate requirement for predicate 2023-03-18 09:15:11 +01:00
Patrick Pelissier c8354aa6ed Update doc 2023-03-18 08:08:33 +01:00
Patrick Pelissier ab3aa33fac Add M_SET_THROUGH_INIT_SET 2023-03-18 08:08:23 +01:00
Patrick Pelissier 01f2f376e2 Update doc 2023-03-18 00:21:46 +01:00
Patrick Pelissier 535e00366a Correct reported errors 2023-03-18 00:21:37 +01:00
Patrick Pelissier 42111ec22a Rename field of m_exception_t 2023-03-17 22:13:18 +01:00
Patrick Pelissier ef0e849616 Fix test 2023-03-17 22:04:50 +01:00
Patrick Pelissier 9c516c2055 Update doc 2023-03-17 21:56:27 +01:00
Patrick Pelissier db48b985c3 Update doc 2023-03-17 21:48:56 +01:00
Patrick Pelissier 888796ca06 Update doc 2023-03-17 21:48:07 +01:00
Patrick Pelissier 144ae9c5ed Add ID support for GAIA 2023-03-17 21:47:04 +01:00
Patrick Pelissier 6223c93b53 Update doc 2023-03-17 20:21:19 +01:00
Patrick Pelissier 30f7656822 Update documentation 2023-03-17 20:15:42 +01:00
PpHd 8209a0c32a Merge pull request #107 from jonadem/patch-1
Fix typos
2023-03-17 20:14:38 +01:00
Jona 92e6957320 Fix typos 2023-03-17 14:00:49 +01:00
Patrick Pelissier b3c9f6ee47 Add support of exception for Visual C++ 2023-03-14 20:00:11 +01:00
Patrick Pelissier ab8bbad3f4 Fix syntax 2023-03-13 23:54:52 +01:00
Patrick Pelissier 9047376b7f Add m-try.h in HEADER 2023-03-13 23:53:36 +01:00
Patrick Pelissier dfed8dbc50 Fix format 2023-03-13 23:53:26 +01:00
Patrick Pelissier 2d3c25cd85 TCC doesn't support the __thread attribute,
which is a GCC extension.
Use this extension only for GCC.
2023-03-13 23:45:28 +01:00
Patrick Pelissier bfa948dc7a Add WIP implementation for the exception memory model:
add header m-try that defines the M_TRY / M_CATCH macros
that macros similarly to the C++ try / catch keywords.
Add implementation for C++, GCC, CLANG and pure C compiler.
2023-03-13 23:31:50 +01:00
Patrick Pelissier 94b6d1b9fd Fix computation of HASH_FINAL 2023-03-13 22:17:10 +01:00
Patrick Pelissier 0ddd5ddc6d Add AARCH64 target for CI 2023-03-13 21:04:05 +01:00
Patrick Pelissier cba93d5bb4 Add SC library 2023-03-12 21:12:21 +01:00
Patrick Pelissier d02de75487 Add control that all initialized testobj are properly cleared at the end of the test suite 2023-03-12 20:29:58 +01:00
Patrick Pelissier 2f57766249 Rename NOEXCEPT to NOCLEAR property as NOEXCEPT
doesn't provide enough guarantee to the exception handler.
2023-03-12 20:23:31 +01:00
Patrick Pelissier 3ff01e37eb Update documentation for properties 2023-03-05 19:44:36 +01:00
Patrick Pelissier 5683df0f22 Adding test for M_TEST_NOEXCEPT_P 2023-03-05 19:44:21 +01:00
Patrick Pelissier 11dc7afc06 Add NOEXCEPT property and M_TEST_NOEXCEPT_P macro to test it 2023-03-05 19:44:04 +01:00
Patrick Pelissier 9e2ae3f101 Update example 2023-03-05 18:30:47 +01:00
Patrick Pelissier c35aa9c891 Replace the M_ASSERT(0) by M_ASSUME(0) since they are not reachable (in order to inform the compiler of this fact) 2023-03-05 00:50:40 +01:00
Patrick Pelissier 2fc31d8c12 Factorization find of item in prioqueue 2023-03-03 23:23:06 +01:00
Patrick Pelissier 4f8d0a7156 Split macro 2023-03-03 23:12:40 +01:00
Patrick Pelissier aaf5bbd6a0 Separate IO from core macro 2023-03-03 23:03:24 +01:00
Patrick Pelissier 2f76652f2b Maintenance 2023-03-03 22:50:14 +01:00
Patrick Pelissier 942cf32519 Maintenance: separate macros for type and core functions. 2023-03-03 22:02:07 +01:00
Patrick Pelissier c1c9cb9cd3 Update example 2023-03-03 20:12:50 +01:00
Patrick Pelissier 76bfb48685 Update freebsd CI to be more robust. 2023-03-02 23:41:59 +01:00
Patrick Pelissier afff412f7a Maintenance: continue splitting huge macros into smaller ones. 2023-03-02 00:39:08 +01:00
Patrick Pelissier e48dcdeecc Factorization & assertions 2023-02-27 14:05:59 +01:00
Patrick Pelissier 12fae5c36c Update example 2023-02-26 23:43:57 +01:00
Patrick Pelissier 3f9129c7ed Update comments 2023-02-26 23:43:57 +01:00
Patrick Pelissier b918f61f4f Update example 2023-02-26 23:43:57 +01:00
Patrick Pelissier 93b69d0f8b Fix call of memcpy with size=0 and src=NULL 2023-02-25 12:17:18 +01:00
Patrick Pelissier b3440a2edd Fix position of assertions 2023-02-24 20:35:32 +01:00
Patrick Pelissier 4140df5bfc Improve test suite 2023-02-24 19:56:56 +01:00
Patrick Pelissier fbab093d52 Avoid warnings about variables never read. 2023-02-24 19:56:26 +01:00
Patrick Pelissier f57a0e0bf8 Update README 2023-02-24 18:21:39 +01:00
Patrick Pelissier 925c06beb8 Fix usage of va_copy 2023-02-24 15:07:29 +01:00
Patrick Pelissier 8e2f67b794 Fix building on exe files: some targets don't link with LDFLAGS if it is not in the last argument 2023-02-23 12:42:11 +01:00
Patrick Pelissier f176d01e49 Fix README 2023-02-23 10:53:32 +01:00
Patrick Pelissier 2b99bbe956 Remove bool oplist as it is globally registered 2023-02-22 22:47:31 +01:00
Patrick Pelissier 700bfc5341 Add documentation for RET in API transformation 2023-02-22 22:47:17 +01:00
Patrick Pelissier 4062525821 Add test for RET in API transformation 2023-02-22 22:47:06 +01:00
Patrick Pelissier 800a1e5c36 Add support for RET in API transformation and register global bool oplist 2023-02-22 22:46:46 +01:00
Patrick Pelissier 1838f675a7 Add more comments, another alternative.
Rename some variables to be clearer.
2023-02-18 20:15:17 +01:00
Patrick Pelissier bf6c1341b3 Add comments to explain what we do
Always use the prefixed version of M*LIB
2023-02-18 09:58:30 +01:00
Patrick Pelissier 55b745b916 Use of M_WORKER_SPAWN_DEF2 in example:
it shows how to add paralelization to a code base.
2023-02-18 00:25:30 +01:00
Patrick Pelissier 5cb0d9214b Adding doc for M_WORKER_SPAWN_DEF2. 2023-02-18 00:25:17 +01:00
Patrick Pelissier 8f99b8e617 Adding test for M_WORKER_SPAWN_DEF2 2023-02-18 00:25:06 +01:00
Patrick Pelissier d2ce71a90a Adding M_WORKER_SPAWN_DEF2 for providing specialization
and type-safe variant of m_worker_spawn.
2023-02-18 00:24:20 +01:00
Patrick Pelissier 8562986eea Avoid dereferencing the table in asserts if the lock is done on the tree:
it usually means that the tree is partially accessed by other
threads (at least the derefencing methods which should be
safe).
2023-02-18 00:15:31 +01:00
Patrick Pelissier ee89858bf0 Add renaming of header in compatibility chapter 2023-02-16 00:20:07 +01:00
Patrick Pelissier 085d7157c0 Add compatibility layer with old header m-mutex
as a transition for current programs.
2023-02-16 00:10:55 +01:00
Patrick Pelissier 91f3174a36 Rename m-mutex header into m-thread
as it is not just about mutex but about thread functions
just like the header pthread or thread.h
2023-02-16 00:09:06 +01:00
Patrick Pelissier 56f51c59af Add comments about locale dependent functions. 2023-02-11 23:47:11 +01:00
Patrick Pelissier df0c95ca46 Adding note on locale for JSON outputs 2023-02-11 14:35:36 +01:00
Patrick Pelissier 482ec38e62 Fix wrong use of isprint function. 2023-02-11 14:34:13 +01:00
Patrick Pelissier 82743ca72c Update pipeline for freebsd 2023-02-11 09:28:12 +01:00
Patrick Pelissier 312821454c Avoid running tests in example for freebsd 2023-02-11 00:39:06 +01:00
Patrick Pelissier c953e87660 Link with stdthreads for FreeBSD 2023-02-11 00:11:48 +01:00
Patrick Pelissier 8846707c8b Fix issue on FreeBSD when building in C11 mode:
thrd_sucess is not equal to 0 on this system,
so replace 0 by thrd_success
2023-02-11 00:08:51 +01:00
Patrick Pelissier bf7d4eee55 Avoid using .log suffix for failure checks
some Make program (like FreeBSD one) doesn't handle
priority of a specific rule over a generic rule.
So the generic rule is used for failure checks and it fails the check.
Use another suffix to avoid collision between rules
2023-02-10 23:57:28 +01:00
Patrick Pelissier d4dc85f89a Add FreeBSD target for CI 2023-02-10 21:36:04 +01:00
Patrick Pelissier 130c32e7d4 Include only sysinfoapi.h on Windows machine to reduce dependency
Add fallback to _SC_NPROCESSORS_CONF if _SC_NPROCESSORS_ONLN is not supported (Android)
2023-02-07 23:17:03 +01:00
Patrick Pelissier 2bcaba3bc0 Factorize into smaller macros 2023-02-06 22:17:12 +01:00
Patrick Pelissier 443c805c22 Fix format 2023-02-06 21:28:19 +01:00
Patrick Pelissier 414c87bb69 Rename internal macros 2023-02-05 23:38:29 +01:00
Patrick Pelissier e9ca506d93 Factorization of macros 2023-02-03 20:53:27 +01:00
Patrick Pelissier 8e58f7d637 Factorize into smaller generation macros. Add emplace support for MPMC/SPSC queues 2023-02-01 20:58:28 +01:00
Patrick Pelissier 254beaf3c7 Factorize into smaller generation macros 2023-02-01 20:43:01 +01:00
Patrick Pelissier 27735eb224 Migrate version of action scripts. 2023-01-29 00:19:22 +01:00
Patrick Pelissier 0afc81bd54 Simplify example by using emplace function. 2023-01-28 14:49:17 +01:00
Patrick Pelissier 39e67eebdc EMPLACE: Fix expansion of methods as macro in the oplist
by performing another evaluation step.
2023-01-28 14:49:07 +01:00
Patrick Pelissier 840226c7fd TREE: Add documentation of emplace functions 2023-01-28 14:48:58 +01:00
Patrick Pelissier e421851525 TREE: Add tests for emplace functions 2023-01-28 14:48:50 +01:00
Patrick Pelissier f70b52c9e4 TREE: Add support for emplace functions 2023-01-28 14:48:12 +01:00
Patrick Pelissier 40249ce5bc Separate macros into smaller more functionnal ones 2023-01-28 14:48:01 +01:00
Patrick Pelissier 97ff413f01 Maintenance:
Separate big macros into several smaller ones
2023-01-22 23:33:13 +01:00
Patrick Pelissier 8e4ac99a35 Separate macro into smaller macros (more maintenable) 2023-01-20 23:45:40 +01:00
Patrick Pelissier 4366e8eeab Separate macro into smaller macros
to ease reading and enable easier customization of generation
2023-01-20 23:45:40 +01:00
Patrick Pelissier 4e5e498bb2 Add new library 2023-01-09 23:35:33 +01:00
Patrick Pelissier 870a6f4b57 Update to 0.7.1 2023-01-02 13:06:29 +01:00
Patrick Pelissier a2ae209992 Happy new year 2023-01-02 12:57:41 +01:00
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
164 changed files with 23243 additions and 10167 deletions

No files matched your search

+58 -8
View File
@@ -10,7 +10,9 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v4
- 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
@@ -24,11 +26,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v4
- name: update package list
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"
@@ -46,7 +50,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v4
- name: CPU Information
run: lscpu || echo "CPU information not available"
- name: Clone TCC
shell: bash
run: git clone https://repo.or.cz/tinycc.git
@@ -58,13 +64,22 @@ jobs:
run: make depend
- name: make check
shell: bash
run: make CC="/tmp/tcc/bin/tcc -std=c99" check
run: make CC="/tmp/tcc/bin/tcc -std=c99" check -j4 || make CC="/tmp/tcc/bin/tcc -std=c99" check -j2 || make CC="/tmp/tcc/bin/tcc -std=c99" check
build_linux_sanitize:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: make sanitize
working-directory: ./tests
run: make sanitize -j 2
build_windows_mingw:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v4
- name: make check
shell: bash
run: mingw32-make -j 2 CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
@@ -75,7 +90,7 @@ jobs:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
@@ -88,7 +103,7 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v4
- name: make check
shell: cmd
working-directory: ./tests
@@ -98,9 +113,44 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v4
- name: make check
shell: cmd
working-directory: ./tests
run: Make-check-cl.bat clang-cl
# The host should always be linux
build_freebsd:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Test in FreeBSD
id: test
uses: vmactions/freebsd-vm@v1
timeout-minutes: 60
with:
usesh: true
run: |
freebsd-version
cd tests
make check -j 2 CC="cc -std=c99 -Wno-unknown-warning-option -Werror" && make clean && make check -j 2 CC="cc -std=c11 -Wno-unknown-warning-option -Werror" LDFLAGS="-lstdthreads" && make clean
# The host should always be linux
build_aarch64:
runs-on: ubuntu-latest
name: Build on aarch64
steps:
- uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2.5.0
name: Run commands on aarch64
id: make
timeout-minutes: 60
with:
arch: aarch64
distro: bullseye
shell: /bin/sh
run: |
apt-get update -q -y
apt-get install -q -y build-essential git gcc
lscpu
cd tests && make check -j 2 && make clean
+3 -3
View File
@@ -28,7 +28,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
@@ -36,7 +36,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -50,4 +50,4 @@ jobs:
run: make exe
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2
+5
View File
@@ -38,8 +38,13 @@ depend
other/
a*.dat
config
config.*
*.log
.vscode
.vs
tmp-serial.*
*~
*.gcda
*.gcno
*.gcov
*.synt
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 2-Clause License
Copyright (c) 2017-2021, Patrick Pelissier
Copyright (c) 2017-2023, Patrick Pelissier
All rights reserved.
Redistribution and use in source and binary forms, with or without
+8 -8
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2017-2021, Patrick Pelissier
# Copyright (c) 2017-2023, 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.2
# 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-generic.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-thread.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tree.h m-try.h m-tuple.h m-variant.h m-worker.h
DOC1=LICENSE README.md
DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/depend.png doc/DEV.md doc/ISSUES.org doc/oplist.odp doc/oplist.png
EXAMPLE=example/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/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
DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/depend.png doc/DEV.md doc/ISSUES.org doc/oplist.odp doc/oplist.png doc/bench-array-log.png doc/bench-array.png doc/bench-list-log.png doc/bench-list.png doc/bench-oset-log.png doc/bench-oset.png doc/bench-umap-log.png doc/bench-umap.png doc/cc.sh
EXAMPLE=example/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex11-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json example/Makefile example/ex-defer01.c example/ex-string01.c example/ex-string02.c example/ex-astar.c example/ex-string03.c example/ex11-tstc.c example/ex-no-stdio.c example/ex11-count-lines.c example/ex11-json-net.c example/ex11-rbtree02.c example/ex-curl.c example/ex-dict05.c example/ex-dict06.c example/exm-lib.c example/exm-main.c example/exn-lib.c example/exn-main.c example/exm-header.h example/exn-header.h example/ex-alloc1.c example/ex-alloc2.c example/ex-try01.c example/ex11-generic01.c
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.c tests/test-mcmempool.c tests/test-mconcurrent.c tests/test-mcore.c tests/test-mdeque.c tests/test-mdict.c tests/test-mfuncobj.c tests/test-mgenint.c tests/test-milist.c tests/test-mlist.c tests/test-mmempool.c tests/test-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.c tests/test-mshared.c tests/test-msnapshot.c tests/test-mstring.c tests/test-mtuple.c tests/test-mvariant.c tests/test-mworker.c tests/tgen-bitset.c tests/tgen-marray.c tests/tgen-mdict.c tests/tgen-mlist.c tests/tgen-mstring.c tests/tgen-openmp.c tests/tgen-queue.c tests/tgen-shared.c tests/tgen-mserial.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt tests/fail-chain-oplist.c tests/fail-incompatible.c tests/fail-no-oplist.c tests/test-mishared.c tests/check-array.cpp tests/check-deque.cpp tests/check-dplist.cpp tests/check-list.cpp tests/check-rbtree.cpp tests/check-uset.cpp tests/check-generic.hpp tests/test-mtree.c tests/check-bptree-map.cpp tests/check-bptree-set.cpp tests/check-prioqueue.cpp tests/check-umap.cpp tests/test-mtry.c tests/tgen-mmap.c tests/tgen-try.c tests/tgen-tuple.c tests/test-mgeneric.c
.PHONY: all test check doc clean distclean depend install uninstall dist
@@ -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
+3359 -2603
View File
File diff suppressed because it is too large. Load diff
+75 -11
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2017-2021, Patrick Pelissier
# Copyright (c) 2017-2023, 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 bench-CC
@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
@@ -311,8 +322,11 @@ bench-xxhash0:
bench-boost:
@if test -n "$${BOOST}" ; then $(MAKE) bench-boost0 ; else echo "Nothing to be done for BOOST." ; fi
bench-boost0:
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${BOOST}" bench-boost.cpp common.c -DMULTI_THREAD_MEASURE -o bench-boost.exe -lpthread
@./bench-boost.exe 60
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${BOOST}" bench-boost.cpp common.c -DMULTI_THREAD_MEASURE -o bench-boost-thread.exe -lpthread
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${BOOST}" bench-boost.cpp common.c -o bench-boost.exe -lpthread
@./bench-boost.exe 42
@./bench-boost.exe 41
@./bench-boost-thread.exe 60
# NEDTRIES shall point to the header location.
bench-nedtries:
@@ -351,6 +365,52 @@ 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
# CCLIB shall point to the source directory of CC (where the headers are)
bench-CC:
@if test -n "$${CCLIB}" ; then $(MAKE) bench-CC0 ; else echo "Nothing to be done for CC." ; fi
bench-CC0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${CCLIB}/ bench-CC.c common.c -o bench-CC.exe
@./bench-CC.exe 10
@./bench-CC.exe 20
@./bench-CC.exe 40
@./bench-CC.exe 41
# VERSTABLE shall point to the source directory of VERSTABLE (where the headers are)
bench-verstable:
@if test -n "$${VERSTABLE}" ; then $(MAKE) bench-verstable0 ; else echo "Nothing to be done for VERSTABLE." ; fi
bench-verstable0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${VERSTABLE}/ bench-verstable.c common.c -o bench-verstable.exe
@./bench-verstable.exe 40
@./bench-verstable.exe 41
############################################################################
bench-mlib-json: bench-mlib
@@ -389,12 +449,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 +464,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 +474,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"
+140
View File
@@ -0,0 +1,140 @@
#define NDEBUG
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "common.h"
#include "cc.h"
/********************************************************************************************/
static void test_array(size_t n)
{
vec( unsigned int ) a1, a2;
init(&a1);
init(&a2);
for(size_t i = 0; i < n; i++) {
push(&a1, rand_get() );
push(&a2, rand_get() );
}
unsigned int s = 0;
for(unsigned long i = 0; i < n; i++) {
s += *get(&a1, i ) * *get(&a2, i );
}
g_result = s;
cleanup(&a1);
cleanup(&a2);
}
/********************************************************************************************/
static void test_list(size_t n)
{
list( unsigned int ) a1, a2;
init(&a1);
init(&a2);
for(size_t i = 0; i < n; i++) {
push(&a1, rand_get() );
push(&a2, rand_get() );
}
unsigned int s = 0;
for(unsigned *it1 = first( &a1 ), *it2 = first( &a2 ); it1 != end( &a1 ); it1 = next( &a1, it1 ), it2 = next(&a2, it2) ) {
s += *it1 * *it2;
}
g_result = s;
cleanup(&a1);
cleanup(&a2);
}
/********************************************************************************************/
static void
test_dict(size_t n)
{
map( unsigned long, unsigned long ) dict;
init(&dict);
for (size_t i = 0; i < n; i++) {
unsigned long value = rand_get();
unsigned long key = rand_get();
insert(&dict, key, value);
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
unsigned long key = rand_get();
const unsigned long *val = get(&dict, key);
if (val != NULL)
s += *val;
}
g_result = s;
cleanup(&dict);
}
/********************************************************************************************/
typedef struct {
char a[256];
} char_array_t;
static inline void char_init (char_array_t *a) { a->a[0] = 0; }
static inline void char_set (char_array_t *a, const char_array_t b) { strcpy(a->a, b.a); }
static inline bool char_equal_p (const char_array_t *a, const char_array_t *b) { return strcmp(a->a,b->a)==0; }
static inline bool char_cmp (const char_array_t *a, const char_array_t *b) { return strcmp(a->a,b->a); }
static inline void char_clear (char_array_t *a) { (void)a; }
static inline size_t char_hash(const char_array_t *a) {
size_t hash = 0;
const char *s = a->a;
while (*s) hash = hash * 31421 + (*s++) + 6927;
return hash;
}
#define CC_DTOR char_array_t, { char_clear(&val); }
#define CC_CMPR char_array_t, { return char_cmp(&val_1, &val_2); }
#define CC_HASH char_array_t, { return char_hash(&val); }
#include "cc.h"
static void
test_dict_big(size_t n)
{
map( char_array_t, char_array_t) dict;
init(&dict);
for (size_t i = 0; i < n; i++) {
char_array_t s1, s2;
sprintf(s1.a, "%u", rand_get());
sprintf(s2.a, "%u", rand_get());
insert(&dict, s1, s2);
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
char_array_t s1;
sprintf(s1.a, "%u", rand_get());
const char_array_t *val = get(&dict, s1);
if (val != NULL)
s ++;
}
g_result = s;
cleanup(&dict);
}
/********************************************************************************************/
const config_func_t table[] = {
{ 10, "List", 10000000, 0, test_list, 0},
{ 20, "Array", 100000000, 0, test_array, 0},
{ 40, "dict", 1000000, 0, test_dict, 0},
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
};
int main(int argc, const char *argv[])
{
test("CC", numberof(table), table, argc, argv);
exit(0);
}
+105 -1
View File
@@ -3,11 +3,111 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "m-thread.h"
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/lockfree/queue.hpp>
#include "common.h"
using namespace std;
/********************************************************************************************/
static void
test_dict2(size_t n)
{
boost::unordered_flat_map<unsigned long, unsigned long> dict;
for (size_t i = 0; i < n; i++) {
dict[rand_get()] = rand_get();
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
boost::unordered_flat_map<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
if (it != dict.end())
s += it->second;
}
g_result = s;
}
static void
test_dict2_linear(size_t n)
{
boost::unordered_flat_map<unsigned long, unsigned long> dict;
for (size_t i = 0; i < n; i++) {
dict[i] = rand_get();
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
boost::unordered_flat_map<unsigned long, unsigned long>::iterator it = dict.find(i);
if (it != dict.end())
s += it->second;
}
g_result = s;
}
/********************************************************************************************/
struct char_array_s {
char a[256];
char_array_s () { a[0] = 0 ; }
char_array_s ( const char_array_s & other) { strcpy(a, other.a); }
bool operator==(const char_array_s &other) const { return strcmp(a, other.a) == 0; }
};
inline std::size_t hash_value(const char_array_s &k) {
size_t hash = 0;
const char *s = k.a;
while (*s) hash = hash * 31421 + (*s++) + 6927;
return hash;
}
static void
test_dict_big(size_t n)
{
boost::unordered_flat_map<char_array_s, char_array_s> dict;
for (size_t i = 0; i < n; i++) {
char_array_s s1, s2;
sprintf(s1.a, "%u", rand_get());
sprintf(s2.a, "%u", rand_get());
dict[s1] = s2;
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
char_array_s s1;
sprintf(s1.a, "%u", rand_get());
boost::unordered_flat_map<char_array_s, char_array_s>::iterator it = dict.find(s1);
if (it != dict.end())
s ++;
}
g_result = s;
}
/********************************************************************************************/
static void
test_dict_str(size_t n)
{
boost::unordered_flat_map<string, string> dict;
for (size_t i = 0; i < n; i++) {
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
dict[s1] = s2;
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
boost::unordered_flat_map<string, string>::iterator it = dict.find(s1);
if (it != dict.end())
s ++;
}
g_result = s;
}
/********************************************************************************************/
boost::lockfree::queue<unsigned int, boost::lockfree::capacity<4*64>> g_buff;
boost::lockfree::queue<unsigned long long, boost::lockfree::capacity<4*64>> g_final;
@@ -86,11 +186,15 @@ static void test_queue(size_t n)
/********************************************************************************************/
const config_func_t table[] = {
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
{ 42, "dict", 1000000, 0, test_dict2, 0},
{ 43, "DictStr", 1000000, 0, test_dict_str, 0},
{ 46, "DictLinear", 1000000, 0, test_dict2_linear, 0},
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
};
int main(int argc, const char *argv[])
{
test("BOOST-LOCKFREE", numberof(table), table, argc, argv);
test("BOOST", numberof(table), table, argc, argv);
exit(0);
}
+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);
}
+25 -29
View File
@@ -14,7 +14,7 @@
#include "m-mempool.h"
#include "m-string.h"
#include "m-buffer.h"
#include "m-mutex.h"
#include "m-thread.h"
#include "m-deque.h"
#include "m-concurrent.h"
#include "m-tuple.h"
@@ -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-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -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-2023 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;
}
+94
View File
@@ -0,0 +1,94 @@
#define NDEBUG
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "m-core.h"
#include "common.h"
#define NAME umap_ulong
#define KEY_TY unsigned long
#define VAL_TY unsigned long
#include "verstable.h"
static void
test_dict(size_t n)
{
umap_ulong dict;
umap_ulong_init(&dict);
for (size_t i = 0; i < n; i++) {
unsigned long value = rand_get();
unsigned long key = rand_get();
umap_ulong_insert(&dict, key, value);
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
umap_ulong_itr it = umap_ulong_get(&dict, rand_get());
if (!umap_ulong_is_end(it) )
s += it.data->val;
}
g_result = s;
umap_ulong_cleanup(&dict);
}
/********************************************************************************************/
#ifndef CHAR_ARRAY_SIZE
#define CHAR_ARRAY_SIZE 256
#endif
typedef char char_array_t[CHAR_ARRAY_SIZE];
typedef struct { char_array_t a; } char_encap;// Cannot use char_array_t directly
static bool char_equal_p (const char_encap a, const char_encap b) { return strcmp(a.a,b.a)==0; }
static size_t char_hash(const char_encap a) { return m_core_hash (a.a, strlen(a.a)); }
#define NAME umap_char_array
#define KEY_TY char_encap
#define VAL_TY char_encap
#define HASH_FN char_hash
#define CMPR_FN char_equal_p
#include "verstable.h"
static void
test_dict_big(size_t n)
{
umap_char_array dict;
umap_char_array_init(&dict);
for (size_t i = 0; i < n; i++) {
char_encap s1, s2;
sprintf(s1.a, "%u", rand_get());
sprintf(s2.a, "%u", rand_get());
umap_char_array_insert(&dict, s1, s2);
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
char_encap s1;
sprintf(s1.a, "%u", rand_get());
umap_char_array_itr it = umap_char_array_get(&dict, s1);
if (!umap_char_array_is_end(it) )
s ++;
}
g_result = s;
umap_char_array_cleanup(&dict);
}
/********************************************************************************************/
const config_func_t table[] = {
{ 40, "dict", 1000000, 0, test_dict, 0},
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
};
int main(int argc, const char *argv[])
{
test("CTL", numberof(table), table, argc, argv);
exit(0);
}
+5 -3
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - common functions for bench module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -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);
}
@@ -235,7 +235,7 @@ test(const char library[], size_t n, const config_func_t functions[], int argc,
sprintf(filename, "plot-%s-%d.dat", library, arg.test_function);
graph_file = fopen(filename, "wt");
if (!graph_file) {
fprintf(stderr, "ERROR: Cannot create plot.dat\n");
fprintf(stderr, "ERROR: Cannot create the file '%s'\n", filename);
exit(-2);
}
fprintf(graph_file, "# plotting %s-%d : %s\n# N T", library, arg.test_function, functions[i].funcname);
@@ -271,6 +271,8 @@ test(const char library[], size_t n, const config_func_t functions[], int argc,
avg /= arg.repeat;
variance = (variance - arg.repeat * avg * avg) / (arg.repeat - 1);
ba = get_best_within(arg.repeat, measure, 1. + arg.within);
} else {
ba = avg;
}
// The average value shall be around best_within (and greater)
+4 -5
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - common functions for bench module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -31,7 +31,7 @@
// Needed for M_THREAD_ATTR
#if defined(MULTI_THREAD_MEASURE)
#include "m-mutex.h"
#include "m-thread.h"
#endif
#if defined(_WIN32)
@@ -55,7 +55,7 @@
// Number of elements of a table
#define numberof(x) (sizeof(x)/sizeof(x[0]))
/* Get the current CPU time. */
/* Get the current CPU time in microsecond. */
#if defined(_WIN32)
/* WINDOWS variant */
static inline unsigned long long
@@ -119,9 +119,8 @@ test_function(const char *str, size_t n, void (*func)(size_t))
(*func)(n);
end = cputime();
result = (double)(end-start) / 1000.0;
end = (end - start) / 1000U;
if (str != NULL) {
printf ("%20.20s time %lu ms for n = %lu [r=%lu]\n", str, (unsigned long) end, (unsigned long) n, g_result);
printf ("%20.20s time %.2f ms for n = %lu [r=%lu]\n", str, result, (unsigned long) n, g_result);
}
return result;
}
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* MLIB - TEST module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
+9
View File
@@ -73,3 +73,12 @@ 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.
V0.7.*: * Rename m-mutex.h header in m-thread.h
+325 -49
View File
@@ -1,5 +1,272 @@
*Long term issues*
------------------
==========================================================
* TODO #33 : Handling of partially constructed object :ANOMALY:
** State
Support of partially constructed object needs special code to handle it
correctly (register a correct cleanup function in case of exception).
Current containers don't support such features.
** Actions
Add such support in M*LIB containers.
It can be difficult. For example, for array _init_set
function due to the copy of the object one per one. Each copied sub object
may throw an exception, so we always need to have the container in a correct
state so that it can be cleanup.
* TODO #32 : User specialization fields in the container :ENHANCEMENT:
** State
Some methods of a contained object may need to have some options that
are neither constant nor global, but are specialized in function of the container.
For example, a memory handler may need a parameter which is needed to identify
which pool of memory has to be used.
** Plan:
Add a new operator "CONTEXT" which is a type to be added in the
defined container. Then it can be accessed by the operator through an extension
of the GAIA by adding support for identification of specialization like this:
( CONTEXT( memory_pool_ref ),
NEW( API(NONE, memory_pool_alloc, CONTEXT, ARG1)),
DEL( API(NONE, memory_pool_free, CONTEXT, ARG1)) )
** Open points:
- How to get access to the specialization field of the container?
==> Define the "self" name as the name of the container for all methods?
- What to do when there are several containers for a method?
==> self shall be the destination?
- How to initialize the specialization field of the container? provide custom initialization functions? It seems to be the hard point.
* INIT: Force a default to NULL ?
* INIT_SET: Force the same value than the src? We may want another pool!
* INIT_MOVE: Force the same value than the src. Mandatory
* MOVE: Assume the same value. Mandatory
* SET: Use the already define pool
* INIT_WITH: Force a default to NULL?
==> init_emplace ?
-- How can we handle containers that allocate on initialization? It cannot, so this solution seems broken
==> Modify constructor prototype to add allocators (except for MOVE/INIT_MOVE)
* INIT(dest) ==> INIT(dest, context)
* INIT(dest, src) ==> INIT_SET(dest, context, src)
* INIT_WITH(dest, ...) ==> INIT_WITH(dest, context, ...)
* INIT emplace(dest [custom]) ==> INIT_emplace(dest, context, [custom])
==> How to pass context? Inherited from master container? A CONTEXT may be present in the parent container but the child may not accept CONTEXT... Same than the Heap Allocator is not the same between different types... The allocator of the parent may be different from the one of the child... ==> Force context to be the same ?
==> If a type A uses CONTEXT, all containers constructed from A shall use CONTEXT too
-- Need to use an oplist for context or force basic type?
* TODO #31 : Uniformize parametrisation options of containers :ENHANCEMENT:
** State
Currently in order to pass some parametrization of the containers,
the parameters are passed to the generation macros through:
- extra parameters of the macros,
- special operators of the contained object oplist.
The extra parameters of some generation macros break the uniformity
of the interface.
It is conceptually wrong to put some special operators of the contained object
that have only meanings for the container object.
In case of adding new options, it break the existing interface or put another
operator in the contained object oplist.
The following parameters are used:
- Fixed size of a queue (buffer / B+Tree),
- Policy of a queue (buffer),
- Type of the container, IT type of the container, Ref type of the iterator
The following operators are used:
- NEW / DEL / REALLOC / FREE
- MEMPOOL / MEMPOOL_LINKAGE
The following new options is planned:
- Interface (See #28)
- Extra parameter for memory allocation function
** Plan
The M\_*\_DEF\_AS macros shall be changed like this:
M_*_DEF_AS(name, cont_oplist, type[, type_oplist])
with cont\_oplist being the container oplist that gives parametrization to the container definition.
The following operators are planned:
- TYPE: to define the type of the container,
- IT\_TYPE: to define the IT type of the container,
- SUBTYPE: to define the type pointed by the iterator,
- FIXED\_SIZE: to define the fixed size of a container,
- POLICY: to define the policy of a container,
- NEW / DEL / REALLOC / FREE: to define the memory interface,
- MEMPOOL / MEMPOOL_LINKAGE: to request a definition of a specialized memory interface,
- INTERFACE: to request a pure header definition, an implementation or both (see #28),
- CONTEXT: to request an extra context parameter to add in the container.
All operators should be optional.
The NEW / DEL / REALLOC / FREE / MEMPOOL / MEMPOOL_LINKAGE won't have any effects anymore if defined in the contained object oplist.
** Pro:
- Uniformize interface
** Con:
- API breakage. It can be mitigated by providing an adaptating layer by prividing the new interface for M\_*\_DEF\_AS only
and *\_DEF\_AS will provide a translation layer.
* TODO #30 : Serialization rework :ENHANCEMENT:
** State
Currently, each container supports 3 serialization methods:
- old format to FILE
- old format to string
- generic serialization
Generic serialiation connect the container format to the serialization object constraints.
It is done through a vtable. As such there is a performance penality and it avoids proper inlining.
** Evolution
Old format should be deprecated and shall use the generic serialization interface.
Serialization object shall provide an OPLIST of serialization.
For example CORE will provide OLD Format oplist and serial-json will provide JSON format oplist.
Each oplist will provide the suffix needed for the serialization, and the interface
(see already existing interface).
Then a container will generate specialized serialization methods for each provided oplist.
Pros:
- Faster
- In the M*LIB philosphy: much like other oplist usage.
Cons:
- compatibility breakage.
Open point:
- how can a user add a new serialization object?
- Can we make a generic serialization object to support migration path?
** Example
serial-json provides
#define M_SERIAL_1() (NAME(_json), READ_INT(...), WRITE_INT(...) )
containers provides
For i in 1 100 ; do
if do exist M_SERIAL_ ## i ()
expand(SERIAL_METHOD with M_SERIAL_1())
SERIAL_METHOD(name, ....)
static inline m_serial_return_code_t \
M_C(M_F(name, _out_serial),M_GET_NAME(serial_op) )(M_GET_TYPE(serial_op) f, const list_t list) \
* DONE #29 : Support of partial initialized object :ANOMALY:
** State
In case of exception during the construction of an object,
if the object is partially constructed, there is no destructor to call.
Therefore if there is some partially constructed object
(with some fields already fully constructed), there will be some links.
This is the same problem with C++
** Proposition
Provide new macros to perform the partial initialization before doing the remaining taf.
Something like:
M_CHAIN_INIT( init_code, clear_code)
or
x is { string_t s; string_t d; int num; }
void struct_init_set(struct_t x, const struct_t y)
{
// First thing is Chained Initialization
M_CHAIN_INIT( string_init_set(x->s, y->s), string_clear(x->s) );
M_CHAIN_INIT( string_init_set(x->d, y->d), string_clear(x->d) );
// End of chain init
x->num = y->num;
}
M_CHAIN_INIT will push the clean code pretty much like M_LET.
Everything else is done in M_LET: when the constructor fully returns,
the index of the clean code to call is reset to its value before calling
the constructor. It means that the partially initialized code will be removed
from this stack before the clean method of the structure itself is pushed.
If an exception is raised after a M_CHAIN_INIT, only the clean methods
of the M_CHAIN_INIT are called.
* TODO #28 : Separate generation of interface to implementation :ENHANCEMENT:
Enable support for generating an interface only for the headers
and an implementation only for the source code.
Try to keep API compatibility
==> Only modify renamed macro with M_ prefix by giving a new mandatory
argument for such generation.
This argument is a generation parametric argument.
oplist is a parameter that define the property of the contained type.
It could be used to pass this information but it will be an abuse of interface.
Another argument is needed.
Used arguments to parameter generation not related to the contained type:
- memory interface (NEW / DEL / ...)
- queue policy
- fixed size for queue
- fixed node size for B+Tree
- generate static inline, public (extern) or private (define) functions.
- name of the type.
- name of the iterator
- name of the iterated element.
- ...
Use another oplist as argument for M_.._DEF_AS (See #31)
M_BUFFER_DEF_AS(name, (TYPE(toto), FIXED_SIZE(10), POLICY(STACK), INTERFACE(header)), int, M_BASIC_OPLIST)
* TODO #27 : Uniformization of m-buffer interface :ENHANCEMENT:
** State
The m-buffer interface requires special argument to work:
- size & policy for BUFFER,
- policy only for the others.
This is not uniform with the others generation macros and not uniform with each other.
Moreover the others are the only one which can be used in a shared memory, so
a fixed size will be good to have too for such interface.
** Plan
- Uniformization of the interface (See #31)
- Provide static size for all QUEUE.
* TODO #26 : Hash-Map for huge objects :ENHANCEMENT:
@@ -34,12 +301,15 @@ unsigned get_small_hash(int64_t x) {
}
#+END_SRC
* TODO #25 : Support of error code model for error handling. :ENHANCEMENT:
Can also (should?) use SIMD to test for several hash entries at the same times
In which case a complete new implementation will be needed
* TODO #25 : Support of error return model for error handling. :ENHANCEMENT:
Find a way to support error return code for the API in case of allocation
failure.
Any service that returns void shall return a "int".
Any service that returns void shall return a "int" (or another type).
In case of allocation failure, it shall return an error.
M_CALL macro shall stop its execution if the service returns an error code
and the error code represents an error (avoid rewritting everything)
@@ -98,19 +368,20 @@ RETCODE/RETCODE
If really needed, the macro can be avoided and code can be hand written.
Open points:
- How to handle warnings on unused labels?
- What about M_LET/ M_EACH?
- What about M_LET / M_EACH? Maybe only supports those.
* TODO #24 : New: Add MIN-MAX-HEAP container :ENHANCEMENT:
* TODO #24 : New MIN-MAX-HEAP container :ENHANCEMENT:
See https://en.wikipedia.org/wiki/Min-max_heap
as DPRIORITY_QUEUE_DEF ?
NOTE: Needs for such container?
* TODO #23 : Strict MOVE semantic to clarify :ENHANCEMENT:
* TODO #23: Strict MOVE semantic to clarify :ENHANCEMENT:
** State
Some type may need to have a force MOVE semantic (for example, they can store
pointer to themselves). Currently the INIT_MOVE & MOVE operators are more
@@ -125,7 +396,7 @@ moving the data before they can be moved using MOVE. Two solutions:
- New operator MOVE_SELF to fix a type after it has been moved.
- If MOVE defined, force another table and then copy by hand the type. This will be slower and consumme more memory.
** MOVE in OPLIST :ENHANCEMENT:
** MOVE in OPLIST
Proposal: do not export INIT_MOVE / MOVE operator in OPLIST if the MOVE operator is
compatible with a pure COPY semantic. An exported MOVE operator will tell
@@ -144,8 +415,22 @@ defined with [1] tricks but without an explicit INIT_MOVE / MOVE
operators as it uses MOVE_DEFAULT which is not (fully compatible).
==> Analyse limitation and possible constraint usages.
Being able to define a correct default for INIT_MOVE will be really good
(compatible with trivial move copy).
In such case, all INIT_MOVE & MOVE operators can be removed from oplist
to only use the default, and theses operators can be disabled or defined
only when really needed in the oplist.
However creating a default INIT_MOVE macro seems problematic.
If the type is typedef T t[1] then passing such an argument to a function,
will transform the argument to T*, and the type of the argument doesn't match
what is expecting resulting in a move of the pointers, not a move of the design data.
* TODO #20: New: Bucket priority queue :ENHANCEMENT:
Defining this type seems possible with C11 _Generic and a TYPE in the oplist,
but without C11 _Generic I don't see any way to define such macro.
Without a way to write such a macro, the ticket seems pretty much a dead end.
* TODO #20 : New: Bucket priority queue :ENHANCEMENT:
Add a new kind of priority queue.
See https://en.wikipedia.org/wiki/Bucket_queue
@@ -161,21 +446,18 @@ except that we can scan 64 entries at a time).
Check if we can use BITSET, or introduce fixed size BITSET or use ad-hock
implementation.
* TODO #19: New: Intrusive Red Black Tree :ENHANCEMENT:
* TODO #19 : New: Intrusive Red Black Tree :ENHANCEMENT:
Add intrusive red black tree.
Look also for AVL tree (NOTE: Is there a performance difference between the two?)
* TODO #18: Missing methods :ENHANCEMENT:
* TODO #18 : Missing methods :ENHANCEMENT:
Some containers don't have all the methods they should.
See the cells in yellow here:
http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Container.html
* TODO #17: New: Ressource handler :ENHANCEMENT:
* TODO #17 : New: Ressource handler :ENHANCEMENT:
A global 'ressouce handler' which shall associated a unique handle to a ressource.
The handle shall be unique for the ressource and shall not be reused.
@@ -202,11 +484,10 @@ http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Co
How to handle multiple resource ?
* variant: works fine. Memory usage can be (much) higher than needed if there is a lot of dissimilarity between the size of the objects.
* embedded the type in the ressource handler: more work, API more complex. Memory usage seems better.
* variant: Pro : easy. Con: Memory usage can be (much) higher than needed if there is a lot of dissimilarity between the size of the objects.
* embedded the type in the ressource handler: Con: more work, API more complex. Pro: Memory usage seems better.
* TODO #16: New: Lock Free List :ENHANCEMENT:
* TODO #16 : New: Lock Free List :ENHANCEMENT:
Implement a lock free list. Most of the difficulty is the memory reclamation part.
Typically this lock free list shall be compatible with RCU method.
@@ -229,31 +510,7 @@ http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Co
- needs to be logically deleted : needs a previous field
(NULL if not logically deleted) ? TBC
* TODO #15: Prologue / Epilogue for Constructor / Destructor for error handling :ENHANCEMENT:
Constructor (and destructor) need to use user-defined prologue / epilogue.
This is in order to register the constructed object into a proper Exception
Handling Stack so that throwing exceptions may work reliably.
Proposal:
- M_CONSTRUCTOR_PROLOGUE(object, oplist);
- M_CONSTRUCTOR_EPILOGUE(object, oplist);
- M_DESTRUCTOR_PROLOGUE(object, oplist);
- M_DESTRUCTOR_EPILOGUE(object, oplist);
Object creation will need to add all sub-objects into the stack,
then unstack all to push instead the root object (which recursively remove them).
See also http://freetype.sourceforge.net/david/reliable-c.html#cseh
- How to handle like allocation of the object?
- How to avoid calling the destructor multiple times? (It is needed?)
- How the code can be factorized with RETCODE needs?
* TODO #14: Memory allocation enhancement :ENHANCEMENT:
* DONE #14 : Memory allocation enhancement :ENHANCEMENT:
Enhancement of the memory allocation scheme to find way to deal properly with advanced allocators:
@@ -287,8 +544,9 @@ Needs some formal operator in the oplist to support it fully and an example.
It is a kind of object inheritance where the container inherits some extra data from its base.
Duplicate with #32 which is more generic ==> Closed
* TODO #12: New: Atomic shared pointer :ENHANCEMENT:
* TODO #12 : New: Atomic shared pointer :ENHANCEMENT:
Add an extension to the SHARED_PTR API:
@@ -362,9 +620,7 @@ Other alternative solution is to use the bit 0 to mark the pointer as being upda
Other implementation seems to have it hard to be lock-free: cf. https://github.com/llvm-mirror/libcxx/commit/5fec82dc0db3623546038e4a86baa44f749e554f
* TODO #5: New: Concurrent dictionary Container :ENHANCEMENT:
* TODO #5 : New: Concurrent dictionary Container :ENHANCEMENT:
Implement a more efficient dictionary than lock + std dictionary for all operations when dealing with threads.
See https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx
@@ -410,7 +666,6 @@ It needs before lock-free list: http://www.cse.yorku.ca/~ruppert/papers/lfll.pdf
Atomic update is done by allocating a new node, update it, and atomicaly store it in the dict, putting the old one as logically deleted and to reclaim later.
(Other threads may still read its data so we cannot free immediatly).
* DONE #22: Enhanced services for SPSC Queue :ENHANCEMENT:
Add services:
@@ -448,6 +703,27 @@ push always succeed and the queue always keep the youngest element.
To simplify it, this interface could only support one kind of import/export
per compilation unit.
* DONE #15: Prologue / Epilogue for Constructor / Destructor for error handling :ENHANCEMENT:
Constructor (and destructor) need to use user-defined prologue / epilogue.
This is in order to register the constructed object into a proper Exception
Handling Stack so that throwing exceptions may work reliably.
Proposal:
- M_CONSTRUCTOR_PROLOGUE(object, oplist);
- M_CONSTRUCTOR_EPILOGUE(object, oplist);
- M_DESTRUCTOR_PROLOGUE(object, oplist);
- M_DESTRUCTOR_EPILOGUE(object, oplist);
Object creation will need to add all sub-objects into the stack,
then unstack all to push instead the root object (which recursively remove them).
See also http://freetype.sourceforge.net/david/reliable-c.html#cseh
- How to handle like allocation of the object?
- How to avoid calling the destructor multiple times? (It is needed?)
- How the code can be factorized with RETCODE needs?
Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Executable
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
mkdir -p /tmp/prepro-$USER
name=/tmp/prepro-$USER/$$.c
param1=""
param2=""
while test $# -gt 0 ; do
case $1 in
-c) param2="$param2 -c" ;;
*\.c) param1="$param1 $1" ;;
*) param1="$param1 $1" ; param2="$param2 $1" ;;
esac
shift
done
cc $param1 -E |grep -v '^#' > ${name} \
&& perl -pi -e 's/\;/\;\n/g' ${name} \
&& cc $param2 ${name}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 128 KiB

+23 -7
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2017-2021, Patrick Pelissier
# Copyright (c) 2017-2023, Patrick Pelissier
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -21,8 +21,9 @@
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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
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 -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,18 +31,33 @@ RM=rm -f
.SUFFIXES: .c .exe
.c.exe:
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) `cat config` $< -o $@
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ `cat config` `cat config.curl` $(LDFLAGS)
.c.o:
@$(MAKE) config
$(CC) $(CFLAGS) $(CPPFLAGS) -O2 `cat config.link` -DNDEBUG -g $< -c -o $@
all: config
$(MAKE) `ls ex-*.c|sed -e 's/\.c/\.exe/g'`
if test "$(CC)" = "cc -std=c99" ; then $(MAKE) `ls ex11-*.c|sed -e 's/\.c/\.exe/g'` CC="cc -std=c11" ; fi
$(MAKE) exm.exe exn.exe
exm.exe: exm-lib.o exm-main.o
$(CC) `cat config.link` -g $^ -o $@
exn.exe: exn-lib.o exn-main.o
$(CC) `cat config.link` -g $^ -o $@
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) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib config-test.c -lgmp -o config-test.exe $(LDFLAGS) 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=0 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0 -DHAVE_MPFR=0 " > config
printf "#include <mpfr.h>\nint main(void){mpfr_t z; mpfr_init(z); return 0;}\n" > config-test.c
$(CC) $(CFLAGS) $(CPPFLAGS) -I$(GMP_DIR)/include -I$(MPFR_DIR)/include -L$(GMP_DIR)/lib -L$(MPFR_DIR)/lib config-test.c -lmpfr -lgmp -o config-test.exe $(LDFLAGS) 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -I$(MPFR_DIR)/include -L$(MPFR_DIR)/lib -lmpfr -lgmp" > config || echo "MPFR not available"
printf "#include <curl/curl.h>\nint main(void){curl_global_init(CURL_GLOBAL_DEFAULT);}" > config-test.c
$(CC) $(CFLAGS) $(CPPFLAGS) config-test.c `curl-config --cflags --libs` -o config-test.exe 2> /dev/null && echo "-DHAVE_CURL=1 `curl-config --cflags --libs`" > config.curl || echo "-DHAVE_CURL=0 " > config.curl
printf "#include <stdio.h>\nint main(void){printf(\"Ok\"); return 0;}\n" > config-test.c
$(CC) $(CFLAGS) $(CPPFLAGS) config-test.c -ffunction-sections -fdata-sections -Wl,--gc-sections 2> /dev/null && echo "-ffunction-sections -fdata-sections -Wl,--gc-sections" > config.link || echo "" > config.link
$(RM) config-test.c config-test.exe
clean:
$(RM) *.exe *.s *~ *.o ./a.dat config
$(RM) *.exe *.s *~ *.o ./a.dat config config.link config.curl
+8 -8
View File
@@ -4,16 +4,16 @@
/* Define a dynamic array of int */
ARRAY_DEF(vector_int, int)
/* Register the oplist of this dynamic array globally */
/* Register the oplist of this dynamic array globally (using implicitely M_BASIC_OPLIST) */
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
/* Define some standards algorithms on this dynamic array */
/* Define some standards algorithms on this dynamic array. We can reuse the prefix of the dynamic array */
ALGO_DEF(vector_int, vector_int_t)
/* Define a dynamic array of bool */
ARRAY_DEF(vector_bool, bool, M_BOOL_OPLIST)
ARRAY_DEF(vector_bool, bool)
/* Register the oplist of this dynamic array globally */
#define M_OPL_vector_bool_t() ARRAY_OPLIST(vector_bool, M_BOOL_OPLIST)
/* Define some standards algorithms on this dynamic array */
/* Define some standards algorithms on this dynamic array. We can reuse the prefix of the dynamic array */
ALGO_DEF(vector_bool, vector_bool_t)
/* ID function */
@@ -41,10 +41,10 @@ int main(void)
#else
for M_EACH(it, myvector, vector_int_t) {
printf(" %d", *it);
}
}
#endif
printf("\n");
}
} /* End of M_LET: myvector & tmp are automaticly cleared */
// Same thing but with booleans
M_LET(myvector, tmp, vector_bool_t) {
@@ -56,13 +56,13 @@ int main(void)
printf("myvector contains:");
for M_EACH(it, myvector, vector_bool_t) {
printf(" %d", (int)*it);
}
}
printf("\n");
printf ("ALL: %d ANY: %d NONE: %d\n",
vector_bool_all_of_p(myvector, id),
vector_bool_any_of_p(myvector, id),
vector_bool_none_of_p(myvector, id) );
}
} /* End of M_LET: myvector & tmp are automaticly cleared */
return 0;
}
+8 -9
View File
@@ -3,18 +3,18 @@
#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)
/* Register the oplist of this array of integer globally */
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
/* Micro macro to detect if a string starts with the given pattern */
/* Micro macro to detect if the key string starts with the given pattern */
#define start_with(pattern, item) \
string_start_with_str_p((item).key, (pattern))
@@ -23,14 +23,13 @@ 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
// Initialize tmp as a dictionanry
M_LET( (m, (STRING_CTE("foo"), 1), (STRING_CTE("bar"), 42), (STRING_CTE("bluez"), 7), (STRING_CTE("stop"), 789) ), tmp, dict_t) {
/* Extract all elements of 'm' that starts with 'b' */
// Initialize m as a dictionnary and initialize it with the given database
// Initialize tmp as a dictionnary
M_LET( (m, (STRING_CTE("foo"), 1), (STRING_CTE("bar"), 42), (STRING_CTE("bluez"), 7), (STRING_CTE("stop"), 789) ), tmp, dict_t) {
/* Extract all elements of 'm' that starts with 'b' and fills tmp with it */
ALGO_EXTRACT(tmp, dict_t, m, dict_t, start_with, "b");
/* Extract the values of theses elements */
ALGO_TRANSFORM(keys, vector_int_t, tmp, dict_t, get_value);
+12 -9
View File
@@ -7,28 +7,31 @@ ARRAY_DEF(vector_int, int)
/* Register the oplist of this array of int globally */
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
/* Set s (string_t) to the integer i */
#define str_ui(s, i) string_printf(s, "%d", i)
/* Concat two strings by insertion a '-' within them */
#define str_cat(s1, s2) (string_cat_str(s1, "-"), string_cat(s1, s2))
int main(void)
{
// Let s be a string_t and initilize it.
// Let 's' be a string_t and initialize it.
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;
// 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 = 0, product = 0;
// Compute the sum of theses integers.
// 'add' is a registered keyword, recognized by M*LIB to perform a sum.
ALGO_REDUCE(sum, v, vector_int_t, add);
// Compute the product of theses integers.
// 'mul' is a registered keyword, recognized by M*LIB to perform a product.
ALGO_REDUCE(product, v, vector_int_t, mul);
/* Example of reduction with a transformation of the type from int to string_t */
ALGO_REDUCE( (s, string_t), v, vector_int_t, str_cat, str_ui);
/* Example of reduction with a transformation of the type from int to string_t
By default, the result ("s") should be of the same type as the base type
of the container. This is not the case here, we want to transform the
type. As such, we add the precision of the type 'string_t' to 's'.
The transformation from string to integer is done by string_set_si */
ALGO_REDUCE( (s, string_t), v, vector_int_t, str_cat, string_set_si);
printf ("sum: %d\n"
"product: %d\n"
+109
View File
@@ -0,0 +1,109 @@
#include <stdio.h>
#include <stdlib.h>
////////////////////////////////////////////////////////////
static size_t allocated_size = 0;
static void* my_alloc(size_t s)
{
printf("Alloc called s=%lu!\n", s);
allocated_size += s;
return malloc(s);
}
static void my_free(void *ptr, size_t s)
{
printf("Free called s=%lu!\n", s);
allocated_size -= s;
free(ptr);
}
////////////////////////////////////////////////////////////
static void *last_alloc;
static void* my_array_alloc(size_t s, void *org, size_t n)
{
printf("Array Alloc called org=%p of n=%zu elements of size s=%lu!\n", org, n, s);
last_alloc = realloc(org, s*n);
return last_alloc;
}
static void my_array_free(void *ptr)
{
printf("Array Free called ptr=%p last_alloc=%p!\n", ptr, last_alloc);
if (ptr != last_alloc) {
printf("Somthing went wrong.\n");
exit(4);
}
free(ptr);
}
////////////////////////////////////////////////////////////
// Allocate for single object
# define M_MEMORY_ALLOC(type) my_alloc (sizeof (type))
# define M_MEMORY_DEL(ptr) my_free(ptr, sizeof *ptr)
// Allocate for array of objects
# define M_MEMORY_REALLOC(type, ptr, n) my_array_alloc (sizeof (type), ptr, n)
# define M_MEMORY_FREE(ptr) my_array_free(ptr)
#include "m-list.h"
#include "m-array.h"
////////////////////////////////////////////////////////////
LIST_DEF(list_int, int)
static void test_list(void)
{
printf("List demo\n");
list_int_t list;
list_int_init(list);
list_int_push_back(list, 34);
list_int_push_back(list, 34);
if (allocated_size == 0) {
printf("Nothing was allocated... Very strange...\n");
exit(1);
}
list_int_clear(list);
if (allocated_size != 0) {
printf("Nothing was freed (%lu)... Very strange...\n", allocated_size);
exit(2);
}
printf("Global custom allocator for list works!\n");
}
////////////////////////////////////////////////////////////
ARRAY_DEF(array_int, int)
static void test_array(void)
{
printf("Array demo\n");
array_int_t array;
array_int_init(array);
array_int_push_back(array, 34);
array_int_push_back(array, 34);
array_int_clear(array);
printf("Global custom allocator for array works!\n");
}
////////////////////////////////////////////////////////////
int main(void)
{
test_list();
test_array();
exit(0);
}
+109
View File
@@ -0,0 +1,109 @@
#include <stdio.h>
#include <stdlib.h>
#include "m-list.h"
#include "m-array.h"
////////////////////////////////////////////////////////////
static size_t allocated_size = 0;
static void* my_alloc(size_t s)
{
printf("Alloc called s=%lu!\n", s);
allocated_size += s;
return malloc(s);
}
static void my_free(void *ptr, size_t s)
{
printf("Free called s=%lu!\n", s);
allocated_size -= s;
free(ptr);
}
// Allocate for single object
# define MY_MEMORY_ALLOC(type) my_alloc (sizeof (type))
# define MY_MEMORY_DEL(ptr) my_free(ptr, sizeof *ptr)
////////////////////////////////////////////////////////////
// Override only for this container the memory allocation function
LIST_DEF(list_int, int, M_OPEXTEND(M_BASIC_OPLIST, NEW(MY_MEMORY_ALLOC), DEL(MY_MEMORY_DEL)))
static void test_list(void)
{
printf("List demo\n");
list_int_t list;
list_int_init(list);
list_int_push_back(list, 34);
list_int_push_back(list, 34);
if (allocated_size == 0) {
printf("Nothing was allocated... Very strange...\n");
exit(1);
}
list_int_clear(list);
if (allocated_size != 0) {
printf("Nothing was freed (%lu)... Very strange...\n", allocated_size);
exit(2);
}
printf("Global custom allocator for list works!\n");
}
////////////////////////////////////////////////////////////
static void *last_alloc;
static void* my_array_alloc(size_t s, void *org, size_t n)
{
printf("Array Alloc called org=%p of n=%zu elements of size s=%lu!\n", org, n, s);
last_alloc = realloc(org, s*n);
return last_alloc;
}
static void my_array_free(void *ptr)
{
printf("Array Free called ptr=%p last_alloc=%p!\n", ptr, last_alloc);
if (ptr != last_alloc) {
printf("Somthing went wrong.\n");
exit(4);
}
free(ptr);
}
// Allocate for array of objects
# define MY_MEMORY_REALLOC(type, ptr, n) my_array_alloc (sizeof (type), ptr, n)
# define MY_MEMORY_FREE(ptr) my_array_free(ptr)
////////////////////////////////////////////////////////////
// Override only for this container the memory allocation function
ARRAY_DEF(array_int, int, M_OPEXTEND(M_BASIC_OPLIST, REALLOC(MY_MEMORY_REALLOC), FREE(MY_MEMORY_FREE)))
static void test_array(void)
{
printf("Array demo\n");
array_int_t array;
array_int_init(array);
array_int_push_back(array, 34);
array_int_push_back(array, 34);
array_int_clear(array);
printf("Global custom allocator for array works!\n");
}
////////////////////////////////////////////////////////////
int main(void)
{
test_list();
test_array();
exit(0);
}
+27 -17
View File
@@ -24,7 +24,8 @@
/* 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.
For bool, M_BOOL_OPLIST will be used.
*/
ARRAY_DEF(r_bool, bool)
@@ -105,7 +106,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 +181,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)
@@ -214,9 +215,9 @@ static char *my_strdup(const char *p)
return d;
}
/* Same with type const char *, representing a contant string.
/* Same with type const char *, representing a contant C string.
We *** need *** an explicit oplist to tell M*LIB
to consider the type as a constant string.
to consider the type as a constant C string.
The oplist to use is M_CSTR_OPLIST.
We could have used M_PTR_OPLIST too,
but in this case, we won't get proper string order or
@@ -231,7 +232,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
@@ -245,13 +246,13 @@ test_cstring(int n)
for(int i = 0; i < n; i++) {
// Get back the string
const char *p = *r_cstring_get(array, i);
// Convert it to integer
// Convert it to an integer
int j = atoi(p);
s += j;
}
// We also need a special unalloc pass
// to free all constant strings we have allocated.
// to free all constant strings we have allocated using my_strdup
for(int i = 0; i < n; i++) {
const char *p = *r_cstring_get(array, i);
free((void*)(uintptr_t)p);
@@ -264,7 +265,7 @@ test_cstring(int n)
/* Same with type string_t of M*LIB, representing a variable string.
/* Same with type string_t of M*LIB, representing a dynamic string.
We don't need explicit oplist to tell M*LIB!
The oplist to use is STRING_OPLIST,
but it has been registered globaly, so we don't need to explicit
@@ -282,7 +283,7 @@ test_string(int n)
for(int i = 0; i < n; i++) {
// create a string from an integer
string_printf(str, "%d", i);
string_set_si(str, i);
// No need to make a copy in the container!
r_string_push_back(array, str);
}
@@ -294,7 +295,7 @@ test_string(int n)
s += j;
}
// No need to explicit dealloc !
// No need to explicit free each term of the array
string_clear(str);
r_string_clear(array);
@@ -304,7 +305,7 @@ test_string(int n)
/* Same with type string_t of M*LIB, representing a variable string
and its explicit oplist. And said above, it generates exactly the
and its explicit oplist. As said above, it generates exactly the
same code. */
ARRAY_DEF(r_string2, string_t, STRING_OPLIST)
@@ -340,6 +341,9 @@ test_vintptr(int n)
int s = 0;
for(int i = 0; i < n; i++) {
// Get the pointer to the integer.
// As the basic type of the container is a pointer,
// and r_vintptr_get return a pointer to the basic type
// we need to dereference its return value to get the pointer value.
volatile unsigned *p = *r_vintptr_get(array, i);
s += *p;
}
@@ -374,6 +378,7 @@ test_rockme(int n)
for(int i = 0; i < n; i++) {
struct rock_me_out rock;
rock.n = i*i - i;
rock.other = 0.0f;
// Push the struct in the array
r_rockme_push_back(array, rock);
}
@@ -414,6 +419,7 @@ test_rockme2(int n)
for(int i = 0; i < n; i++) {
rock_me_in rock;
rock->n = i*i - i;
rock->other = 0.0f;
r_rockme2_push_back(array, rock);
}
@@ -458,6 +464,7 @@ test_rockme2b(int n)
for(int i = 0; i < n; i++) {
rock_me_in rock;
rock->n = i*i - i;
rock->other = 0.0f;
r_rockme2b_push_back(array, rock);
}
@@ -478,15 +485,18 @@ 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 by default.
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,
and the oplists of the tuple.
The main advantage of a tuple over a classic structure is that you get
free classic methods of your structure.
*/
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 +530,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 +543,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 +622,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,
+9 -4
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)
{
@@ -25,7 +25,9 @@ int main(void)
map_employee_id_set_at(Employees, 11632, STRING_CTE("John Do"));
map_employee_id_set_at(Employees, 852, STRING_CTE("Peter"));
map_employee_id_set_at(Employees, 530, STRING_CTE("Amanda"));
map_employee_id_set_at(Employees, 4258, STRING_CTE("Elisabeth"));
// You can also emplace the structure
map_employee_id_emplace_val(Employees, 4258, "Elisabeth");
printf("Number of employees: %zu\n", map_employee_id_size(Employees));
@@ -57,9 +59,12 @@ int main(void)
}
// Print
printf("\nElisabeth has id = %d\n", *map_employee_name_get(Employees_r, STRING_CTE("Elisabeth")));
printf("\nElisabeth has id = %d\n", *map_employee_name_get(Employees_r, STRING_CTE("Elisabeth")));
// Print using emplace (we give a const char [] isntead of a const string_t, avoiding macro STRING_CTE)
printf("\nElisabeth has id = %d\n", *map_employee_name_get_emplace(Employees_r, "Elisabeth"));
} /* Employees_r is cleared beyond this point */
// But employee is not since we don't use M_LET
map_employee_id_clear(Employees);
return 0;
}
+1 -1
View File
@@ -2,7 +2,7 @@
#include "m-buffer.h"
#include "m-shared.h"
#include "m-mutex.h"
#include "m-thread.h"
/* Global variable to stop scheduling */
atomic_bool continue_threading_g;
+160
View File
@@ -0,0 +1,160 @@
#if HAVE_CURL
#include <curl/curl.h>
#include "m-dict.h"
#include "m-tuple.h"
#include "m-string.h"
#include "m-list.h"
#include "m-serial-json.h"
/////////////////////////////////////////
// Define container types
// First a generic map string to string
DICT_DEF2(map_str, string_t, string_t)
#define M_OPL_map_str_t() DICT_OPLIST(map_str, STRING_OPLIST, STRING_OPLIST)
// This structure matches the JSON structure returns by the used WEB server
// for the GET command.
// It can be whatever you want provided it matches what is expected by the WEB server
TUPLE_DEF2(web_data,
(args, map_str_t),
(headers, map_str_t),
(origin, string_t),
(url, string_t))
#define M_OPL_web_data_t() TUPLE_OPLIST(web_data, M_OPL_map_str_t(), M_OPL_map_str_t(), STRING_T, STRING_T)
/////////////////////////////////////////
static size_t
write_data(void *buffer, size_t size, size_t nmemb, void *userp)
{
(void) size; // Parameter not used
char *src = buffer;
string_ptr str = userp;
for(size_t i = 0; i < nmemb; i++) {
string_push_back(str, src[i]);
}
return nmemb;
}
static bool get_data(web_data_t data, const char url[])
{
m_serial_return_code_t r = M_SERIAL_FAIL;
CURLcode res;
string_t str;
CURL *handle = curl_easy_init();
if (handle) {
string_init(str);
// Perform an http GET request and fill in str with the JSON answer
curl_easy_setopt(handle, CURLOPT_URL, url);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, str);
res = curl_easy_perform(handle);
curl_easy_cleanup(handle);
if (res == CURLE_OK) {
// Parse the string and fill in the object
m_serial_str_json_read_t serial;
m_serial_str_json_read_init(serial, string_get_cstr(str));
r = web_data_in_serial(data, serial);
m_serial_str_json_read_clear(serial);
}
string_clear(str);
}
return r == M_SERIAL_OK_DONE;
}
/////////////////////////////////////////
static size_t
ignore_data(void *buffer, size_t size, size_t nmemb, void *userp)
{
(void) buffer; // Parameter not used
(void) size; // Parameter not used
(void) userp; // Parameter not used
return nmemb;
}
static bool post_data(web_data_t data, const char url[], bool display_answer)
{
m_serial_return_code_t r = M_SERIAL_FAIL;
CURLcode res = 0;
string_t str;
CURL *handle = curl_easy_init();
if (handle) {
string_init(str);
// Get a JSON string
m_serial_str_json_write_t serial;
m_serial_str_json_write_init(serial, str);
r = web_data_out_serial(serial, data);
m_serial_str_json_write_clear(serial);
if (r == M_SERIAL_OK_DONE) {
// Post JSON string
struct curl_slist *headers=NULL;
headers = curl_slist_append(headers, "Content-Type: text/json");
if (headers != NULL) {
curl_easy_setopt(handle, CURLOPT_POSTFIELDS, string_get_cstr(str));
curl_easy_setopt(handle, CURLOPT_URL, url);
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
if (display_answer == false) {
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ignore_data);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL);
}
res = curl_easy_perform(handle);
curl_slist_free_all(headers);
}
}
curl_easy_cleanup(handle);
string_clear(str);
}
return (r == M_SERIAL_OK_DONE) && (res == CURLE_OK);
}
/////////////////////////////////////////
// Remote server URL
#define URL_GET "https://httpbin.org/get"
#define URL_POST "https://httpbin.org/post"
int main(void)
{
CURLcode ret = curl_global_init(CURL_GLOBAL_DEFAULT);
if (ret != CURLE_OK) abort();
web_data_t data;
web_data_init(data);
// Test http GET
bool b = get_data(data, URL_GET);
if (b) {
// We success receiving the JSON object and fill in the C object web_data with it.
// Let's display the object content:
printf("SUCCESS. Receive data =\n");
web_data_out_str(stdout, data);
printf("\n");
} else {
printf("ERROR: Cannot GET data or get data are not in expected format\n");
}
// Test http POST
web_data_emplace_origin(data, "This is the origin");
web_data_emplace_url(data, "This is the URL");
//web_data_set_origin(data, STRING_CTE("This is the origin"));
//web_data_set_url(data, STRING_CTE("This is the URL"));
b = post_data(data, URL_POST, false);
if (b) {
printf("SUCCESS: Post\n");
} else {
printf("ERROR post\n");
}
web_data_clear(data);
curl_global_cleanup();
return 0;
}
#else
int main(void) { return 0; }
#endif
+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)) {
+56
View File
@@ -0,0 +1,56 @@
#include <stdio.h>
#include "m-dict.h"
/*
* Provide OOR methods for OA Hashmap.
* See documentation for definition of OOR
* OOR values are represented as:
* empty (0) is INT_MIN
* deleted (1) is INT_MIN + 1
* So valid range for integers are [INT_MIN+2, INT_MAX]
*/
static inline bool oor_equal_p(int k, char n)
{
return k == INT_MIN + n;
}
static inline int oor_set(char n)
{
return INT_MIN + n;
}
/*
* Provide a custom hash function (optional for OA)
*/
static inline size_t hash(int n)
{
return (size_t) n; // Identity hash!
}
/* Define an OA dictionnay which performs a hashmap between an int to an int */
DICT_OA_DEF2(dict_oa,
int, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set)), HASH(hash)),
int, M_BASIC_OPLIST)
int main(void)
{
dict_oa_t d;
dict_oa_init(d);
for(int i = 0; i < 10; i++) {
dict_oa_set_at(d, i*i, 4*i);
}
dict_oa_set_at(d, 3, -17);
printf("DICT[3] = %d\n", *dict_oa_get(d, 3));
dict_oa_it_t it;
printf("DICT=");
for(dict_oa_it(it, d); !dict_oa_end_p(it); dict_oa_next(it)) {
printf("%d:%d, ", dict_oa_cref(it)->key, dict_oa_cref(it)->value);
}
printf("\n");
dict_oa_clear(d);
return 0;
}
+64
View File
@@ -0,0 +1,64 @@
#include <stdio.h>
#include "m-dict.h"
/*
* Provide OOR methods for OA Hashmap.
* See documentation for definition of OOR
* OOR values are represented as:
* empty (0) is "EMPTY"
* deleted (1) is "DELETED"
*/
static const char empty_str[] = "EMPTY";
static const char deleted_str[] = "DELETED";
static const char *const oor_table[] = { empty_str, deleted_str };
static inline bool oor_equal_p(const char *k, int n)
{
return k == oor_table[n];
}
static inline const char *oor_set(int n)
{
return oor_table[n];
}
/*
* Provide a custom hash function (optional for OA)
*/
static inline size_t hash(const char *k)
{
size_t r = 17;
while (*k) {
r = *k * 33 + r;
k++;
}
return r;
}
/* Define an OA dictionnay which performs a hashmap between a CSTR to an int */
DICT_OA_DEF2(dict_oa,
const char *, M_OPEXTEND(M_CSTR_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set)), HASH(hash)),
int, M_BASIC_OPLIST)
int main(void)
{
dict_oa_t d;
dict_oa_init(d);
dict_oa_set_at(d, "THIS", -17);
dict_oa_set_at(d, "IS", -170);
dict_oa_set_at(d, "AN", 7);
dict_oa_set_at(d, "EXAMPLE", 77);
printf("DICT[\"AN\"] = %d\n", *dict_oa_get(d, "AN"));
dict_oa_it_t it;
printf("DICT=");
for(dict_oa_it(it, d); !dict_oa_end_p(it); dict_oa_next(it)) {
printf("%s:%d, ", dict_oa_cref(it)->key, dict_oa_cref(it)->value);
}
printf("\n");
dict_oa_clear(d);
return 0;
}
+58 -22
View File
@@ -8,43 +8,54 @@
#include "m-string.h"
#include "m-algo.h"
// Let's create a list of string.
// Let's create a list of string by using the M*LIB dynamic string 'string_t'
// The prefix used for generating functions will be 'list_string'
LIST_DEF(list_string, string_t)
// Let's register the oplist globally so that other m*lib macros
// Let's register the oplist globally so that other M*LIB macros
// can get the oplist without us giving it explictly to them.
// An oplist is the association of operators to the provided methods
// so that generic code can use correctly an object of such type.
// LIST_OPLIST is a macro used to generate the oplist associated to the
// list itself. It needs the prefix used for generating the list (aka list_string here)
// and the oplist of the item in the list (aka the string oplist)
#define M_OPL_list_string_t() LIST_OPLIST(list_string, STRING_OPLIST)
// Let's define some basic algorithms over this list of string.
ALGO_DEF(astring, M_OPL_list_string_t())
// We reuse the prefix of the list to simplify usage, but algorithms can use separate namespace.
ALGO_DEF(list_string, M_OPL_list_string_t())
int main(void)
{
// Let's create a variable named 'grow' which is a list of string_t
// Let's create a variable named 'list' which is a list of string_t
// This variable is only defined within the associated '{' '}' block.
// The constructor/destructor of the variable will be called within this block
// You can also define the variable (list_string_t) and use explicitly
// its constructor (list_string_init) / destructor (list_string_clear).
M_LET (grow, list_string_t)
M_LET (list, list_string_t)
M_LET (tmpstr, string_t) { // And let's create also a string_t
// add string elements to the list
list_string_push_back (grow, STRING_CTE("AB"));
// add string elements to the list in different ways
// First is pushing a const string.
// The macro STRING_CTE creates a const string_t based on the given const char * string.
list_string_push_back (list, STRING_CTE("AB"));
// Second is creating a separate string_t and then pushing it in the list
string_printf(tmpstr, "%d", 12);
list_string_push_back (grow, tmpstr);
list_string_push_back (grow, STRING_CTE("CD"));
list_string_push_back (list, tmpstr);
// Third is to emplace directly in the list by constructing a new string_t based on the given const char *
list_string_emplace_back (list, "CD");
// Serialize the list of string into a big string.
list_string_get_str (tmpstr, grow, false);
list_string_get_str (tmpstr, list, false);
// print out
printf("Number of elements = %zu\n", list_string_size(grow));
// print it
printf("Number of elements = %zu\n", list_string_size(list));
printf("Final string = %s\n", string_get_cstr(tmpstr));
// Let's iterate over each element of the list
// using the macro for iteration over a container.
printf ("Using macro EACH :\n");
for M_EACH (item, grow, list_string_t) {
printf ("Using macro EACH:\n");
for M_EACH (item, list, list_string_t) {
printf ("Item = ");
string_fputs (stdout, *item);
printf ("\n");
@@ -52,34 +63,59 @@ int main(void)
// You can also use classic iterator:
list_string_it_t it;
printf ("Using iterators :\n");
for(list_string_it(it, grow) ; !list_string_end_p(it) ; list_string_next(it)) {
printf ("Using iterators:\n");
for(list_string_it(it, list) ; !list_string_end_p(it) ; list_string_next(it)) {
const string_t *item = list_string_cref (it);
printf ("Item = ");
string_fputs (stdout, *item);
printf ("\n");
}
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
// Another way: we map each element to the M_PRINT function.
printf ("Using macro ALGO_FOR_EACH:");
ALGO_FOR_EACH(list, list_string_t, M_PRINT, "\nItem = ");
printf ("\n");
#endif
// Get the min and the max of the list
string_t *p = astring_min(grow);
string_t *p = list_string_min(list);
printf ("Min string is %s\n", string_get_cstr(*p));
p = astring_max(grow);
p = list_string_max(list);
printf ("Max string is %s\n", string_get_cstr(*p));
// We can even sort the list.
astring_sort(grow);
for M_EACH (item, grow, list_string_t) {
list_string_sort(list);
for M_EACH (item, list, list_string_t) {
printf ("Sort Item = %s\n", string_get_cstr(*item) );
}
// Split a string into a list.
string_set_str(tmpstr, "HELLO;JOHN;HOW;ARE;YOU");
astring_split(grow, tmpstr, ';');
for M_EACH (item, grow, list_string_t) {
list_string_split(list, tmpstr, ';');
// Iterate over the splitted list
for M_EACH (item, list, list_string_t) {
printf ("Split Item = %s\n", string_get_cstr(*item) );
}
} // Everything is cleared after this point.
// Let's create another list of string and init it.
list_string_t list;
list_string_init(list);
// Let's put some elements in it:
list_string_emplace_back (list, "A");
list_string_emplace_back (list, "B");
list_string_emplace_back (list, "C");
list_string_emplace_back (list, "D");
// Reverse it
list_string_reverse(list);
// Let's display the string by serializing the elements of the list:
printf ("List of string = ");
list_string_out_str(stdout, list);
printf ("\n");
// Don't forget to clear the list before leaving
list_string_clear(list);
return 0;
}
+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
+71
View File
@@ -0,0 +1,71 @@
#include "m-try.h"
#include "m-array.h"
// Define & register an array of int
ARRAY_DEF(array, int)
#define M_OPL_array_t() ARRAY_OPLIST(array, M_BASIC_OPLIST)
// This shall be defined once per program to define the global variables needed
// to handle the exceptions.
M_TRY_DEF_ONCE()
static void f(void)
{
M_TRY(f_exception) {
// Let's define a variable and do stuff:
// Using M_LET allows the register of destructors for the exception handler.
M_LET(a, array_t) {
array_push_back(a, 5);
array_push_back(a, 4);
array_push_back(a, 3);
array_push_back(a, 2);
array_push_back(a, 1);
// Throw a M_ERROR_MEMORY exception
M_THROW(M_ERROR_MEMORY);
printf("This should never be printed!\n");
}
} M_CATCH(f_exception, M_ERROR_MEMORY) {
// Exception handler than catches the M_ERROR_MEMORY errors.
// Here the destructor of variable a has been called to free memory
printf("Memory exception %d received in f function, thrown by %s:%d\n",
f_exception->error_code, f_exception->filename, f_exception->line);
}
}
static void g(void)
{
M_TRY(f_exception) {
// Let's define a variable and do stuff:
// Using M_LET allows the register of destructors for the exception handler.
M_LET(a, array_t) {
array_push_back(a, 5);
array_push_back(a, 4);
array_push_back(a, 3);
array_push_back(a, 2);
array_push_back(a, 1);
// Throw an unkown exception
M_THROW(42);
printf("This should never be printed!\n");
}
} M_CATCH(f_exception, M_ERROR_MEMORY) {
printf("Memory exception %d received in f function, thrown by %s:%d\n",
f_exception->error_code, f_exception->filename, f_exception->line);
printf("This should never be printed!\n");
}
}
int main(void)
{
// Let's do a global exception handler
M_TRY(main_exception) {
f();
g();
} M_CATCH(main_exception, 0) {
// Exception handler than catches all errors.
// Here the destructor of variable a has been called to free memory
printf("Exception %d received in main function, thrown by %s:%d\n",
main_exception->error_code, main_exception->filename, main_exception->line);
}
printf("You should run it under valgrind to check that all memory allocations are freed.\n");
exit(0);
}
+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)
+232
View File
@@ -0,0 +1,232 @@
#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"
/* Define the comparison function for atomic_uint type
to 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;
}
/* Define the oplist for atomic_uint and register it globally.
This oplist extends the basic oplist by:
* disabling HASH for atomic as the default hash method won't work.
* providing the methods for CMP, INIT_SET and SET operators (with their API adaptator) */
#define M_OPL_atomic_uint() M_OPEXTEND(M_BASIC_OPLIST, HASH(0), CMP(API_6(atomic_uint_cmp)), INIT_SET(API_2(atomic_store)), SET(API_2(atomic_store)))
/* Define a directory as a tree where each node contains:
* the number of lines of the files in this directory,
* and the name of the directory/
Since we want to sort with the number of lines only, we extend the oplist of a string by disabling the compare method.
So first, let's define the node as a tuple of such elements:
*/
M_TUPLE_DEF2( dir, (nlines, atomic_uint), (name, m_string_t, M_OPEXTEND(M_STRING_OPLIST, CMP(0))))
/* Register globally the oplist of this tuple */
#define M_OPL_dir_t() M_TUPLE_OPLIST(dir, M_OPL_atomic_uint(), M_STRING_OPLIST)
/* Define a hierarchical tree of directory.
Note that it will use the globally registered oplist associated to dir_t to use it */
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
/* Define the pool of worker threads */
m_worker_t workers;
/* Global synchronous block for all threads */
m_worker_sync_t workers_block;
/* Add a specialization of the spawn function for the scan_file function.
This functions takes as input an iterator of a tree (treated as a POD data),
and a file name */
M_WORKER_SPAWN_DEF2(scan_file, (parent, tree_it_t, M_POD_OPLIST), (filename, m_string_t) )
/* Add either the root node or a child to parent in function of the existence of parent */
static tree_it_t
add_directory(tree_it_t parent, const m_string_t dirname)
{
if (tree_end_p(parent)) {
return tree_emplace_root( tree_tree(parent), 0, dirname);
} else {
return tree_emplace_child(parent, 0, dirname);
}
}
/* count the number of end of line character in the buffer */
static unsigned
count_eol(size_t num, const char buffer[num])
{
unsigned count = 0;
for(size_t i = 0; i < num; i++) {
count += buffer[i] == '\n';
}
return count;
}
/* Test if a filename suffix ends with a C++ or C suffix */
static bool
is_a_c_file(const m_string_t filename)
{
return (m_string_end_with_str_p(filename, ".c")
|| m_string_end_with_str_p(filename, ".h")
|| m_string_end_with_str_p(filename, ".cpp")
|| m_string_end_with_str_p(filename, ".hpp"));
}
/* Scan the file and count its number of lines */
static void
scan_file(tree_it_t parent, m_string_t filename)
{
FILE *f = fopen(m_string_get_cstr(filename), "rt");
if (f == NULL) {
fprintf(stderr, "ERROR: Cannot open %s as a text file.\n", m_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(num, buffer);
} while (num == MAX_READ_BUFFER);
fclose(f);
/* Adding the number of lines to the parent directory */
dir_t *d = tree_ref(parent);
/* atomic add because the scan of files is done in parallel */
atomic_fetch_add( &(*d)->nlines, count );
}
/* Scan the directories recursively for all files */
static void
scan_directories(tree_it_t parent, const m_string_t dirname)
{
tree_it_t it = add_directory(parent, dirname);
m_string_t filename;
m_string_init(filename);
DIR *dir = opendir(m_string_get_cstr(dirname));
if (dir == NULL) {
fprintf(stderr, "ERROR: Cannot open %s as a directory.\n", m_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 by concatenating dirname, "/" and d_name
m_string_sets(filename, dirname, "/", entry->d_name);
// Get the property of this filename
struct stat buf;
int err = stat(m_string_get_cstr(filename), &buf);
if (err != 0) {
fprintf(stderr, "ERROR: Cannot stat %s\n", m_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 if (is_a_c_file(filename)) {
// Spawn a scan of file to available workers or run it ourselves
m_worker_spawn_scan_file(workers_block, scan_file, it, filename);
}
}
// Next entry in the directory
entry = readdir(dir);
}
closedir(dir);
m_string_clear(filename);
}
/* Consolidate all lines number to the parent directory */
static void
consolidate_directories(tree_t directories)
{
// Scan all entries, first the children, 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 children by the number of lines
tree_sort_child(it);
}
}
/* Print the consolidated results on stdout */
static void
print_result(tree_t directories)
{
// Scan all entries, first the parent, then the children
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, m_string_get_cstr( (*d)->name ) );
}
}
int main(int argc, const char *argv[])
{
tree_t directories;
m_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);
}
/* Initialize the worker threads */
m_worker_init(workers);
/* 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);
m_string_init_set_cstr(str, argv[1]);
tree_it_t it = tree_it_end(directories);
/* Main processing */
m_worker_start(workers_block, workers);
scan_directories(it, str);
worker_sync(workers_block);
consolidate_directories(directories);
print_result(directories);
/* Clear everything & quit */
m_string_clear(str);
tree_clear(directories);
m_worker_clear(workers);
exit(0);
}
+25
View File
@@ -0,0 +1,25 @@
#include "m-list.h"
#include "m-generic.h"
LIST_DEF(list_uint, unsigned int)
// Register for M_LET & M_EACH
#define M_OPL_list_uint_t() LIST_OPLIST(list_uint, M_BASIC_OPLIST)
// Register for Generic:
#define M_GENERIC_ORG_1() (USER)
#define M_GENERIC_ORG_USER_COMP_1() (CORE)
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_1() M_OPL_list_uint_t()
int main(void)
{
M_LET(list, list_uint_t) {
// We can push in the list. It will call the registered method.
push(list, 42);
push(list, 17);
// We can iterate over the list
for each(item, list) {
M_PRINT("ITEM=", *item, "\n");
}
// We can print directly the list. It will use the registered method
M_PRINT("List = ", list, "\n");
}
}
+82
View File
@@ -0,0 +1,82 @@
// 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;
/* Let's define a string 'buffer' that will receive the JSON representation of our message*/
string_init(buffer);
/* Encode our message */
{
SimpleMessage_t message;
SimpleMessage_init(message);
/* Create a stream that will write to our string 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
* It is represented in a string 'buffer'
* 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) {
+243
View File
@@ -0,0 +1,243 @@
#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 (aka a typed union) over three kind of numbers named my_number_t
Notice than mpz_t/mpfr_t has special init & clear functions.
This is handled by the library.
*/
VARIANT_DEF2(my_number,
(n, long long),
(z, mpz_t),
(fr, mpfr_t) )
/* Register the oplist associated to this variant named my_number_t */
#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)
/* Register the oplist associated to this dictionary named my_dict_t */
#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)
/* Register the oplist associated to this array (of dictionary of variant) named my_array_t*/
#define M_OPL_my_array_t() ARRAY_OPLIST(my_array, M_OPL_my_dict_t())
// Show how to define an array of mpz_t and some algorithms on it
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)
// Show how to define an array of mpfr_t and some algorithms on it
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'
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 first root
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);
// Compute second root
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);
} // Clear the mpfr_t variables after this point.
}
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)) {
// Print it.
M_PRINT("It is a long long, value = ", *my_number_cget_n(p->value), "\n");
}
if (my_number_z_p(p->value)) {
// Print it. Since mpz_t isn't a native type, M_PRINT macro doesn't know it by default
// So we need to add the type to the value.
// M_PRINT will then look at its globally registered oplist
// and known how to print it.
M_PRINT("It is a mpz_t, value = ", (*my_number_cget_z(p->value), mpz_t), "\n");
}
if (my_number_fr_p(p->value)) {
// Same but with a MPFR number.
M_PRINT("It is a mpfr_t, value = ", (*my_number_cget_fr(p->value), mpfr_t), "\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 / string / double)
// 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
+132
View File
@@ -0,0 +1,132 @@
#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)
{
// Let's declare a tree on the stack.
// Even if the tree itself is allocated on the stack,
// the nodes will be allocated on the heap.
tree_cstr_t tree;
// Initialize the tree using the provided constructor
tree_cstr_init(tree);
// Let's fill in the tree
// Note that the object of the tree are pointer
// to array of char. Therefore the strings themselves
// are not stored in the tree but only a reference to then
// As such, the pointed objects shall not moved nor being
// destroyed, which is the case for const C string.
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");
// Let's print the tree.
// We'll use the OUT_STR method to display the tree
// without iterating ourself in the tree.
printf("\nUsing C string, the generated (sorted) tree is ");
tree_cstr_out_str(stdout, tree);
printf ("\n");
// Let's search for the key "How" in the tree.
// If it is not found a NULL pointer is returned.
// Otherwise a pointer to the key within the tree is returned.
// This pointer is valid until a modification operation on the tree is done.
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);
// Destroy the tree by calling the destructor.
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.
// since the oplist of a string_t is registered globally.
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.
// Note that this time the full string is stored within the tree,
// and not only a pointer to it.
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"));
// We may also push a const C string into a string_t by calling the emplace function
tree_str_emplace (tree, "You");
// Let's print the tree
printf("\nUsing M*LIB string_t, the generated (sorted) tree is ");
tree_str_out_str(stdout, tree);
printf ("\n");
// Let's search for the string "How"
// We convert it to a temporary string_t, and let's test
// if it is found or not by testing if the returned pointer to string_t
// is null or not.
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)
{
+12
View File
@@ -0,0 +1,12 @@
#ifndef MY_HEADER
#define MY_HEADER
// Request M*LIB to not inline functions if not the library source
#define M_USE_DECL
#include "m-string.h"
#include "m-array.h"
ARRAY_DEF(array_str, string_t)
#endif
+5
View File
@@ -0,0 +1,5 @@
// Request M*LIB to define functions
// This include both m-string functions and array_str templated functions
// Defining M_USE_EXTERN_DEF override M_USE_EXTERN_DECL definition
#define M_USE_DEF
#include "exm-header.h"
+14
View File
@@ -0,0 +1,14 @@
#include "exm-header.h"
int main(void)
{
array_str_t a;
array_str_init(a);
array_str_emplace_back(a, "Hello");
array_str_emplace_back(a, "World");
printf("a=");
array_str_out_str(stdout, a);
printf("\n");
array_str_clear(a);
return 0;
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef MY_HEADER
#define MY_HEADER
// Request M*LIB to not always inline functions
#define M_USE_FINE_GRAINED_LINKAGE
#include "m-string.h"
#include "m-array.h"
// The following functions will not be inlined:
#define M_USE_DECL
ARRAY_DEF(array_str, string_t)
#undef M_USE_DECL
#endif
+4
View File
@@ -0,0 +1,4 @@
// Request M*LIB to define functions for functions defined within M_USE_DECL.
#define M_USE_DEF
#include "exn-header.h"
+19
View File
@@ -0,0 +1,19 @@
#include "exn-header.h"
int main(void)
{
string_t s;
string_init_set_str(s, "a=");
string_fputs(stdout, s);
string_clear(s);
array_str_t a;
array_str_init(a);
array_str_emplace_back(a, "Hello");
array_str_emplace_back(a, "World");
//printf("a=");
array_str_out_str(stdout, a);
printf("\n");
array_str_clear(a);
//main2();
return 0;
}
+199 -162
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - ALGO module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -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'.
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,13 +86,15 @@
/* 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) )
/********************************** INTERNAL ************************************/
/*****************************************************************************/
/******************************** INTERNAL ***********************************/
/*****************************************************************************/
/* Try to expand the algorithms */
#define M_ALG0_DEF_P1(name, cont_oplist) \
@@ -115,36 +121,41 @@
M_CHECK_COMPATIBLE_OPLIST(name, 10, container_t, cont_oplist) \
M_CHECK_COMPATIBLE_OPLIST(name, 11, type_t, type_oplist) \
\
M_ALG0_CALLBACK_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_IF_FUNCOBJ(M_ALG0_FUNCOBJ_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t)) \
M_ALG0_DEF_CALLBACK(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_IF_FUNCOBJ(M_ALG0_DEF_FUNCOBJ(name, container_t, cont_oplist, type_t, type_oplist, it_t)) \
\
M_IF_METHOD(EQUAL, type_oplist)( \
M_ALG0_FIND_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_ALG0_DEF_FIND(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
, /* NO EQUAL */) \
\
M_ALG0_FIND_IF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, if, M_C(name, _test_cb_ct), M_C(name, _eq_cb_ct), M_APPLY, M_APPLY) \
M_IF_FUNCOBJ(M_ALG0_FIND_IF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, fo, M_C(name, _test_obj_t), M_C(name, _eq_obj_t), M_C(name, _test_obj_call), M_C(name, _eq_obj_call))) \
M_ALG0_DEF_FIND_IF(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
if, M_F(name,_test_cb_ct), M_F(name,_eq_cb_ct), M_APPLY, M_APPLY) \
M_IF_FUNCOBJ(M_ALG0_DEF_FIND_IF(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
fo, M_F(name,_test_obj_t), M_F(name,_eq_obj_t), M_F(name, _test_obj_call), M_F(name, _eq_obj_call))) \
\
M_ALG0_MAP_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_ALG0_DEF_MAP(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
M_ALG0_ALL_OF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, _, M_C(name, _test_cb_ct), M_APPLY) \
M_IF_FUNCOBJ(M_ALG0_ALL_OF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, _fo_, M_C(name, _test_obj_t), M_C(name, _test_obj_call)) ) \
M_ALG0_DEF_ALL_OF(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
_, M_F(name,_test_cb_ct), M_APPLY) \
M_IF_FUNCOBJ(M_ALG0_DEF_ALL_OF(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
_fo_, M_F(name,_test_obj_t), M_F(name,_test_obj_call)) ) \
\
/* If there is a IT_REF method, we consider the container as modifiable through iterator */ \
M_IF_METHOD(IT_REF, cont_oplist)( \
M_ALG0_FILL_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_ALG0_VECTOR_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_ALG0_DEF_FILL(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_ALG0_DEF_VECTOR(name, container_t, cont_oplist, type_t, type_oplist, it_t)\
\
M_IF_METHOD(CMP, type_oplist)( \
M_ALG0_MINMAX_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_ALG0_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, +, _sort) \
M_ALG0_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, -, _sort_dsc) \
M_ALG0_DEF_MINMAX(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_ALG0_DEF_SORT(name, container_t, cont_oplist, type_t, type_oplist, it_t, +, _sort) \
M_ALG0_DEF_SORT(name, container_t, cont_oplist, type_t, type_oplist, it_t, -, _sort_dsc) \
M_IF_METHOD(IT_REMOVE, cont_oplist)( \
M_ALG0_REMOVE_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_ALG0_DEF_REMOVE(name, container_t, cont_oplist, type_t, type_oplist, it_t)\
, /* No IT_REMOVE method */) \
, /* No CMP method */) \
\
M_IF_FUNCOBJ(M_ALG0_SORT_DEF_P6(name, container_t, cont_oplist, type_t, type_oplist, it_t, _sort_fo, M_ALG0_SORT_CALL_OBJ_P4, M_ALG0_SORT_PARAM_OBJ_P4, M_ALG0_SORT_ARG_OBJ_P4) ) \
M_IF_FUNCOBJ(M_ALG0_DEF_SORT_AUX(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
_sort_fo, M_ALG0_SORT_CALL_OBJ_P4, M_ALG0_SORT_PARAM_OBJ_P4, M_ALG0_SORT_ARG_OBJ_P4) ) \
, /* No IT_REF method */) \
\
M_IF_METHOD(EXT_ALGO, type_oplist)( \
@@ -154,36 +165,36 @@
/* Define the types of the callbacks associated to the algorithms.
* Types remain internal */
#define M_ALG0_CALLBACK_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
#define M_ALG0_DEF_CALLBACK(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
typedef bool (*M_C(name, _test_cb_ct))(type_t const); \
typedef bool (*M_C(name, _eq_cb_ct))(type_t const, type_t const); \
typedef int (*M_C(name, _cmp_cb_ct))(type_t const, type_t const); \
typedef void (*M_C(name, _transform_cb_ct))(type_t *, type_t const); \
typedef void (*M_C(name, _apply_cb_ct))(type_t); \
typedef bool (*M_F(name, _test_cb_ct))(type_t const); \
typedef bool (*M_F(name, _eq_cb_ct))(type_t const, type_t const); \
typedef int (*M_F(name, _cmp_cb_ct))(type_t const, type_t const); \
typedef void (*M_F(name, _transform_cb_ct))(type_t *, type_t const); \
typedef void (*M_F(name, _apply_cb_ct))(type_t); \
/* Define the function objects associated to the algorithms.
* Created Function objects are part of the public interface */
#define M_ALG0_FUNCOBJ_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
#define M_ALG0_DEF_FUNCOBJ(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
FUNC_OBJ_ITF_DEF(M_C(name, _test_obj), bool, type_t const) \
FUNC_OBJ_ITF_DEF(M_C(name, _eq_obj), bool, type_t const, type_t const ) \
FUNC_OBJ_ITF_DEF(M_C(name, _cmp_obj), int, type_t const, type_t const ) \
FUNC_OBJ_ITF_DEF(M_C(name, _transform_obj), void, type_t *, type_t const ) \
FUNC_OBJ_ITF_DEF(M_C(name, _apply_obj), void, type_t * ) \
FUNC_OBJ_ITF_DEF(M_F(name, _test_obj), bool, type_t const) \
FUNC_OBJ_ITF_DEF(M_F(name, _eq_obj), bool, type_t const, type_t const ) \
FUNC_OBJ_ITF_DEF(M_F(name, _cmp_obj), int, type_t const, type_t const ) \
FUNC_OBJ_ITF_DEF(M_F(name, _transform_obj), void, type_t *, type_t const ) \
FUNC_OBJ_ITF_DEF(M_F(name, _apply_obj), void, type_t * ) \
/* Define the sort functions with the CMP operator using the order selected */
#define M_ALG0_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, order, sort_name) \
#define M_ALG0_DEF_SORT(name, container_t, cont_oplist, type_t, type_oplist, it_t, order, sort_name) \
\
/* Define the encapsulation function that perform the selected order */ \
static inline int M_C3(name,sort_name,_cmp)(type_t const*a,type_t const*b) \
M_INLINE int M_C3(name,sort_name,_cmp)(type_t const*a,type_t const*b) \
{ \
return order M_CALL_CMP(type_oplist, *a, *b); \
} \
\
M_ALG0_SORT_DEF_P6(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, M_ALG0_SORT_CALL_CMP_P4, M_EAT, /*empty*/ )
M_ALG0_DEF_SORT_AUX(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, M_ALG0_SORT_CALL_CMP_P4, M_EAT, /*empty*/ )
// Call the comparaison function of the type oplist (Using CMP operator)
#define M_ALG0_SORT_CALL_CMP_P4(name, sort_name, ref1, ref2) \
@@ -192,9 +203,9 @@
// Call the created function object
#define M_ALG0_SORT_CALL_OBJ_P4(name, sort_name, ref1, ref2) \
M_C(name, _cmp_obj_call)(funcobj, *ref1, *ref2)
M_F(name, _cmp_obj_call)(funcobj, *ref1, *ref2)
// Adding a parameter named 'funcobj' to the algorithm functions
#define M_ALG0_SORT_PARAM_OBJ_P4(name) M_DEFERRED_COMMA M_C(name, _cmp_obj_t) funcobj
#define M_ALG0_SORT_PARAM_OBJ_P4(name) M_DEFERRED_COMMA M_F(name, _cmp_obj_t) funcobj
#define M_ALG0_SORT_ARG_OBJ_P4 M_DEFERRED_COMMA funcobj
@@ -211,10 +222,10 @@
It is needed to add another argument to the function.
- cmp_arg: Name of such argument.
*/
#define M_ALG0_SORT_DEF_P6(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, cmp_func, cmp_param, cmp_arg) \
#define M_ALG0_DEF_SORT_AUX(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, cmp_func, cmp_param, cmp_arg) \
\
/* Test if the container is sorted */ \
static inline bool \
M_INLINE bool \
M_C3(name,sort_name,_p)(const container_t l cmp_param(name)) \
{ \
it_t it1; \
@@ -242,7 +253,7 @@
/* - a selection sort */ \
M_IF(M_AND(M_TEST_METHOD_P(SORT, cont_oplist), M_EMPTY_P(cmp_arg)))( \
/******** OPTIMIZED SORT FOR CONTAINER *********/ \
static inline void M_C(name,sort_name)(container_t l) \
M_INLINE void M_F(name,sort_name)(container_t l) \
{ \
M_CALL_SORT(cont_oplist, l, M_C3(name, sort_name,_cmp)); \
} \
@@ -254,7 +265,7 @@
\
/* Split the container 'l' into near even size l1 and l2 * \
using odd/even splitting */ \
static inline void \
M_INLINE void \
M_C3(name,sort_name,_split)(container_t l1, container_t l2, container_t l) \
{ \
it_t it; \
@@ -269,7 +280,7 @@
} \
\
/* Merge in empty 'l' the sorted container 'l1' and 'l2' */ \
static inline void \
M_INLINE void \
M_C3(name,sort_name,_merge)(container_t l, container_t l1, container_t l2 cmp_param(name)) \
{ \
/* M_ASSERT(M_CALL_EMPTY_P (cont_oplist, l)); */ \
@@ -309,8 +320,8 @@
} \
\
/* Sort the container 'l' */ \
static inline void \
M_C(name,sort_name)(container_t l cmp_param(name)) \
M_INLINE void \
M_F(name,sort_name)(container_t l cmp_param(name)) \
{ \
container_t l1; \
container_t l2; \
@@ -342,8 +353,8 @@
M_CALL_INIT(cont_oplist, l1); \
M_CALL_INIT(cont_oplist, l2); \
M_C3(name,sort_name,_split)(l1, l2, l); \
M_C(name,sort_name)(l1 cmp_arg); \
M_C(name,sort_name)(l2 cmp_arg); \
M_F(name,sort_name)(l1 cmp_arg); \
M_F(name,sort_name)(l2 cmp_arg); \
M_C3(name,sort_name,_merge)(l, l1, l2 cmp_arg); \
/* l1 & l2 shall be empty now */ \
M_CALL_CLEAR(cont_oplist, l2); \
@@ -352,7 +363,7 @@
, \
M_IF_METHOD(IT_PREVIOUS, cont_oplist)( \
/******** GENERIC INSERTION SORT *********/ \
static inline void M_C(name,sort_name)(container_t l cmp_param(name)) \
M_INLINE void M_F(name,sort_name)(container_t l cmp_param(name)) \
{ \
it_t it1; \
it_t it2; \
@@ -389,7 +400,7 @@
\
, \
/********** GENERIC SELECTION SORT ************/ \
static inline void M_C(name,sort_name)(container_t l cmp_param(name)) \
M_INLINE void M_F(name,sort_name)(container_t l cmp_param(name)) \
{ \
it_t it1; \
it_t it2; \
@@ -422,7 +433,7 @@
) /* IF SORT METHOD */ \
/* Compute the union of two ***sorted*** containers */ \
M_IF_METHOD(IT_INSERT, cont_oplist)( \
static inline void \
M_INLINE void \
M_C3(name,sort_name,_union)(container_t dst, const container_t src cmp_param(name)) \
{ \
it_t itSrc; \
@@ -467,7 +478,7 @@
\
/* Compute the intersection of two ***sorted*** containers */ \
M_IF_METHOD(IT_REMOVE, cont_oplist)( \
static inline void \
M_INLINE void \
M_C3(name,sort_name,_intersect)(container_t dst, const container_t src cmp_param(name)) \
{ \
it_t itSrc; \
@@ -503,11 +514,11 @@
TODO: Define _find_sorted that find in a sorted random access container
(binary search)
*/
#define M_ALG0_FIND_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
#define M_ALG0_DEF_FIND(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
/* It supposes that the container is not sorted */ \
/* Find the next occurence from it (included) of data */ \
static inline void \
M_C(name, _find_again) (it_t it, type_t const data) \
/* Find the next occurrence from it (included) of data */ \
M_INLINE void \
M_F(name, _find_again) (it_t it, type_t const data) \
{ \
for ( /*nothing*/ ; !M_CALL_IT_END_P(cont_oplist, it) ; \
M_CALL_IT_NEXT(cont_oplist, it)) { \
@@ -516,30 +527,30 @@
} \
} \
\
/* Find the first occurence of data */ \
static inline void \
M_C(name, _find) (it_t it, container_t const l, type_t const data) \
/* Find the first occurrence of data */ \
M_INLINE void \
M_F(name, _find) (it_t it, container_t const l, type_t const data) \
{ \
M_CALL_IT_FIRST(cont_oplist, it, l); \
M_C(name, _find_again)(it, data); \
M_F(name, _find_again)(it, data); \
} \
\
/* Test if data is within the container */ \
static inline bool \
M_C(name, _contain_p) (container_t const l, type_t const data) \
M_INLINE bool \
M_F(name, _contain_p) (container_t const l, type_t const data) \
{ \
it_t it; \
M_C(name,_find)(it, l, data); \
M_F(name,_find)(it, l, data); \
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) \
( \
static inline void \
M_C(name, _find_last) (it_t it, container_t const l, type_t const data) \
M_INLINE void \
M_F(name, _find_last) (it_t it, container_t const l, type_t const data) \
{ \
for (M_CALL_IT_LAST(cont_oplist, it, l); \
!M_CALL_IT_END_P(cont_oplist, it) ; \
@@ -550,9 +561,9 @@
} \
} \
, \
/* Otherwise search forward, but don't stop on the first occurence */ \
static inline void \
M_C(name, _find_last) (it_t it, container_t const l, type_t const data) \
/* Otherwise search forward, but don't stop on the first occurrence */ \
M_INLINE void \
M_F(name, _find_last) (it_t it, container_t const l, type_t const data) \
{ \
M_CALL_IT_END(cont_oplist, it, l); \
it_t it2; \
@@ -566,9 +577,9 @@
} \
) /* End of alternative of _find_last */ \
\
/* Count the number of occurence of data in the container */ \
static inline size_t \
M_C(name, _count) (container_t const l, type_t const data) \
/* Count the number of occurrence of data in the container */ \
M_INLINE size_t \
M_F(name, _count) (container_t const l, type_t const data) \
{ \
it_t it; \
size_t count = 0; \
@@ -583,8 +594,8 @@
\
\
/* Find the next mismatch between the containers */ \
static inline void \
M_C(name, _mismatch_again) (it_t it1, it_t it2) \
M_INLINE void \
M_F(name, _mismatch_again) (it_t it1, it_t it2) \
{ \
for (/* nothing */ ; !M_CALL_IT_END_P(cont_oplist, it1) && \
!M_CALL_IT_END_P(cont_oplist, it2); \
@@ -597,12 +608,12 @@
} \
\
/* Find the first mismatch between the containers */ \
static inline void \
M_C(name, _mismatch) (it_t it1, it_t it2, container_t const l1, container_t const l2 ) \
M_INLINE void \
M_F(name, _mismatch) (it_t it1, it_t it2, container_t const l1, container_t const l2 ) \
{ \
M_CALL_IT_FIRST(cont_oplist, it1, l1); \
M_CALL_IT_FIRST(cont_oplist, it2, l2); \
M_C(name, _mismatch_again)(it1, it2); \
M_F(name, _mismatch_again)(it1, it2); \
} \
@@ -611,10 +622,10 @@
TODO: Define _find_sorted that find in a sorted random access container
(binary search)
*/
#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) \
#define M_ALG0_DEF_FIND_IF(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, test_t, eq_t, call_test, call_eq) \
\
/* Find the next occurence that matches the condition */ \
static inline void \
/* Find the next occurrence that matches the condition */ \
M_INLINE void \
M_C3(name, _find_again_, suffix) (it_t it, test_t func) \
{ \
for (/*nothing */ ; !M_CALL_IT_END_P(cont_oplist, it) ; \
@@ -624,16 +635,16 @@
} \
} \
\
/* Find the first occurence that matches the condition */ \
static inline void \
/* Find the first occurrence that matches the condition */ \
M_INLINE void \
M_C3(name, _find_, suffix) (it_t it, container_t l, test_t func) \
{ \
M_CALL_IT_FIRST(cont_oplist, it, l); \
M_C3(name, _find_again_, suffix)(it, func); \
} \
\
/* Count the number of occurence that matches the condition */ \
static inline size_t \
/* Count the number of occurrence that matches the condition */ \
M_INLINE size_t \
M_C3(name, _count_, suffix) (container_t const l, test_t func) \
{ \
it_t it; \
@@ -649,7 +660,7 @@
} \
\
/* Find the next mismatch between the containers according to the condition */ \
static inline void \
M_INLINE void \
M_C3(name, _mismatch_again_, suffix) (it_t it1, it_t it2, eq_t func) \
{ \
for (/*nothing */ ; !M_CALL_IT_END_P(cont_oplist, it1) && \
@@ -663,7 +674,7 @@
} \
\
/* Find the first mismatch between the containers according to the condition */ \
static inline void \
M_INLINE void \
M_C3(name, _mismatch_, suffix) (it_t it1, it_t it2, container_t const l1, \
container_t l2, eq_t func) \
{ \
@@ -674,21 +685,21 @@
/* Define the FILL algorithms */
#define M_ALG0_FILL_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
#define M_ALG0_DEF_FILL(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
/* Fill all the container with value (overwritten) */ \
static inline void \
M_C(name, _fill) (container_t l, type_t const value) \
M_INLINE void \
M_F(name, _fill) (container_t l, type_t const value) \
{ \
for M_EACH(item, l, cont_oplist) { \
M_CALL_SET(type_oplist, *item, value); \
} \
} \
\
/* 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) \
M_INLINE void \
M_F(name, _fill_n) (container_t l, size_t n, type_t const value) \
{ \
M_CALL_RESET(cont_oplist, l); \
for(size_t i = 0; i < n; i++) { \
@@ -699,8 +710,8 @@
\
/* Fill the container with FOR('value'; 'value'+'inc') */ \
M_IF_METHOD(ADD, type_oplist)( \
static inline void \
M_C(name, _fill_a) (container_t l, type_t const value, type_t const inc) \
M_INLINE void \
M_F(name, _fill_a) (container_t l, type_t const value, type_t const inc) \
{ \
type_t tmp; \
M_CALL_INIT_SET(type_oplist, tmp, value); \
@@ -713,8 +724,8 @@
\
/* Fill the container with n occurences of FOR('value'; 'value'+'inc') */ \
M_IF_METHOD(PUSH, cont_oplist)( \
static inline void \
M_C(name, _fill_an) (container_t l, size_t n, type_t const value, type_t const inc) \
M_INLINE void \
M_F(name, _fill_an) (container_t l, size_t n, type_t const value, type_t const inc) \
{ \
type_t tmp; \
M_CALL_INIT_SET(type_oplist, tmp, value); \
@@ -730,11 +741,11 @@
/* Define MAP algorithms */
#define M_ALG0_MAP_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
#define M_ALG0_DEF_MAP(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
/* Apply func for all elements of the container */ \
static inline void \
M_C(name, _for_each) (container_t l, M_C(name, _apply_cb_ct) func) \
M_INLINE void \
M_F(name, _for_each) (container_t l, M_F(name, _apply_cb_ct) func) \
{ \
for M_EACH(item, l, cont_oplist) { \
func(*item); \
@@ -745,10 +756,10 @@
M_IF_METHOD(PUSH_MOVE, cont_oplist)( \
\
/* Apply func for all elements of the container src and push the result in dst */ \
static inline void \
M_C(name, _transform) (container_t dst, \
M_INLINE void \
M_F(name, _transform) (container_t dst, \
container_t src, \
M_C(name, _transform_cb_ct) func) \
M_F(name, _transform_cb_ct) func) \
{ \
M_ASSERT(dst != src); \
M_CALL_RESET(cont_oplist, dst); \
@@ -764,9 +775,9 @@
\
/* Reduce all elements of the container in dst in function of func */ \
M_IF_METHOD(SET, type_oplist)( \
static inline void \
M_C(name, _reduce) (type_t *dest, container_t const l, \
M_C(name, _transform_cb_ct) func) \
M_INLINE void \
M_F(name, _reduce) (type_t *dest, container_t const l, \
M_F(name, _transform_cb_ct) func) \
{ \
bool initDone = false; \
for M_EACH(item, l, cont_oplist) { \
@@ -782,11 +793,11 @@
\
/* Reduce all transformed elements of the container in dst in function of func */ \
M_IF_METHOD(INIT, type_oplist)( \
static inline \
void M_C(name, _map_reduce) (type_t *dest, \
M_INLINE \
void M_F(name, _map_reduce) (type_t *dest, \
const container_t l, \
M_C(name, _transform_cb_ct) redFunc, \
M_C(name, _transform_cb_ct) mapFunc) \
M_F(name, _transform_cb_ct) redFunc, \
M_F(name, _transform_cb_ct) mapFunc) \
{ \
bool initDone = false; \
type_t tmp; \
@@ -806,9 +817,9 @@
/* Define ALL_OF algorithms */
#define M_ALG0_ALL_OF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, func_t, call) \
#define M_ALG0_DEF_ALL_OF(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, func_t, call) \
\
static inline bool \
M_INLINE bool \
M_C4(name, _any_of, suffix, p) (container_t const l, \
func_t func ) \
{ \
@@ -819,7 +830,7 @@
return false; \
} \
\
static inline bool \
M_INLINE bool \
M_C4(name, _all_of, suffix, p) (container_t const l, \
func_t func ) \
{ \
@@ -830,7 +841,7 @@
return true; \
} \
\
static inline bool \
M_INLINE bool \
M_C4(name, _none_of, suffix, p) (container_t l, \
func_t func ) \
{ \
@@ -843,10 +854,10 @@
/* Define MIN / MAX algorithms */
#define M_ALG0_MINMAX_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
#define M_ALG0_DEF_MINMAX(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
static inline type_t * \
M_C(name, _min) (const container_t l) \
M_INLINE type_t * \
M_F(name, _min) (const container_t l) \
{ \
type_t *min = NULL; \
for M_EACH(cref, l, cont_oplist) { \
@@ -858,8 +869,8 @@
return min; \
} \
\
static inline type_t * \
M_C(name, _max) (const container_t l) \
M_INLINE type_t * \
M_F(name, _max) (const container_t l) \
{ \
type_t *max = NULL; \
for M_EACH(cref, l, cont_oplist) { \
@@ -871,8 +882,8 @@
return max; \
} \
\
static inline void \
M_C(name, _minmax) (type_t **min_p, type_t **max_p, \
M_INLINE void \
M_F(name, _minmax) (type_t **min_p, type_t **max_p, \
const container_t l) \
{ \
type_t *min = NULL; \
@@ -891,15 +902,15 @@
*max_p = max; \
} \
#define M_ALG0_REMOVE_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
/* Define functions based on remove method */
#define M_ALG0_DEF_REMOVE(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
static inline void \
M_C(name, _uniq)(container_t l) \
M_INLINE void \
M_F(name, _uniq)(container_t l) \
{ \
it_t it1; \
it_t it2; \
M_ASSERT(M_C(name, _sort_p)(l)); \
M_ASSERT(M_F(name, _sort_p)(l)); \
M_CALL_IT_FIRST(cont_oplist, it1, l); \
M_CALL_IT_SET(cont_oplist, it2, it1); \
M_CALL_IT_NEXT(cont_oplist, it2); \
@@ -916,8 +927,8 @@
} \
} \
\
static inline void \
M_C(name, _remove_val)(container_t l, type_t const val) \
M_INLINE void \
M_F(name, _remove_val)(container_t l, type_t const val) \
{ \
it_t it1; \
M_CALL_IT_FIRST(cont_oplist, it1, l); \
@@ -931,8 +942,8 @@
} \
} \
\
static inline void \
M_C(name, _remove_if)(container_t l, M_C(name, _test_cb_ct) func) \
M_INLINE void \
M_F(name, _remove_if)(container_t l, M_F(name, _test_cb_ct) func) \
{ \
it_t it1; \
M_CALL_IT_FIRST(cont_oplist, it1, l); \
@@ -946,11 +957,11 @@
} \
} \
#define M_ALG0_VECTOR_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
/* Define vector algorithms */
#define M_ALG0_DEF_VECTOR(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
M_IF_METHOD(ADD, type_oplist)( \
static inline void M_C(name, _add) (container_t dst, const container_t src) \
M_INLINE void M_F(name, _add) (container_t dst, const container_t src) \
{ \
it_t itSrc; \
it_t itDst; \
@@ -961,14 +972,14 @@
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); \
} \
} \
, /* NO_ADD METHOD */ ) \
\
M_IF_METHOD(SUB, type_oplist)( \
static inline void M_C(name, _sub) (container_t dst, const container_t src) \
M_INLINE void M_F(name, _sub) (container_t dst, const container_t src) \
{ \
it_t itSrc; \
it_t itDst; \
@@ -979,14 +990,14 @@
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); \
} \
} \
, /* NO_SUB METHOD */ ) \
\
M_IF_METHOD(MUL, type_oplist)( \
static inline void M_C(name, _mul) (container_t dst, const container_t src) \
M_INLINE void M_F(name, _mul) (container_t dst, const container_t src) \
{ \
it_t itSrc; \
it_t itDst; \
@@ -997,14 +1008,14 @@
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); \
} \
} \
, /* NO_MUL METHOD */ ) \
\
M_IF_METHOD(DIV, type_oplist)( \
static inline void M_C(name, _div) (container_t dst, const container_t src) \
M_INLINE void M_F(name, _div) (container_t dst, const container_t src) \
{ \
it_t itSrc; \
it_t itDst; \
@@ -1015,7 +1026,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); \
} \
} \
@@ -1030,6 +1041,7 @@
// fast _uniq for array
// _flatten (takes a set of containers and returns a new container containing all flatten objects)
/******************************** INTERNAL ***********************************/
#define M_ALG0_FOR_EACH(container, cont_oplist, func) do { \
for M_EACH(_item, container, cont_oplist) { \
@@ -1044,6 +1056,8 @@
} while (0)
/******************************** INTERNAL ***********************************/
#define M_ALG0_TRANSFORM(contD, contDop, contS, contSop, func) do { \
M_CALL_RESET(contDop, contD); \
for M_EACH(_item, contS, contSop) { \
@@ -1067,8 +1081,11 @@
} while (0)
#define M_ALG0_EXTRACT(contDst, contDstOplist, \
contSrc, contSrcOplist) do { \
/******************************** INTERNAL ***********************************/
#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 +1097,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 +1114,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) { \
@@ -1113,6 +1134,8 @@
} while (0)
/******************************** INTERNAL ***********************************/
#define M_ALG0_REDUCE_DISPATCH(dest, destOp, dest_t, cont, contOp, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(M_ALG0_REDUCE_BASIC(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
@@ -1188,6 +1211,8 @@
} while (0)
/******************************** INTERNAL ***********************************/
#define M_ALG0_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) do { \
M_GET_IT_TYPE contSrcOp _itSrc; \
M_GET_IT_TYPE contDstOp _itDst; \
@@ -1200,4 +1225,16 @@
} \
} while (0)
/******************************** INTERNAL ***********************************/
#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
+394 -371
View File
File diff suppressed because it is too large. Load diff
+10 -3
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Thin stdatomic wrapper for C++ compatibility
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -154,7 +154,7 @@ using std::memory_order_seq_cst;
*/
#else
#include "m-mutex.h"
#include "m-thread.h"
#include "m-core.h"
M_BEGIN_PROTECTED_CODE
@@ -226,7 +226,7 @@ typedef _Atomic(uintmax_t) atomic_uintmax_t;
#endif
/* (INTERNAL) Unlock the mutex and return the given value */
static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
M_INLINE long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
{
m_mutex_unlock (*lock);
return val;
@@ -332,4 +332,11 @@ M_END_PROTECTED_CODE
#endif
// C17 deprecated ATOMIC_VAR_INIT
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201710L
# define M_ATOMIC_VAR_INIT(x) (x)
#else
# define M_ATOMIC_VAR_INIT(x) ATOMIC_VAR_INIT(x)
#endif
#endif
+306 -219
View File
File diff suppressed because it is too large. Load diff
+416 -399
View File
File diff suppressed because it is too large. Load diff
+305 -241
View File
File diff suppressed because it is too large. Load diff
+177 -173
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Concurrent memory pool allocator
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -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) \
@@ -46,55 +46,55 @@ M_BEGIN_PROTECTED_CODE
/* Classic internal Singly List without allocation */
#define M_CMEMP00L_DEF_SINGLY_LIST(name, type_t) \
\
typedef struct M_C(name, _slist_node_s) { \
struct M_C(name, _slist_node_s) *next; \
typedef struct M_F(name, _slist_node_s) { \
struct M_F(name, _slist_node_s) *next; \
type_t data; \
} M_C(name, _slist_node_ct); \
} M_F(name, _slist_node_ct); \
\
typedef struct M_C(name, _slist_node_s) *M_C(name, _slist_ct)[1]; \
typedef struct M_F(name, _slist_node_s) *M_F(name, _slist_ct)[1]; \
\
static inline void \
M_C(name, _slist_init)(M_C(name, _slist_ct) list) \
M_INLINE void \
M_F(name, _slist_init)(M_F(name, _slist_ct) list) \
{ \
*list = NULL; \
} \
\
static inline void \
M_C(name, _slist_push)(M_C(name, _slist_ct) list, \
M_C(name, _slist_node_ct) *node) \
M_INLINE void \
M_F(name, _slist_push)(M_F(name, _slist_ct) list, \
M_F(name, _slist_node_ct) *node) \
{ \
node->next = *list; \
*list = node; \
} \
\
static inline M_C(name, _slist_node_ct) * \
M_C(name, _slist_pop)(M_C(name, _slist_ct) list) \
M_INLINE M_F(name, _slist_node_ct) * \
M_F(name, _slist_pop)(M_F(name, _slist_ct) list) \
{ \
M_ASSERT (*list != NULL); \
M_C(name, _slist_node_ct) *node = *list; \
M_F(name, _slist_node_ct) *node = *list; \
*list = node->next; \
M_IF_DEBUG(node->next = NULL;) \
return node; \
} \
\
static inline bool \
M_C(name, _slist_empty_p)(M_C(name, _slist_ct) list) \
M_INLINE bool \
M_F(name, _slist_empty_p)(M_F(name, _slist_ct) list) \
{ \
return *list == NULL; \
} \
\
static inline void \
M_C(name, _slist_move)(M_C(name, _slist_ct) list, \
M_C(name, _slist_ct) src) \
M_INLINE void \
M_F(name, _slist_move)(M_F(name, _slist_ct) list, \
M_F(name, _slist_ct) src) \
{ \
*list = *src; \
*src = NULL; \
} \
\
static inline void \
M_C(name, _slist_clear)(M_C(name, _slist_ct) list) \
M_INLINE void \
M_F(name, _slist_clear)(M_F(name, _slist_ct) list) \
{ \
M_C(name, _slist_node_ct) *it = *list, *next; \
M_F(name, _slist_node_ct) *it = *list, *next; \
while (it) { \
next = it->next; \
M_MEMORY_DEL(it); \
@@ -125,41 +125,41 @@ M_BEGIN_PROTECTED_CODE
to reduce memory consumption too (non compatible with C++ ...) */
#define M_CMEMP00L_DEF_LF_QUEUE(name, type_t) \
\
typedef struct M_C(name, _lf_node_s) { \
M_ATTR_EXTENSION _Atomic(struct M_C(name, _lf_node_s) *) next; \
typedef struct M_F(name, _lf_node_s) { \
M_ATTR_EXTENSION _Atomic(struct M_F(name, _lf_node_s) *) next; \
m_gc_atomic_ticket_ct cpt; \
M_C(name, _slist_ct) list; \
} M_C(name, _lf_node_t); \
M_F(name, _slist_ct) list; \
} M_F(name, _lf_node_t); \
\
typedef struct M_C(name, _lflist_s) { \
M_ATTR_EXTENSION _Atomic(M_C(name, _lf_node_t) *) head; \
typedef struct M_F(name, _lflist_s) { \
M_ATTR_EXTENSION _Atomic(M_F(name, _lf_node_t) *) head; \
char align1[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
M_ATTR_EXTENSION _Atomic(M_C(name, _lf_node_t) *) tail; \
M_ATTR_EXTENSION _Atomic(M_F(name, _lf_node_t) *) tail; \
char align2[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
M_C(name, _lf_node_t) nil; \
} M_C(name, _lflist_ct)[1]; \
M_F(name, _lf_node_t) nil; \
} M_F(name, _lflist_ct)[1]; \
\
static inline void \
M_C(name, _lflist_init)(M_C(name, _lflist_ct) list, \
M_C(name, _lf_node_t) *node) \
M_INLINE void \
M_F(name, _lflist_init)(M_F(name, _lflist_ct) list, \
M_F(name, _lf_node_t) *node) \
{ \
atomic_init(&list->head, node); \
atomic_init(&list->tail, node); \
atomic_store_explicit(&node->next, &list->nil, memory_order_relaxed); \
} \
\
static inline bool \
M_C(name, _lflist_empty_p)(M_C(name, _lflist_ct) list) \
M_INLINE bool \
M_F(name, _lflist_empty_p)(M_F(name, _lflist_ct) list) \
{ \
return atomic_load(&list->tail) == atomic_load(&list->head); \
} \
\
static inline void \
M_C(name, _lflist_push)(M_C(name, _lflist_ct) list, \
M_C(name, _lf_node_t) *node, m_core_backoff_ct bkoff) \
M_INLINE void \
M_F(name, _lflist_push)(M_F(name, _lflist_ct) list, \
M_F(name, _lf_node_t) *node, m_core_backoff_ct bkoff) \
{ \
M_C(name, _lf_node_t) *tail; \
M_C(name, _lf_node_t) *next; \
M_F(name, _lf_node_t) *tail; \
M_F(name, _lf_node_t) *next; \
\
atomic_store_explicit(&node->next, &list->nil, memory_order_relaxed); \
m_core_backoff_reset(bkoff); \
@@ -190,12 +190,12 @@ M_BEGIN_PROTECTED_CODE
memory_order_relaxed); \
} \
\
static inline M_C(name, _lf_node_t) * \
M_C(name, _lflist_pop)(M_C(name, _lflist_ct) list, m_core_backoff_ct bkoff) \
M_INLINE M_F(name, _lf_node_t) * \
M_F(name, _lflist_pop)(M_F(name, _lflist_ct) list, m_core_backoff_ct bkoff) \
{ \
M_C(name, _lf_node_t) *head; \
M_C(name, _lf_node_t) *tail; \
M_C(name, _lf_node_t) *next; \
M_F(name, _lf_node_t) *head; \
M_F(name, _lf_node_t) *tail; \
M_F(name, _lf_node_t) *next; \
\
/* Reinitialize backoff */ \
m_core_backoff_reset(bkoff); \
@@ -236,18 +236,18 @@ M_BEGIN_PROTECTED_CODE
provided that the node we return is older than the one we should return, \
Therefore, we return the previous dummy head. \
As such, it is not the original MSqueue algorithm. */ \
M_IF_DEBUG(atomic_store(&head->next, (M_C(name, _lf_node_t) *) 0);) \
M_IF_DEBUG(atomic_store(&head->next, (M_F(name, _lf_node_t) *) 0);) \
return head; \
} \
\
/* Dequeue a node if the node is old enough */ \
static inline M_C(name, _lf_node_t) * \
M_C(name, _lflist_pop_if)(M_C(name, _lflist_ct) list, \
M_INLINE M_F(name, _lf_node_t) * \
M_F(name, _lflist_pop_if)(M_F(name, _lflist_ct) list, \
m_gc_ticket_ct age, m_core_backoff_ct bkoff) \
{ \
M_C(name, _lf_node_t) *head; \
M_C(name, _lf_node_t) *tail; \
M_C(name, _lf_node_t) *next; \
M_F(name, _lf_node_t) *head; \
M_F(name, _lf_node_t) *tail; \
M_F(name, _lf_node_t) *next; \
\
m_core_backoff_reset(bkoff); \
while (true) { \
@@ -277,28 +277,28 @@ M_BEGIN_PROTECTED_CODE
} \
} \
} \
M_IF_DEBUG(atomic_store(&head->next, (M_C(name, _lf_node_t) *) 0);) \
M_IF_DEBUG(atomic_store(&head->next, (M_F(name, _lf_node_t) *) 0);) \
return head; \
} \
\
static inline void \
M_C(name, _lflist_clear)(M_C(name, _lflist_ct) list) \
M_INLINE void \
M_F(name, _lflist_clear)(M_F(name, _lflist_ct) list) \
{ \
m_core_backoff_ct bkoff; \
m_core_backoff_init(bkoff); \
while (true) { \
M_C(name, _lf_node_t) *node = M_C(name, _lflist_pop)(list, bkoff); \
M_F(name, _lf_node_t) *node = M_F(name, _lflist_pop)(list, bkoff); \
if (node == NULL) break; \
M_C(name, _lf_node_t) *next = atomic_load_explicit(&node->next, \
M_F(name, _lf_node_t) *next = atomic_load_explicit(&node->next, \
memory_order_relaxed); \
M_C(name, _slist_clear)(node->list); \
M_F(name, _slist_clear)(node->list); \
M_MEMORY_DEL(node); \
node = next; \
} \
/* Dummy node to free too */ \
M_C(name, _lf_node_t) *dummy; \
M_F(name, _lf_node_t) *dummy; \
dummy = atomic_load_explicit(&list->head, memory_order_relaxed); \
M_C(name, _slist_clear)(dummy->list); \
M_F(name, _slist_clear)(dummy->list); \
M_MEMORY_DEL(dummy); \
} \
@@ -306,26 +306,26 @@ M_BEGIN_PROTECTED_CODE
As such it is a non Lock-Free path. */
#define M_CMEMP00L_DEF_SYSTEM_ALLOC(name, type_t) \
\
static inline M_C(name, _lf_node_t) * \
M_C(name, _alloc_node)(unsigned int initial) \
M_INLINE M_F(name, _lf_node_t) * \
M_F(name, _alloc_node)(unsigned int initial) \
{ \
M_C(name, _lf_node_t) * node; \
node = M_MEMORY_ALLOC(M_C(name, _lf_node_t)); \
if (M_UNLIKELY(node == NULL)) { \
M_MEMORY_FULL(sizeof(M_C(name, _lf_node_t))); \
M_F(name, _lf_node_t) * node; \
node = M_MEMORY_ALLOC(M_F(name, _lf_node_t)); \
if (M_UNLIKELY_NOMEM (node == NULL)) { \
M_MEMORY_FULL(sizeof(M_F(name, _lf_node_t))); \
return NULL; \
} \
atomic_init(&node->next, (M_C(name, _lf_node_t) *) 0); \
atomic_init(&node->next, (M_F(name, _lf_node_t) *) 0); \
atomic_init(&node->cpt, 0UL); \
M_C(name, _slist_init)(node->list); \
M_F(name, _slist_init)(node->list); \
for(unsigned i = 0; i < initial; i++) { \
M_C(name, _slist_node_ct) *n; \
n = M_MEMORY_ALLOC(M_C(name, _slist_node_ct)); \
if (M_UNLIKELY(n == NULL)) { \
M_MEMORY_FULL(sizeof(M_C(name, _lf_node_t))); \
M_F(name, _slist_node_ct) *n; \
n = M_MEMORY_ALLOC(M_F(name, _slist_node_ct)); \
if (M_UNLIKELY_NOMEM (n == NULL)) { \
M_MEMORY_FULL(sizeof(M_F(name, _lf_node_t))); \
return NULL; \
} \
M_C(name, _slist_push)(node->list, n); \
M_F(name, _slist_push)(node->list, n); \
} \
return node; \
} \
@@ -388,99 +388,99 @@ M_BEGIN_PROTECTED_CODE
*/
#define M_CMEMP00L_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
\
typedef struct M_C(name, _lfmp_thread_s) { \
M_C(name, _slist_ct) free; \
M_C(name, _slist_ct) to_be_reclaimed; \
M_CACHELINE_ALIGN(align1, M_C(name, _slist_ct), M_C(name, _slist_ct)); \
} M_C(name, _lfmp_thread_ct); \
typedef struct M_F(name, _lfmp_thread_s) { \
M_F(name, _slist_ct) free; \
M_F(name, _slist_ct) to_be_reclaimed; \
M_CACHELINE_ALIGN(align1, M_F(name, _slist_ct), M_F(name, _slist_ct)); \
} M_F(name, _lfmp_thread_ct); \
\
static inline void \
M_C(name, _lfmp_thread_init)(M_C(name, _lfmp_thread_ct) *t) \
M_INLINE void \
M_F(name, _lfmp_thread_init)(M_F(name, _lfmp_thread_ct) *t) \
{ \
M_C(name, _slist_init)(t->free); \
M_C(name, _slist_init)(t->to_be_reclaimed); \
M_F(name, _slist_init)(t->free); \
M_F(name, _slist_init)(t->to_be_reclaimed); \
} \
\
static inline void \
M_C(name, _lfmp_thread_clear)(M_C(name, _lfmp_thread_ct) *t) \
M_INLINE void \
M_F(name, _lfmp_thread_clear)(M_F(name, _lfmp_thread_ct) *t) \
{ \
M_ASSERT(M_C(name, _slist_empty_p)(t->to_be_reclaimed)); \
M_C(name, _slist_clear)(t->free); \
M_C(name, _slist_clear)(t->to_be_reclaimed); \
M_ASSERT(M_F(name, _slist_empty_p)(t->to_be_reclaimed)); \
M_F(name, _slist_clear)(t->free); \
M_F(name, _slist_clear)(t->to_be_reclaimed); \
} \
/* NOTE: once a node is deleted, its data are kept readable until the future GC */
#define M_CMEMP00L_DEF_LF_MEMPOOL(name, type_t) \
\
typedef struct M_C(name, _s) { \
typedef struct M_F(name, _s) { \
unsigned initial; \
M_C(name, _lfmp_thread_ct) *thread_data; \
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_F(name, _lfmp_thread_ct) *thread_data; \
M_F(name, _lflist_ct) free; \
M_F(name, _lflist_ct) to_be_reclaimed; \
M_F(name, _lflist_ct) empty; \
m_cmemp00l_list_ct mempool_node; \
struct m_gc_s *gc_mem; \
} M_C(name, _t)[1]; \
} M_F(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_INLINE void \
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); \
struct M_F(name, _s) *mempool = \
M_TYPE_FROM_FIELD(struct M_F(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)) { \
M_C(name, _lf_node_t) *node; \
if (!M_F(name, _slist_empty_p)(mempool->thread_data[id].to_be_reclaimed)) { \
M_F(name, _lf_node_t) *node; \
/* Get a new empty group of nodes */ \
node = M_C(name, _lflist_pop)(mempool->empty, gc_mem->thread_data[id].bkoff); \
node = M_F(name, _lflist_pop)(mempool->empty, gc_mem->thread_data[id].bkoff); \
if (M_UNLIKELY (node == NULL)) { \
/* Fail to get an empty group of node. \
Alloc a new one from the system */ \
node = M_C(name, _alloc_node)(0); \
node = M_F(name, _alloc_node)(0); \
M_ASSERT(node != NULL); \
} \
M_ASSERT(M_C(name, _slist_empty_p)(node->list)); \
M_C(name, _slist_move)(node->list, mempool->thread_data[id].to_be_reclaimed); \
M_ASSERT(M_F(name, _slist_empty_p)(node->list)); \
M_F(name, _slist_move)(node->list, mempool->thread_data[id].to_be_reclaimed); \
atomic_store_explicit(&node->cpt, ticket, memory_order_relaxed); \
M_C(name, _lflist_push)(mempool->to_be_reclaimed, node, gc_mem->thread_data[id].bkoff); \
M_F(name, _lflist_push)(mempool->to_be_reclaimed, node, gc_mem->thread_data[id].bkoff); \
} \
\
/* Perform a GC of the freelist of nodes */ \
while (true) { \
M_C(name, _lf_node_t) *node; \
node = M_C(name, _lflist_pop_if)(mempool->to_be_reclaimed, \
M_F(name, _lf_node_t) *node; \
node = M_F(name, _lflist_pop_if)(mempool->to_be_reclaimed, \
min_ticket, gc_mem->thread_data[id].bkoff); \
if (node == NULL) break; \
M_C(name, _lflist_push)(mempool->free, node, gc_mem->thread_data[id].bkoff); \
M_F(name, _lflist_push)(mempool->free, node, gc_mem->thread_data[id].bkoff); \
} \
} \
\
static inline void \
M_C(name, _init)(M_C(name, _t) mem, m_gc_t gc_mem, \
M_INLINE void \
M_F(name, _init)(M_F(name, _t) mem, m_gc_t gc_mem, \
unsigned init_node_count, unsigned init_group_count) \
{ \
const size_t max_thread = gc_mem->max_thread; \
/* Initialize the thread data of the mempool */ \
mem->thread_data = M_MEMORY_REALLOC(M_C(name, _lfmp_thread_ct), NULL, max_thread); \
if (mem->thread_data == NULL) { \
M_MEMORY_FULL(max_thread * sizeof(M_C(name, _lfmp_thread_ct))); \
mem->thread_data = M_MEMORY_REALLOC(M_F(name, _lfmp_thread_ct), NULL, max_thread); \
if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) { \
M_MEMORY_FULL(max_thread * sizeof(M_F(name, _lfmp_thread_ct))); \
return; \
} \
for(unsigned i = 0; i < max_thread;i++) { \
M_C(name, _lfmp_thread_init)(&mem->thread_data[i]); \
M_F(name, _lfmp_thread_init)(&mem->thread_data[i]); \
} \
/* Preallocate some group of nodes for the mempool */ \
mem->initial = M_MAX(M_CMEMP00L_MIN_NODE_PER_GROUP, init_node_count); \
M_C(name, _lflist_init)(mem->free, M_C(name, _alloc_node)(init_node_count)); \
M_C(name, _lflist_init)(mem->to_be_reclaimed, M_C(name, _alloc_node)(init_node_count)); \
M_C(name, _lflist_init)(mem->empty, M_C(name, _alloc_node)(0)); \
M_F(name, _lflist_init)(mem->free, M_F(name, _alloc_node)(init_node_count)); \
M_F(name, _lflist_init)(mem->to_be_reclaimed, M_F(name, _alloc_node)(init_node_count)); \
M_F(name, _lflist_init)(mem->empty, M_F(name, _alloc_node)(0)); \
for(unsigned i = 1; i < init_group_count; i++) { \
M_C(name, _lflist_push)(mem->free, M_C(name, _alloc_node)(init_node_count), \
M_F(name, _lflist_push)(mem->free, M_F(name, _alloc_node)(init_node_count), \
gc_mem->thread_data[0].bkoff); \
M_C(name, _lflist_push)(mem->empty, M_C(name, _alloc_node)(0), \
M_F(name, _lflist_push)(mem->empty, M_F(name, _alloc_node)(0), \
gc_mem->thread_data[0].bkoff); \
} \
/* Register the mempool in the GC */ \
@@ -490,56 +490,56 @@ M_BEGIN_PROTECTED_CODE
mem->gc_mem = gc_mem; \
} \
\
static inline void \
M_C(name, _clear)(M_C(name, _t) mem) \
M_INLINE void \
M_F(name, _clear)(M_F(name, _t) mem) \
{ \
const unsigned max_thread = mem->gc_mem->max_thread; \
for(unsigned i = 0; i < max_thread;i++) { \
M_C(name, _lfmp_thread_clear)(&mem->thread_data[i]); \
M_F(name, _lfmp_thread_clear)(&mem->thread_data[i]); \
} \
M_MEMORY_FREE(mem->thread_data); \
mem->thread_data = NULL; \
M_C(name, _lflist_clear)(mem->empty); \
M_C(name, _lflist_clear)(mem->free); \
M_ASSERT(M_C(name, _lflist_empty_p)(mem->to_be_reclaimed)); \
M_C(name, _lflist_clear)(mem->to_be_reclaimed); \
M_F(name, _lflist_clear)(mem->empty); \
M_F(name, _lflist_clear)(mem->free); \
M_ASSERT(M_F(name, _lflist_empty_p)(mem->to_be_reclaimed)); \
M_F(name, _lflist_clear)(mem->to_be_reclaimed); \
/* TODO: Unregister from the GC? */ \
} \
\
static inline type_t * \
M_C(name, _new)(M_C(name, _t) mem, m_gc_tid_t id) \
M_INLINE type_t * \
M_F(name, _new)(M_F(name, _t) mem, m_gc_tid_t id) \
{ \
M_C(name, _slist_node_ct) *snode; \
M_C(name, _lf_node_t) *node; \
M_F(name, _slist_node_ct) *snode; \
M_F(name, _lf_node_t) *node; \
while (true) { \
/* Fast & likely path where we access the thread pool of nodes */ \
if (M_LIKELY(!M_C(name, _slist_empty_p)(mem->thread_data[id].free))) { \
snode = M_C(name, _slist_pop)(mem->thread_data[id].free); \
if (M_LIKELY(!M_F(name, _slist_empty_p)(mem->thread_data[id].free))) { \
snode = M_F(name, _slist_pop)(mem->thread_data[id].free); \
return &snode->data; \
} \
/* Request a group node to the freelist of groups */ \
node = M_C(name, _lflist_pop)(mem->free, mem->gc_mem->thread_data[id].bkoff); \
node = M_F(name, _lflist_pop)(mem->free, mem->gc_mem->thread_data[id].bkoff); \
if (M_UNLIKELY (node == NULL)) { \
/* Request a new group to the system. Non Lock Free path */ \
M_ASSERT(mem->initial > 0); \
node = M_C(name, _alloc_node)(mem->initial); \
node = M_F(name, _alloc_node)(mem->initial); \
M_ASSERT(node != NULL); \
M_ASSERT(!M_C(name, _slist_empty_p)(node->list)); \
M_ASSERT(!M_F(name, _slist_empty_p)(node->list)); \
} \
M_C(name, _slist_move)(mem->thread_data[id].free, node->list); \
M_F(name, _slist_move)(mem->thread_data[id].free, node->list); \
/* Push back the empty group */ \
M_ASSERT (M_C(name, _slist_empty_p)(node->list)); \
M_C(name, _lflist_push)(mem->empty, node, mem->gc_mem->thread_data[id].bkoff); \
M_ASSERT (M_F(name, _slist_empty_p)(node->list)); \
M_F(name, _lflist_push)(mem->empty, node, mem->gc_mem->thread_data[id].bkoff); \
} \
} \
\
static inline void \
M_C(name, _del)(M_C(name, _t) mem, type_t *d, m_gc_tid_t id) \
M_INLINE void \
M_F(name, _del)(M_F(name, _t) mem, type_t *d, m_gc_tid_t id) \
{ \
M_C(name, _slist_node_ct) *snode; \
M_F(name, _slist_node_ct) *snode; \
M_ASSERT( d != NULL); \
snode = M_TYPE_FROM_FIELD(M_C(name, _slist_node_ct), d, type_t, data); \
M_C(name, _slist_push)(mem->thread_data[id].to_be_reclaimed, snode); \
snode = M_TYPE_FROM_FIELD(M_F(name, _slist_node_ct), d, type_t, data); \
M_F(name, _slist_push)(mem->thread_data[id].to_be_reclaimed, snode); \
} \
@@ -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,21 +574,21 @@ 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
M_INLINE void
m_gc_init(m_gc_t gc_mem, size_t max_thread)
{
M_ASSERT(gc_mem != NULL);
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) {
if (M_UNLIKELY_NOMEM (gc_mem->thread_data == NULL)) {
M_MEMORY_FULL(max_thread * sizeof(m_gc_lfmp_thread_ct));
return;
}
@@ -600,7 +600,7 @@ m_gc_init(m_gc_t gc_mem, size_t max_thread)
gc_mem->mempool_list = NULL;
}
static inline void
M_INLINE void
m_gc_clear(m_gc_t gc_mem)
{
M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0);
@@ -610,29 +610,29 @@ 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
M_INLINE m_gc_tid_t
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);
}
static inline void
M_INLINE void
m_gc_detach_thread(m_gc_t gc_mem, m_gc_tid_t id)
{
M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0);
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
M_INLINE void
m_gc_awake(m_gc_t gc_mem, m_gc_tid_t id)
{
M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0);
@@ -643,7 +643,7 @@ m_gc_awake(m_gc_t gc_mem, m_gc_tid_t id)
atomic_store(&gc_mem->thread_data[id].ticket, t);
}
static inline m_gc_ticket_ct
M_INLINE m_gc_ticket_ct
m_cmemp00l_gc_min_ticket(m_gc_t gc_mem)
{
m_gc_ticket_ct min = atomic_load(&gc_mem->thread_data[0].ticket);
@@ -654,7 +654,7 @@ m_cmemp00l_gc_min_ticket(m_gc_t gc_mem)
return min;
}
static inline void
M_INLINE void
m_gc_sleep(m_gc_t gc_mem, m_gc_tid_t id)
{
/* Increase life time of the thread */
@@ -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 */
@@ -690,13 +690,13 @@ typedef struct m_vlapool_lfmp_thread_s {
M_CACHELINE_ALIGN(align1, m_vlapool_slist_ct);
} m_vlapool_lfmp_thread_ct;
static inline void
M_INLINE void
m_vlapool_lfmp_thread_init(m_vlapool_lfmp_thread_ct *t)
{
m_vlapool_slist_init(t->to_be_reclaimed);
}
static inline void
M_INLINE void
m_vlapool_lfmp_thread_clear(m_vlapool_lfmp_thread_ct *t)
{
M_ASSERT(m_vlapool_slist_empty_p(t->to_be_reclaimed));
@@ -707,18 +707,18 @@ typedef struct m_vlapool_s {
m_vlapool_lflist_ct to_be_reclaimed;
m_vlapool_lflist_ct empty;
m_vlapool_lfmp_thread_ct *thread_data;
m_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_INLINE void
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)) {
@@ -751,14 +751,14 @@ m_cmemp00l_vlapool_on_sleep(m_gc_t gc_mem, m_gM_CMEMP00L_list_ct *data,
}
}
static inline void
M_INLINE void
m_vlapool_init(m_vlapool_t mem, m_gc_t gc_mem)
{
const size_t max_thread = gc_mem->max_thread;
/* Initialize the thread data of the vlapool */
mem->thread_data = M_MEMORY_REALLOC(m_vlapool_lfmp_thread_ct, NULL, max_thread);
if (mem->thread_data == NULL) {
if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) {
M_MEMORY_FULL(max_thread * sizeof(m_vlapool_lfmp_thread_ct));
return;
}
@@ -777,7 +777,7 @@ m_vlapool_init(m_vlapool_t mem, m_gc_t gc_mem)
mem->gc_mem = gc_mem;
}
static inline void
M_INLINE void
m_vlapool_clear(m_vlapool_t mem)
{
const unsigned max_thread = mem->gc_mem->max_thread;
@@ -792,7 +792,7 @@ m_vlapool_clear(m_vlapool_t mem)
/* TODO: Unregister from the GC? */
}
static inline void *
M_INLINE void *
m_vlapool_new(m_vlapool_t mem, m_gc_tid_t id, size_t size)
{
M_ASSERT(mem != NULL && mem->gc_mem != NULL);
@@ -811,7 +811,7 @@ m_vlapool_new(m_vlapool_t mem, m_gc_tid_t id, size_t size)
return (ptr == NULL) ? NULL : M_ASSIGN_CAST(void *, ptr + offsetof(struct m_vlapool_slist_node_s, data));
}
static inline void
M_INLINE void
m_vlapool_del(m_vlapool_t mem, void *d, m_gc_tid_t id)
{
M_ASSERT(mem != NULL && mem->gc_mem != NULL);
@@ -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
+276 -260
View File
File diff suppressed because it is too large. Load diff
+1818 -511
View File
File diff suppressed because it is too large. Load diff
+324 -286
View File
File diff suppressed because it is too large. Load diff
+540 -526
View File
File diff suppressed because it is too large. Load diff
+90 -74
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Function Object module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -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_F(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_F(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,19 +86,19 @@
* 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__)
/********************************************************************************/
/********************************** INTERNAL ************************************/
/********************************************************************************/
/*****************************************************************************/
/******************************** INTERNAL ***********************************/
/*****************************************************************************/
/* 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.
@@ -111,9 +111,9 @@
/* Specialization of the OPLIST in function if there is at least one member or not */
#define M_FUNC0BJ_INS_NO_ATTR_OPLIST(name) ( \
NAME(name), \
TYPE(M_C(name, _ct)), \
CLEAR(M_C(name, _clear)), \
INIT(M_C(name,_init)) \
TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \
CLEAR(M_F(name, _clear)), \
INIT(M_F(name,_init)) \
)
/* Validate the oplist before going further */
@@ -127,40 +127,42 @@
/* Define the oplist of the instance */
#define M_FUNC0BJ_INS_ATTR_OPLIST_P3(name, ...) ( \
NAME(name), \
TYPE(M_C(name, _ct)), \
INIT_WITH(M_C(name, _init_with)), \
CLEAR(M_C(name, _clear)), \
M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \
INIT_WITH(M_F(name, _init_with)), \
CLEAR(M_F(name, _clear)), \
M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_F(name,_init)),), \
PROPERTIES(( LET_AS_INIT_WITH(1) )) \
)
/******************************** INTERNAL ***********************************/
/* Specialization of the definition a function object interface of name 'name'
* with a function like "retcode (void)" that doesn't have any input parameters.
* Define the following types to be used by instance:
* - M_C(name, _retcode_ct): internal type of the return code
* - M_C(name, _callback_ct): internal type of the callback.
* - M_C(name, _ct): synonym of main type used by oplist.
* - M_F(name, _retcode_ct): internal type of the return code
* - M_F(name, _callback_ct): internal type of the callback.
* - M_F(name, _ct): synonym of main type used by oplist.
*/
#define M_FUNC0BJ_ITF_NO_PARAM_DEF(name, interface_t, retcode) \
\
/* Forward declaration */ \
struct M_C(name, _s); \
struct M_F(name, _s); \
\
/* Internal type for instance */ \
typedef retcode M_C(name, _retcode_ct); \
typedef retcode M_F(name, _retcode_ct); \
/* No parameters to the callback */ \
typedef retcode(*M_C(name, _callback_ct))(struct M_C(name, _s) *); \
typedef retcode(*M_F(name, _callback_ct))(struct M_F(name, _s) *); \
\
typedef struct M_C(name, _s) { \
M_C(name, _callback_ct) callback; \
} interface_t[1]; \
typedef struct M_F(name, _s) { \
M_F(name, _callback_ct) callback; \
} *interface_t; \
\
/* Internal type for oplist & instance */ \
typedef interface_t M_C(name, _ct); \
typedef interface_t M_F(name, _ct); \
\
static inline retcode \
M_C(name, _call)(interface_t funcobj) \
M_INLINE retcode \
M_F(name, _call)(interface_t funcobj) \
{ \
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
funcobj->callback(funcobj); \
@@ -171,32 +173,32 @@
* with a function like retcode, type of param1, type of param 2, ...
* with mandatory input parameters.
* Define the following types to be used by instance:
* - M_C(name, _retcode_ct): internal type of the return code
* - M_C(name, _callback_ct): internal type of the callback.
* - M_F(name, _retcode_ct): internal type of the return code
* - M_F(name, _callback_ct): internal type of the callback.
* - M_C4(name, _param_, num, _ct) for each parameter defined
* - M_C(name, _ct): synonym of main type used by oplist.
* - M_F(name, _ct): synonym of main type used by oplist.
*/
#define M_FUNC0BJ_ITF_PARAM_DEF(name, interface_t, retcode, ...) \
\
/* Forward declaration */ \
struct M_C(name, _s); \
struct M_F(name, _s); \
\
/* Internal types for instance */ \
typedef retcode M_C(name, _retcode_ct); \
typedef retcode M_F(name, _retcode_ct); \
/* Define types for all parameters */ \
M_MAP3(M_FUNC0BJ_BASE_TYPE, name, __VA_ARGS__) \
/* Define callback type with all parameters */ \
typedef retcode(*M_C(name, _callback_ct))(struct M_C(name, _s) *, __VA_ARGS__); \
typedef retcode(*M_F(name, _callback_ct))(struct M_F(name, _s) *, __VA_ARGS__); \
\
typedef struct M_C(name, _s) { \
M_C(name, _callback_ct) callback; \
} interface_t[1]; \
typedef struct M_F(name, _s) { \
M_F(name, _callback_ct) callback; \
} *interface_t; \
\
/* Internal type for oplist & instance */ \
typedef interface_t M_C(name, _ct); \
typedef interface_t M_F(name, _ct); \
\
static inline retcode \
M_C(name, _call)(interface_t funcobj \
M_INLINE retcode \
M_F(name, _call)(interface_t funcobj \
M_MAP3(M_FUNC0BJ_BASE_ARGLIST, name, __VA_ARGS__) ) \
{ \
/* If the retcode is 'void', don't return the value of the callback */ \
@@ -205,52 +207,54 @@
}
/******************************** INTERNAL ***********************************/
/* Specialization of the definition a function object instance of name 'name'
* with no member attribute.
*/
#define M_FUNC0BJ_INS_NO_ATTR_DEF(name, instance_t, base_name, param_list, callback_core) \
typedef struct M_C(name, _s) { \
typedef struct M_F(name, _s) { \
M_C(base_name, _callback_ct) callback; \
} instance_t[1]; \
\
/* Internal type for oplist */ \
typedef instance_t M_C(name, _ct); \
typedef instance_t M_F(name, _ct); \
\
static inline M_C(base_name, _retcode_ct) \
M_C(name, _callback)(M_C(base_name, _ct) _self \
M_INLINE M_C(base_name, _retcode_ct) \
M_F(name, _callback)(M_C(base_name, _ct) _self \
M_IF_EMPTY(M_OPFLAT param_list)( \
/* No param */, \
M_MAP3(M_FUNC0BJ_INS_ARGLIST, base_name, M_OPFLAT param_list) \
) \
) \
{ \
struct M_C(name, _s) *self = (struct M_C(name, _s) *)_self; \
struct M_F(name, _s) *self = (struct M_F(name, _s) *)_self; \
(void) self; /* maybe unused */ \
callback_core; \
} \
\
static inline void \
M_C(name, _init_with)(instance_t obj) \
M_INLINE void \
M_F(name, _init_with)(instance_t obj) \
{ \
obj->callback = M_C(name, _callback); \
obj->callback = M_F(name, _callback); \
} \
\
static inline void \
M_C(name, _clear)(instance_t obj) \
M_INLINE void \
M_F(name, _clear)(instance_t obj) \
{ \
(void) obj; /* nothing to do */ \
} \
\
static inline struct M_C(base_name, _s) * \
M_C(name, _as_interface)(instance_t obj) \
M_INLINE struct M_C(base_name, _s) * \
M_F(name, _as_interface)(instance_t obj) \
{ \
return (struct M_C(base_name, _s) *) obj; \
} \
\
static inline void \
M_C(name, _init)(instance_t obj) \
M_INLINE void \
M_F(name, _init)(instance_t obj) \
{ \
obj->callback = M_C(name, _callback); \
obj->callback = M_F(name, _callback); \
} \
@@ -266,7 +270,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
@@ -290,7 +294,7 @@
/* Expand the Function Object with members */
#define M_FUNC0BJ_INS_ATTR_DEF_P3(name, instance_t, base_name, param_list, callback_core, ...) \
typedef struct M_C(name, _s) { \
typedef struct M_F(name, _s) { \
/* Callback is the mandatory first argument */ \
M_C(base_name, _callback_ct) callback; \
/* All the member attribute of the Function Object */ \
@@ -298,48 +302,50 @@
} instance_t[1]; \
\
/* Internal type for oplist */ \
typedef instance_t M_C(name, _ct); \
typedef instance_t M_F(name, _ct); \
\
M_FUNC0BJ_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
\
static inline M_C(base_name, _retcode_ct) \
M_C(name, _callback)(M_C(base_name, _ct) _self \
M_INLINE M_C(base_name, _retcode_ct) \
M_F(name, _callback)(M_C(base_name, _ct) _self \
M_IF_EMPTY(M_OPFLAT param_list)( \
/* No param */, \
M_MAP3(M_FUNC0BJ_INS_ARGLIST, base_name, M_OPFLAT param_list) \
) \
) \
{ \
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_F(name, _s) *self = (struct M_F(name, _s) *)(void*)__self; \
(void) self; /* maybe unused */ \
callback_core; \
} \
\
static inline void \
M_C(name, _init_with)(instance_t obj M_MAP(M_FUNC0BJ_INS_ATTR_LIST, __VA_ARGS__)) \
M_INLINE void \
M_F(name, _init_with)(instance_t obj M_MAP(M_FUNC0BJ_INS_ATTR_LIST, __VA_ARGS__)) \
{ \
obj->callback = M_C(name, _callback); \
obj->callback = M_F(name, _callback); \
M_MAP(M_FUNC0BJ_INS_ATTR_INIT_SET, __VA_ARGS__); \
} \
\
static inline void \
M_C(name, _clear)(instance_t obj) \
M_INLINE void \
M_F(name, _clear)(instance_t obj) \
{ \
M_MAP(M_FUNC0BJ_INS_ATTR_CLEAR, __VA_ARGS__); \
} \
\
static inline struct M_C(base_name, _s) * \
M_C(name, _as_interface)(instance_t obj) \
M_INLINE struct M_C(base_name, _s) * \
M_F(name, _as_interface)(instance_t obj) \
{ \
return (struct M_C(base_name, _s) *) obj; \
} \
\
M_IF(M_FUNC0BJ_TEST_METHOD_P(INIT, __VA_ARGS)) \
( \
static inline void \
M_C(name, _init)(instance_t obj) \
M_INLINE void \
M_F(name, _init)(instance_t obj) \
{ \
obj->callback = M_C(name, _callback); \
obj->callback = M_F(name, _callback); \
M_MAP(M_FUNC0BJ_INS_ATTR_INIT, __VA_ARGS__); \
} \
, /* END OF INIT METHOD */ ) \
@@ -396,4 +402,14 @@
M_CHECK_COMPATIBLE_OPLIST(name, M_RET_ARG1 a, M_RET_ARG2 a, M_RET_ARG3 a)
/******************************** INTERNAL ***********************************/
#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
+343
View File
@@ -0,0 +1,343 @@
/*
* M*LIB - Generic module
*
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MSTARLIB_GENERIC_H
#define MSTARLIB_GENERIC_H
#include "m-core.h"
/* Define the generic macro-functions */
// TODO: m_ prefix?
#define init(x) M_G3N_CALL_1(INIT, x)
#define init_set(x, y) M_G3N_CALL_2(INIT_SET, x, TYPE, x, TYPE, y)
#define init_move(x, y) M_G3N_CALL_2(INIT_MOVE, x, TYPE, x, TYPE, y)
#define move(x, y) M_G3N_CALL_2(MOVE, x, TYPE, x, TYPE, y)
#define set(x, y) M_G3N_CALL_2(SET, x, TYPE, x , TYPE, y)
#define clear(x) M_G3N_CALL_1(CLEAR, x)
#define swap(x, y) M_G3N_CALL_2(SWAP, x, TYPE, x , TYPE, y)
#define hash(x) M_G3N_CALL_1(HASH, x)
#define equal(x, y) M_G3N_CALL_2(EQUAL, x, TYPE, x , TYPE, y)
#define cmp(x, y) M_G3N_CALL_2(CMP, x, TYPE, x , TYPE, y)
#define sort(x) M_G3N_CALL_1(SORT, x)
#define splice_back(d, s, i) M_G3N_CALL_3(SPLICE_BACK, d, TYPE, d, TYPE, s, IT_TYPE, i)
#define splice_at(d, id, s, is) M_G3N_CALL_4(SPLICE_BACK, d, TYPE, d, IT_TYPE, id, TYPE, s, IT_TYPE, is)
#define it_type(x) m_typeof(M_G3N_TYPE_1(IT_TYPE, x))
#define sub_type(x) m_typeof(M_G3N_TYPE_1(SUBTYPE, x))
#define key_type(x) m_typeof(M_G3N_TYPE_1(KEY_TYPE, x))
#define value_type(x) m_typeof(M_G3N_TYPE_1(VALUE_TYPE, x))
#define it_first(x, y) M_G3N_CALL_2(IT_FIRST, y, IT_TYPE, x, TYPE, y)
#define it_last(x, y) M_G3N_CALL_i2(IT_LAST, y, IT_TYPE, x, TYPE, y)
#define it_end(x, y) M_G3N_CALL_i2(IT_END, y, IT_TYPE, x, TYPE, y)
#define it_set(d, s) M_G3N_CALL_2i(IT_SET, d, IT_TYPE, d, IT_TYPE, s)
#define it_end_p(i) M_G3N_CALL_1i(IT_END_P, i)
#define it_last_p(i) M_G3N_CALL_1i(IT_LAST_P, i)
#define it_next(i) M_G3N_CALL_1i(IT_NEXT, i)
#define it_previous(i) M_G3N_CALL_1i(IT_PREVIOUS, i)
#define it_ref(i) M_G3N_CALL_1i(IT_REF, i)
#define it_cref(i) M_G3N_CALL_1i(IT_CREF, i)
#define it_equal(x, y) M_G3N_CALL_2i(IT_EQUAL, x, IT_TYPE, x, IT_TYPE, y)
#define it_insert(c, i, o) M_G2N_CALL_3(IT_INSERT, c, TYPE, c, IT_TYPE, i, SUBTYPE, o)
#define it_remove(c, i) M_G3N_CALL_2(IT_REMOVE, c, TYPE, c, IT_TYPE, i)
#define empty_p(x) M_G3N_CALL_1(EMPTY_P, x)
#define add(x, y) M_G3N_CALL_2(ADD, x, TYPE, x, TYPE, y)
#define sub(x, y) M_G3N_CALL_2(SUB, x, TYPE, x, TYPE, y)
#define mul(x, y) M_G3N_CALL_2(MUL, x, TYPE, x, TYPE, y)
#define div(x, y) M_G3N_CALL_2(DIV, x, TYPE, x, TYPE, y)
#define reset(x) M_G3N_CALL_1(RESET, x)
#define get(x, y) M_G3N_CALL_2(GET_KEY, x, TYPE, x, KEY_TYPE, y)
#define set_at(x, y, z) M_G3N_CALL_3(SET_KEY, x, TYPE, x, KEY_TYPE, y, VALUE_TYPE, z)
#define safe_get(x, y) M_G3N_CALL_2(SAFE_GET_KEY, x, TYPE, x, KEY_TYPE, y)
#define erase(x, y) M_G3N_CALL_2(ERASE, x, TYPE, x, KEY_TYPE, y)
#define get_size(x) M_G3N_CALL_1(GET_SIZE, x)
#define push(x, y) M_G3N_CALL_2(PUSH, x, TYPE, x, SUBTYPE, y)
#define pop(x, y) M_G3N_CALL_2(POP, y, SUBTYPE_PTR, x, TYPE, y)
#define push_move(x, y) M_G3N_CALL_2(PUSH_MOVE, x, TYPE, x, SUBTYPE_PTR, y)
#define pop_move(x, y) M_G3N_CALL_2(POP_MOVE, y, SUBTYPE_PTR, x, TYPE, y)
#define reverse(x) M_G3N_CALL_1(REVERSE, x)
#define get_str(s, c, b) M_G3N_CALL_3(GET_STR, c, string_t, s, TYPE, c, bool, b)
#define parse_str(c, s, e) M_G3N_CALL_3(PARSE_STR, c, TYPE, c, m_g3n_cstring, s, m_g3n_cstring_end, e)
#define out_str(x, y) M_G3N_CALL_2(OUT_STR, y, m_g3n_file, x, TYPE, y)
#define in_str(x, y) M_G3N_CALL_2(IN_STR, x, TYPE, x, m_g3n_file, y)
#define out_serial(x, y) M_G3N_CALL_2(OUT_SERIAL, y, m_serial_write_t, x, TYPE, y)
#define in_serial(x, y) M_G3N_CALL_2(IN_SERIAL, x, TYPE, x, m_serial_read_t, y)
// for each(item, container)
#define each(item, container) \
M_G3N_EACHI(item, container, M_C(m_local_it_, __LINE__), M_C(local_pass_, __LINE__))
/* User code has to register oplists like this:
#define M_GENERIC_ORG_2() (USER)
#define M_GENERIC_ORG_USER_COMP_1() (CORE)
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_6() FLT1
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_7() STR1
*/
/*****************************************************************************/
/********************************** INTERNAL *********************************/
/*****************************************************************************/
/* Definition of the typeof keyword
In C23, we can use the standard keyword.
Otherwise we use some extensions of the compilers. */
#ifdef _MSC_VER
#define m_typeof(x) decltype(x)
#elif defined(__GNUC__)
#define m_typeof(x) __typeof__(x)
#else
#define m_typeof(x) typeof(x)
#endif
/* Warnings disabled for CLANG in C mode:
Due to the genericity of the _Generic generation,
we cannot avoid generating both T and const T in the generic association. */
#if defined(__clang__) && __clang_major__ >= 15
#define M_G3N_BEGIN_PROTECTED_CODE \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wunreachable-code-generic-assoc\"")
#define M_G3N_END_PROTECTED_CODE \
_Pragma("clang diagnostic pop")
#else
#define M_G3N_BEGIN_PROTECTED_CODE
#define M_G3N_END_PROTECTED_CODE
#endif
// Instead of using expensive M_SEQ(1,50), precompute it:
#define M_G3N_SEQ_INT \
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, \
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, \
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50
/* Generate a sequence of the oplist that have been registered.
3 levels of indirection are needed:
* One level is the organisation.
* One level is the component of the organisation.
* One level is the oplist within the component of the organisation
Return the list of unevaluated oplist that are registered across all organizations, all components.
M*LIB Organisation (MLIB) is the default organisation and is always registered
Usage Domain: Nb organizations * Nb components * Nb oplist <= M_MAX_NB_ARGUMENT
*/
#define M_G3N_REGISTERED_ITEMS() \
M_CROSS_MAP( M_G3N_IS_PRESENT3, ( comp M_CROSS_MAP(M_G3N_IS_PRESENT2, (MLIB M_MAP(M_G3N_IS_PRESENT, M_G3N_SEQ_INT)), ( M_G3N_SEQ_INT ) ) ), ( M_G3N_SEQ_INT ) )
#define M_G3N_IS_PRESENT(num) \
M_IF(M_PARENTHESIS_P(M_C(M_GENERIC_ORG_, num)() ))(M_DEFERRED_COMMA M_ID M_C(M_GENERIC_ORG_, num)(), )
#define M_G3N_IS_PRESENT2(el1, num) \
M_IF(M_PARENTHESIS_P(M_C4(M_GENERIC_ORG_, el1, _COMP_, num)()))(M_DEFERRED_COMMA M_APPLY(M_C3, el1, _COMP_, M_ID M_C4(M_GENERIC_ORG_, el1, _COMP_, num)()), )
#define M_G3N_IS_PRESENT3(el1, num) \
M_IF(M_OPLIST_P(M_C4(M_GENERIC_ORG_, el1, _OPLIST_, num)()))(M_DEFERRED_COMMA M_C4(M_GENERIC_ORG_, el1, _OPLIST_, num), )
// Dummy unused structure. Just to fill in default case of the _Generic
struct m_g3neric_dummy_s;
// Synonymous for some basic pointers doesn't work well with preprocessing code
typedef FILE *m_g3n_file;
typedef const char *m_g3n_cstring;
typedef const char **m_g3n_cstring_end;
// If x is of typex, return y else return (typey){O}
#define M_AS_LINKED_TYPE(typex, x, typey, y) _Generic(((void)0,(x)), typex: (y), default: (typey) {0})
// Return IT_TYPE of oplist promoted to a type suitable for a _Generic statement
// i.e. transform array type into corresponding pointer type
#define M_G3N_GEN_IT_TYPE(oplist) m_typeof( ((void)0, (M_GET_IT_TYPE oplist()){0}))
#define M_G3N_GEN_TYPE(oplist) M_GET_GENTYPE oplist()
// Translate type' into the container type if type == TYPE, IT_TYPE into its iterator
// KEY_TYPE, VALUE_TYPE, SUBTYPE into the associated type in the oplist,
// or keep 'type' otherwise
// Handle also specially SUBTYPE_PTR
#define M_G3N_TYPE(type, oplist) M_G3N_TYPE_B(type, oplist())
#define M_G3N_TYPE_B(type, oplist) M_GET_METHOD(type, type, SUBTYPE_PTR(M_GET_SUBTYPE oplist *), M_OPFLAT oplist)
// Call the OPERATOR call of the oplist registered to the variable 'x'
// which takes one argument.
#define M_G3N_CALL_1(op, x) \
M_G3N_BEGIN_PROTECTED_CODE \
_Generic( ((void)0, (x)), \
M_MAP2(M_G3N_CALL_1_func, (op, x) M_G3N_REGISTERED_ITEMS() ) \
struct m_g3neric_dummy_s *: /* cannot happen */ (void)0) \
M_G3N_END_PROTECTED_CODE
#define M_G3N_CALL_1_func(x, oplist) \
M_G3N_CALL_1_func_test(M_G3N_GEN_TYPE(oplist), M_PAIR_1 x, M_PAIR_2 x, oplist)
#define M_G3N_CALL_1_func_test(gentype, op, x, oplist) \
M_IF_METHOD(op, oplist())(M_G3N_CALL_1_func_expand, M_EAT)(gentype, op, x, oplist)
#define M_G3N_CALL_1_func_expand(gentype, op, x, oplist) \
gentype: M_C(M_CALL_, op)(oplist(), M_AS_TYPE(gentype, x)), \
const gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(const gentype, x, gentype, x)),
// Call the OPERATOR call of the oplist registered to the variable 'svar'
// which takes 2 arguments of the given type
#define M_G3N_CALL_2(op, svar, type1, var1, type2, var2) \
M_G3N_BEGIN_PROTECTED_CODE \
_Generic( ((void)0, (svar)), \
M_MAP2(M_G3N_CALL_2_func, (op, svar, type1, var1, type2, var2) M_G3N_REGISTERED_ITEMS() ) \
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
M_G3N_END_PROTECTED_CODE
#define M_G3N_CALL_2_func(x, oplist) \
M_APPLY(M_G3N_CALL_2_func_test, M_G3N_GEN_TYPE(oplist), M_ID x, oplist)
#define M_G3N_CALL_2_func_test(gentype, op, svar, type1, var1, type2, var2, oplist) \
M_IF_METHOD(op, oplist())(M_G3N_CALL_2_func_expand, M_EAT)(gentype, op, svar, M_G3N_TYPE(type1, oplist), var1, M_G3N_TYPE(type2, oplist), var2, oplist)
#define M_G3N_CALL_2_func_expand(gentype, op, svar, type1, var1, type2, var2, oplist) \
gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(gentype, svar, type1, var1), M_AS_LINKED_TYPE(gentype, svar, type2, var2) ), \
const gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(const gentype, svar, type1, var1), M_AS_LINKED_TYPE(const gentype, svar, type2, var2) ),
// Call the OPERATOR call of the oplist registered to the variable 'svar'
// which takes 3 arguments of the given type
#define M_G3N_CALL_3(op, svar, type1, var1, type2, var2, type3, var3) \
M_G3N_BEGIN_PROTECTED_CODE \
_Generic( ((void)0, (svar)), \
M_MAP2(M_G3N_CALL_3_func, (op, svar, type1, var1, type2, var2, type3, var3) M_G3N_REGISTERED_ITEMS() ) \
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
M_G3N_END_PROTECTED_CODE
#define M_G3N_CALL_3_func(x, oplist) \
M_APPLY(M_G3N_CALL_3_func_test, M_G3N_GEN_TYPE(oplist), M_ID x, oplist)
#define M_G3N_CALL_3_func_test(gentype, op, svar, type1, var1, type2, var2, type3, var3, oplist) \
M_IF_METHOD(op, oplist())(M_G3N_CALL_3_func_expand, M_EAT)(gentype, op, svar, M_G3N_TYPE(type1, oplist), var1, M_G3N_TYPE(type2, oplist), var2, M_G3N_TYPE(type3, oplist), var3, oplist)
#define M_G3N_CALL_3_func_expand(gentype, op, svar, type1, var1, type2, var2, oplist) \
gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(gentype, svar, type1, var1), M_AS_LINKED_TYPE(gentype, svar, type2, var2) ), \
const gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(const gentype, svar, type1, var1), M_AS_LINKED_TYPE(const gentype, svar, type2, var2) ),
// Call the OPERATOR call of the oplist registered to the variable 'svar'
// which takes 4 arguments of the given type
#define M_G3N_CALL_4(op, svar, type1, var1, type2, var2, type3, var3, type4, var4) \
M_G3N_BEGIN_PROTECTED_CODE \
_Generic( ((void)0, (svar)), \
M_MAP2(M_G3N_CALL_4_func, (op, svar, type1, var1, type2, var2, type3, var3, type4, var4) M_G3N_REGISTERED_ITEMS() ) \
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
M_G3N_END_PROTECTED_CODE
#define M_G3N_CALL_4_func(x, oplist) \
M_APPLY(M_G3N_CALL_4_func_test, M_G3N_GEN_TYPE(oplist), M_ID x, oplist)
#define M_G3N_CALL_4_func_test(gentype, op, svar, type1, var1, type2, var2, type3, var3, type4, var4, oplist) \
M_IF_METHOD(op, oplist())(M_G3N_CALL_4_func_expand, M_EAT)(gentype, op, svar, M_G3N_TYPE(type1, oplist), var1, M_G3N_TYPE(type2, oplist), var2, M_G3N_TYPE(type3, oplist), var3, M_G3N_TYPE(type4, oplist), var4, oplist)
#define M_G3N_CALL_4_func_expand(gentype, op, svar, type1, var1, type2, var2, oplist) \
gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(gentype, svar, type1, var1), M_AS_LINKED_TYPE(gentype, svar, type2, var2) ), \
const gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(const gentype, svar, type1, var1), M_AS_LINKED_TYPE(const gentype, svar, type2, var2) ),
// Call the OPERATOR call of the oplist registered to the variable 'x'
// which takes one argument, it_type
#define M_G3N_CALL_1i(op, x) \
M_G3N_BEGIN_PROTECTED_CODE \
_Generic( ((void)0, (x)), \
M_MAP2(M_G3N_CALL_1i_func, (op, x) M_G3N_REGISTERED_ITEMS() ) \
struct m_g3neric_dummy_s *: /* cannot happen */ (void)0) \
M_G3N_END_PROTECTED_CODE
#define M_G3N_CALL_1i_func(x, oplist) \
M_G3N_CALL_1_func_test(M_G3N_GEN_IT_TYPE(oplist), M_PAIR_1 x, M_PAIR_2 x, oplist)
// Call the OPERATOR call of the oplist registered to the variable 'svar'
// which takes 2 arguments of the given it_type
#define M_G3N_CALL_2i(op, svar, type1, var1, type2, var2) \
M_G3N_BEGIN_PROTECTED_CODE \
_Generic( ((void)0, (svar)), \
M_MAP2(M_G3N_CALL_2i_func, (op, svar, type1, var1, type2, var2) M_G3N_REGISTERED_ITEMS() ) \
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
M_G3N_END_PROTECTED_CODE
#define M_G3N_CALL_2i_func(x, oplist) \
M_APPLY(M_G3N_CALL_2_func_test, M_G3N_GEN_IT_TYPE(oplist), M_ID x, oplist)
// Create a variable of type OPERATOR call of the oplist registered to the variable 'x'
#define M_G3N_TYPE_1(op, x) \
M_G3N_BEGIN_PROTECTED_CODE \
_Generic( ((void)0, (x)), \
M_MAP2(M_G3N_TYPE_1_func, (op, x) M_G3N_REGISTERED_ITEMS() ) \
struct m_g3neric_dummy_s *: /* cannot happen */ (void)0) \
M_G3N_END_PROTECTED_CODE
#define M_G3N_TYPE_1_func(x, oplist) \
M_G3N_TYPE_1_func_test(M_G3N_GEN_TYPE(oplist), M_PAIR_1 x, M_PAIR_2 x, oplist)
#define M_G3N_TYPE_1_func_test(gentype, op, x, oplist) \
M_IF_METHOD(op, oplist())(M_G3N_TYPE_1_func_expand, M_EAT)(gentype, op, x, oplist)
#define M_G3N_TYPE_1_func_expand(gentype, op, x, oplist) \
gentype: (M_G3N_TYPE(op, oplist)){0}, \
const gentype: (M_G3N_TYPE(op, oplist)){0},
// for each item in the container
// Same as M_EACH except it uses the generic macros
#define M_G3N_EACHI(item, container, l_it, l_pass) \
(bool l_pass = true; l_pass; l_pass = false) \
for(sub_type(container) *item; l_pass ; l_pass = false) \
for(it_type(container) l_it; l_pass ; l_pass = false) \
for(it_first(l_it, container) ; \
!it_end_p(l_it) \
&& (item = it_ref(l_it), true) ; \
it_next(l_it))
// TODO: init_with ? How to handle the different type of parameters ? Using EMPLACE_TYPE ?
// TODO: support of PUSH_EMPLACE ?
// TODO: support of "let" directly to avoid using the post-processing registration of M_LET?
// Overwrite M_FPRINT & M_PRINT to support global oplists registration
#define M_FPRINT_ARG_G3N(f, x) \
M_G3N_BEGIN_PROTECTED_CODE \
_Generic(((void)0,(x)), \
char: fprintf(f, "%c", M_AS_TYPE(char,x)), \
bool: fprintf(f, "%d", M_AS_TYPE(bool,x)), \
signed char: fprintf(f, "%hhd", M_AS_TYPE(signed char,x)), \
unsigned char: fprintf(f, "%hhu", M_AS_TYPE(unsigned char,x)), \
signed short: fprintf(f, "%hd", M_AS_TYPE(signed short,x)), \
unsigned short: fprintf(f, "%hu", M_AS_TYPE(unsigned short,x)), \
signed int: fprintf(f, "%d", M_AS_TYPE(signed int,x)), \
unsigned int: fprintf(f, "%u", M_AS_TYPE(unsigned int,x)), \
long int: fprintf(f, "%ld", M_AS_TYPE(long int,x)), \
unsigned long int: fprintf(f, "%lu", M_AS_TYPE(unsigned long int,x)), \
long long int: fprintf(f, "%lld", M_AS_TYPE(long long int,x)), \
unsigned long long int: fprintf(f, "%llu", M_AS_TYPE(unsigned long long int,x)), \
float: fprintf(f, "%f", M_AS_TYPE(float,x)), \
double: fprintf(f, "%f", M_AS_TYPE(double,x)), \
long double: fprintf(f, "%Lf", M_AS_TYPE(long double,x)), \
const char *: fprintf(f, "%s", M_AS_TYPE(const char*,x)), \
char *: fprintf(f, "%s", M_AS_TYPE(char*,x)), \
const void *: fprintf(f, "%p", M_AS_TYPE(const void *,x)), \
void *: fprintf(f, "%p", M_AS_TYPE(void *,x)), \
M_MAP2(M_G3N_CALL_2_func, (OUT_STR, x, m_g3n_file, f, TYPE, x) M_G3N_REGISTERED_ITEMS() ) \
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
M_G3N_END_PROTECTED_CODE
#define M_G3N_FPRINT_ARG(f, x) \
M_IF(M_PARENTHESIS_P(x)) \
( M_FPRINT_ARG_OUT_STR(f, M_PAIR_2 x, M_PAIR_1 x), \
M_FPRINT_ARG_G3N(f, x) )
/* Ovverride M_PRINT */
#undef M_PRINT
#define M_PRINT(...) do { M_REDUCE2(M_G3N_FPRINT_ARG, M_SEPARATE_PER_SEMICOLON, stdout, __VA_ARGS__); } while (0)
#undef M_FPRINT
#define M_FPRINT(f,...) do { M_REDUCE2(M_G3N_FPRINT_ARG, M_SEPARATE_PER_SEMICOLON, f, __VA_ARGS__); } while (0)
// Register CORE component of M*LIB
#define M_GENERIC_ORG_MLIB_COMP_1() (CORE)
#endif
+38 -40
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Integer Generator (GENINT) module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -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
@@ -105,14 +103,14 @@ typedef struct genint_s {
* meaning it can be used to index global unique resources shared
* for all threads.
*/
static inline void
genint_init(genint_t s, unsigned int n)
M_INLINE void
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);
if (M_UNLIKELY (ptr == NULL)) {
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
M_MEMORY_FULL(alloc);
return;
}
@@ -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_INLINE void
m_genint_clear(m_genint_t s)
{
M_GEN1NT_CONTRACT(s);
M_MEMORY_FREE(s->data);
@@ -137,8 +135,8 @@ genint_clear(genint_t s)
}
/* Return the maximum integer that the generator will provide */
static inline size_t
genint_size(genint_t s)
M_INLINE size_t
m_genint_size(m_genint_t s)
{
M_GEN1NT_CONTRACT(s);
return s->n;
@@ -146,23 +144,23 @@ 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_INLINE unsigned int
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_INLINE void
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 {
+196 -184
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Intrusive List module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -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_F(name,_t), M_F(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,21 @@
/* 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 ************************************/
/*****************************************************************************/
/******************************** 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
@@ -93,35 +95,36 @@ typedef struct m_ilist_head_s {
/* Define the oplist of an ilist of type */
#define M_IL1ST_OPLIST_P3(name, oplist) \
(INIT(M_C(name, _init)), \
CLEAR(M_C(name, _clear)), \
INIT_MOVE(M_C(name, _init_move)), \
MOVE(M_C(name, _move)), \
(INIT(M_F(name, _init)), \
CLEAR(M_F(name, _clear)), \
INIT_MOVE(M_F(name, _init_move)), \
MOVE(M_F(name, _move)), \
NAME(name), \
TYPE(M_C(name,_ct)), \
RESET(M_C(name,_reset)), \
SUBTYPE(M_C(name,_subtype_ct)), \
EMPTY_P(M_C(name,_empty_p)), \
IT_TYPE(M_C(name,_it_ct)), \
IT_FIRST(M_C(name,_it)), \
IT_SET(M_C(name,_it_set)), \
IT_LAST(M_C(name,_it_last)), \
IT_END(M_C(name,_it_end)), \
IT_END_P(M_C(name,_end_p)), \
IT_LAST_P(M_C(name,_last_p)), \
IT_EQUAL_P(M_C(name,_it_equal_p)), \
IT_NEXT(M_C(name,_next)), \
IT_PREVIOUS(M_C(name,_previous)), \
IT_REF(M_C(name,_ref)), \
IT_CREF(M_C(name,_cref)), \
IT_REMOVE(M_C(name,_remove)), \
M_IF_METHOD(NEW, oplist)(IT_INSERT(M_C(name,_insert)),), \
TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
RESET(M_F(name,_reset)), \
SUBTYPE(M_F(name,_subtype_ct)), \
EMPTY_P(M_F(name,_empty_p)), \
IT_TYPE(M_F(name,_it_ct)), \
IT_FIRST(M_F(name,_it)), \
IT_SET(M_F(name,_it_set)), \
IT_LAST(M_F(name,_it_last)), \
IT_END(M_F(name,_it_end)), \
IT_END_P(M_F(name,_end_p)), \
IT_LAST_P(M_F(name,_last_p)), \
IT_EQUAL_P(M_F(name,_it_equal_p)), \
IT_NEXT(M_F(name,_next)), \
IT_PREVIOUS(M_F(name,_previous)), \
IT_REF(M_F(name,_ref)), \
IT_CREF(M_F(name,_cref)), \
IT_REMOVE(M_F(name,_remove)), \
M_IF_METHOD(NEW, oplist)(IT_INSERT(M_F(name,_insert)),), \
OPLIST(oplist), \
SPLICE_BACK(M_C(name,_splice_back)) \
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
SPLICE_BACK(M_F(name,_splice_back)) \
)
/******************************** INTERNAL ***********************************/
/* Contract respected by all intrusive lists */
#define M_IL1ST_CONTRACT(name, list) do { \
M_ASSERT(list != NULL); \
@@ -140,8 +143,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) \
@@ -160,34 +163,43 @@ typedef struct m_ilist_head_s {
it_t: iterator of the intrusive list (name##_it_t)
*/
#define M_IL1ST_DEF_P3(name, type, oplist, list_t, it_t) \
M_IL1ST_DEF_TYPE(name, type, oplist, list_t, it_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_IL1ST_DEF_CORE(name, type, oplist, list_t, it_t) \
/* Used of internal macro from m-list */ \
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
/* Define the type of an intrusive list */
#define M_IL1ST_DEF_TYPE(name, type, oplist, list_t, it_t) \
\
/* Define the list as a structure containing pointers \
* to the front & back nodes */ \
typedef struct M_C(name, _s) { \
struct m_ilist_head_s name; \
typedef struct M_F(name, _s) { \
struct m_il1st_head_s name; \
} list_t[1]; \
\
/* Define internal types pointers to such a list */ \
typedef struct M_C(name, _s) *M_C(name, _ptr); \
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
typedef struct M_F(name, _s) *M_F(name, _ptr); \
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
\
/* 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; \
typedef struct M_F(name, _it_s) { \
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 */ \
typedef type M_C(name, _subtype_ct); \
typedef list_t M_C(name, _ct); \
typedef it_t M_C(name, _it_ct); \
typedef type M_F(name, _subtype_ct); \
typedef list_t M_F(name, _ct); \
typedef it_t M_F(name, _it_ct); \
/* Define core functions for intrusive lists */
#define M_IL1ST_DEF_CORE(name, type, oplist, list_t, it_t) \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void \
M_C(name, _init)(list_t list) \
M_INLINE void \
M_F(name, _init)(list_t list) \
{ \
M_ASSERT (list != NULL); \
list->name.next = &list->name; \
@@ -195,15 +207,15 @@ typedef struct m_ilist_head_s {
M_IL1ST_CONTRACT(name, list); \
} \
\
static inline void \
M_C(name, _reset)(list_t list) \
M_INLINE void \
M_F(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,37 +229,31 @@ 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) \
M_INLINE void \
M_F(name, _clear)(list_t list) \
{ \
/* Nothing to do more than clean the list itself */ \
M_C(name, _reset)(list); \
M_F(name, _reset)(list); \
/* For safety purpose (create invalid represenation of object) */ \
list->name.next = NULL; \
list->name.prev = NULL; \
} \
\
static inline bool \
M_C(name, _empty_p)(const list_t list) \
M_INLINE bool \
M_F(name, _empty_p)(const list_t list) \
{ \
M_IL1ST_CONTRACT(name, list); \
return list->name.next == &list->name; \
} \
\
\
static inline void \
M_C(name, _init_move)(list_t list, list_t ref) \
M_INLINE void \
M_F(name, _init_move)(list_t list, list_t ref) \
{ \
M_IL1ST_CONTRACT(name, ref); \
M_ASSERT (list != ref); \
M_C(name,_init)(list); \
if (!M_C(name,_empty_p)(ref)) { \
M_F(name,_init)(list); \
if (!M_F(name,_empty_p)(ref)) { \
list->name.next = ref->name.next; \
list->name.prev = ref->name.prev; \
list->name.next->prev = &list->name; \
@@ -258,20 +264,20 @@ typedef struct m_ilist_head_s {
M_IL1ST_CONTRACT(name, list); \
} \
\
static inline void \
M_C(name, _move)(list_t list, list_t ref) \
M_INLINE void \
M_F(name, _move)(list_t list, list_t ref) \
{ \
M_C(name, _clear)(list); \
M_C(name, _init_move)(list, ref); \
M_F(name, _clear)(list); \
M_F(name, _init_move)(list, ref); \
} \
\
static inline size_t \
M_C(name, _size)(const list_t list) \
M_INLINE size_t \
M_F(name, _size)(const list_t list) \
{ \
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++; \
@@ -279,12 +285,12 @@ typedef struct m_ilist_head_s {
return s; \
} \
\
static inline void \
M_C(name, _push_back)(list_t list, type *obj) \
M_INLINE void \
M_F(name, _push_back)(list_t list, type *obj) \
{ \
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; \
@@ -292,12 +298,12 @@ typedef struct m_ilist_head_s {
M_IL1ST_CONTRACT(name, list); \
} \
\
static inline void \
M_C(name, _push_front)(list_t list, type *obj) \
M_INLINE void \
M_F(name, _push_front)(list_t list, type *obj) \
{ \
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; \
@@ -305,21 +311,21 @@ typedef struct m_ilist_head_s {
M_IL1ST_CONTRACT(name, list); \
} \
\
static inline void \
M_C(name, _push_after)(type *obj_pos, type *obj) \
M_INLINE void \
M_F(name, _push_after)(type *obj_pos, type *obj) \
{ \
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; \
next->prev = &obj->name; \
} \
\
static inline void \
M_C(name, _init_field)(type *obj) \
M_INLINE void \
M_F(name, _init_field)(type *obj) \
{ \
M_ASSERT (obj != NULL); \
/* Init the fields of the node. To be used in object constructor */ \
@@ -327,14 +333,14 @@ typedef struct m_ilist_head_s {
obj->name.prev = NULL; \
} \
\
static inline void \
M_C(name, _unlink)(type *obj) \
M_INLINE void \
M_F(name, _unlink)(type *obj) \
{ \
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 */ \
@@ -342,48 +348,48 @@ typedef struct m_ilist_head_s {
obj->name.prev = NULL; \
} \
\
static inline type * \
M_C(name, _back)(const list_t list) \
M_INLINE type * \
M_F(name, _back)(const list_t list) \
{ \
M_IL1ST_CONTRACT(name, list); \
M_ASSERT(!M_C(name, _empty_p)(list)); \
M_ASSERT(!M_F(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 * \
M_C(name, _front)(const list_t list) \
M_INLINE type * \
M_F(name, _front)(const list_t list) \
{ \
M_IL1ST_CONTRACT(name, list); \
M_ASSERT(!M_C(name, _empty_p)(list)); \
M_ASSERT(!M_F(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 * \
M_C(name, _next_obj)(const list_t list, type const *obj) \
M_INLINE type * \
M_F(name, _next_obj)(const list_t list, type const *obj) \
{ \
M_IL1ST_CONTRACT(name, list); \
M_ASSERT (obj != NULL); \
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 * \
M_C(name, _previous_obj)(const list_t list, type const *obj) \
M_INLINE type * \
M_F(name, _previous_obj)(const list_t list, type const *obj) \
{ \
M_IL1ST_CONTRACT(name, list); \
M_ASSERT (obj != NULL); \
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 \
M_C(name, _it)(it_t it, const list_t list) \
M_INLINE void \
M_F(name, _it)(it_t it, const list_t list) \
{ \
M_IL1ST_CONTRACT(name, list); \
M_ASSERT (it != NULL); \
@@ -394,8 +400,8 @@ typedef struct m_ilist_head_s {
M_IL1ST_NODE_CONTRACT(it->current); \
} \
\
static inline void \
M_C(name, _it_set)(it_t it, const it_t cit) \
M_INLINE void \
M_F(name, _it_set)(it_t it, const it_t cit) \
{ \
M_ASSERT (it != NULL && cit != NULL); \
it->head = cit->head; \
@@ -405,8 +411,8 @@ typedef struct m_ilist_head_s {
M_IL1ST_NODE_CONTRACT(it->current); \
} \
\
static inline void \
M_C(name, _it_last)(it_t it, list_t const list) \
M_INLINE void \
M_F(name, _it_last)(it_t it, list_t const list) \
{ \
M_IL1ST_CONTRACT(name, list); \
M_ASSERT (it != NULL); \
@@ -417,8 +423,8 @@ typedef struct m_ilist_head_s {
M_IL1ST_NODE_CONTRACT(it->current); \
} \
\
static inline void \
M_C(name, _it_end)(it_t it, list_t const list) \
M_INLINE void \
M_F(name, _it_end)(it_t it, list_t const list) \
{ \
M_ASSERT (it != NULL && list != NULL); \
it->head = list->name.next->prev; \
@@ -428,24 +434,24 @@ typedef struct m_ilist_head_s {
M_IL1ST_NODE_CONTRACT(it->current); \
} \
\
static inline bool \
M_C(name, _end_p)(const it_t it) \
M_INLINE bool \
M_F(name, _end_p)(const it_t it) \
{ \
M_ASSERT (it != NULL); \
M_IL1ST_NODE_CONTRACT(it->current); \
return it->current == it->head; \
} \
\
static inline bool \
M_C(name, _last_p)(const it_t it) \
M_INLINE bool \
M_F(name, _last_p)(const it_t it) \
{ \
M_ASSERT (it != NULL); \
M_IL1ST_NODE_CONTRACT(it->current); \
return it->next == it->head || it->current == it->head; \
} \
\
static inline void \
M_C(name, _next)(it_t it) \
M_INLINE void \
M_F(name, _next)(it_t it) \
{ \
M_ASSERT (it != NULL); \
/* Cannot check node for it->current: it may have been deleted! */ \
@@ -459,8 +465,8 @@ typedef struct m_ilist_head_s {
M_IL1ST_NODE_CONTRACT(it->current); \
} \
\
static inline void \
M_C(name, _previous)(it_t it) \
M_INLINE void \
M_F(name, _previous)(it_t it) \
{ \
M_ASSERT (it != NULL); \
/* Cannot check node for it->current: it may have been deleted! */ \
@@ -474,97 +480,97 @@ typedef struct m_ilist_head_s {
M_IL1ST_NODE_CONTRACT(it->current); \
} \
\
static inline bool \
M_C(name, _it_equal_p)(const it_t it1, const it_t it2 ) \
M_INLINE bool \
M_F(name, _it_equal_p)(const it_t it1, const it_t it2 ) \
{ \
M_ASSERT (it1 != NULL && it2 != NULL); \
/* No need to check for next & previous */ \
return it1->head == it2->head && it1->current == it2->current; \
} \
\
static inline type * \
M_C(name, _ref)(const it_t it) \
M_INLINE type * \
M_F(name, _ref)(const it_t it) \
{ \
M_ASSERT (it != NULL && it->current != NULL); \
M_IL1ST_NODE_CONTRACT(it->current); \
/* check if 'it' was not deleted */ \
M_ASSERT (it->current->next == it->next); \
M_ASSERT (it->current->prev == it->previous); \
M_ASSERT (!M_C(name, _end_p)(it)); \
M_ASSERT (!M_F(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 * \
M_C(name, _cref)(const it_t it) \
M_INLINE type const * \
M_F(name, _cref)(const it_t it) \
{ \
type *ptr = M_C(name, _ref)(it); \
type *ptr = M_F(name, _ref)(it); \
return M_CONST_CAST(type, ptr); \
} \
\
static inline void \
M_C(name, _remove)(list_t list, it_t it) \
M_INLINE void \
M_F(name, _remove)(list_t list, it_t it) \
{ \
M_IL1ST_CONTRACT(name, list); \
M_IL1ST_NODE_CONTRACT(it->current); \
(void)list; /* list param is not used */ \
type *obj = M_TYPE_FROM_FIELD(type, it->current, \
struct m_ilist_head_s, name); \
M_C(name, _unlink)(obj); \
struct m_il1st_head_s, name); \
M_F(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_F(name, _next)(it); \
} \
\
M_IF_METHOD(NEW, oplist)( \
static inline void \
M_C(name, _insert)(list_t list, it_t it, type x) \
M_IF_METHOD2(NEW, INIT_SET, oplist)( \
M_INLINE void \
M_F(name, _insert)(list_t list, it_t it, type x) \
{ \
M_IL1ST_CONTRACT(name, list); \
M_IL1ST_NODE_CONTRACT(it->current); \
type *p = M_CALL_NEW(oplist, type); \
if (M_UNLIKELY (p == NULL)) { \
if (M_UNLIKELY_NOMEM (p == NULL)) { \
M_MEMORY_FULL (sizeof (type)); \
return ; \
} \
M_CALL_INIT_SET(oplist, *p, x); \
type *obj = M_C(name, _ref)(it); \
M_C(name, _push_after)(obj, p); \
type *obj = M_F(name, _ref)(it); \
M_F(name, _push_after)(obj, p); \
it->current = p; \
(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) \
M_INLINE type * \
M_F(name, _pop_back)(list_t list) \
{ \
M_IL1ST_CONTRACT(name, list); \
M_ASSERT (!M_C(name, _empty_p)(list)); \
type *obj = M_C(name, _back)(list); \
M_ASSERT (!M_F(name, _empty_p)(list)); \
type *obj = M_F(name, _back)(list); \
list->name.prev = list->name.prev->prev; \
list->name.prev->next = &list->name; \
return obj; \
} \
\
static inline type * \
M_C(name, _pop_front)(list_t list) \
M_INLINE type * \
M_F(name, _pop_front)(list_t list) \
{ \
M_IL1ST_CONTRACT(name, list); \
M_ASSERT (!M_C(name, _empty_p)(list)); \
type *obj = M_C(name, _front)(list); \
M_ASSERT (!M_F(name, _empty_p)(list)); \
type *obj = M_F(name, _front)(list); \
list->name.next = list->name.next->next; \
list->name.next->prev = &list->name; \
return obj; \
} \
\
static inline void \
M_C(name, _splice)(list_t list1, list_t list2) \
M_INLINE void \
M_F(name, _splice)(list_t list1, list_t list2) \
{ \
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; \
@@ -575,44 +581,44 @@ typedef struct m_ilist_head_s {
M_IL1ST_CONTRACT(name, list2); \
} \
\
static inline void \
M_C(name, _splice_back)(list_t nv, list_t ov, it_t it) \
M_INLINE void \
M_F(name, _splice_back)(list_t nv, list_t ov, it_t it) \
{ \
M_IL1ST_CONTRACT(name, nv); \
M_IL1ST_CONTRACT(name, ov); \
M_IL1ST_NODE_CONTRACT(it->current); \
M_ASSERT (it != NULL); \
(void) ov; \
type *obj = M_C(name, _ref)(it); \
M_C(name, _unlink)(obj); \
M_C(name, _push_back)(nv, obj); \
M_C(name, _next)(it); \
type *obj = M_F(name, _ref)(it); \
M_F(name, _unlink)(obj); \
M_F(name, _push_back)(nv, obj); \
M_F(name, _next)(it); \
M_IL1ST_CONTRACT(name, nv); \
M_IL1ST_CONTRACT(name, ov); \
} \
\
static inline void \
M_C(name, _splice_at)(list_t nlist, it_t npos, \
M_INLINE void \
M_F(name, _splice_at)(list_t nlist, it_t npos, \
list_t olist, it_t opos) \
{ \
M_IL1ST_CONTRACT(name, nlist); \
M_IL1ST_CONTRACT(name, olist); \
M_ASSERT (npos != NULL && opos != NULL); \
M_ASSERT (!M_C(name, _end_p)(opos)); \
M_ASSERT (!M_F(name, _end_p)(opos)); \
/* npos may be end */ \
(void) olist, (void) nlist; \
type *obj = M_C(name, _ref)(opos); \
struct m_ilist_head_s *ref = npos->current; \
type *obj = M_F(name, _ref)(opos); \
struct m_il1st_head_s *ref = npos->current; \
/* Remove object */ \
M_C(name, _unlink)(obj); \
M_F(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; \
next->prev = &obj->name; \
/* Move iterator in old list */ \
M_C(name, _next)(opos); \
M_F(name, _next)(opos); \
/* Set npos iterator to new position of object */ \
npos->previous = ref; \
npos->current = &obj->name; \
@@ -621,13 +627,13 @@ typedef struct m_ilist_head_s {
M_IL1ST_CONTRACT(name, olist); \
} \
\
static inline void \
M_C(name, _swap)(list_t d, list_t e) \
M_INLINE void \
M_F(name, _swap)(list_t d, list_t e) \
{ \
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; \
@@ -644,11 +650,11 @@ typedef struct m_ilist_head_s {
M_IL1ST_CONTRACT(name, e); \
} \
\
static inline void \
M_C(name, _reverse)(list_t list) \
M_INLINE void \
M_F(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; \
@@ -659,9 +665,15 @@ typedef struct m_ilist_head_s {
it->prev = next; \
M_IL1ST_CONTRACT(name, list); \
} \
\
/* Used of internal macro from m-list */ \
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
/******************************** INTERNAL ***********************************/
#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
+79 -65
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - INTRUSIVE SHARED PTR Module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -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) \
atomic_int M_C(name, _cpt)
#define M_ISHARED_PTR_INTERFACE(name, type) \
atomic_int M_F(name, _cpt)
/* Value of the interface field for static intialization (Uses C99 designated element). */
#define ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
.M_C(name, _cpt) = ATOMIC_VAR_INIT(0)
#define M_ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
.M_F(name, _cpt) = M_ATOMIC_VAR_INIT(0)
/* Value of the interface field for static intialization (Uses C89 designated element). */
#define ISHARED_PTR_STATIC_INIT(name, type) \
ATOMIC_VAR_INIT(0)
#define M_ISHARED_PTR_STATIC_INIT(name, type) \
M_ATOMIC_VAR_INIT(0)
/* Define the intrusive shared pointer type and its static inline functions.
/* Define the intrusive shared pointer type and its M_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_F(name,_t), __VA_ARGS__)
/* Define the intrusive shared pointer type and its static inline functions
/* Define the intrusive shared pointer type and its M_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 ), \
@@ -72,7 +72,9 @@ M_BEGIN_PROTECTED_CODE
M_END_PROTECTED_CODE
/********************************** INTERNAL ************************************/
/*****************************************************************************/
/******************************** INTERNAL ***********************************/
/*****************************************************************************/
// Deferred evaluation
#define M_ISHAR3D_PTR_OPLIST_P1(arg) M_ISHAR3D_PTR_OPLIST_P2 arg
@@ -88,21 +90,21 @@ M_BEGIN_PROTECTED_CODE
// Define the oplist
#define M_ISHAR3D_PTR_OPLIST_P3(name, oplist) ( \
INIT(M_INIT_DEFAULT), \
INIT_SET(API_4(M_C(name, _init_set))), \
SET(M_C(name, _set) M_IPTR), \
CLEAR(M_C(name, _clear)), \
RESET(M_C(name, _reset) M_IPTR), \
INIT_SET(API_4(M_F(name, _init_set))), \
SET(M_F(name, _set) M_IPTR), \
CLEAR(M_F(name, _clear)), \
RESET(M_F(name, _reset) M_IPTR), \
NAME(name), \
TYPE(M_C(name, _ct)), \
TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \
OPLIST(oplist), \
SUBTYPE(M_C(name, _subtype_ct)) \
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
SUBTYPE(M_F(name, _subtype_ct)) \
)
/******************************** INTERNAL ***********************************/
// 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) \
@@ -113,31 +115,38 @@ M_BEGIN_PROTECTED_CODE
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ISHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
#define M_ISHAR3D_PTR_DEF_P3(name, type, oplist, shared_t) \
M_ISHAR3D_PTR_DEF_TYPE(name, type, oplist, shared_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_ISHAR3D_PTR_DEF_CORE(name, type, oplist, shared_t) \
/* Define the types */
#define M_ISHAR3D_PTR_DEF_TYPE(name, type, oplist, shared_t) \
\
/* The shared pointer is only a pointer to the type */ \
typedef type *shared_t; \
\
/* Define internal types for oplist */ \
typedef shared_t M_C(name, _ct); \
typedef type M_C(name, _subtype_ct); \
typedef shared_t M_F(name, _ct); \
typedef type M_F(name, _subtype_ct); \
/* Define the core functions */
#define M_ISHAR3D_PTR_DEF_CORE(name, type, oplist, shared_t) \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline shared_t \
M_C(name, _init)(type *ptr) \
M_INLINE shared_t \
M_F(name, _init)(type *ptr) \
{ \
/* Initialize the type referenced by the pointer */ \
if (M_LIKELY (ptr != NULL)) { \
atomic_init(&ptr->M_C(name, _cpt), 2); \
atomic_init(&ptr->M_F(name, _cpt), 2); \
} \
return ptr; \
} \
\
static inline shared_t \
M_C(name, _init_set)(shared_t shared) \
M_INLINE shared_t \
M_F(name, _init_set)(shared_t shared) \
{ \
if (M_LIKELY (shared != NULL)) { \
int n = atomic_fetch_add(&(shared->M_C(name, _cpt)), 2); \
int n = atomic_fetch_add(&(shared->M_F(name, _cpt)), 2); \
(void) n; \
} \
return shared; \
@@ -147,95 +156,100 @@ M_BEGIN_PROTECTED_CODE
M_IF_DISABLED_METHOD(NEW, oplist) \
( \
/* This function is only for static object */ \
static inline shared_t \
M_C(name, _init_once)(type *shared) \
M_INLINE shared_t \
M_F(name, _init_once)(type *shared) \
{ \
if (M_LIKELY (shared != NULL)) { \
/* Pretty much like atomic_add, except the first one increment by 1, others by 2 */ \
int o = atomic_load(&(shared->M_C(name, _cpt))); \
int o = atomic_load(&(shared->M_F(name, _cpt))); \
int n; \
do { \
n = o + 1 + (o != 0); \
} while (!atomic_compare_exchange_strong(&(shared->M_C(name, _cpt)), &o, n)); \
} while (!atomic_compare_exchange_strong(&(shared->M_F(name, _cpt)), &o, n)); \
if (o == 0) { \
/* Partial initialization: _cpt is odd */ \
/* Call the INIT function once */ \
M_CALL_INIT(oplist, *shared); \
/* Finish initialization: _cpt is even */ \
atomic_fetch_add(&(shared->M_C(name, _cpt)), 1); \
atomic_fetch_add(&(shared->M_F(name, _cpt)), 1); \
} else if ( (o&1) != 0) { \
/* Not fully initialized yet: wait for initialization */ \
m_core_backoff_ct bkoff; \
m_core_backoff_init(bkoff); \
/* Wait for _cpt to be _even */ \
while ((atomic_load(&(shared->M_C(name, _cpt)))&1) != 0 ) { \
while ((atomic_load(&(shared->M_F(name, _cpt)))&1) != 0 ) { \
m_core_backoff_wait(bkoff); \
} \
} \
M_ASSERT( (atomic_load(&(shared->M_C(name, _cpt)))&1) == 0); \
M_ASSERT( (atomic_load(&(shared->M_F(name, _cpt)))&1) == 0); \
} \
return shared; \
} \
, \
/* This function is only for dynamic object */ \
static inline shared_t \
M_C(name, _init_new)(void) \
M_INLINE shared_t \
M_F(name, _init_new)(void) \
{ \
type *ptr = M_CALL_NEW(oplist, type); \
if (ptr == NULL) { \
if (M_UNLIKELY_NOMEM (ptr == NULL)) { \
M_MEMORY_FULL(sizeof(type)); \
return NULL; \
} \
M_CALL_INIT(oplist, *ptr); \
atomic_init (&ptr->M_C(name, _cpt), 2); \
atomic_init (&ptr->M_F(name, _cpt), 2); \
return ptr; \
} \
/* End of NEW */) \
, /* End of INIT */) \
\
static inline void \
M_C(name, _clear)(shared_t shared) \
M_INLINE void \
M_F(name, _clear)(shared_t shared) \
{ \
if (shared != NULL) { \
if (atomic_fetch_sub(&(shared->M_C(name, _cpt)), 2) == 2) { \
if (atomic_fetch_sub(&(shared->M_F(name, _cpt)), 2) == 2) { \
M_CALL_CLEAR(oplist, *shared); \
M_IF_DISABLED_METHOD(DEL, oplist)(, M_CALL_DEL(oplist, shared);) \
} \
} \
} \
\
static inline void \
M_C(name, _clear_ptr)(shared_t *shared) \
M_INLINE void \
M_F(name, _clear_ptr)(shared_t *shared) \
{ \
M_ASSERT(shared != NULL); \
M_C(name, _clear)(*shared); \
M_F(name, _clear)(*shared); \
*shared = NULL; \
} \
\
static inline void \
M_C(name, _reset)(shared_t *shared) \
M_INLINE void \
M_F(name, _reset)(shared_t *shared) \
{ \
M_C(name, _clear)(*shared); \
M_F(name, _clear)(*shared); \
*shared = NULL; \
} \
\
static inline void M_ATTR_DEPRECATED \
M_C(name, _clean)(shared_t *shared) \
{ \
M_C(name, _reset)(shared); \
} \
\
static inline void \
M_C(name, _set)(shared_t *ptr, shared_t shared) \
M_INLINE void \
M_F(name, _set)(shared_t *ptr, shared_t shared) \
{ \
M_ASSERT (ptr != NULL); \
if (M_LIKELY (*ptr != shared)) { \
M_C(name, _clear)(*ptr); \
*ptr = M_C(name, _init_set)(shared); \
M_F(name, _clear)(*ptr); \
*ptr = M_F(name, _init_set)(shared); \
} \
} \
\
M_END_PROTECTED_CODE
/******************************** INTERNAL ***********************************/
#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
+452 -404
View File
File diff suppressed because it is too large. Load diff
+70 -43
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - MEMPOOL module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -27,35 +27,38 @@
#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
*/
#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_F(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) \
@@ -63,40 +66,56 @@
#endif
/********************************** INTERNAL ************************************/
/*****************************************************************************/
/********************************** INTERNAL *********************************/
/*****************************************************************************/
/*
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 M_M3MPOOL_DEF_P2(name, type, name_t) \
M_M3MPOOL_DEF_TYPE(name, type, name_t) \
M_M3MPOOL_DEF_CORE(name, type, name_t)
/* Define the types of the mempool */
#define M_M3MPOOL_DEF_TYPE(name, type, name_t) \
\
/* Define the type of element in a segment of the mempool. \
Either it is the basic type or a pointer to another one. */ \
typedef union M_C(name,_union_s) { \
typedef union M_F(name,_union_s) { \
type t; \
union M_C(name,_union_s) *next; \
} M_C(name,_union_ct); \
union M_F(name,_union_s) *next; \
} M_F(name,_union_ct); \
\
/* Define a segment of a mempool. \
It is an array of basic type, each segment is in a linked list */ \
typedef struct M_C(name,_segment_s) { \
typedef struct M_F(name,_segment_s) { \
unsigned int count; \
struct M_C(name,_segment_s) *next; \
M_C(name,_union_ct) tab[M_USE_MEMPOOL_MAX_PER_SEGMENT(type)]; \
} M_C(name,_segment_ct); \
struct M_F(name,_segment_s) *next; \
M_F(name,_union_ct) tab[M_USE_MEMPOOL_MAX_PER_SEGMENT(type)]; \
} M_F(name,_segment_ct); \
\
/* Define a mempool. \
It is a pointer to the first free object within the segments \
and the segments themselves */ \
typedef struct M_C(name, _s) { \
M_C(name,_union_ct) *free_list; \
M_C(name,_segment_ct) *current_segment; \
typedef struct M_F(name, _s) { \
M_F(name,_union_ct) *free_list; \
M_F(name,_segment_ct) *current_segment; \
} name_t[1]; \
/* Define the core functions of the mempool */
#define M_M3MPOOL_DEF_CORE(name, type, name_t) \
\
static inline void \
M_C(name,_init)(name_t mem) \
M_INLINE void \
M_F(name,_init)(name_t mem) \
{ \
mem->free_list = NULL; \
mem->current_segment = M_MEMORY_ALLOC(M_C(name,_segment_ct)); \
if (mem->current_segment == NULL) { \
M_MEMORY_FULL(sizeof (M_C(name,_segment_ct))); \
mem->current_segment = M_MEMORY_ALLOC(M_F(name,_segment_ct)); \
if (M_UNLIKELY_NOMEM(mem->current_segment == NULL)) { \
M_MEMORY_FULL(sizeof (M_F(name,_segment_ct))); \
return; \
} \
mem->current_segment->next = NULL; \
@@ -104,13 +123,13 @@
M_M3MPOOL_CONTRACT(mem, type); \
} \
\
static inline void \
M_C(name,_clear)(name_t mem) \
M_INLINE void \
M_F(name,_clear)(name_t mem) \
{ \
M_M3MPOOL_CONTRACT(mem, type); \
M_C(name,_segment_ct) *segment = mem->current_segment; \
M_F(name,_segment_ct) *segment = mem->current_segment; \
while (segment != NULL) { \
M_C(name,_segment_ct) *next = segment->next; \
M_F(name,_segment_ct) *next = segment->next; \
M_MEMORY_DEL (segment); \
segment = next; \
} \
@@ -119,26 +138,26 @@
mem->current_segment = NULL; \
} \
\
static inline type * \
M_C(name,_alloc)(name_t mem) \
M_INLINE type * \
M_F(name,_alloc)(name_t mem) \
{ \
M_M3MPOOL_CONTRACT(mem, type); \
/* Test if one object is in the free list */ \
M_C(name,_union_ct) *ret = mem->free_list; \
M_F(name,_union_ct) *ret = mem->free_list; \
if (ret != NULL) { \
/* Yes, so return it, and pop it from the free list */ \
mem->free_list = ret->next; \
return &ret->t; \
} \
/* No cheap free object exist. Test within a segment */ \
M_C(name,_segment_ct) *segment = mem->current_segment; \
M_F(name,_segment_ct) *segment = mem->current_segment; \
M_ASSERT(segment != NULL); \
unsigned int count = segment->count; \
/* If segment is full, allocate a new one from the system */ \
if (M_UNLIKELY (count >= M_USE_MEMPOOL_MAX_PER_SEGMENT(type))) { \
M_C(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (M_C(name,_segment_ct)); \
if (M_UNLIKELY (new_segment == NULL)) { \
M_MEMORY_FULL(sizeof (M_C(name,_segment_ct))); \
M_F(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (M_F(name,_segment_ct)); \
if (M_UNLIKELY_NOMEM (new_segment == NULL)) { \
M_MEMORY_FULL(sizeof (M_F(name,_segment_ct))); \
return NULL; \
} \
new_segment->next = segment; \
@@ -154,13 +173,13 @@
return &ret->t; \
} \
\
static inline void \
M_C(name,_free)(name_t mem, type *ptr) \
M_INLINE void \
M_F(name,_free)(name_t mem, type *ptr) \
{ \
M_M3MPOOL_CONTRACT(mem, type); \
/* NOTE: Unsafe cast: suppose that the given pointer \
was allocated by the previous alloc function. */ \
M_C(name,_union_ct) *ret = (M_C(name,_union_ct) *)(uintptr_t)ptr; \
M_F(name,_union_ct) *ret = (M_F(name,_union_ct) *)(uintptr_t)ptr; \
/* Add the object back in the free list */ \
ret->next = mem->free_list; \
mem->free_list = ret; \
@@ -169,11 +188,19 @@
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)
/********************************** INTERNAL *********************************/
#if M_USE_SMALL_NAME
#define MEMPOOL_DEF M_MEMPOOL_DEF
#define MEMPOOL_DEF_AS M_MEMPOOL_DEF_AS
#endif
#endif
+5 -504
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Thin Mutex & Thread wrapper
* M*LIB - Thin Mutex & Thread wrapper (compatibility layer)
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -22,506 +22,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MSTARLIB_MUTEX_H
#define MSTARLIB_MUTEX_H
/* Auto-detect the thread backend to use if the user has not override it */
#ifndef M_USE_THREAD_BACKEND
# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \
&& !defined(__STDC_NO_THREADS__)
# define M_USE_THREAD_BACKEND 1
# elif defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
# define M_USE_THREAD_BACKEND 2
# else
# define M_USE_THREAD_BACKEND 3
# endif
#endif
/****************************** C11 version ********************************/
#if M_USE_THREAD_BACKEND == 1
#include <threads.h>
#include <assert.h>
#include <stdbool.h>
#include "m-core.h"
M_BEGIN_PROTECTED_CODE
/* Define a mutex type based on C11 definition */
typedef mtx_t m_mutex_t[1];
/* Define a condition variable type based on C11 definition */
typedef cnd_t m_cond_t[1];
/* Define a thread type based on C11 definition */
typedef thrd_t m_thread_t[1];
/* Initialize the mutex (constructor) */
static inline void m_mutex_init(m_mutex_t m)
{
int rc = mtx_init(m, mtx_plain);
// Abort program in case of initialization failure
// There is really nothing else to do if a mutex cannot be constructed
M_ASSERT_INIT (rc == 0, "mutex");
}
/* Clear the mutex (destructor) */
static inline void m_mutex_clear(m_mutex_t m)
{
mtx_destroy(m);
}
/* Lock the mutex */
static inline void m_mutex_lock(m_mutex_t m)
{
mtx_lock(m);
}
/* Unlock the mutex */
static inline void m_mutex_unlock(m_mutex_t m)
{
mtx_unlock(m);
}
/* Initialize the condition variable (constructor) */
static inline void m_cond_init(m_cond_t c)
{
int rc = cnd_init(c);
// Abort program in case of initialization failure
// There is really nothing else to do if the object cannot be constructed
M_ASSERT_INIT (rc == 0, "conditional variable");
}
/* Clear the condition variable (destructor) */
static inline void m_cond_clear(m_cond_t c)
{
cnd_destroy(c);
}
/* Signal the condition variable to at least one waiting thread */
static inline void m_cond_signal(m_cond_t c)
{
cnd_signal(c);
}
/* Signal the condition variable to all waiting threads */
static inline void m_cond_broadcast(m_cond_t c)
{
cnd_broadcast(c);
}
/* Wait for signaling the condition variable by another thread */
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
{
cnd_wait(c, m);
}
/* Create the thread (constructor) and start it */
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void* arg)
{
int rc = thrd_create(t, (int(*)(void*))(void(*)(void))func, arg);
// Abort program in case of initialization failure
M_ASSERT_INIT (rc == thrd_success, "thread");
}
/* Wait for the thread to terminate and destroy it (destructor) */
static inline void m_thread_join(m_thread_t t)
{
int rc = thrd_join(*t, NULL);
M_ASSERT (rc == thrd_success);
// Avoid warning about variable unused.
(void) rc;
}
/* The thread has nothing meaningfull to do.
Inform the OS to let other threads be scheduled */
static inline void m_thread_yield(void)
{
thrd_yield();
}
/* Sleep the thread for at least usec microseconds.
Return true if the sleep was successful */
static inline bool m_thread_sleep(unsigned long long usec)
{
struct timespec tv;
tv.tv_sec = (long) (usec / 1000000ULL);
tv.tv_nsec = (long) ((usec % 1000000ULL) * 1000UL);
int retval = thrd_sleep(&tv, NULL);
return retval == 0;
}
// Internal type, not exported.
typedef once_flag m_once_ct[1];
// Initial value for m_once_ct
#define M_ONCEI_INIT_VALUE { ONCE_FLAG_INIT }
// Call the function exactly once
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
{
call_once(o,func);
}
// Attribute to use to allocate a global variable to a thread.
#define M_THREAD_ATTR _Thread_local
M_END_PROTECTED_CODE
/****************************** WIN32 version ******************************/
#elif M_USE_THREAD_BACKEND == 2
/* CLANG provides some useless and wrong warnings:
* - _WIN32_WINNT starts with '_' which is reserved by the standard
* as per the MSVC compiler, it is needed to be defined by the user
* to define which version of windows it want to be compatible with.
* - windows.h may be different than the case used by the file sytem
* there is however no normalized case.
*
* So, theses warnings have to be ignored and are disabled.
*
* We cannot add theses warnings in M_BEGIN_PROTECTED_CODE
* as they need to be disabled **BEFORE** including any system header
* and m-core includes some system headers.
* So we need to disable them explictly here.
*/
#if defined(__clang__) && __clang_major__ >= 4
_Pragma("clang diagnostic push")
_Pragma("clang diagnostic ignored \"-Wreserved-id-macro\"")
_Pragma("clang diagnostic ignored \"-Wnonportable-system-include-path\"")
#endif
/* CriticalSection & ConditionVariable are available from Windows Vista */
#ifndef WINVER
#define WINVER _WIN32_WINNT_VISTA
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT _WIN32_WINNT_VISTA
#endif
/* Include system headers */
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include "m-core.h"
#if defined(__clang__) && __clang_major__ >= 4
_Pragma("clang diagnostic pop")
#endif
M_BEGIN_PROTECTED_CODE
/* Define a thread type based on WINDOWS definition */
typedef HANDLE m_thread_t[1];
/* Define a mutex type based on WINDOWS definition */
typedef CRITICAL_SECTION m_mutex_t[1];
/* Define a condition variable type based on WINDOWS definition */
typedef CONDITION_VARIABLE m_cond_t[1];
/* Initialize a mutex (Constructor)*/
static inline void m_mutex_init(m_mutex_t m)
{
InitializeCriticalSection(m);
}
/* Clear a mutex (destructor) */
static inline void m_mutex_clear(m_mutex_t m)
{
DeleteCriticalSection(m);
}
/* Lock a mutex */
static inline void m_mutex_lock(m_mutex_t m)
{
EnterCriticalSection(m);
}
/* Unlock a mutex */
static inline void m_mutex_unlock(m_mutex_t m)
{
LeaveCriticalSection(m);
}
/* Initialize a condition variable (constructor) */
static inline void m_cond_init(m_cond_t c)
{
InitializeConditionVariable(c);
}
/* Clear a condition variable (destructor) */
static inline void m_cond_clear(m_cond_t c)
{
(void) c; // There is no destructor for this object.
}
/* Signal a condition variable to at least one waiting thread */
static inline void m_cond_signal(m_cond_t c)
{
WakeConditionVariable(c);
}
/* Signal a condition variable to all waiting threads */
static inline void m_cond_broadcast(m_cond_t c)
{
WakeAllConditionVariable(c);
}
/* Wait for a condition variable */
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
{
SleepConditionVariableCS(c, m, INFINITE);
}
/* Create a thread (constructor) and start it */
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void *arg)
{
*t = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) (uintptr_t) func, arg, 0, NULL);
M_ASSERT_INIT (*t != NULL, "thread");
}
/* Wait for the thread to terminate and destroy it (destructor) */
static inline void m_thread_join(m_thread_t t)
{
DWORD dwWaitResult = WaitForSingleObject(*t, INFINITE);
(void) dwWaitResult;
M_ASSERT (dwWaitResult == WAIT_OBJECT_0);
CloseHandle(*t);
}
/* The thread has nothing meaningfull to do.
Inform the OS to let other threads be scheduled */
static inline void m_thread_yield(void)
{
Sleep(0);
}
/* Sleep the thread for at least usec microseconds
Return true if the sleep was successful */
static inline bool m_thread_sleep(unsigned long long usec)
{
LARGE_INTEGER ft;
M_ASSERT (usec <= LLONG_MAX);
ft.QuadPart = -(10LL*(long long) usec);
HANDLE hd = CreateWaitableTimer(NULL, TRUE, NULL);
M_ASSERT_INIT (hd != NULL, "timer");
SetWaitableTimer(hd, &ft, 0, NULL, NULL, 0);
DWORD dwWaitResult = WaitForSingleObject(hd, INFINITE);
CloseHandle(hd);
return dwWaitResult == WAIT_OBJECT_0;
}
// 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)
{
void (*func)(void);
(void) InitOnce;
(void) lpContext;
func = (void (*)(void))(uintptr_t) Parameter;
(*func)();
return TRUE;
}
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
{
InitOnceExecuteOnce(o, m_oncei_callback, (void*)(intptr_t)func, NULL);
}
#if defined(_MSC_VER)
// Attribute to use to allocate a global variable to a thread (MSVC def).
# define M_THREAD_ATTR __declspec( thread )
#else
// Attribute to use to allocate a global variable to a thread (GCC def).
# define M_THREAD_ATTR __thread
#endif
M_END_PROTECTED_CODE
/**************************** PTHREAD version ******************************/
#else
#include <pthread.h>
#ifdef _POSIX_PRIORITY_SCHEDULING
#include <sched.h>
#endif
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include <stdbool.h>
#include "m-core.h"
M_BEGIN_PROTECTED_CODE
/* Define a mutex type based on PTHREAD definition */
typedef pthread_mutex_t m_mutex_t[1];
/* Define a condition variable type based on PTHREAD definition */
typedef pthread_cond_t m_cond_t[1];
/* Define a thread type based on PTHREAD definition */
typedef pthread_t m_thread_t[1];
/* Initialize the mutex (constructor) */
static inline void m_mutex_init(m_mutex_t m)
{
int _rc = pthread_mutex_init(m, NULL);
// Abort program in case of initialization failure
// There is really nothing else to do if a mutex cannot be constructed
M_ASSERT_INIT (_rc == 0, "mutex");
}
/* Clear the mutex (destructor) */
static inline void m_mutex_clear(m_mutex_t m)
{
pthread_mutex_destroy(m);
}
/* Lock the mutex */
static inline void m_mutex_lock(m_mutex_t m)
{
pthread_mutex_lock(m);
}
/* Unlock the mutex */
static inline void m_mutex_unlock(m_mutex_t m)
{
pthread_mutex_unlock(m);
}
/* Lazy lock initialization */
#define M_MUTEXI_INIT_VALUE { PTHREAD_MUTEX_INITIALIZER }
/* Internal function compatible with lazy lock */
static inline void m_mutexi_lazy_lock(m_mutex_t m)
{
pthread_mutex_lock(m);
}
/* Initialize the condition variable (constructor) */
static inline void m_cond_init(m_cond_t c)
{
int _rc = pthread_cond_init(c, NULL);
// Abort program in case of initialization failure
// There is really nothing else to do if a mutex cannot be constructed
M_ASSERT_INIT (_rc == 0, "conditional variable");
}
/* Clear the condition variable (destructor) */
static inline void m_cond_clear(m_cond_t c)
{
pthread_cond_destroy(c);
}
/* Signal a condition variable to at least a waiting thread */
static inline void m_cond_signal(m_cond_t c)
{
pthread_cond_signal(c);
}
/* Signal a condition variable to all waiting threads */
static inline void m_cond_broadcast(m_cond_t c)
{
pthread_cond_broadcast(c);
}
/* Waiting for a condition variable */
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
{
pthread_cond_wait(c, m);
}
/* Create a thread (constructor) and start it */
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void *arg)
{
int _rc = pthread_create(t, NULL, (void*(*)(void*))(void(*)(void))func, arg);
M_ASSERT_INIT (_rc == 0, "thread");
}
/* Wait for the thread to terminate and destroy it (destructor) */
static inline void m_thread_join(m_thread_t t)
{
int _rc = pthread_join(*t, NULL);
(void)_rc; // Avoid warning about variable unused.
M_ASSERT (_rc == 0);
}
/* The thread has nothing meaningfull to do.
Inform the OS to let other threads be scheduled */
static inline void m_thread_yield(void)
{
#ifdef _POSIX_PRIORITY_SCHEDULING
sched_yield();
#endif
}
/* Sleep for at least usec microseconds
Return true if the sleep was successful */
static inline bool m_thread_sleep(unsigned long long usec)
{
struct timeval tv;
/* We don't want to use usleep or nanosleep so that
we remain compatible with strict C99 build */
tv.tv_sec = (time_t) (usec / 1000000ULL);
tv.tv_usec = (suseconds_t) (usec % 1000000ULL);
int retval = select(1, NULL, NULL, NULL, &tv);
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))
{
pthread_once(o,func);
}
#define M_THREAD_ATTR __thread
M_END_PROTECTED_CODE
#endif
// TODO: Obsolete M_LOCK macro.
/* M_LOCK macro. Allow simple locking encapsulation.
USAGE:
static M_LOCK_DECL(name);
int f(int n) {
M_LOCK(name) {
// Exclusive access
}
}
*/
/* NOTE: Either using direct support by the OS (WIN32/PTHREAD)
or using C11's ONCE mechanism */
#ifdef M_MUTEXI_INIT_VALUE
# define M_LOCK_DECL(name) m_mutex_t name = M_MUTEXI_INIT_VALUE
# define M_LOCK(name) \
M_LOCKI_DO(name, M_C(local_cont_, __LINE__), m_mutexi_lazy_lock, m_mutex_unlock)
#else
# define M_LOCK_DECL(name) \
m_mutex_t name; \
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
# define M_LOCKI_BY_ONCE(name) \
(m_oncei_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)
#endif
#define M_LOCKI_DO(name, cont, lock_func, unlock_func) \
for(bool cont = true \
; cont && (lock_func (name), true); \
(unlock_func (name), cont = false))
#if defined(__GNUC__) && __GNUC__ >= 4
#warning "m-mutex.h is an obsolete header. Use m-thread.h instead."
#endif
#include "m-thread.h"
+284 -206
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - dynamic priority queue module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -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_F(name,_t), M_F(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,14 +49,15 @@
/* 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__ )))
/********************************** INTERNAL ************************************/
/*****************************************************************************/
/********************************** INTERNAL *********************************/
/*****************************************************************************/
/* Deferred evaluation for the definition,
so that all arguments are evaluated before further expansion */
@@ -72,38 +73,46 @@
/* Define oplist of a priority queue */
#define M_PR1OQUEUE_OPLIST_P3(name, oplist) \
(INIT(M_C(name, _init)) \
,INIT_SET(M_C(name, _init_set)) \
(INIT(M_F(name, _init)) \
,INIT_SET(M_F(name, _init_set)) \
,INIT_WITH(API_1(M_INIT_VAI)) \
,SET(M_C(name, _set)) \
,CLEAR(M_C(name, _clear)) \
,INIT_MOVE(M_C(name, _init_move)) \
,MOVE(M_C(name, _move)) \
,SWAP(M_C(name, _swap)) \
,SET(M_F(name, _set)) \
,CLEAR(M_F(name, _clear)) \
,INIT_MOVE(M_F(name, _init_move)) \
,MOVE(M_F(name, _move)) \
,SWAP(M_F(name, _swap)) \
,NAME(name) \
,TYPE(M_C(name,_ct)) \
,SUBTYPE(M_C(name, _subtype_ct)) \
,RESET(M_C(name,_reset)) \
,PUSH(M_C(name,_push)) \
,POP(M_C(name,_pop)) \
,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \
,SUBTYPE(M_F(name, _subtype_ct)) \
,RESET(M_F(name,_reset)) \
,PUSH(M_F(name,_push)) \
,POP(M_F(name,_pop)) \
,OPLIST(oplist) \
,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)), \
,EMPTY_P(M_F(name, _empty_p)) \
,GET_SIZE(M_F(name, _size)) \
,IT_TYPE(M_F(name, _it_ct)) \
,IT_FIRST(M_F(name,_it)) \
,IT_END(M_F(name,_it_end)) \
,IT_SET(M_F(name,_it_set)) \
,IT_END_P(M_F(name,_end_p)) \
,IT_EQUAL_P(M_F(name,_it_equal_p)) \
,IT_LAST_P(M_F(name,_last_p)) \
,IT_NEXT(M_F(name,_next)) \
,IT_CREF(M_F(name,_cref)) \
,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_F(name, _get_str)),) \
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_F(name, _parse_str)),) \
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \
,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_F(name, _in_str)),) \
,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_F(name, _out_serial)),) \
,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_F(name, _in_serial)),) \
)
/********************************** INTERNAL *********************************/
/* 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) \
@@ -121,322 +130,391 @@
- it_t: iterator of the container
*/
#define M_PR1OQUEUE_DEF_P3(name, type, oplist, prioqueue_t, it_t) \
\
/* Definition of the internal array used to construct the priority queue */ \
ARRAY_DEF(M_C(name, _array), type, oplist) \
ARRAY_DEF(M_F(name, _array), type, oplist) \
M_PR1OQUEUE_DEF_TYPE(name, type, oplist, prioqueue_t, it_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_PR1OQUEUE_DEF_CORE(name, type, oplist, prioqueue_t, it_t) \
M_PR1OQUEUE_DEF_IT(name, type, oplist, prioqueue_t, it_t) \
M_PR1OQUEUE_DEF_IO(name, type, oplist, prioqueue_t, it_t) \
M_EMPLACE_QUEUE_DEF(name, prioqueue_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
/* Define the types */
#define M_PR1OQUEUE_DEF_TYPE(name, type, oplist, prioqueue_t, it_t) \
\
/* Define the priority queue over the defined array */ \
typedef struct M_C(name, _s) { \
M_C(name, _array_t) array; \
typedef struct M_F(name, _s) { \
M_F(name, _array_t) array; \
} prioqueue_t[1]; \
/* Define the pointer references to the priority queue */ \
typedef struct M_C(name, _s) *M_C(name, _ptr); \
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
typedef struct M_F(name, _s) *M_F(name, _ptr); \
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
\
/* The iterator is the same one as the one of the internal array */ \
typedef M_C(name, _array_it_t) it_t; \
typedef M_F(name, _array_it_t) it_t; \
\
/* Definition of the internal types used by the oplist */ \
typedef prioqueue_t M_C(name, _ct); \
typedef type M_C(name, _subtype_ct); \
typedef it_t M_C(name, _it_ct); \
typedef prioqueue_t M_F(name, _ct); \
typedef type M_F(name, _subtype_ct); \
typedef it_t M_F(name, _it_ct); \
/* Define the core functions */
#define M_PR1OQUEUE_DEF_CORE(name, type, oplist, prioqueue_t, it_t) \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void \
M_C(name, _init)(prioqueue_t p) \
M_INLINE void \
M_F(name, _init)(prioqueue_t p) \
{ \
M_C(name, _array_init)(p->array); \
M_F(name, _array_init)(p->array); \
} \
\
static inline void \
M_C(name, _init_set)(prioqueue_t p, prioqueue_t const o) \
M_INLINE void \
M_F(name, _init_set)(prioqueue_t p, prioqueue_t const o) \
{ \
M_C(name, _array_init_set)(p->array, o->array); \
M_F(name, _array_init_set)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _set)(prioqueue_t p, prioqueue_t const o) \
M_INLINE void \
M_F(name, _set)(prioqueue_t p, prioqueue_t const o) \
{ \
M_C(name, _array_set)(p->array, o->array); \
M_F(name, _array_set)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _clear)(prioqueue_t p) \
M_INLINE void \
M_F(name, _clear)(prioqueue_t p) \
{ \
M_C(name, _array_clear)(p->array); \
M_F(name, _array_clear)(p->array); \
} \
\
static inline void \
M_C(name, _init_move)(prioqueue_t p, prioqueue_t o) \
M_INLINE void \
M_F(name, _init_move)(prioqueue_t p, prioqueue_t o) \
{ \
M_C(name, _array_init_move)(p->array, o->array); \
M_F(name, _array_init_move)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _move)(prioqueue_t p, prioqueue_t o) \
M_INLINE void \
M_F(name, _move)(prioqueue_t p, prioqueue_t o) \
{ \
M_C(name, _array_move)(p->array, o->array); \
M_F(name, _array_move)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _swap)(prioqueue_t p, prioqueue_t o) \
M_INLINE void \
M_F(name, _swap)(prioqueue_t p, prioqueue_t o) \
{ \
M_C(name, _array_swap)(p->array, o->array); \
M_F(name, _array_swap)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _reset)(prioqueue_t p) \
M_INLINE void \
M_F(name, _reset)(prioqueue_t p) \
{ \
M_C(name, _array_reset)(p->array); \
M_F(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) \
M_INLINE size_t \
M_F(name, _i_parent)(size_t i) \
{ \
M_ASSERT (i > 0); \
return (i - 1) / 2; \
} \
\
static inline size_t \
M_C(name, _i_lchild)(size_t i) \
M_INLINE size_t \
M_F(name, _i_lchild)(size_t i) \
{ \
M_ASSERT(i <= ((SIZE_MAX)-2)/2); \
return 2*i + 1; \
} \
\
static inline size_t \
M_C(name, _i_rchild)(size_t i) \
M_INLINE size_t \
M_F(name, _i_rchild)(size_t i) \
{ \
M_ASSERT(i <= ((SIZE_MAX)-2)/2); \
return 2*i + 2; \
} \
\
static inline int \
M_C(name, _i_cmp)(const prioqueue_t p, size_t i, size_t j) \
M_INLINE int \
M_F(name, _i_cmp)(const prioqueue_t p, size_t i, size_t j) \
{ \
return M_CALL_CMP(oplist, *M_C(name, _array_cget)(p->array, i), \
*M_C(name, _array_cget)(p->array, j)); \
return M_CALL_CMP(oplist, *M_F(name, _array_cget)(p->array, i), \
*M_F(name, _array_cget)(p->array, j)); \
} \
\
static inline bool \
M_C(name, _empty_p)(prioqueue_t const p) \
M_INLINE bool \
M_F(name, _empty_p)(prioqueue_t const p) \
{ \
return M_C(name, _array_empty_p)(p->array); \
return M_F(name, _array_empty_p)(p->array); \
} \
\
static inline size_t \
M_C(name, _size)(prioqueue_t const p) \
M_INLINE size_t \
M_F(name, _size)(prioqueue_t const p) \
{ \
return M_C(name, _array_size)(p->array); \
return M_F(name, _array_size)(p->array); \
} \
\
static inline void \
M_C(name, _push)(prioqueue_t p, type const x) \
M_INLINE void \
M_F(name, _push)(prioqueue_t p, type const x) \
{ \
/* Push back the new element at the end of the array */ \
M_C(name, _array_push_back)(p->array, x); \
M_F(name, _array_push_back)(p->array, x); \
\
/* Reorder the array by swapping with its parent \
* until it reaches the right position */ \
size_t i = M_C(name, _array_size)(p->array)-1; \
size_t i = M_F(name, _array_size)(p->array)-1; \
while (i > 0) { \
size_t j = M_C(name, _i_parent)(i); \
if (M_C(name, _i_cmp)(p, j, i) <= 0) \
size_t j = M_F(name, _i_parent)(i); \
if (M_F(name, _i_cmp)(p, j, i) <= 0) \
break; \
M_C(name, _array_swap_at) (p->array, i, j); \
M_F(name, _array_swap_at) (p->array, i, j); \
i = j; \
} \
} \
\
static inline type const * \
M_C(name, _front)(prioqueue_t const p) \
M_INLINE type const * \
M_F(name, _front)(prioqueue_t const p) \
{ \
return M_C(name, _array_cget)(p->array, 0); \
return M_F(name, _array_cget)(p->array, 0); \
} \
\
static inline void \
M_C(name, _pop)(type *x, prioqueue_t p) \
M_INLINE void \
M_F(name, _pop)(type *x, prioqueue_t p) \
{ \
/* Swap the front element with the last element */ \
size_t size = M_C(name, _array_size)(p->array)-1; \
M_C(name, _array_swap_at) (p->array, 0, size); \
size_t size = M_F(name, _array_size)(p->array)-1; \
M_F(name, _array_swap_at) (p->array, 0, size); \
/* Swap the new last element */ \
M_C(name, _array_pop_back)(x, p->array); \
M_F(name, _array_pop_back)(x, p->array); \
\
/* Reorder the heap */ \
size_t i = 0; \
while (true) { \
size_t child = M_C(name, _i_lchild)(i); \
size_t child = M_F(name, _i_lchild)(i); \
if (child >= size) \
break; \
size_t otherChild = M_C(name, _i_rchild)(i); \
size_t otherChild = M_F(name, _i_rchild)(i); \
if (otherChild < size \
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
&& M_F(name, _i_cmp)(p, otherChild, child) < 0 ) { \
child = otherChild; \
} \
if (M_C(name, _i_cmp)(p, i, child) <= 0) \
if (M_F(name, _i_cmp)(p, i, child) <= 0) \
break; \
M_C(name, _array_swap_at) (p->array, i, child); \
M_F(name, _array_swap_at) (p->array, i, child); \
i = child; \
} \
} \
\
/* Define iterators over the array iterator */ \
static inline void \
M_C(name, _it)(it_t it, prioqueue_t const v) \
{ \
M_C(name, _array_it)(it, v->array); \
} \
\
static inline void \
M_C(name, _it_last)(it_t it, prioqueue_t const v) \
{ \
M_C(name, _array_it_last)(it, v->array); \
} \
\
static inline void \
M_C(name, _it_end)(it_t it, prioqueue_t const v) \
{ \
M_C(name, _array_it_end)(it, v->array); \
} \
\
static inline void \
M_C(name, _it_set)(it_t it, const it_t org) \
{ \
M_C(name, _array_it_set)(it, org); \
} \
\
static inline bool \
M_C(name, _end_p)(const it_t it) \
{ \
return M_C(name, _array_end_p)(it); \
} \
\
static inline bool \
M_C(name, _last_p)(const it_t it) \
{ \
return M_C(name, _array_last_p)(it); \
} \
\
static inline bool \
M_C(name, _it_equal_p)(const it_t it1, \
const it_t it2) \
{ \
return M_C(name, _array_it_equal_p)(it1, it2); \
} \
\
static inline void \
M_C(name, _next)(it_t it) \
{ \
M_C(name, _array_next)(it); \
} \
\
static inline void \
M_C(name, _previous)(it_t it) \
{ \
M_C(name, _array_previous)(it); \
} \
\
static inline type const * \
M_C(name, _cref)(const it_t it) \
{ \
return M_C(name, _array_cref)(it); \
} \
\
M_IF_METHOD(EQUAL, oplist) \
( \
/* EQUAL & CMP may be uncorrelated */ \
static inline bool \
M_C(name, _equal_p)(prioqueue_t const p, prioqueue_t const q) \
M_INLINE bool \
M_F(name, _equal_p)(prioqueue_t const p, prioqueue_t const q) \
{ \
return M_C(name, _array_equal_p)(p->array, q->array); \
return M_F(name, _array_equal_p)(p->array, q->array); \
} \
\
static inline bool \
M_C(name, _erase)(prioqueue_t p, type x) \
M_INLINE size_t \
M_F(name, _i_find)(prioqueue_t p, type const x) \
{ \
/* First pass: search for an item EQUAL to x */ \
/* NOTE: An HASHMAP may be a good idea to optimize this pass. */ \
size_t size = M_C(name, _array_size)(p->array); \
size_t size = M_F(name, _array_size)(p->array); \
size_t i = 0; \
for(i = 0; i < size; i++) { \
if (M_CALL_EQUAL(oplist, *M_C(name, _array_cget)(p->array, i), x)) \
/* We cannot use CMP and the partial order to go faster \
EQUAL & CMP may be uncorrelated */ \
if (M_CALL_EQUAL(oplist, *M_F(name, _array_cget)(p->array, i), x)) \
break; \
} \
return i; \
} \
\
M_INLINE bool \
M_F(name, _erase)(prioqueue_t p, type const x) \
{ \
/* First pass: search for an item EQUAL to x */ \
size_t size = M_F(name, _array_size)(p->array); \
size_t i = M_F(name, _i_find)(p, x); \
/* If x is not found, then stop */ \
if (i >= size) \
return false; \
/* Swap the found item and the last element */ \
size--; \
M_C(name, _array_swap_at) (p->array, i, size); \
M_C(name, _array_pop_back)(NULL, p->array); \
M_F(name, _array_swap_at) (p->array, i, size); \
M_F(name, _array_pop_back)(NULL, p->array); \
/* Move back the last swapped element to its right position in the heap */ \
while (true) { \
size_t child = M_C(name, _i_lchild)(i); \
size_t child = M_F(name, _i_lchild)(i); \
if (child >= size) break; \
size_t otherChild = M_C(name, _i_rchild)(i); \
size_t otherChild = M_F(name, _i_rchild)(i); \
if (otherChild < size \
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
&& M_F(name, _i_cmp)(p, otherChild, child) < 0 ) { \
child = otherChild; \
} \
if (M_C(name, _i_cmp)(p, i, child) <= 0) break; \
M_C(name, _array_swap_at) (p->array, i, child); \
if (M_F(name, _i_cmp)(p, i, child) <= 0) break; \
M_F(name, _array_swap_at) (p->array, i, child); \
i = child; \
} \
return true; \
} \
\
static inline void \
M_C(name, _update)(prioqueue_t p, type const xold, type const xnew) \
M_INLINE void \
M_F(name, _update)(prioqueue_t p, type const xold, type const xnew) \
{ \
/* NOTE: xold can be the same pointer than xnew */ \
/* First pass: search for an item EQUAL to x */ \
size_t size = M_C(name, _array_size)(p->array); \
size_t i = 0; \
for(i = 0; i < size; i++) { \
if (M_CALL_EQUAL(oplist, *M_C(name, _array_cget)(p->array, i), xold)) \
break; \
} \
size_t size = M_F(name, _array_size)(p->array); \
size_t i = M_F(name, _i_find)(p, xold); \
/* We shall have found the item */ \
M_ASSERT (i < size); \
/* Test if the position of the old data is further or nearer than the new */ \
int cmp = M_CALL_CMP(oplist, *M_C(name, _array_cget)(p->array, i), xnew); \
int cmp = M_CALL_CMP(oplist, *M_F(name, _array_cget)(p->array, i), xnew); \
/* Set the found item to the new element */ \
M_C(name, _array_set_at) (p->array, i, xnew); \
M_F(name, _array_set_at) (p->array, i, xnew); \
if (cmp < 0) { \
/* Move back the updated element to its new position, further in the heap */ \
while (true) { \
size_t child = M_C(name, _i_lchild)(i); \
size_t child = M_F(name, _i_lchild)(i); \
if (child >= size) break; \
size_t otherChild = M_C(name, _i_rchild)(i); \
size_t otherChild = M_F(name, _i_rchild)(i); \
if (otherChild < size \
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
&& M_F(name, _i_cmp)(p, otherChild, child) < 0 ) { \
child = otherChild; \
} \
if (M_C(name, _i_cmp)(p, i, child) <= 0) break; \
M_C(name, _array_swap_at) (p->array, i, child); \
if (M_F(name, _i_cmp)(p, i, child) <= 0) break; \
M_F(name, _array_swap_at) (p->array, i, child); \
i = child; \
} \
} else { \
/* Move back the updated element to its new position, nearest in the heap */ \
while (i > 0) { \
size_t parent = M_C(name, _i_parent)(i); \
if (M_C(name, _i_cmp)(p, parent, i) <= 0) break; \
M_C(name, _array_swap_at) (p->array, i, parent); \
size_t parent = M_F(name, _i_parent)(i); \
if (M_F(name, _i_cmp)(p, parent, i) <= 0) break; \
M_F(name, _array_swap_at) (p->array, i, parent); \
i = parent; \
} \
} \
} \
, /* No EQUAL */ ) \
/* Define the IT based functions */
#define M_PR1OQUEUE_DEF_IT(name, type, oplist, prioqueue_t, it_t) \
\
/* Define iterators over the array iterator */ \
M_INLINE void \
M_F(name, _it)(it_t it, prioqueue_t const v) \
{ \
M_F(name, _array_it)(it, v->array); \
} \
\
M_INLINE void \
M_F(name, _it_last)(it_t it, prioqueue_t const v) \
{ \
M_F(name, _array_it_last)(it, v->array); \
} \
\
M_INLINE void \
M_F(name, _it_end)(it_t it, prioqueue_t const v) \
{ \
M_F(name, _array_it_end)(it, v->array); \
} \
\
M_INLINE void \
M_F(name, _it_set)(it_t it, const it_t org) \
{ \
M_F(name, _array_it_set)(it, org); \
} \
\
M_INLINE bool \
M_F(name, _end_p)(const it_t it) \
{ \
return M_F(name, _array_end_p)(it); \
} \
\
M_INLINE bool \
M_F(name, _last_p)(const it_t it) \
{ \
return M_F(name, _array_last_p)(it); \
} \
\
M_INLINE bool \
M_F(name, _it_equal_p)(const it_t it1, \
const it_t it2) \
{ \
return M_F(name, _array_it_equal_p)(it1, it2); \
} \
\
M_INLINE void \
M_F(name, _next)(it_t it) \
{ \
M_F(name, _array_next)(it); \
} \
\
M_INLINE void \
M_F(name, _previous)(it_t it) \
{ \
M_F(name, _array_previous)(it); \
} \
\
M_INLINE type const * \
M_F(name, _cref)(const it_t it) \
{ \
return M_F(name, _array_cref)(it); \
} \
/* Define the IO functions */
#define M_PR1OQUEUE_DEF_IO(name, type, oplist, prioqueue_t, it_t) \
M_IF_METHOD(OUT_STR, oplist)( \
M_INLINE void \
M_F(name, _out_str)(FILE *file, const prioqueue_t p) \
{ \
M_F(name, _array_out_str)(file, p->array); \
} \
,/* No OUT_STR */) \
\
M_IF_METHOD(IN_STR, oplist)( \
M_INLINE bool \
M_F(name, _in_str)(prioqueue_t p, FILE *file) \
{ \
return M_F(name, _array_in_str)(p->array, file); \
} \
,/* No IN_STR */) \
\
M_IF_METHOD(GET_STR, oplist)( \
M_INLINE void \
M_F(name, _get_str)(string_t str, const prioqueue_t p, bool append) \
{ \
M_F(name, _array_get_str)(str, p->array, append); \
} \
,/* No GET_STR */) \
\
M_IF_METHOD(PARSE_STR, oplist)( \
M_INLINE bool \
M_F(name, _parse_str)(prioqueue_t p, const char str[], const char **endp) \
{ \
return M_F(name, _array_parse_str)(p->array, str, endp); \
} \
,/* No PARSE_STR */) \
\
M_IF_METHOD(OUT_SERIAL, oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _out_serial)(m_serial_write_t f, const prioqueue_t p) \
{ \
return M_F(name, _array_out_serial)(f, p->array); \
} \
,/* No OUT_SERIAL */) \
\
M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _in_serial)(prioqueue_t p, m_serial_read_t f) \
{ \
return M_F(name, _array_in_serial)(p->array, f); \
} \
,/* No in_SERIAL */) \
// TODO: set all & remove all function
/********************************** INTERNAL *********************************/
#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
+240 -232
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - RED BLACK TREE module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -29,26 +29,26 @@
/* 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_F(name,_t), M_F(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 ), \
(name, __VA_ARGS__, name_t, M_C(name, _node_ct), it_t ))) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, M_F(name, _node_ct), it_t ), \
(name, __VA_ARGS__, name_t, M_F(name, _node_ct), it_t ))) \
M_END_PROTECTED_CODE
/* 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__ )))
@@ -72,48 +72,48 @@
NOTE: IT_REF is not exported so that the container appears as not modifiable
by algorithm.*/
#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)), \
SET(M_C(name, _set)), \
CLEAR(M_C(name, _clear)), \
INIT_MOVE(M_C(name, _init_move)), \
MOVE(M_C(name, _move)), \
SWAP(M_C(name, _swap)), \
(INIT(M_F(name, _init)), \
INIT_SET(M_F(name, _init_set)), \
INIT_WITH(API_1(M_INIT_EMPLACE_VAI)), \
SET(M_F(name, _set)), \
CLEAR(M_F(name, _clear)), \
INIT_MOVE(M_F(name, _init_move)), \
MOVE(M_F(name, _move)), \
SWAP(M_F(name, _swap)), \
NAME(name), \
TYPE(M_C(name,_ct)), \
SUBTYPE(M_C(name, _subtype_ct)), \
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_SET(M_C(name,_it_set)), \
IT_LAST(M_C(name,_it_last)), \
IT_END(M_C(name,_it_end)), \
IT_END_P(M_C(name,_end_p)), \
IT_LAST_P(M_C(name,_last_p)), \
IT_EQUAL_P(M_C(name,_it_equal_p)), \
IT_NEXT(M_C(name,_next)), \
IT_PREVIOUS(M_C(name,_previous)), \
IT_CREF(M_C(name,_cref)), \
IT_REMOVE(M_C(name,_remove)), \
RESET(M_C(name,_reset)), \
PUSH(M_C(name,_push)), \
GET_MIN(M_C(name,_min)), \
GET_MAX(M_C(name,_max)), \
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)),), \
M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),), \
M_IF_METHOD(HASH, oplist)(HASH(M_C(name, _hash)),) \
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
SUBTYPE(M_F(name, _subtype_ct)), \
EMPTY_P(M_F(name,_empty_p)), \
GET_SIZE(M_F(name, _size)), \
IT_TYPE(M_F(name, _it_ct)), \
IT_FIRST(M_F(name,_it)), \
IT_SET(M_F(name,_it_set)), \
IT_LAST(M_F(name,_it_last)), \
IT_END(M_F(name,_it_end)), \
IT_END_P(M_F(name,_end_p)), \
IT_LAST_P(M_F(name,_last_p)), \
IT_EQUAL_P(M_F(name,_it_equal_p)), \
IT_NEXT(M_F(name,_next)), \
IT_PREVIOUS(M_F(name,_previous)), \
IT_CREF(M_F(name,_cref)), \
IT_REMOVE(M_F(name,_remove)), \
RESET(M_F(name,_reset)), \
PUSH(M_F(name,_push)), \
GET_MIN(M_F(name,_min)), \
GET_MAX(M_F(name,_max)), \
M_IF_METHOD(GET_STR, oplist)(GET_STR(M_F(name, _get_str)),), \
M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_F(name, _parse_str)),), \
M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),), \
M_IF_METHOD(IN_STR, oplist)(IN_STR(M_F(name, _in_str)),), \
M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_F(name, _out_serial)),), \
M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_F(name, _in_serial)),), \
M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),), \
M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \
)
/********************************** INTERNAL *********************************/
/* Max depth of the binary tree
It is at worst twice the depth of a perfectly even tree with maximum elements.
The maximum number of elements is the max of size_t.
@@ -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) \
@@ -175,73 +175,78 @@ typedef enum {
- node_t: alias for the node of an element of the container
*/
#define M_RBTR33_DEF_P3(name, type, oplist, tree_t, node_t, it_t) \
M_RBTR33_DEF_TYPE(name, type, oplist, tree_t, node_t, it_t) \
M_RBTR33_DEF_MEMPOOL(name, type, oplist, tree_t, node_t, it_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_RBTR33_DEF_CORE(name, type, oplist, tree_t, node_t, it_t) \
M_RBTR33_DEF_IO(name, type, oplist, tree_t, node_t, it_t) \
M_EMPLACE_QUEUE_DEF(name, tree_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
/* Define the types associated to a R/B Tree */
#define M_RBTR33_DEF_TYPE(name, type, oplist, tree_t, node_t, it_t) \
\
/* Node of Red/Black tree. \
Each node has up to two child, a color (Red or black) \
and the data stored in it */ \
typedef struct M_C(name, _node_s) { \
struct M_C(name, _node_s) *child[2]; \
typedef struct M_F(name, _node_s) { \
struct M_F(name, _node_s) *child[2]; \
type data; \
rbtreei_color_e color; \
m_rbtr33_color_e color; \
} node_t; \
\
/* Define the Red/Black tree */ \
typedef struct M_C(name, _s) { \
typedef struct M_F(name, _s) { \
size_t size; /* Number of elements in the tree */ \
node_t *node; /* Root node of the tree */ \
} tree_t[1]; \
typedef struct M_C(name, _s) *M_C(name, _ptr); \
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
typedef struct M_F(name, _s) *M_F(name, _ptr); \
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
\
/* Iterator on a tree. The iterator stores the full path to the \
current node through all its parents and its depth */ \
typedef struct M_C(name, _it_s) { \
typedef struct M_F(name, _it_s) { \
node_t *stack[M_RBTR33_MAX_STACK]; \
int8_t which[M_RBTR33_MAX_STACK]; \
unsigned int cpt; \
} it_t[1]; \
\
/* Definition of the alias used by the oplists */ \
typedef type M_C(name, _subtype_ct); \
typedef tree_t M_C(name, _ct); \
typedef it_t M_C(name, _it_ct); \
\
typedef type M_F(name, _subtype_ct); \
typedef tree_t M_F(name, _ct); \
typedef it_t M_F(name, _it_ct); \
/* Define the mempool encapsulation */
#define M_RBTR33_DEF_MEMPOOL(name, type, oplist, tree_t, node_t, it_t) \
/* Link with fast memory allocator if requested */ \
M_IF_METHOD(MEMPOOL, oplist)( \
/* Definition of the memory pool of this kind of node */ \
MEMPOOL_DEF(M_C(name, _mempool), node_t) \
MEMPOOL_DEF(M_F(name, _mempool), node_t) \
/* Definition of the global variable used to reference this pool */ \
M_GET_MEMPOOL_LINKAGE oplist M_C(name, _mempool_t) M_GET_MEMPOOL oplist; \
M_GET_MEMPOOL_LINKAGE oplist M_F(name, _mempool_t) M_GET_MEMPOOL oplist; \
/* Allocator function */ \
static inline node_t *M_C3(m_rbtr33_,name,_new)(void) { \
return M_C(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \
M_INLINE node_t *M_C3(m_rbtr33_,name,_new)(void) { \
return M_F(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \
} \
/* Deallocator function */ \
static inline void M_C3(m_rbtr33_,name,_del)(node_t *ptr) { \
M_C(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \
M_INLINE void M_C3(m_rbtr33_,name,_del)(node_t *ptr) { \
M_F(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \
} \
\
, /* No mempool allocation */ \
/* Callic allocator function (common case) */ \
static inline node_t *M_C3(m_rbtr33_,name,_new)(void) { \
/* Classic Allocator function (common case) */ \
M_INLINE node_t *M_C3(m_rbtr33_,name,_new)(void) { \
return M_CALL_NEW(oplist, node_t); \
} \
/* Callic deallocator function (common case) */ \
static inline void M_C3(m_rbtr33_,name,_del)(node_t *ptr) { \
/* Classic deallocator function (common case) */ \
M_INLINE void M_C3(m_rbtr33_,name,_del)(node_t *ptr) { \
M_CALL_DEL(oplist, ptr); \
} ) \
\
/* Check if the given oplist is compatible with the given type */ \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
/* Generate all functions */ \
M_RBTR33_DEF_P4(name, type, oplist, tree_t, node_t, it_t)
#define M_RBTR33_DEF_P4(name, type, oplist, tree_t, node_t, it_t) \
/* Define the core functions */
#define M_RBTR33_DEF_CORE(name, type, oplist, tree_t, node_t, it_t) \
\
static inline void \
M_C(name, _init)(tree_t tree) \
M_INLINE void \
M_F(name, _init)(tree_t tree) \
{ \
M_ASSERT (tree != NULL); \
tree->size = 0; \
@@ -249,8 +254,8 @@ typedef enum {
M_RBTR33_CONTRACT(tree); \
} \
\
static inline void \
M_C(name, _reset)(tree_t tree) \
M_INLINE void \
M_F(name, _reset)(tree_t tree) \
{ \
M_RBTR33_CONTRACT(tree); \
node_t *stack[M_RBTR33_MAX_STACK]; \
@@ -294,21 +299,15 @@ 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) \
M_INLINE void \
M_F(name, _clear)(tree_t tree) \
{ \
/* Nothing more than clean the tree as everything is cleared */ \
M_C(name, _reset)(tree); \
M_F(name, _reset)(tree); \
} \
\
static inline void \
M_C(name, _push)(tree_t tree, type const data) \
M_INLINE void \
M_F(name, _push)(tree_t tree, type const data) \
{ \
M_RBTR33_CONTRACT(tree); \
node_t *tab[M_RBTR33_MAX_STACK]; \
@@ -318,7 +317,7 @@ typedef enum {
/* If there is no root node, create a new node */ \
if (n == NULL) { \
n = M_C3(m_rbtr33_,name,_new)(); \
if (M_UNLIKELY (n == NULL)) { \
if (M_UNLIKELY_NOMEM (n == NULL)) { \
M_MEMORY_FULL(sizeof (node_t)); \
return; \
} \
@@ -359,7 +358,7 @@ typedef enum {
} \
/* Create new node to store the data */ \
n = M_C3(m_rbtr33_,name,_new)(); \
if (M_UNLIKELY (n == NULL) ) { \
if (M_UNLIKELY_NOMEM (n == NULL) ) { \
M_MEMORY_FULL (sizeof (node_t)); \
return; \
} \
@@ -433,15 +432,15 @@ typedef enum {
M_RBTR33_CONTRACT (tree); \
} \
\
static inline size_t \
M_C(name, _size)(const tree_t tree) \
M_INLINE size_t \
M_F(name, _size)(const tree_t tree) \
{ \
M_RBTR33_CONTRACT (tree); \
return tree->size; \
} \
\
/* Set the iterator to the first (child=0) or last (child=1) element */ \
static inline void \
M_INLINE void \
M_C3(m_rbtr33_,name,_it)(it_t it, const tree_t tree, int child) \
{ \
M_RBTR33_CONTRACT (tree); \
@@ -463,42 +462,43 @@ typedef enum {
it->cpt = cpt; \
} \
\
static inline void \
M_C(name, _it)(it_t it, const tree_t tree) \
M_INLINE void \
M_F(name, _it)(it_t it, const tree_t tree) \
{ \
M_C3(m_rbtr33_,name,_it)(it, tree, 0); \
} \
\
static inline void \
M_C(name, _it_last)(it_t it, const tree_t tree) \
M_INLINE void \
M_F(name, _it_last)(it_t it, const tree_t tree) \
{ \
M_C3(m_rbtr33_,name,_it)(it, tree, 1); \
} \
\
static inline void \
M_C(name, _it_end)(it_t it, const tree_t tree) \
M_INLINE void \
M_F(name, _it_end)(it_t it, const tree_t tree) \
{ \
M_RBTR33_CONTRACT (tree); \
M_ASSERT (it != NULL); \
(void) tree; /* parameter not used */ \
it->cpt = 0; \
} \
\
static inline void \
M_C(name, _it_set)(it_t it, const it_t ref) \
M_INLINE void \
M_F(name, _it_set)(it_t it, const it_t ref) \
{ \
M_ASSERT (it != NULL && ref != NULL); \
*it = *ref; \
} \
\
static inline bool \
M_C(name, _end_p)(const it_t it) \
M_INLINE bool \
M_F(name, _end_p)(const it_t it) \
{ \
M_ASSERT (it != NULL); \
return it->cpt == 0; \
} \
\
/* Go to the next (child = 0)or previous element (child = 1) */ \
static inline void \
M_INLINE void \
M_C3(m_rbtr33_,name,_next)(it_t it, int child) \
{ \
M_ASSERT (it != NULL); \
@@ -530,20 +530,20 @@ typedef enum {
it->cpt = cpt; \
} \
\
static inline void \
M_C(name, _next)(it_t it) \
M_INLINE void \
M_F(name, _next)(it_t it) \
{ \
M_C3(m_rbtr33_,name,_next)(it, 0); \
} \
\
static inline void \
M_C(name, _previous)(it_t it) \
M_INLINE void \
M_F(name, _previous)(it_t it) \
{ \
M_C3(m_rbtr33_,name,_next)(it, 1); \
} \
\
static inline type * \
M_C(name, _ref)(const it_t it) \
M_INLINE type * \
M_F(name, _ref)(const it_t it) \
{ \
M_ASSERT(it != NULL); \
/* There shall be at least one element */ \
@@ -552,14 +552,14 @@ typedef enum {
return &(it->stack[it->cpt-1]->data); \
} \
\
static inline type const * \
M_C(name, _cref)(const it_t it) \
M_INLINE type const * \
M_F(name, _cref)(const it_t it) \
{ \
return M_CONST_CAST(type, M_C(name, _ref)(it)); \
return M_CONST_CAST(type, M_F(name, _ref)(it)); \
} \
\
static inline bool \
M_C(name, _it_equal_p)(const it_t it1, const it_t it2) \
M_INLINE bool \
M_F(name, _it_equal_p)(const it_t it1, const it_t it2) \
{ \
M_ASSERT(it1 != NULL && it2 != NULL); \
/* There can be no element */ \
@@ -569,8 +569,8 @@ typedef enum {
&& (it1->cpt == 0 || it1->stack[it1->cpt-1] == it2->stack[it2->cpt-1]); \
} \
\
static inline void \
M_C(name, _it_from)(it_t it, const tree_t tree, type const data) \
M_INLINE void \
M_F(name, _it_from)(it_t it, const tree_t tree, type const data) \
{ \
M_RBTR33_CONTRACT (tree); \
M_ASSERT (it != NULL); \
@@ -594,12 +594,12 @@ typedef enum {
/* The iterator found may be strictly lower than data. \
In this case, go to the next element */ \
if (cmp < 0) { \
M_C(name, _next)(it); \
M_F(name, _next)(it); \
} \
} \
\
static inline bool \
M_C(name, _it_until_p)(it_t it, type const data) \
M_INLINE bool \
M_F(name, _it_until_p)(it_t it, type const data) \
{ \
M_ASSERT (it != NULL); \
if (M_UNLIKELY(it->cpt == 0)) return true; \
@@ -609,8 +609,8 @@ typedef enum {
return (cmp >= 0); \
} \
\
static inline bool \
M_C(name, _it_while_p)(it_t it, type const data) \
M_INLINE bool \
M_F(name, _it_while_p)(it_t it, type const data) \
{ \
M_ASSERT (it != NULL); \
if (M_UNLIKELY(it->cpt == 0)) return false; \
@@ -620,8 +620,8 @@ typedef enum {
return (cmp <= 0); \
} \
\
static inline type * \
M_C(name, _min)(const tree_t tree) \
M_INLINE type * \
M_F(name, _min)(const tree_t tree) \
{ \
M_RBTR33_CONTRACT (tree); \
node_t *n = tree->node; \
@@ -633,8 +633,8 @@ typedef enum {
return &n->data; \
} \
\
static inline type * \
M_C(name, _max)(const tree_t tree) \
M_INLINE type * \
M_F(name, _max)(const tree_t tree) \
{ \
M_RBTR33_CONTRACT (tree); \
node_t *n = tree->node; \
@@ -646,20 +646,20 @@ typedef enum {
return &n->data; \
} \
\
static inline type const * \
M_C(name, _cmin)(const tree_t tree) \
M_INLINE type const * \
M_F(name, _cmin)(const tree_t tree) \
{ \
return M_CONST_CAST(type, M_C(name, _min)(tree)); \
return M_CONST_CAST(type, M_F(name, _min)(tree)); \
} \
\
static inline type const * \
M_C(name, _cmax)(const tree_t tree) \
M_INLINE type const * \
M_F(name, _cmax)(const tree_t tree) \
{ \
return M_CONST_CAST(type, M_C(name, _max)(tree)); \
return M_CONST_CAST(type, M_F(name, _max)(tree)); \
} \
\
static inline type * \
M_C(name, _get)(const tree_t tree, type const data) \
M_INLINE type * \
M_F(name, _get)(const tree_t tree, type const data) \
{ \
M_RBTR33_CONTRACT (tree); \
node_t *n = tree->node; \
@@ -677,19 +677,19 @@ typedef enum {
return NULL; \
} \
\
static inline type const * \
M_C(name, _cget)(const tree_t tree, type const data) \
M_INLINE type const * \
M_F(name, _cget)(const tree_t tree, type const data) \
{ \
return M_CONST_CAST(type, M_C(name, _get)(tree, data)); \
return M_CONST_CAST(type, M_F(name, _get)(tree, data)); \
} \
\
/* Create a copy of the given node (recursively) */ \
static inline node_t * \
M_INLINE node_t * \
M_C3(m_rbtr33_,name,_copy_node)(const node_t *o) \
{ \
if (o == NULL) return NULL; \
node_t *n = M_C3(m_rbtr33_,name,_new)(); \
if (M_UNLIKELY (n == NULL) ) { \
if (M_UNLIKELY_NOMEM (n == NULL) ) { \
M_MEMORY_FULL (sizeof (node_t)); \
return NULL; \
} \
@@ -700,8 +700,8 @@ typedef enum {
return n; \
} \
\
static inline void \
M_C(name, _init_set)(tree_t tree, const tree_t ref) \
M_INLINE void \
M_F(name, _init_set)(tree_t tree, const tree_t ref) \
{ \
M_RBTR33_CONTRACT (ref); \
M_ASSERT (tree != NULL && tree != ref); \
@@ -711,18 +711,18 @@ typedef enum {
M_RBTR33_CONTRACT (tree); \
} \
\
static inline void \
M_C(name, _set)(tree_t tree, const tree_t ref) \
M_INLINE void \
M_F(name, _set)(tree_t tree, const tree_t ref) \
{ \
M_RBTR33_CONTRACT (tree); \
M_RBTR33_CONTRACT (ref); \
if (tree == ref) return; \
M_C(name,_clear)(tree); \
M_C(name,_init_set)(tree, ref); \
M_F(name,_clear)(tree); \
M_F(name,_init_set)(tree, ref); \
} \
\
static inline void \
M_C(name, _init_move)(tree_t tree, tree_t ref) \
M_INLINE void \
M_F(name, _init_move)(tree_t tree, tree_t ref) \
{ \
M_RBTR33_CONTRACT (ref); \
M_ASSERT (tree != NULL && tree != ref); \
@@ -733,19 +733,19 @@ typedef enum {
M_RBTR33_CONTRACT (tree); \
} \
\
static inline void \
M_C(name, _move)(tree_t tree, tree_t ref) \
M_INLINE void \
M_F(name, _move)(tree_t tree, tree_t ref) \
{ \
M_RBTR33_CONTRACT (tree); \
M_RBTR33_CONTRACT (ref); \
M_ASSERT (tree != ref); \
M_C(name,_clear)(tree); \
M_C(name,_init_move)(tree, ref); \
M_F(name,_clear)(tree); \
M_F(name,_init_move)(tree, ref); \
M_RBTR33_CONTRACT (tree); \
} \
\
static inline void \
M_C(name, _swap)(tree_t tree1, tree_t tree2) \
M_INLINE void \
M_F(name, _swap)(tree_t tree1, tree_t tree2) \
{ \
M_RBTR33_CONTRACT (tree1); \
M_RBTR33_CONTRACT (tree2); \
@@ -755,27 +755,27 @@ typedef enum {
M_RBTR33_CONTRACT (tree2); \
} \
\
static inline bool \
M_C(name, _empty_p)(const tree_t tree) \
M_INLINE bool \
M_F(name, _empty_p)(const tree_t tree) \
{ \
M_RBTR33_CONTRACT (tree); \
return tree->size == 0; \
} \
\
/* Take care of the case n == NULL too */ \
static inline bool \
M_INLINE bool \
M_C3(m_rbtr33_,name,_black_p)(const node_t *n) \
{ \
return (n == NULL) ? true : M_RBTR33_IS_BLACK(n); \
} \
\
static inline void \
M_INLINE void \
M_C3(m_rbtr33_,name,_set_black)(node_t *n) \
{ \
if (n != NULL) M_RBTR33_SET_BLACK(n); \
} \
\
static inline node_t * \
M_INLINE node_t * \
M_C3(m_rbtr33_,name,_rotate)(node_t *pp, node_t *ppp, const bool right) \
{ \
M_ASSERT (pp != NULL && ppp != NULL); \
@@ -792,7 +792,7 @@ typedef enum {
\
M_IF_DEBUG( \
/* Compute the depth of a node */ \
static size_t \
M_INLINE size_t \
M_C3(m_rbtr33_,name,_compute_depth)(const node_t *n) \
{ \
if (n == NULL) return 1; \
@@ -801,8 +801,8 @@ typedef enum {
} \
) \
\
static inline bool \
M_C(name, _pop_at)(type *data_ptr, tree_t tree, type const key) \
M_INLINE bool \
M_F(name, _pop_at)(type *data_ptr, tree_t tree, type const key) \
{ \
M_RBTR33_CONTRACT (tree); \
node_t *tab[M_RBTR33_MAX_STACK]; \
@@ -837,7 +837,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 +883,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 +924,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); \
@@ -961,22 +961,22 @@ typedef enum {
return true; \
} \
\
static inline void M_C(name,_remove)(tree_t t, it_t it) \
M_INLINE void M_F(name,_remove)(tree_t t, it_t it) \
{ \
/* Not optimum: another search in the tree is performed */ \
type data; \
M_CALL_INIT_SET(oplist, data, *M_C(name,_cref)(it)); \
M_C(name,_next)(it); \
M_C(name, _pop_at)(NULL, t, data); \
M_CALL_INIT_SET(oplist, data, *M_F(name,_cref)(it)); \
M_F(name,_next)(it); \
M_F(name, _pop_at)(NULL, t, data); \
/* We have changed the tree: the iterator is partialy invalid */ \
if (!M_C(name, _end_p)(it)) { \
M_C(name, _it_from)(it, t, *M_C(name,_cref)(it)); \
if (!M_F(name, _end_p)(it)) { \
M_F(name, _it_from)(it, t, *M_F(name,_cref)(it)); \
} \
M_CALL_CLEAR(oplist, data); \
} \
\
M_IF_METHOD(EQUAL, oplist)( \
static inline bool M_C(name,_equal_p)(const tree_t t1, const tree_t t2) { \
M_INLINE bool M_F(name,_equal_p)(const tree_t t1, const tree_t t2) { \
M_RBTR33_CONTRACT(t1); \
M_RBTR33_CONTRACT(t2); \
if (t1->size != t2->size) return false; \
@@ -986,77 +986,79 @@ typedef enum {
structuraly different but functionnaly equal (you get this by \
constructing the tree in a different way). We have to \
compare the ordered value within the tree. */ \
M_C(name, _it)(it1, t1); \
M_C(name, _it)(it2, t2); \
while (!M_C(name, _end_p)(it1) \
&& !M_C(name, _end_p)(it2)) { \
type const *ref1 = M_C(name, _cref)(it1); \
type const *ref2 = M_C(name, _cref)(it2); \
M_F(name, _it)(it1, t1); \
M_F(name, _it)(it2, t2); \
while (!M_F(name, _end_p)(it1) \
&& !M_F(name, _end_p)(it2)) { \
type const *ref1 = M_F(name, _cref)(it1); \
type const *ref2 = M_F(name, _cref)(it2); \
if (M_CALL_EQUAL(oplist, *ref1, *ref2) == false) \
return false; \
M_C(name, _next)(it1); \
M_C(name, _next)(it2); \
M_F(name, _next)(it1); \
M_F(name, _next)(it2); \
} \
return M_C(name, _end_p)(it1) \
&& M_C(name, _end_p)(it2); \
return M_F(name, _end_p)(it1) \
&& M_F(name, _end_p)(it2); \
} \
, /* NO EQUAL METHOD */ ) \
\
M_IF_METHOD(HASH, oplist)( \
static inline size_t M_C(name,_hash)(const tree_t t1) { \
M_INLINE size_t M_F(name,_hash)(const tree_t t1) { \
M_RBTR33_CONTRACT(t1); \
M_HASH_DECL(hash); \
/* NOTE: We can't compute the hash directly for the same reason \
than for EQUAL operator. */ \
it_t it1; \
M_C(name, _it)(it1, t1); \
while (!M_C(name, _end_p)(it1)) { \
type const *ref1 = M_C(name, _cref)(it1); \
M_F(name, _it)(it1, t1); \
while (!M_F(name, _end_p)(it1)) { \
type const *ref1 = M_F(name, _cref)(it1); \
M_HASH_UP(hash, M_CALL_HASH(oplist, *ref1)); \
M_C(name, _next)(it1); \
M_F(name, _next)(it1); \
} \
return M_HASH_FINAL (hash); \
} \
, /* NO HASH METHOD */ ) \
\
/* Define the I/O functions */
#define M_RBTR33_DEF_IO(name, type, oplist, tree_t, node_t, it_t) \
M_IF_METHOD(GET_STR, oplist)( \
static inline void M_C(name, _get_str)(string_t str, \
M_INLINE void M_F(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)) { \
M_F(name, _it)(it1, t1); \
while (!M_F(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); \
type const *ref1 = M_F(name, _cref)(it1); \
M_CALL_GET_STR(oplist, str, *ref1, true); \
M_C(name, _next)(it1); \
M_F(name, _next)(it1); \
} \
string_push_back (str, ']'); \
m_string_push_back (str, ']'); \
} \
, /* NO GET_STR */ ) \
\
M_IF_METHOD(OUT_STR, oplist)( \
static inline void \
M_C(name, _out_str)(FILE *file, tree_t const rbtree) \
M_INLINE void \
M_F(name, _out_str)(FILE *file, tree_t const rbtree) \
{ \
M_RBTR33_CONTRACT(rbtree); \
M_ASSERT (file != NULL); \
fputc ('[', file); \
it_t it; \
bool commaToPrint = false; \
for (M_C(name, _it)(it, rbtree) ; \
!M_C(name, _end_p)(it); \
M_C(name, _next)(it)){ \
for (M_F(name, _it)(it, rbtree) ; \
!M_F(name, _end_p)(it); \
M_F(name, _next)(it)){ \
if (commaToPrint) \
fputc (M_GET_SEPARATOR oplist, file); \
commaToPrint = true; \
type const *item = M_C(name, _cref)(it); \
type const *item = M_F(name, _cref)(it); \
M_CALL_OUT_STR(oplist, file, *item); \
} \
fputc (']', file); \
@@ -1064,12 +1066,12 @@ typedef enum {
, /* no out_str */ ) \
\
M_IF_METHOD(PARSE_STR, oplist)( \
static inline bool \
M_C(name, _parse_str)(tree_t rbtree, const char str[], const char **endp) \
M_INLINE bool \
M_F(name, _parse_str)(tree_t rbtree, const char str[], const char **endp) \
{ \
M_RBTR33_CONTRACT(rbtree); \
M_ASSERT (str != NULL); \
M_C(name,_reset)(rbtree); \
M_F(name,_reset)(rbtree); \
bool success = false; \
int c = *str++; \
if (M_UNLIKELY (c != '[')) goto exit; \
@@ -1083,7 +1085,7 @@ typedef enum {
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
do { c = *str++; } while (isspace(c)); \
if (b == false || c == 0) goto exit_clear; \
M_C(name, _push)(rbtree, item); \
M_F(name, _push)(rbtree, item); \
} while (c == M_GET_SEPARATOR oplist); \
success = (c == ']'); \
exit_clear: \
@@ -1095,12 +1097,12 @@ typedef enum {
, /* no parse_str */ ) \
\
M_IF_METHOD(IN_STR, oplist)( \
static inline bool \
M_C(name, _in_str)(tree_t rbtree, FILE *file) \
M_INLINE bool \
M_F(name, _in_str)(tree_t rbtree, FILE *file) \
{ \
M_RBTR33_CONTRACT(rbtree); \
M_ASSERT (file != NULL); \
M_C(name,_reset)(rbtree); \
M_F(name,_reset)(rbtree); \
int c = fgetc(file); \
if (M_UNLIKELY (c != '[')) return false; \
c = fgetc(file); \
@@ -1113,7 +1115,7 @@ typedef enum {
bool b = M_CALL_IN_STR(oplist, item, file); \
do { c = fgetc(file); } while (isspace(c)); \
if (b == false || c == EOF) break; \
M_C(name, _push)(rbtree, item); \
M_F(name, _push)(rbtree, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_CALL_CLEAR(oplist, item); \
return c == ']'; \
@@ -1121,21 +1123,21 @@ typedef enum {
, /* no in_str */ ) \
\
M_IF_METHOD(OUT_SERIAL, oplist)( \
static inline m_serial_return_code_t \
M_C(name, _out_serial)(m_serial_write_t f, tree_t const t1) \
M_INLINE m_serial_return_code_t \
M_F(name, _out_serial)(m_serial_write_t f, tree_t const t1) \
{ \
M_RBTR33_CONTRACT(t1); \
M_ASSERT (f != NULL && f->m_interface != NULL); \
m_serial_local_t local; \
m_serial_return_code_t ret; \
M_C(name, _subtype_ct) const *item; \
M_F(name, _subtype_ct) const *item; \
bool first_done = false; \
it_t it; \
ret = f->m_interface->write_array_start(local, f, t1->size); \
for (M_C(name, _it)(it, t1) ; \
!M_C(name, _end_p)(it); \
M_C(name, _next)(it)){ \
item = M_C(name, _cref)(it); \
for (M_F(name, _it)(it, t1) ; \
!M_F(name, _end_p)(it); \
M_F(name, _next)(it)){ \
item = M_F(name, _cref)(it); \
if (first_done) \
ret |= f->m_interface->write_array_next(local, f); \
ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \
@@ -1147,8 +1149,8 @@ typedef enum {
, /* no OUT_SERIAL */ ) \
\
M_IF_METHOD(IN_SERIAL, oplist)( \
static inline m_serial_return_code_t \
M_C(name, _in_serial)(tree_t t1, m_serial_read_t f) \
M_INLINE m_serial_return_code_t \
M_F(name, _in_serial)(tree_t t1, m_serial_read_t f) \
{ \
M_RBTR33_CONTRACT(t1); \
M_ASSERT (f != NULL && f->m_interface != NULL); \
@@ -1156,23 +1158,29 @@ typedef enum {
m_serial_return_code_t ret; \
size_t estimated_size = 0; \
type key; \
M_C(name,_reset)(t1); \
M_F(name,_reset)(t1); \
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
M_CALL_INIT(oplist, key); \
do { \
ret = M_CALL_IN_SERIAL(oplist, key, f); \
if (ret != M_SERIAL_OK_DONE) { break; } \
M_C(name, _push)(t1, key); \
M_F(name, _push)(t1, key); \
} while ((ret = f->m_interface->read_array_next(local, f)) == M_SERIAL_OK_CONTINUE); \
M_CALL_CLEAR(oplist, key); \
return ret; \
} \
, /* no in_serial */ ) \
\
\
/********************************** INTERNAL *********************************/
// 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
+140 -183
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Serial BIN
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -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_INLINE bool
m_ser1al_bin_write_size(FILE *f, const size_t size)
{
bool b;
if (M_LIKELY(size < 253))
@@ -83,8 +88,8 @@ m_serial_bin_write_size(FILE *f, const size_t size)
* Read size_t in the stream from a compact form to reduce consumption
* (and I/O bandwidth)
*/
static inline bool
m_serial_bin_read_size(FILE *f, size_t *size)
M_INLINE bool
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;
@@ -106,8 +111,8 @@ 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_INLINE m_serial_return_code_t
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);
@@ -116,76 +121,61 @@ 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_INLINE m_serial_return_code_t
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;
int32_t i32;
int64_t i64;
size_t n;
FILE *f = (FILE *)serial->data[0].p;
switch (size_of_type) {
case 1:
i8 = (int8_t) data;
if (size_of_type == 1) {
int8_t i8 = (int8_t) data;
n = fwrite (M_ASSIGN_CAST(const void*, &i8), sizeof i8, 1, f);
break;
case 2:
i16 = (int16_t) data;
} else if (size_of_type == 2) {
int16_t i16 = (int16_t) data;
n = fwrite (M_ASSIGN_CAST(const void*, &i16), sizeof i16, 1, f);
break;
case 4:
i32 = (int32_t) data;
} else if (size_of_type == 4) {
int32_t i32 = (int32_t) data;
n = fwrite (M_ASSIGN_CAST(const void*, &i32), sizeof i32, 1, f);
break;
case 8:
i64 = (int64_t) data;
} else {
M_ASSERT(size_of_type == 8);
int64_t i64 = (int64_t) data;
n = fwrite (M_ASSIGN_CAST(const void*, &i64), sizeof i64, 1, f);
break;
default:
M_ASSERT_INIT(false, "an integer of suitable size (8/16/32/64)");
break;
}
return n == 1 ? 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_bin_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
{
float f1;
double f2;
long double f3;
size_t n;
FILE *f = (FILE *)serial->data[0].p;
if (size_of_type == sizeof f1) {
f1 = (float) data;
if (size_of_type == sizeof (float) ) {
float f1 = (float) data;
n = fwrite (M_ASSIGN_CAST(const void*, &f1), sizeof f1, 1, f);
} else if (size_of_type == sizeof f2) {
f2 = (double) data;
} else if (size_of_type == sizeof (double) ) {
double f2 = (double) data;
n = fwrite (M_ASSIGN_CAST(const void*, &f2), sizeof f2, 1, f);
} else if (size_of_type == sizeof f3) {
f3 = (long double) data;
n = fwrite (M_ASSIGN_CAST(const void*, &f3), sizeof f3, 1, f);
} else {
M_ASSERT_INIT(false, "a float of suitable size");
M_ASSERT(size_of_type == sizeof (long double) );
long double f3 = (long double) data;
n = fwrite (M_ASSIGN_CAST(const void*, &f3), sizeof f3, 1, f);
}
return n == 1 ? 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_bin_write_string(m_serial_write_t serial, const char data[], size_t length)
M_INLINE m_serial_return_code_t
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);
@@ -198,51 +188,40 @@ m_serial_bin_write_string(m_serial_write_t serial, const char data[], size_t len
Initialize 'local' so that it can be used to serialize the array
(local is an unique serialization object of the array).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
{
(void) local; //Unused
if (number_of_elements == (size_t)-1) return M_SERIAL_FAIL_RETRY;
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);
local->data[0].b = (number_of_elements == 0);
return n == 1 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
/* 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_INLINE m_serial_return_code_t
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
if (local->data[0].b) {
size_t n = 0xABCDEF;
n = fwrite (M_ASSIGN_CAST(const void*, &n), sizeof n, 1, f);
return n == 1 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
} else {
return M_SERIAL_OK_CONTINUE;
}
(void) local; // Unused
(void) serial; // Unused
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_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial)
M_INLINE m_serial_return_code_t
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
if (local->data[0].b) {
size_t n = 0x12345678;
n = fwrite (M_ASSIGN_CAST(const void*, &n), sizeof n, 1, f);
return n == 1 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
} else {
return M_SERIAL_OK_CONTINUE;
}
(void) local; // Unused
(void) serial; // Unused
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_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
(void) serial;
@@ -253,8 +232,8 @@ m_serial_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
Initialize 'local' so that it can serial the tuple
(local is an unique serialization object of the tuple).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
(void) serial;
@@ -263,8 +242,8 @@ 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_INLINE m_serial_return_code_t
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;
@@ -276,8 +255,8 @@ 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_INLINE m_serial_return_code_t
m_ser1al_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
(void) serial;
@@ -289,8 +268,8 @@ m_serial_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise
Otherwise, the field 'field_name[index]' will be filled.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_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_INLINE m_serial_return_code_t
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;
@@ -302,8 +281,8 @@ 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_INLINE m_serial_return_code_t
m_ser1al_bin_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
(void) serial;
@@ -311,32 +290,32 @@ 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)
M_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);
}
static inline void m_serial_bin_write_clear(m_serial_write_t serial)
M_INLINE void m_serial_bin_write_clear(m_serial_write_t serial)
{
(void) serial; // Nothing to do
}
@@ -344,16 +323,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_INLINE m_serial_return_code_t
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();
@@ -362,34 +347,27 @@ m_serial_bin_read_boolean(m_serial_read_t serial, bool *b){
/* Read from the stream 'serial' an integer that can be represented with 'size_of_type' bytes.
Set '*i' with the integer value if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
M_INLINE m_serial_return_code_t
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;
int64_t i64;
size_t n;
FILE *f = (FILE *)serial->data[0].p;
switch (size_of_type) {
case 1:
if (size_of_type == 1) {
n = fread (M_ASSIGN_CAST(void*, &i8), sizeof i8, 1, f);
*i = i8;
break;
case 2:
} else if (size_of_type == 2) {
n = fread (M_ASSIGN_CAST(void*, &i16), sizeof i16, 1, f);
*i = i16;
break;
case 4:
} else if (size_of_type == 4) {
n = fread (M_ASSIGN_CAST(void*, &i32), sizeof i32, 1, f);
*i = i32;
break;
case 8:
} else {
M_ASSERT(size_of_type == 8);
n = fread (M_ASSIGN_CAST(void*, &i64), sizeof i64, 1, f);
*i = i64;
break;
default:
M_ASSERT_INIT(false, "an integer of suitable size");
break;
}
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
@@ -397,8 +375,8 @@ m_serial_bin_read_integer(m_serial_read_t serial, long long *i, const size_t siz
/* Read from the stream 'serial' a float that can be represented with 'size_of_type' bytes.
Set '*r' with the boolean value if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
M_INLINE m_serial_return_code_t
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;
@@ -410,11 +388,10 @@ m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
} else if (size_of_type == sizeof f2) {
n = fread (M_ASSIGN_CAST(void*, &f2), sizeof f2, 1, f);
*r = f2;
} else if (size_of_type == sizeof f3) {
} else {
M_ASSERT(size_of_type == sizeof f3);
n = fread (M_ASSIGN_CAST(void*, &f3), sizeof f3, 1, f);
*r = f3;
} else {
M_ASSERT_INIT(false, "a float of suitable size");
}
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
@@ -422,13 +399,13 @@ m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
/* Read from the stream 'serial' a string.
Set 's' with the string if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_string(m_serial_read_t serial, struct string_s *s){
M_INLINE m_serial_return_code_t
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);
@@ -447,54 +424,34 @@ m_serial_bin_read_string(m_serial_read_t serial, struct string_s *s){
Return M_SERIAL_OK_CONTINUE if it succeeds and the array continue,
M_SERIAL_OK_DONE if it succeeds and the array ends (the array is empty),
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
M_INLINE m_serial_return_code_t
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);
if (n != 1)
return m_core_serial_fail();
local->data[0].b = (*num == 0);
local->data[1].s = *num;
if (local->data[0].b) {
// Size not know ==> use of marker in the stream.
size_t p;
n = fread (M_ASSIGN_CAST(void*, &p), sizeof p, 1, f);
if (n != 1)
return m_core_serial_fail();
return p == 0xABCDEF ? M_SERIAL_OK_CONTINUE : p == 0x12345678 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
return M_SERIAL_OK_CONTINUE;
return (n != 1) ? m_core_serial_fail() : (local->data[1].s == 0) ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE;
}
/* Continue reading from the stream 'serial' an array.
Return M_SERIAL_OK_CONTINUE if it succeeds and the array continue,
M_SERIAL_OK_DONE if it succeeds and the array ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_array_next(m_serial_local_t local, m_serial_read_t serial)
M_INLINE m_serial_return_code_t
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) {
// Size not know ==> use of marker in the stream.
size_t p, n;
n = fread (M_ASSIGN_CAST(void*, &p), sizeof p, 1, f);
if (n != 1)
return m_core_serial_fail();
return p == 0xABCDEF ? M_SERIAL_OK_CONTINUE : p == 0x12345678 ? M_SERIAL_OK_DONE : m_core_serial_fail();
} else {
M_ASSERT(local->data[1].s > 0);
local->data[1].s --;
return local->data[1].s == 0 ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE;
}
(void) serial; // Unused
M_ASSERT(local->data[1].s > 0);
local->data[1].s --;
return local->data[1].s == 0 ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE;
}
/* Continue reading from the stream 'serial' the value separator
Return M_SERIAL_OK_CONTINUE if it succeeds and the map continue,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_map_value(m_serial_local_t local, m_serial_read_t serial)
M_INLINE m_serial_return_code_t
m_ser1al_bin_read_map_value(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
(void) serial;
@@ -504,8 +461,8 @@ m_serial_bin_read_map_value(m_serial_local_t local, m_serial_read_t serial)
/* Start reading a tuple from the stream 'serial'.
Return M_SERIAL_OK_CONTINUE if it succeeds and the tuple continues,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
M_INLINE m_serial_return_code_t
m_ser1al_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
{
(void) serial;
local->data[1].i = 0;
@@ -518,8 +475,8 @@ m_serial_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
Return M_SERIAL_OK_CONTINUE if it succeeds and the tuple continues,
Return M_SERIAL_OK_DONE if it succeeds and the tuple ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_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_INLINE m_serial_return_code_t
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;
@@ -535,8 +492,8 @@ m_serial_bin_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const
Return M_SERIAL_OK_CONTINUE if it succeeds and the variant continues,
Return M_SERIAL_OK_DONE if it succeeds and the variant ends(variant is empty),
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_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_INLINE m_serial_return_code_t
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;
@@ -549,37 +506,37 @@ m_serial_bin_read_variant_start(m_serial_local_t local, m_serial_read_t serial,
/* End reading a variant from the stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds and the variant ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_bin_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
M_INLINE m_serial_return_code_t
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)
M_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);
}
static inline void m_serial_bin_read_clear(m_serial_read_t serial)
M_INLINE void m_serial_bin_read_clear(m_serial_read_t serial)
{
(void) serial; // Nothing to do
}
+289 -286
View File
File diff suppressed because it is too large. Load diff
+194 -142
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - SHARED Module
* M*LIB - SHARED Pointer Module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -31,24 +31,16 @@
M_BEGIN_PROTECTED_CODE
/* Define the oplist of a shared pointer.
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
#define SHARED_PTR_OPLIST(...) \
M_SHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_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_F(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 ), \
@@ -56,16 +48,24 @@ M_BEGIN_PROTECTED_CODE
M_END_PROTECTED_CODE
/* Define the oplist of a shared pointer.
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
#define M_SHARED_PTR_OPLIST(...) \
M_SHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_BASIC_OPLIST ), \
(__VA_ARGS__ )))
/* 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_F(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_F(name,_t), M_F(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 ), \
@@ -93,7 +93,9 @@ M_BEGIN_PROTECTED_CODE
/********************************** INTERNAL ************************************/
/*****************************************************************************/
/********************************** INTERNAL *********************************/
/*****************************************************************************/
// deferred evaluation
#define M_SHAR3D_PTR_OPLIST_P1(arg) M_SHAR3D_PTR_OPLIST_P2 arg
@@ -107,19 +109,16 @@ M_BEGIN_PROTECTED_CODE
((M_LIB_ERROR(ARGUMENT_OF_SHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
#define M_SHAR3D_PTR_OPLIST_P3(name, oplist) ( \
INIT(M_C(name, _init)), \
CLEAR(M_C(name, _clear)), \
INIT_SET(M_C(name, _init_set)), \
SET(M_C(name, _set)) \
INIT_MOVE(M_C(name, _init_move)), \
RESET(M_C(name, _reset)), \
MOVE(M_C(name, _move)), \
SWAP(M_C(name, _swap)) \
INIT(M_F(name, _init)), \
CLEAR(M_F(name, _clear)), \
INIT_SET(M_F(name, _init_set)), \
SET(M_F(name, _set)) \
INIT_MOVE(M_F(name, _init_move)), \
RESET(M_F(name, _reset)), \
MOVE(M_F(name, _move)), \
SWAP(M_F(name, _swap)) \
,NAME(name) \
,TYPE(M_C(name, _ct)) \
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
,TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*) \
)
// OPLIST to handle a counter of atomic type
@@ -137,10 +136,13 @@ M_BEGIN_PROTECTED_CODE
IT_CREF(m_shar3d_integer_cref))
/* Atomic like interface for basic integers */
static inline void m_shar3d_integer_init_set(int *p, int val) { *p = val; }
static inline int m_shar3d_integer_add(int *p, int val) { int r = *p; *p += val; return r; }
static inline int m_shar3d_integer_sub(int *p, int val) { int r = *p; *p -= val; return r; }
static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_INLINE void m_shar3d_integer_init_set(int *p, int val) { *p = val; }
M_INLINE int m_shar3d_integer_add(int *p, int val) { int r = *p; *p += val; return r; }
M_INLINE int m_shar3d_integer_sub(int *p, int val) { int r = *p; *p -= val; return r; }
M_INLINE int m_shar3d_integer_cref(int *p) { return *p; }
/********************************** INTERNAL *********************************/
/* Contract of a shared pointer */
#define M_SHAR3D_CONTRACT(shared, cpt_oplist) do { \
@@ -149,7 +151,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) \
@@ -161,44 +163,53 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
/* Code generation */
#define M_SHAR3D_PTR_DEF_P3(name, type, oplist, cpt_oplist, shared_t) \
M_SHAR3D_PTR_DEF_TYPE(name, type, oplist, cpt_oplist, shared_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_SHAR3D_PTR_DEF_CORE(name, type, oplist, cpt_oplist, shared_t) \
M_EMPLACE_QUEUE_DEF(name, cpt_oplist, M_F(name, _init_with), oplist, M_SHAR3D_PTR_DEF_EMPLACE)
/* Define the types */
#define M_SHAR3D_PTR_DEF_TYPE(name, type, oplist, cpt_oplist, shared_t) \
\
typedef struct M_C(name, _s){ \
typedef struct M_F(name, _s){ \
type *data; /* Pointer to the data */ \
M_GET_TYPE cpt_oplist cpt; /* Counter of how many refs the data */ \
bool combineAlloc; /* Does the data and the ptr share the slot? */ \
} *shared_t[1]; \
typedef struct M_C(name, _s) *M_C(name, _ptr); \
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
typedef struct M_F(name, _s) *M_F(name, _ptr); \
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
\
/* Internal type for oplist */ \
typedef shared_t M_C(name, _ct); \
typedef shared_t M_F(name, _ct); \
typedef type M_F(name, _subtype_ct); \
\
typedef struct M_C(name, combine_s) { \
typedef struct M_F(name, _combine_s) { \
struct M_F(name, _s) ptr; \
type data; \
struct M_C(name, _s) ptr; \
} M_C(name, combine_ct)[1]; \
} M_F(name, combine_ct)[1]; \
/* Define the core functions */
#define M_SHAR3D_PTR_DEF_CORE(name, type, oplist, cpt_oplist, shared_t) \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void \
M_C(name, _init)(shared_t shared) \
M_INLINE void \
M_F(name, _init)(shared_t shared) \
{ \
*shared = NULL; \
} \
\
static inline void \
M_C(name, _init2)(shared_t shared, type *data) \
M_INLINE void \
M_F(name, _init2)(shared_t shared, type *data) \
{ \
M_ASSERT (shared != NULL); \
/* The shared ptr get exclusive access to data */ \
struct M_C(name, _s) *ptr; \
struct M_F(name, _s) *ptr; \
if (M_UNLIKELY (data == NULL)) { \
*shared = NULL; \
return; \
} \
ptr = M_CALL_NEW(oplist, struct M_C(name, _s)); \
if (M_UNLIKELY (ptr == NULL)) { \
M_MEMORY_FULL(sizeof(struct M_C(name, _s))); \
ptr = M_CALL_NEW(oplist, struct M_F(name, _s)); \
if (M_UNLIKELY_NOMEM (ptr == NULL)) { \
M_MEMORY_FULL(sizeof(struct M_F(name, _s))); \
return; \
} \
ptr->data = data; \
@@ -208,35 +219,37 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
} \
\
static inline void \
M_C(name, _init_new)(shared_t shared) \
M_IF_METHOD(INIT, oplist)( \
M_INLINE void \
M_F(name, _init_new)(shared_t shared) \
{ \
/* NOTE: Alloc 1 struct with both structures. */ \
struct M_C(name, combine_s) *p = \
M_CALL_NEW(oplist, struct M_C(name, combine_s)); \
if (M_UNLIKELY (p == NULL)) { \
M_MEMORY_FULL(sizeof(struct M_C(name, combine_s))); \
struct M_F(name, _combine_s) *p = \
M_CALL_NEW(oplist, struct M_F(name, _combine_s)); \
if (M_UNLIKELY_NOMEM (p == NULL)) { \
M_MEMORY_FULL(sizeof(struct M_F(name, _combine_s))); \
return; \
} \
struct M_C(name, _s) *ptr = &p->ptr; \
struct M_F(name, _s) *ptr = &p->ptr; \
ptr->combineAlloc = true; \
type *data = &p->data; \
M_CALL_INIT( oplist, *data); \
ptr->data = data; \
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
ptr->combineAlloc = true; \
*shared = ptr; \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
} \
, /* No INIT */ ) \
\
static inline bool \
M_C(name, _NULL_p)(const shared_t shared) \
M_INLINE bool \
M_F(name, _NULL_p)(const shared_t shared) \
{ \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
return *shared == NULL; \
} \
\
static inline void \
M_C(name, _init_set)(shared_t dest, \
M_INLINE void \
M_F(name, _init_set)(shared_t dest, \
const shared_t shared) \
{ \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
@@ -249,8 +262,8 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
} \
\
static inline void \
M_C(name, _clear)(shared_t dest) \
M_INLINE void \
M_F(name, _clear)(shared_t dest) \
{ \
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
if (*dest != NULL) { \
@@ -261,40 +274,35 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
first element, aka data itself. Static analyzer tools don't \
seem to detect this and report error. */ \
M_CALL_CLEAR(oplist, *(*dest)->data); \
M_CALL_DEL(oplist, (*dest)->data); \
if (combineAlloc == false) \
M_CALL_DEL(oplist, *dest); \
if (combineAlloc == false) { \
M_CALL_DEL(oplist, (*dest)->data); \
} \
M_CALL_DEL(oplist, *dest); \
} \
*dest = NULL; \
} \
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
} \
\
static inline void \
M_C(name, _reset)(shared_t dest) \
M_INLINE void \
M_F(name, _reset)(shared_t dest) \
{ \
/* NOTE: Clear will also set dest to NULL */ \
M_C(name, _clear)(dest); \
M_F(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, \
M_INLINE void \
M_F(name, _set)(shared_t dest, \
const shared_t shared) \
{ \
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
M_C(name, _clear)(dest); \
M_C(name, _init_set)(dest, shared); \
M_F(name, _clear)(dest); \
M_F(name, _init_set)(dest, shared); \
} \
\
static inline void \
M_C(name, _init_move)(shared_t dest, \
M_INLINE void \
M_F(name, _init_move)(shared_t dest, \
shared_t shared) \
{ \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
@@ -304,31 +312,31 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
} \
\
static inline void \
M_C(name, _move)(shared_t dest, \
M_INLINE void \
M_F(name, _move)(shared_t dest, \
shared_t shared) \
{ \
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
M_ASSERT (dest != shared); \
M_C(name, _clear)(dest); \
M_C(name, _init_move)(dest, shared); \
M_F(name, _clear)(dest); \
M_F(name, _init_move)(dest, shared); \
} \
\
static inline void \
M_C(name, _swap)(shared_t p1, \
M_INLINE void \
M_F(name, _swap)(shared_t p1, \
shared_t p2) \
{ \
M_SHAR3D_CONTRACT(p1, cpt_oplist); \
M_SHAR3D_CONTRACT(p2, cpt_oplist); \
/* NOTE: SWAP is not atomic */ \
M_SWAP (struct M_C(name, _s)*, *p1, *p2); \
M_SWAP (struct M_F(name, _s)*, *p1, *p2); \
M_SHAR3D_CONTRACT(p1, cpt_oplist); \
M_SHAR3D_CONTRACT(p2, cpt_oplist); \
} \
\
static inline bool \
M_C(name, _equal_p)(const shared_t p1, \
M_INLINE bool \
M_F(name, _equal_p)(const shared_t p1, \
const shared_t p2) \
{ \
M_SHAR3D_CONTRACT(p1, cpt_oplist); \
@@ -336,8 +344,8 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
return *p1 == *p2; \
} \
\
static inline type const * \
M_C(name, _cref)(const shared_t shared) \
M_INLINE type const * \
M_F(name, _cref)(const shared_t shared) \
{ \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
M_ASSERT(*shared != NULL); \
@@ -346,8 +354,8 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
return M_CONST_CAST (type, data); \
} \
\
static inline type * \
M_C(name, _ref)(shared_t shared) \
M_INLINE type * \
M_F(name, _ref)(shared_t shared) \
{ \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
M_ASSERT(*shared != NULL); \
@@ -355,10 +363,33 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_ASSERT (data != NULL); \
return data; \
} \
/* Definition of the emplace_back function for arrays */
#define M_SHAR3D_PTR_DEF_EMPLACE(name, cpt_oplist, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE void \
function_name(M_F(name, _ct) shared \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
/* NOTE: Alloc 1 struct with both structures. */ \
struct M_F(name, _combine_s) *p = \
M_CALL_NEW(oplist, struct M_F(name, _combine_s)); \
if (M_UNLIKELY_NOMEM (p == NULL)) { \
M_MEMORY_FULL(sizeof(struct M_F(name, _combine_s))); \
return; \
} \
struct M_F(name, _s) *ptr = &p->ptr; \
ptr->combineAlloc = true; \
M_F(name, _subtype_ct) *data = &p->data; \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
ptr->data = data; \
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
*shared = ptr; \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
} \
/********************************** SHARED RESOURCE ************************************/
/********************************** INTERNAL *********************************/
#define M_SHAR3D_RESOURCE_CONTRACT(s) do { \
M_ASSERT (s != NULL); \
@@ -366,7 +397,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) \
@@ -377,120 +408,129 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_RESOURCE_DEF): the given argument is not a valid oplist: " #oplist)
#define M_SHAR3D_RESOURCE_DEF_P3(name, type, oplist, shared_t, it_t) \
M_SHAR3D_RESOURCE_DEF_TYPE(name, type, oplist, shared_t, it_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_SHAR3D_RESOURCE_DEF_CORE(name, type, oplist, shared_t, it_t) \
/* Define the types */
#define M_SHAR3D_RESOURCE_DEF_TYPE(name, type, oplist, shared_t, it_t) \
\
/* Create an aligned type to avoid false sharing between threads */ \
typedef struct M_C(name, _atype_s) { \
typedef struct M_F(name, _atype_s) { \
atomic_uint cpt; \
type x; \
M_CACHELINE_ALIGN(align, type, atomic_uint); \
} M_C(name, _atype_ct); \
} M_F(name, _atype_ct); \
\
typedef struct M_C(name, _s) { \
genint_t core; \
M_C(name, _atype_ct) *buffer; \
typedef struct M_F(name, _s) { \
m_genint_t core; \
M_F(name, _atype_ct) *buffer; \
} shared_t[1]; \
\
typedef struct M_C(name, _it_s) { \
typedef struct M_F(name, _it_s) { \
unsigned int idx; \
struct M_C(name, _s) *ref; \
struct M_F(name, _s) *ref; \
} it_t[1]; \
\
/* Internal Types for oplist */ \
typedef shared_t M_C(name, _ct); \
\
static inline void \
M_C(name, _init)(shared_t s, size_t n) \
typedef shared_t M_F(name, _ct); \
typedef type M_F(name, _subtype_ct); \
/* Define the core functions */
#define M_SHAR3D_RESOURCE_DEF_CORE(name, type, oplist, shared_t, it_t) \
M_INLINE void \
M_F(name, _init)(shared_t s, size_t n) \
{ \
M_ASSERT(s != NULL); \
M_ASSERT (n > 0 && n < UINT_MAX); \
s->buffer = M_CALL_REALLOC(oplist, M_C(name, _atype_ct), NULL, n); \
if (M_UNLIKELY (s->buffer == NULL)) { \
M_MEMORY_FULL(sizeof(M_C(name, _atype_ct)) * n); \
s->buffer = M_CALL_REALLOC(oplist, M_F(name, _atype_ct), NULL, n); \
if (M_UNLIKELY_NOMEM (s->buffer == NULL)) { \
M_MEMORY_FULL(sizeof(M_F(name, _atype_ct)) * n); \
return; \
} \
for(size_t i = 0; i < n; i++) { \
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); \
} \
\
static inline void \
M_C(name, _clear)(shared_t s) \
M_INLINE void \
M_F(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 \
M_C(name, _it)(it_t it, shared_t s) \
M_INLINE void \
M_F(name, _it)(it_t it, shared_t s) \
{ \
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); \
} \
} \
\
static inline bool \
M_C(name, _end_p)(it_t it) \
M_INLINE bool \
M_F(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_INLINE type * \
M_F(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; \
} \
\
static inline type const * \
M_C(name, _cref)(it_t it) \
M_INLINE type const * \
M_F(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); \
} \
\
static inline void \
M_C(name, _end)(it_t it, shared_t s) \
M_INLINE void \
M_F(name, _end)(it_t it, shared_t s) \
{ \
M_SHAR3D_RESOURCE_CONTRACT(s); \
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; \
} \
} \
\
static inline void \
M_C(name, _it_set)(it_t itd, it_t its) \
M_INLINE void \
M_F(name, _it_set)(it_t itd, it_t its) \
{ \
M_ASSERT (itd != NULL && its != NULL); \
M_SHAR3D_RESOURCE_CONTRACT(its->ref); \
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 +538,16 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
M_END_PROTECTED_CODE
/********************************** INTERNAL *********************************/
#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
+188 -155
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - SNAPSHOT Module
*
* Copyright (c) 2017-2021, Patrick Pelissier
* Copyright (c) 2017-2023, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -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_F(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_F(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_F(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,13 +84,15 @@ 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__ )))
/********************************** INTERNAL ************************************/
/*****************************************************************************/
/********************************** INTERNAL *********************************/
/*****************************************************************************/
// deferred evaluation of the input
#define M_SNAPSH0T_OPLIST_P1(arg) M_SNAPSH0T_OPLIST_P2 arg
@@ -105,20 +107,20 @@ M_BEGIN_PROTECTED_CODE
/* Define the oplist of a snapshot */
#define M_SNAPSH0T_OPLIST_P3(name, oplist) \
(INIT(M_C(name, _init)) \
,INIT_SET(M_C(name, _init_set)) \
,SET(M_C(name, _set)) \
,CLEAR(M_C(name, _clear)) \
(INIT(M_F(name, _init)) \
,INIT_SET(M_F(name, _init_set)) \
,SET(M_F(name, _set)) \
,CLEAR(M_F(name, _clear)) \
,NAME(name) \
,TYPE(M_C(name, _ct)) \
,SUBTYPE(M_C(name, _subtype_ct)) \
,TYPE(M_F(name, _ct)) , GENTYPE(struct M_F(name,_s)*) \
,SUBTYPE(M_F(name, _subtype_ct)) \
,OPLIST(oplist) \
,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(M_C(name, _init_move)),) \
,M_IF_METHOD(MOVE, oplist)(MOVE(M_C(name, _move)),) \
,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(M_F(name, _init_move)),) \
,M_IF_METHOD(MOVE, oplist)(MOVE(M_F(name, _move)),) \
)
/******************************** INTERNAL SPSC **********************************/
/********************************** INTERNAL *********************************/
/* Flag defining the atomic state of a snapshot:
* - r: Index of the read buffer Range [0..2]
@@ -156,7 +158,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) \
@@ -168,28 +170,35 @@ M_BEGIN_PROTECTED_CODE
/* Expand the type and the functions of a SPSC snapshot */
#define M_SNAPSH0T_SPSC_DEF_P3(name, type, oplist, snapshot_t) \
M_SNAPSH0T_SPSC_DEF_TYPE(name, type, oplist, snapshot_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_SNAPSH0T_SPSC_DEF_CORE(name, type, oplist, snapshot_t) \
/* Define the type */
#define M_SNAPSH0T_SPSC_DEF_TYPE(name, type, oplist, snapshot_t) \
\
/* Create an aligned type to avoid false sharing between threads */ \
typedef struct M_C(name, _aligned_type_s) { \
typedef struct M_F(name, _aligned_type_s) { \
type x; \
M_CACHELINE_ALIGN(align, type); \
} M_C(name, _aligned_type_ct); \
} M_F(name, _aligned_type_ct); \
\
typedef struct M_C(name, _s) { \
M_C(name, _aligned_type_ct) data[M_SNAPSH0T_SPSC_MAX_BUFFER]; \
typedef struct M_F(name, _s) { \
M_F(name, _aligned_type_ct) data[M_SNAPSH0T_SPSC_MAX_BUFFER]; \
atomic_uchar flags; \
} snapshot_t[1]; \
typedef struct M_C(name, _s) *M_C(name, _ptr); \
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
typedef struct M_F(name, _s) *M_F(name, _ptr); \
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
\
/* Define internal types for oplist */ \
typedef snapshot_t M_C(name, _ct); \
typedef type M_C(name, _subtype_ct); \
typedef snapshot_t M_F(name, _ct); \
typedef type M_F(name, _subtype_ct); \
/* Define the core functions */
#define M_SNAPSH0T_SPSC_DEF_CORE(name, type, oplist, snapshot_t) \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void \
M_C(name, _init)(snapshot_t snap) \
M_INLINE void \
M_F(name, _init)(snapshot_t snap) \
{ \
M_ASSERT(snap != NULL); \
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
@@ -199,8 +208,8 @@ M_BEGIN_PROTECTED_CODE
M_SNAPSH0T_SPSC_CONTRACT(snap); \
} \
\
static inline void \
M_C(name, _clear)(snapshot_t snap) \
M_INLINE void \
M_F(name, _clear)(snapshot_t snap) \
{ \
M_SNAPSH0T_SPSC_CONTRACT(snap); \
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
@@ -209,8 +218,8 @@ M_BEGIN_PROTECTED_CODE
} \
\
/* const is missing for org due to use of atomic_load of org */ \
static inline void \
M_C(name, _init_set)(snapshot_t snap, snapshot_t org) \
M_INLINE void \
M_F(name, _init_set)(snapshot_t snap, snapshot_t org) \
{ \
M_SNAPSH0T_SPSC_CONTRACT(org); \
M_ASSERT(snap != NULL && snap != org); \
@@ -222,8 +231,8 @@ M_BEGIN_PROTECTED_CODE
} \
\
/* const is missing for org due to use of atomic_load of org */ \
static inline void \
M_C(name, _set)(snapshot_t snap, snapshot_t org) \
M_INLINE void \
M_F(name, _set)(snapshot_t snap, snapshot_t org) \
{ \
M_SNAPSH0T_SPSC_CONTRACT(snap); \
M_SNAPSH0T_SPSC_CONTRACT(org); \
@@ -235,8 +244,8 @@ M_BEGIN_PROTECTED_CODE
} \
\
M_IF_METHOD(INIT_MOVE, oplist)( \
static inline void \
M_C(name, _init_move)(snapshot_t snap, snapshot_t org) \
M_INLINE void \
M_F(name, _init_move)(snapshot_t snap, snapshot_t org) \
{ \
M_SNAPSH0T_SPSC_CONTRACT(org); \
M_ASSERT(snap != NULL && snap != org); \
@@ -250,8 +259,8 @@ M_BEGIN_PROTECTED_CODE
,) /* IF_METHOD (INIT_MOVE) */ \
\
M_IF_METHOD(MOVE, oplist)( \
static inline void \
M_C(name, _move)(snapshot_t snap, \
M_INLINE void \
M_F(name, _move)(snapshot_t snap, \
snapshot_t org) \
{ \
M_SNAPSH0T_SPSC_CONTRACT(snap); \
@@ -266,8 +275,8 @@ M_BEGIN_PROTECTED_CODE
} \
,) /* IF_METHOD (MOVE) */ \
\
static inline type * \
M_C(name, _write)(snapshot_t snap) \
M_INLINE type * \
M_F(name, _write)(snapshot_t snap) \
{ \
M_SNAPSH0T_SPSC_CONTRACT(snap); \
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
@@ -285,8 +294,8 @@ M_BEGIN_PROTECTED_CODE
return &snap->data[M_SNAPSH0T_SPSC_W(nextFlags)].x; \
} \
\
static inline type const * \
M_C(name, _read)(snapshot_t snap) \
M_INLINE type const * \
M_F(name, _read)(snapshot_t snap) \
{ \
M_SNAPSH0T_SPSC_CONTRACT(snap); \
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
@@ -310,8 +319,8 @@ M_BEGIN_PROTECTED_CODE
} \
\
/* Non const due to use of atomic_load */ \
static inline bool \
M_C(name, _updated_p)(snapshot_t snap) \
M_INLINE bool \
M_F(name, _updated_p)(snapshot_t snap) \
{ \
M_SNAPSH0T_SPSC_CONTRACT(snap); \
unsigned char flags = atomic_load (&snap->flags); \
@@ -319,8 +328,8 @@ M_BEGIN_PROTECTED_CODE
} \
\
/* Non const due to use of atomic_load */ \
static inline type * \
M_C(name, _get_write_buffer)(snapshot_t snap) \
M_INLINE type * \
M_F(name, _get_write_buffer)(snapshot_t snap) \
{ \
M_SNAPSH0T_SPSC_CONTRACT(snap); \
unsigned char flags = atomic_load(&snap->flags); \
@@ -328,8 +337,8 @@ M_BEGIN_PROTECTED_CODE
} \
\
/* Non const due to use of atomic_load */ \
static inline type const * \
M_C(name, _get_read_buffer)(snapshot_t snap) \
M_INLINE type const * \
M_F(name, _get_read_buffer)(snapshot_t snap) \
{ \
M_SNAPSH0T_SPSC_CONTRACT(snap); \
unsigned char flags = atomic_load(&snap->flags); \
@@ -337,8 +346,7 @@ M_BEGIN_PROTECTED_CODE
} \
/******************************** INTERNAL SPMC **********************************/
/********************************** INTERNAL *********************************/
#define M_SNAPSH0T_SPMC_INT_FLAG(w, n) ( ((w) << 1) | (n) )
#define M_SNAPSH0T_SPMC_INT_FLAG_W(f) ((f) >> 1)
@@ -347,7 +355,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 +364,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 +381,9 @@ typedef struct m_snapshot_mrsw_s {
M_ASSERT (s->cptTab != NULL); \
} while (0)
/* Initialize m_snapshot_mrsw_ct for n readers (constructor) */
static inline void
m_snapsh0t_mrsw_init(m_snapshot_mrsw_ct s, size_t n)
/* Initialize m_snapsh0t_mrsw_ct for n readers (constructor) */
M_INLINE void
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);
@@ -384,50 +392,50 @@ m_snapsh0t_mrsw_init(m_snapshot_mrsw_ct s, size_t n)
// Initialize the counters to zero (no reader use it)
atomic_uint *ptr = M_MEMORY_REALLOC (atomic_uint, NULL, n);
if (M_UNLIKELY (ptr == NULL)) {
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
M_MEMORY_FULL(sizeof (atomic_uint) * n);
return;
}
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) */
static inline void
m_snapsh0t_mrsw_clear(m_snapshot_mrsw_ct s)
/* Clear m_snapsh0t_mrsw_ct (destructor) */
M_INLINE void
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_INLINE unsigned int
m_snapsh0t_mrsw_get_write_idx(m_snapsh0t_mrsw_ct s)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
return s->currentWrite;
}
/* Return the number of readers */
static inline unsigned int
m_snapsh0t_mrsw_size(m_snapshot_mrsw_ct s)
M_INLINE unsigned int
m_snapsh0t_mrsw_size(m_snapsh0t_mrsw_ct s)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
return (unsigned int) s->n_reader;
@@ -435,8 +443,8 @@ 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_INLINE unsigned int
m_snapsh0t_mrsw_write_idx(m_snapsh0t_mrsw_ct s, unsigned int idx)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
@@ -462,8 +470,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.
@@ -477,8 +485,8 @@ 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_INLINE unsigned int
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);
@@ -486,13 +494,13 @@ 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_INLINE unsigned int
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);
@@ -501,8 +509,8 @@ 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_INLINE void
m_snapsh0t_mrsw_write_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
@@ -517,14 +525,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_INLINE unsigned int
m_snapsh0t_mrsw_read_start(m_snapsh0t_mrsw_ct s)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
unsigned int idx, previous;
@@ -558,7 +566,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);
@@ -566,8 +574,8 @@ 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_INLINE void
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,11 +585,14 @@ 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);
}
/********************************** INTERNAL *********************************/
/* Contract of a SPMC snapshot.
Nothing notable as it can be accessed concurrently */
#define M_SNAPSH0T_SPMC_CONTRACT(snap) do { \
@@ -591,7 +602,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) \
@@ -603,33 +614,40 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
/* Expand the type and the functions of a SPMC snapshot */
#define M_SNAPSH0T_SPMC_DEF_P3(name, type, oplist, snapshot_t) \
M_SNAPSH0T_SPMC_DEF_TYPE(name, type, oplist, snapshot_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_SNAPSH0T_SPMC_DEF_CORE(name, type, oplist, snapshot_t) \
/* Define the type */
#define M_SNAPSH0T_SPMC_DEF_TYPE(name, type, oplist, snapshot_t) \
\
/* Create an aligned type to avoid false sharing between threads */ \
typedef struct M_C(name, _aligned_type_s) { \
typedef struct M_F(name, _aligned_type_s) { \
type x; \
M_CACHELINE_ALIGN(align, type); \
} M_C(name, _aligned_type_ct); \
} M_F(name, _aligned_type_ct); \
\
typedef struct M_C(name, _s) { \
M_C(name, _aligned_type_ct) *data; \
m_snapshot_mrsw_ct core; \
typedef struct M_F(name, _s) { \
M_F(name, _aligned_type_ct) *data; \
m_snapsh0t_mrsw_ct core; \
} snapshot_t[1]; \
\
/* Define internal types for oplist */ \
typedef snapshot_t M_C(name, _ct); \
typedef type M_C(name, _subtype_ct); \
typedef snapshot_t M_F(name, _ct); \
typedef type M_F(name, _subtype_ct); \
/* Define the core functions */
#define M_SNAPSH0T_SPMC_DEF_CORE(name, type, oplist, snapshot_t) \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void \
M_C(name, _init)(snapshot_t snap, size_t nReader) \
M_INLINE void \
M_F(name, _init)(snapshot_t snap, size_t nReader) \
{ \
M_ASSERT (snap != NULL); \
M_ASSERT (nReader > 0 && nReader <= M_SNAPSH0T_SPMC_MAX_READER); \
snap->data = M_CALL_REALLOC(oplist, M_C(name, _aligned_type_ct), \
snap->data = M_CALL_REALLOC(oplist, M_F(name, _aligned_type_ct), \
NULL, nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
if (M_UNLIKELY (snap->data == NULL)) { \
M_MEMORY_FULL(sizeof(M_C(name, _aligned_type_ct)) * \
if (M_UNLIKELY_NOMEM (snap->data == NULL)) { \
M_MEMORY_FULL(sizeof(M_F(name, _aligned_type_ct)) * \
(nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER)); \
return; \
} \
@@ -640,8 +658,8 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
M_SNAPSH0T_SPMC_CONTRACT(snap); \
} \
\
static inline void \
M_C(name, _clear)(snapshot_t snap) \
M_INLINE void \
M_F(name, _clear)(snapshot_t snap) \
{ \
M_SNAPSH0T_SPMC_CONTRACT(snap); \
size_t nReader = m_snapsh0t_mrsw_size(snap->core); \
@@ -652,29 +670,29 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
m_snapsh0t_mrsw_clear(snap->core); \
} \
\
static inline type * \
M_C(name, _write)(snapshot_t snap) \
M_INLINE type * \
M_F(name, _write)(snapshot_t snap) \
{ \
M_SNAPSH0T_SPMC_CONTRACT(snap); \
const unsigned int idx = m_snapsh0t_mrsw_write(snap->core); \
return &snap->data[idx].x; \
} \
\
static inline type const * \
M_C(name, _read_start)(snapshot_t snap) \
M_INLINE type const * \
M_F(name, _read_start)(snapshot_t snap) \
{ \
M_SNAPSH0T_SPMC_CONTRACT(snap); \
const unsigned int idx = m_snapsh0t_mrsw_read_start(snap->core); \
return M_CONST_CAST(type, &snap->data[idx].x); \
} \
\
static inline void \
M_C(name, _read_end)(snapshot_t snap, type const *old) \
M_INLINE void \
M_F(name, _read_end)(snapshot_t snap, type const *old) \
{ \
M_SNAPSH0T_SPMC_CONTRACT(snap); \
M_ASSERT (old != NULL); \
const M_C(name, _aligned_type_ct) *oldx; \
oldx = M_CTYPE_FROM_FIELD(M_C(name, _aligned_type_ct), old, type, x); \
const M_F(name, _aligned_type_ct) *oldx; \
oldx = M_CTYPE_FROM_FIELD(M_F(name, _aligned_type_ct), old, type, x); \
M_ASSERT (oldx >= snap->data); \
M_ASSERT (oldx < snap->data + snap->core->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
M_ASSERT(snap->core->n_reader +M_SNAPSH0T_SPMC_EXTRA_BUFFER < UINT_MAX); \
@@ -682,8 +700,8 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
m_snapsh0t_mrsw_read_end(snap->core, idx); \
} \
\
static inline type * \
M_C(name, _get_write_buffer)(snapshot_t snap) \
M_INLINE type * \
M_F(name, _get_write_buffer)(snapshot_t snap) \
{ \
M_SNAPSH0T_SPMC_CONTRACT(snap); \
const unsigned int idx = m_snapsh0t_mrsw_get_write_idx(snap->core); \
@@ -691,16 +709,13 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
} \
\
//FIXME: Evaluate the needs for the methods _set_, _init_set.
/******************************** INTERNAL MPMC **********************************/
/********************************** INTERNAL *********************************/
// 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) \
@@ -712,48 +727,54 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
/* Expand the type and the functions of a MPMC snapshot */
#define M_SNAPSH0T_MPMC_DEF_P3(name, type, oplist, snapshot_t) \
M_SNAPSH0T_SPMC_DEF_P1((M_F(name, _mrsw), type, oplist, M_F(name, _mrsw_pct))) \
M_SNAPSH0T_MPMC_DEF_TYPE(name, type, oplist, snapshot_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_SNAPSH0T_MPMC_DEF_CORE(name, type, oplist, snapshot_t) \
/* Define the types */
#define M_SNAPSH0T_MPMC_DEF_TYPE(name, type, oplist, snapshot_t) \
\
M_SNAPSH0T_SPMC_DEF_P1((M_C(name, _mrsw), type, oplist, M_C(name, _mrsw_pct))) \
\
typedef struct M_C(name, _s) { \
M_C(name, _mrsw_pct) core; \
typedef struct M_F(name, _s) { \
M_F(name, _mrsw_pct) core; \
} snapshot_t[1]; \
\
/* Define internal types for oplist */ \
typedef snapshot_t M_C(name, _ct); \
typedef type M_C(name, _subtype_ct); \
typedef snapshot_t M_F(name, _ct); \
typedef type M_F(name, _subtype_ct); \
/* Define the core functions */
#define M_SNAPSH0T_MPMC_DEF_CORE(name, type, oplist, snapshot_t) \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void \
M_C(name, _init)(snapshot_t snap, size_t nReader, size_t nWriter) \
M_INLINE void \
M_F(name, _init)(snapshot_t snap, size_t nReader, size_t nWriter) \
{ \
M_C(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \
M_F(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); \
} \
\
static inline void \
M_C(name, _clear)(snapshot_t snap) \
M_INLINE void \
M_F(name, _clear)(snapshot_t snap) \
{ \
M_C(name, _mrsw_clear)(snap->core); \
M_F(name, _mrsw_clear)(snap->core); \
} \
\
static inline type * \
M_C(name, _write_start)(snapshot_t snap) \
M_INLINE type * \
M_F(name, _write_start)(snapshot_t snap) \
{ \
M_SNAPSH0T_SPMC_CONTRACT(snap->core); \
const unsigned int idx = m_snapsh0t_mrsw_write_start(snap->core->core); \
return &snap->core->data[idx].x; \
} \
\
static inline void \
M_C(name, _write_end)(snapshot_t snap, type *old) \
M_INLINE void \
M_F(name, _write_end)(snapshot_t snap, type *old) \
{ \
M_SNAPSH0T_SPMC_CONTRACT(snap->core); \
const M_C(name, _mrsw_aligned_type_ct) *oldx; \
oldx = M_CTYPE_FROM_FIELD(M_C(name, _mrsw_aligned_type_ct), old, type, x); \
const M_F(name, _mrsw_aligned_type_ct) *oldx; \
oldx = M_CTYPE_FROM_FIELD(M_F(name, _mrsw_aligned_type_ct), old, type, x); \
M_ASSERT (oldx >= snap->core->data); \
M_ASSERT (oldx < snap->core->data + snap->core->core->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
M_ASSERT(snap->core->core->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER < UINT_MAX); \
@@ -761,16 +782,16 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
m_snapsh0t_mrsw_write_end(snap->core->core, idx); \
} \
\
static inline type const * \
M_C(name, _read_start)(snapshot_t snap) \
M_INLINE type const * \
M_F(name, _read_start)(snapshot_t snap) \
{ \
return M_C(name, _mrsw_read_start)(snap->core); \
return M_F(name, _mrsw_read_start)(snap->core); \
} \
\
static inline void \
M_C(name, _read_end)(snapshot_t snap, type const *old) \
M_INLINE void \
M_F(name, _read_end)(snapshot_t snap, type const *old) \
{ \
M_C(name, _mrsw_read_end)(snap->core, old); \
M_F(name, _mrsw_read_end)(snap->core, old); \
} \
\
@@ -778,4 +799,16 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
M_END_PROTECTED_CODE
/********************************** INTERNAL *********************************/
#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
+1109 -715
View File
File diff suppressed because it is too large. Load diff
Loaded 100 of 164 files, more files were not shown because too many files have changed in this diff. Show more