756 Commits
Author SHA1 Message Date
Patrick Pelissier 91d40a0f43 V0.5.0 2021-01-13 20:18:01 +01:00
Patrick Pelissier 25fe26deaa Happy new year 2021-01-13 20:18:01 +01:00
Patrick Pelissier cd357c5eb7 Rewrite the wrappers of strncpy & strncat:
Add one argument about the allocation of the dest buffer
Theses wrappers are internal (so no impact to API)
and only used in a few place in m-string.
This make the wrappers able to use the function
strncpy_s & strncat_s for MSVC rather than using
reimplementation of the original functions.
2021-01-13 08:34:47 +01:00
Patrick Pelissier 561f67b3b9 Update list of ignored files 2021-01-13 08:27:00 +01:00
Patrick Pelissier 15a02e3306 Update final message 2021-01-10 20:04:14 +01:00
Patrick Pelissier 944d29e8bc Workaround CLANG preprocessor failure on Windows platform 2021-01-10 20:03:28 +01:00
Patrick Pelissier aefba70c1e Rework once again how to detect a failure in an application:
IF errorlevel 1 only works for positive error code
  IF not errorlevel 0 only works for negative error code
There are not reliable. So, use && and || instead.

Remove expected failure on test as all tests pass now
(and it was broken).
2021-01-10 18:08:48 +01:00
Patrick Pelissier c9ed4ba820 Fix compiler error with MSVC with new implementation of offsetof 2021-01-10 18:01:19 +01:00
Patrick Pelissier df97ea848c Fix error for C++ 2021-01-10 10:01:54 +01:00
Patrick Pelissier 93d810421d Fix warning with newest gcc 2021-01-10 09:57:07 +01:00
Patrick Pelissier f560839516 Add example of string_sets 2021-01-10 09:51:53 +01:00
Patrick Pelissier 8a9d5f6a00 Add macro string_sets (like string_cats) 2021-01-10 09:51:38 +01:00
Patrick Pelissier 5f05c1e169 Make stdarg an optional header. Some works remain to do to make stdio fully optional 2021-01-10 09:40:37 +01:00
Patrick Pelissier 3df2408ffb Add macro M_CSTR 2021-01-10 09:26:27 +01:00
Patrick Pelissier ffc2ec8c4b Fix format 2021-01-10 09:25:27 +01:00
Patrick Pelissier b0ebbb306e Update 2021-01-10 09:20:42 +01:00
Patrick Pelissier c3574aa290 Update comments 2021-01-10 09:02:52 +01:00
Patrick Pelissier eabc867c2a Rename used namespace for C++ to m_lib 2021-01-10 08:48:46 +01:00
Patrick Pelissier a03b2e80c6 Document string_cats 2021-01-07 22:13:10 +01:00
Patrick Pelissier c4f23640d5 Add test for string_cats 2021-01-07 22:13:10 +01:00
Patrick Pelissier a42b854f14 Add macro string_cats to concat multiple strings 2021-01-07 22:13:10 +01:00
Patrick Pelissier 9aa08bfc59 Add support for struct in M_AS_TYPE 2021-01-07 22:13:10 +01:00
Patrick Pelissier 06b79a6caa Add tests for M_AS_TYPE 2021-01-07 22:13:10 +01:00
Patrick Pelissier 6d533bd52a Add (internal) macro M_CONDITIONAL 2021-01-07 22:13:10 +01:00
Patrick Pelissier 1b4c608087 Rename operator TEST_EMPTY into EMPTY_P to be compliant with iterator operator 2021-01-07 22:13:10 +01:00
Patrick Pelissier 6ccc81fd92 Remove unused operator UPDATE_TYPE 2021-01-07 22:13:09 +01:00
Patrick Pelissier 6f7d3fcd79 Add limiation on M_EMPTY_P 2020-12-31 00:12:36 +01:00
Patrick Pelissier 7484dee707 Fix a corner case for M_EMPTY_P where it performs too much evaluation steps 2020-12-31 00:12:21 +01:00
Patrick Pelissier a580aaac83 Add more test cases for M_EMPTY_P 2020-12-31 00:11:37 +01:00
Patrick Pelissier 52bef353e0 Workaround WIN clang that claims to be C11 but fails to deliver a working assert.h (See #85) 2020-12-30 19:03:10 +01:00
Patrick Pelissier 826ecf76c0 Workaround a compiler warning 2020-12-30 19:02:00 +01:00
Patrick Pelissier 2cf5bff32d Fix negative error code termination for MSVS (See #86) 2020-12-30 17:58:43 +01:00
Patrick Pelissier 1377d7a1c2 Fix usage of strncpy_s and strncat_s
Provides a full wrapper around strncpy & strncat
(for MSVS as it complains on using strncpy & strncat).
See #86
2020-12-28 23:35:50 +01:00
Patrick Pelissier ab9284ca20 Update documentation 2020-12-27 10:44:41 +01:00
Patrick Pelissier 5dab01c1c7 Fix spelling 2020-12-26 09:08:42 +01:00
Patrick Pelissier f9c434401b Fix M_GET_STRING_ARG (See #84) 2020-12-26 09:00:39 +01:00
Patrick Pelissier 76b9f9a715 Add test cases for M_GET_STRING 2020-12-26 08:58:52 +01:00
Patrick Pelissier 2ee82c478b Remove useless type (see #82) 2020-12-24 10:58:51 +01:00
Patrick Pelissier 211121435d Fix warning in C++ mode with G++ 10 2020-12-24 08:13:44 +01:00
Patrick Pelissier fffd1702a5 CLANG 3.8 stdatomic works. Update minimun version 2020-12-24 07:35:45 +01:00
Patrick Pelissier 9aa99bf230 Update package list before installing multilib 2020-12-21 15:23:49 +01:00
Patrick Pelissier 1671ca8d67 Add more assertions 2020-12-21 15:16:16 +01:00
Patrick Pelissier ad16b310e1 Fix overflow issue in bitset_last_p (see #81) 2020-12-21 15:08:19 +01:00
Patrick Pelissier 4dbcfd25b3 Fix non support of break in M_LET_IF 2020-12-16 15:27:41 +01:00
Patrick Pelissier 01167b09c4 Add an example of M_LET_IF 2020-12-16 11:07:11 +01:00
Patrick Pelissier 15d0b86c62 Update documentation & add tests as per lastest changes 2020-12-16 11:07:11 +01:00
Patrick Pelissier edbcecb272 Add support for else condition in M_LET_IF. Fix also a bug in computing unique variable per line 2020-12-16 11:07:11 +01:00
Patrick Pelissier 1689db7b9c Fix spelling 2020-12-16 11:07:11 +01:00
Patrick Pelissier f5bc8796f7 Add functions:
* string_vprintf
* string_init_vprintf
2020-12-15 22:14:43 +01:00
Patrick Pelissier e893560a48 Add macros M_LET_IF and M_DEFER to help handling with runtime errors 2020-12-14 21:26:07 +01:00
Patrick Pelissier a4ff7c71f2 Update documentation 2020-12-13 00:18:53 +01:00
Patrick Pelissier 9f780805f0 Update 2020-12-10 07:59:28 +01:00
Patrick Pelissier 749273d1bb Update list of methods 2020-12-06 08:32:54 +01:00
Patrick Pelissier d8fd2e3e69 Update doc as per latest changes 2020-12-06 00:16:53 +01:00
Patrick Pelissier d443a84254 Remove deprecated funtion 2020-12-06 00:15:17 +01:00
Patrick Pelissier ef614b19ee Fix ISO C warning. 2020-12-05 18:33:26 +01:00
Patrick Pelissier 1c5c4aa50f Fix compatibility with C++
which doesn't support designated init.
2020-12-05 18:28:30 +01:00
Patrick Pelissier 5533ffffaa Add tests for intrusive shared pointers. 2020-12-05 18:14:38 +01:00
Patrick Pelissier 34c990e259 Add function _init_once for intrusive shared pointer 2020-12-05 18:14:22 +01:00
Patrick Pelissier 5f0b6b9f26 Fix format 2020-12-05 12:42:45 +01:00
Patrick Pelissier 26eb882a30 Rename tuple function :
* _init_set2 in _init_emplace
* _set2 in _emplace
due to better & clearer naming.
(API break)
2020-12-05 12:29:20 +01:00
Patrick Pelissier 4d0e799c7a Remove obsolete function. 2020-12-05 12:27:33 +01:00
Patrick Pelissier 6801f688a4 Clarify atomic thin layer limitation (see #79) 2020-12-01 07:27:14 +01:00
Patrick Pelissier bdf29af9e9 * Add DJB Xor hash * Rename function (see #78) 2020-11-29 22:05:24 +01:00
Patrick Pelissier 79dabfc52f Update documentation as per #76 2020-11-29 20:34:05 +01:00
Patrick Pelissier de2268c406 Factorization of comparaison by using memcmp 2020-11-29 20:06:56 +01:00
Patrick Pelissier 85ea1f40dc Use classic hash rather than fast one for C-String (fix assertion failure for C-String hash) 2020-11-29 19:36:28 +01:00
Patrick Pelissier f89ba94689 Add test for computing C-string hash (raise assertion failure) 2020-11-29 19:35:52 +01:00
Patrick Pelissier 0279dcc3cc Fix issue on MacOS 2020-11-25 22:56:51 +01:00
Patrick Pelissier 62c8e005bb Add a new example of array of strings. 2020-11-25 22:41:25 +01:00
Patrick Pelissier 2a28f8d407 Add string_init_printf 2020-11-25 22:41:11 +01:00
Patrick Pelissier 9802fc5098 Remove rapidstring as it is no longer maintained, and the author deleted the repository. 2020-11-24 23:04:33 +01:00
Patrick Pelissier f372a72fd8 Update list of libraries 2020-11-23 20:29:30 +01:00
Patrick Pelissier 9d661852b2 Factorization of replace_all function for all libraries 2020-11-23 20:14:17 +01:00
Patrick Pelissier b343d356c3 Add support for empty replaced string 2020-11-22 23:29:38 +01:00
Patrick Pelissier 2e4404ca7e Fix a (strange) warning for gcc 8 without assertions.
Add back the assertions as compile hints.
2020-11-22 23:20:04 +01:00
Patrick Pelissier 29eebaf38d Factorization of the allocation. 2020-11-22 23:11:09 +01:00
Patrick Pelissier d0d69aebfa Add final null char in computation of the needed size for the new function _replace_all 2020-11-22 23:09:37 +01:00
Patrick Pelissier 477c5853f1 Update bench to use new function. 2020-11-22 23:04:50 +01:00
Patrick Pelissier 55e7b3083a Add function string_replace_all[_str]
to replace all occurences of a string by another.
2020-11-22 23:04:32 +01:00
Patrick Pelissier 0b9e27fb7f Add note on 32 bits systems where atomic library is needed 2020-11-21 11:45:25 +01:00
Patrick Pelissier 36ac6d5104 Fix issue on single core system 2020-11-21 10:53:11 +01:00
Patrick Pelissier d898d6d4cc Remove duplicate function 2020-11-21 10:26:02 +01:00
Patrick Pelissier e7388929c4 Migrate to msys2 v2 for github actions. 2020-11-19 22:43:05 +01:00
Patrick Pelissier 45f8b31efc Add function string_subset 2020-11-19 22:31:33 +01:00
Patrick Pelissier ebf440731d Fix address sanitizer issue 2020-11-15 09:43:41 +01:00
Patrick Pelissier 501a4a65ec Add test cases 2020-11-15 09:39:29 +01:00
Patrick Pelissier 800d03f728 Update documentation. 2020-11-15 09:39:15 +01:00
Patrick Pelissier 19ff6bfeac Add equal_p method for m-prioqueue 2020-11-15 09:39:01 +01:00
Patrick Pelissier 24f5739a3b Update documentation. 2020-11-14 23:56:28 +01:00
Patrick Pelissier b658598e02 Update documentation for _update & _erase of priority queues. 2020-11-14 23:48:46 +01:00
Patrick Pelissier 47343a2893 Add proper test cases for _update of priority queue 2020-11-14 23:48:23 +01:00
Patrick Pelissier c1f99359be Fix issue in update of priority in priority queue:
* Rename _update_further into _update.
* it now supports increase or decrease of priority.
* _update_further is deprecated (and was broken).
2020-11-14 23:48:08 +01:00
Patrick Pelissier bd89e162fc Add support for additional parameter id 2020-11-14 23:45:38 +01:00
Patrick Pelissier 983a63fbbc Add more comments to explain how it works. 2020-11-14 22:45:39 +01:00
Patrick Pelissier 978e0ea5d7 Fix format 2020-11-14 22:45:18 +01:00
Patrick Pelissier 85c4b50b6f Improve coverage of prioriy queue. 2020-11-08 01:00:17 +01:00
Patrick Pelissier e77aec4619 Reduce test case for MacOS / MINGW (returning incorrect return value for printf) 2020-11-05 23:33:26 +01:00
Patrick Pelissier d67e084010 Fix introduced warning 2020-11-05 22:55:03 +01:00
Patrick Pelissier b0a74f162e Fix string_printf in case of error in formating. 2020-11-05 22:51:28 +01:00
Patrick Pelissier d92126b97e Add more tests (improve coverage) 2020-11-05 22:51:02 +01:00
Patrick Pelissier c055358fa2 Reformat 2020-11-05 22:50:38 +01:00
Patrick Pelissier 9f89148b69 Remove valgrind
(not working in Multithread code)
2020-11-05 22:02:44 +01:00
Patrick Pelissier ef1145603a Update comments. 2020-10-31 17:30:14 +01:00
Patrick Pelissier d169a06f79 Rename STRING_ASSERT_SLOW into M_ASERT_SLOW 2020-10-31 17:30:14 +01:00
Patrick Pelissier 8e15a8cfe9 Fix warnings of CodeQL 2020-10-31 00:35:28 +01:00
Patrick Pelissier 6466cefbf4 Fix yml syntax 2020-10-31 00:17:13 +01:00
Patrick Pelissier bec9a897c9 Update codeql to use test executable 2020-10-31 00:13:03 +01:00
Patrick Pelissier 37d47cb0f1 Cleanup static analyser 2020-10-31 00:12:40 +01:00
Patrick Pelissier 0854136005 Add target exe for analyser
Cleanup of static analyzer
2020-10-31 00:12:02 +01:00
Patrick Pelissier 9427931e45 Add CodeQL in continuous integration backend 2020-10-31 00:01:05 +01:00
Patrick Pelissier 6aa28b4cfe Fix warnings on ARM 2020-10-30 08:02:37 +01:00
Patrick Pelissier a29682ca29 Create M_ASSERT macro to encapsulate assert within M*LIB
The goal is to enable the user to override this macro if needed so that it can enable or disable the M*LIB witout impacting its own assertions.
2020-10-29 22:46:17 +01:00
Patrick Pelissier f5afd6e275 Update comments. 2020-10-25 21:16:43 +01:00
Patrick Pelissier 7b5fd14bcf Update comment. 2020-10-24 23:29:02 +02:00
Patrick Pelissier 22ce001f03 Remove incorrect use of M_ASSUME by assert 2020-10-24 23:14:14 +02:00
Patrick Pelissier 6f761091cc Update comment. 2020-10-24 23:07:29 +02:00
Patrick Pelissier bb9e0e4f6e Adding test for M_LET for bounded string 2020-10-24 14:03:31 +02:00
Patrick Pelissier 5e658a81fe Adding INIT_WITH support for bounded string within M_LET 2020-10-24 14:03:27 +02:00
Patrick Pelissier ddc722bf78 Add FIXME 2020-10-23 21:50:57 +02:00
Patrick Pelissier 0818d0ac7c Fix macro formatting. 2020-10-23 21:46:34 +02:00
Patrick Pelissier 2f315793cd Use of M_ASSERT_INDEX for deque 2020-10-23 21:45:37 +02:00
Patrick Pelissier 067a034bc9 Use of M_ASSERT_INDEX for list. 2020-10-23 21:39:33 +02:00
Patrick Pelissier 201cc45fd8 Use of M_ASSERT_INDEX for bitset. 2020-10-23 21:37:44 +02:00
Patrick Pelissier 7a270ffacb Update documentation 2020-10-23 21:32:06 +02:00
Patrick Pelissier 27bb62533a Use of M_ASSERT_INDEX
to validate user input.
2020-10-21 23:57:52 +02:00
Patrick Pelissier 032388b790 Update message 2020-10-21 23:57:24 +02:00
Patrick Pelissier f1e2f81e79 Improve formating of macros:
if the line is too long
and can be reduced,
reduce it.
2020-10-21 23:56:55 +02:00
Patrick Pelissier 54d4b80368 Reformat macro to 80 characters 2020-10-21 23:23:40 +02:00
Patrick Pelissier 8a0a556604 Add utility to reformat automatically
macro to 80 characters.
2020-10-21 23:23:16 +02:00
Patrick Pelissier 895f362628 Fix a majorant stack usage of B+TREE 2020-10-17 22:46:43 +02:00
Patrick Pelissier d24b52586d Put a type within internal namespaces. 2020-10-17 22:25:22 +02:00
Patrick Pelissier d76585cb0e Update test as per latest changes. 2020-10-17 22:25:05 +02:00
Patrick Pelissier fb44be6efe Remove argument itret_t from *SET_DEF_AS
as it is useless
(Return type IS the key type for a set).
2020-10-17 22:24:53 +02:00
Patrick Pelissier 0b6a5aaa97 Port to last API version of CMC 2020-10-17 20:14:06 +02:00
Patrick Pelissier c00fdc65a2 Change installation directory
so that all M*LIB headers are in one directory.
2020-10-17 13:22:17 +02:00
Patrick Pelissier ab7490eb8a Fix list of distributed files. 2020-10-17 13:17:47 +02:00
Patrick Pelissier 1a46c0cd3f Clarify should usage in the documentation. 2020-10-17 13:07:41 +02:00
Patrick Pelissier 22f595c015 Update comment 2020-10-17 12:39:09 +02:00
Patrick Pelissier 68c76ad146 Update example with latest changes. 2020-10-16 21:59:53 +02:00
Patrick Pelissier 0b18792b96 Document _DEF_AS macros
Fix #60
2020-10-16 21:56:42 +02:00
Patrick Pelissier 464e8e5f8f Clean usage of 'shall' within the documentation. 2020-10-16 21:33:01 +02:00
Patrick Pelissier 45410f3f0c Update README. 2020-10-16 21:04:07 +02:00
Patrick Pelissier 556e706343 Update doc as per last rename 2020-10-16 21:01:41 +02:00
Patrick Pelissier 1e534bd307 Rename derefence type of an iterator of a dict or a B+Treee into _ittref_t. 2020-10-16 21:01:29 +02:00
Patrick Pelissier 7a517ee3ae Upate comments. 2020-10-16 20:53:34 +02:00
Patrick Pelissier 9bb1957afa Rename internal types. 2020-10-16 20:51:24 +02:00
Patrick Pelissier 86f942ee5f Fix forgotten external type in internal function. 2020-10-15 22:15:01 +02:00
Patrick Pelissier a23df528e4 Add DICT_*_AS macros. 2020-10-15 22:05:18 +02:00
Patrick Pelissier 0e9af6dfac Prepare user name integration for OA dictionnaries. 2020-10-15 21:53:11 +02:00
Patrick Pelissier 99a8db1111 Prepare integration for custom names for dict. 2020-10-15 21:41:53 +02:00
Patrick Pelissier 24cdf1ca5c Use of internal types within the code
instead of external ones.
2020-10-03 16:07:32 +02:00
Patrick Pelissier f1b794b239 Use of external documented type
instead of internal type.
2020-10-03 16:07:14 +02:00
Patrick Pelissier b4fdcbc547 Factorization of the it_deref name for overloading 2020-10-03 15:48:44 +02:00
Patrick Pelissier ce9986f6d8 Factorization of common pattern for bucket dictionnaries. 2020-10-03 14:47:47 +02:00
Patrick Pelissier ad4dcae1db Add macro VARIANT_DEF2_AS 2020-10-03 14:07:14 +02:00
Patrick Pelissier b3fa63c971 Factorization of name usage 2020-10-03 14:07:14 +02:00
Patrick Pelissier 364101592b Remove unused file 2020-10-03 14:07:14 +02:00
Patrick Pelissier 5b89196cd7 Add macro TUPLE_DEF2_AS 2020-10-03 14:07:14 +02:00
Patrick Pelissier feb8b30048 Factorization of M_C(name, _t) 2020-10-03 14:07:14 +02:00
Patrick Pelissier 8340cf70fb Add macros
FUNC_OBJ_ITF_DEF_AS
FUNC_OBJ_INS_DEF_AS
2020-10-03 14:07:14 +02:00
Patrick Pelissier affb3778a0 Rename internal types to _ct 2020-10-03 14:07:14 +02:00
Patrick Pelissier c039f07f2d Add macros
BPTREE_DEF2_AS
BPTREE_DEF_AS
BPTREE_MULTI_DEF2_AS
BPTREE_MULTI_DEF_AS
2020-10-03 14:07:14 +02:00
Patrick Pelissier c180981768 Add macros
CONCURRENT_DEF_AS
CONCURRENT_RP_DEF_AS
2020-10-03 14:07:14 +02:00
Patrick Pelissier 2cfac5c332 Fix build issue in C11 for new macros. 2020-10-03 14:07:14 +02:00
Patrick Pelissier 8ba489eef3 Add macros
SNAPSHOT_SPSC_DEF_AS
SNAPSHOT_SPMC_DEF_AS
SNAPSHOT_MPMC_DEF_AS
2020-10-03 14:07:14 +02:00
Patrick Pelissier a4cb6e3681 Add macros SHARED_PTR_DEF_AS, SHARED_PTR_RELAXED_DEF_AS, SHARED_RESOURCE_DEF_AS 2020-10-03 14:07:14 +02:00
Patrick Pelissier 379e0be211 Use of new macro to define internal types not exported. 2020-10-03 14:07:14 +02:00
Patrick Pelissier acb886c391 Add macro RBTREE_DEF_AS 2020-10-03 14:07:14 +02:00
Patrick Pelissier 7f26ef0f1c Add new macros to define container
with the full given name.
2020-10-03 14:07:14 +02:00
Patrick Pelissier 1d8e541205 Add macros BUFFER_DEF_AS, QUEUE_MPMC_DEF_AS, QUEUE_SPSC_DEF_AS 2020-10-03 14:07:14 +02:00
Patrick Pelissier a4fa70a478 Add macro DEQUE_DEF_AS 2020-10-03 14:07:14 +02:00
Patrick Pelissier 3d3a473716 Add macro ILIST_DEF_AS 2020-10-03 14:07:14 +02:00
Patrick Pelissier e04b120d41 Add new macros _DEF_AS so that
user can define its own name for the generated types.
2020-10-03 14:07:14 +02:00
Patrick Pelissier 63eee6bba3 Update comments 2020-10-03 14:07:14 +02:00
Patrick Pelissier b396b42808 Update comments 2020-10-03 14:07:14 +02:00
Patrick Pelissier eb8b106f48 Update comments. 2020-10-03 14:07:14 +02:00
Patrick Pelissier 5d144991cb Reformat & add more assertions. 2020-10-03 14:07:14 +02:00
Patrick Pelissier 35718ae551 Rename type as internal types 2020-10-03 14:07:14 +02:00
Patrick Pelissier 1dd9aff402 Factorize the name of the object at top level. 2020-10-03 14:07:14 +02:00
Patrick Pelissier 6d47074457 Rename internal types of m-core 2020-10-03 14:07:14 +02:00
Patrick Pelissier 1943650ca3 Factorization of the name of the object
at the top level to be able to create
new high level macros that enables
to select the full name of the type.
2020-10-03 14:07:14 +02:00
Patrick Pelissier 5722f19939 Update comments 2020-10-03 14:07:14 +02:00
Patrick Pelissier 7cf14b5d8a Update formatting 2020-10-03 14:07:14 +02:00
Patrick Pelissier b3a1a75f6f Rename internal types:
a suffix ending with _ct means confidential type
ans is reserved for M*LIB internal usage.

OPLIST doesn't use the external types
but rather the internal types.
It enables to be independent of the real names
of the external types.
Such external names are planned to be fully customizable
(i.e. the user may define a name that suits its coding style)
2020-10-03 14:07:14 +02:00
Patrick Pelissier eb7556f88f Replace abort by assert for static analyszer 2020-08-22 18:58:48 +02:00
Patrick Pelissier 805c747c60 Add more assertions (help static analyzer) 2020-08-22 18:54:51 +02:00
Patrick Pelissier 5f9feb833c Replace TAB by SPACE 2020-07-25 19:17:25 +02:00
Patrick Pelissier efef35c1e1 Reformat 2020-07-25 18:20:17 +02:00
Patrick Pelissier b1b32f565d Transform TAB into SPACE. 2020-07-25 18:15:57 +02:00
Patrick Pelissier f4cd8eaff9 Rename internal macro to TUPLEI_ 2020-07-25 18:01:34 +02:00
Patrick Pelissier 2cd5258f89 Add comments
Replace TAB by SPACE.
2020-07-25 17:54:01 +02:00
Patrick Pelissier 1b206931df Transform TAB into SPACE 2020-07-22 20:51:45 +02:00
Patrick Pelissier f68840ef8c Update doc 2020-07-19 01:12:12 +02:00
Patrick Pelissier 779c15ec08 Update tests as per new semantics 2020-07-19 01:11:15 +02:00
Patrick Pelissier 29bcc00202 Update format 2020-07-19 01:06:48 +02:00
Patrick Pelissier 1ff0d9fac0 Add test for _sort_intersect 2020-07-19 01:01:53 +02:00
Patrick Pelissier 4488853642 Factorization of _sort_union 2020-07-19 00:59:11 +02:00
Patrick Pelissier d5dc5d083d Fix _sort_union bug 2020-07-19 00:55:51 +02:00
Patrick Pelissier 784c42d850 Update _insert functions to update
iterators as per new specification.
2020-07-19 00:55:35 +02:00
Patrick Pelissier 8c1eb1fcb5 Add tests for _sort_union 2020-07-19 00:53:58 +02:00
Patrick Pelissier 49180bfbe5 Add documentation on IT_INSERT operator 2020-07-19 00:53:43 +02:00
Patrick Pelissier a3116dd813 Update comments 2020-07-18 09:54:12 +02:00
Patrick Pelissier 23df465401 Update comments 2020-07-14 14:44:10 +02:00
Patrick Pelissier 966170452f Improve test representativity by simulating various speeds for readers and writers 2020-07-14 14:43:14 +02:00
Patrick Pelissier eaf7ae7dee Fix spelling 2020-07-14 00:47:25 +02:00
Patrick Pelissier 8a6652646a Fix formatting (Replace TAB with SPACE) 2020-07-14 00:34:59 +02:00
Patrick Pelissier 2063bf879d Formatting: replace TAB by SPACE. 2020-07-14 00:26:26 +02:00
Patrick Pelissier 2529d4ae49 Update comments & remove warning about _Atomic 2020-07-12 22:52:36 +02:00
Patrick Pelissier 439bc06423 Fix unused value warning 2020-07-12 00:32:09 +02:00
Patrick Pelissier ab6c90f42f Fix issue with a warning that it triggers now but now before, whereas the code has not changed. Another random warning 2020-07-11 20:39:27 +02:00
Patrick Pelissier ac9e9a83b9 Fix issue with warnings on MacOS 2020-07-11 20:38:51 +02:00
Patrick Pelissier e495b92ae5 Workaround warnings about unused return value 2020-07-11 20:29:55 +02:00
Patrick Pelissier 50b1bedc54 Workaround some warnings 2020-07-11 20:13:31 +02:00
Patrick Pelissier 4a80ccd5f4 Add optimization to enable more warnings 2020-07-11 20:13:13 +02:00
Patrick Pelissier 6ca65dd60c Update comment 2020-07-11 18:36:46 +02:00
Patrick Pelissier b2be4d5397 Improve checking of failure detection 2020-07-11 18:02:27 +02:00
Patrick Pelissier de34cefa83 add test for detecting call to disable method 2020-07-11 18:02:11 +02:00
Patrick Pelissier 40c8dbae1e Update detection of disabled method 2020-07-11 18:01:48 +02:00
Patrick Pelissier 18af53cf38 Disable Wformat-nonliteral in the protected section 2020-07-11 17:18:43 +02:00
Patrick Pelissier 8510318ba5 Another minor warning about casting a double into a float 2020-07-11 17:17:59 +02:00
Patrick Pelissier 6ad02ffe56 Stop on warnings for CI 2020-07-11 16:57:03 +02:00
Patrick Pelissier 535e45d564 Update flags 2020-07-10 13:00:07 +02:00
Patrick Pelissier e2c60aa45c Fix another warnings that are triggered in another random combinaison of compiler settings 2020-07-10 12:59:31 +02:00
Patrick Pelissier 56d2a74818 Fix some warnings 2020-07-09 23:38:34 +02:00
Patrick Pelissier 8a36b5ff15 Workaround to avoid CLANG unused function warnings 2020-07-09 22:14:00 +02:00
Patrick Pelissier 7607645636 Reeanble Wunused-function 2020-07-09 22:13:24 +02:00
Patrick Pelissier cbb84accfe Add build on linux 32 bits 2020-07-09 17:31:16 +02:00
Patrick Pelissier 3e70cf7b5f TCC doesn't support -MM, so use cc to generate them 2020-07-09 10:45:09 +02:00
Patrick Pelissier 1a7deef735 Add TCC target 2020-07-09 10:38:35 +02:00
Patrick Pelissier 748771ab72 Update comment 2020-07-09 10:37:37 +02:00
Patrick Pelissier 6ef279dd2f Add comments 2020-07-07 18:30:14 +02:00
Patrick Pelissier abcf37dc72 Update 2020-07-07 13:07:54 +02:00
Patrick Pelissier 690b7bf9c1 Fix other warning for msys2 2020-07-05 23:53:06 +02:00
Patrick Pelissier 71cec5155a Fix uncompliant m-atomic support
if __STDC_NO_ATOMICS__ is defined, then in C11, there is no stdatomic header
2020-07-04 23:34:24 +02:00
Patrick Pelissier d2b0873a95 Add missing make for msys2 2020-07-04 23:09:37 +02:00
Patrick Pelissier 4cecdbb93e Add missing packages for msys2 as per https://www.msys2.org/docs/ci/ 2020-07-04 23:01:47 +02:00
Patrick Pelissier 2abca7d244 Update command line for msys2 as per https://www.msys2.org/docs/ci/ 2020-07-04 22:58:16 +02:00
Patrick Pelissier c26b467e86 Update command line for msys2 2020-07-04 22:48:41 +02:00
Patrick Pelissier 19514b09b0 Add msys2 target 2020-07-04 22:34:07 +02:00
Patrick Pelissier ab98577deb Fix warning 2020-07-04 12:50:34 +02:00
Patrick Pelissier aae5f00dbd Add new benchmark 2020-07-04 00:47:06 +02:00
Patrick Pelissier 04706d48b9 Fix further warnings 2020-07-03 23:03:12 +02:00
Patrick Pelissier c7df60c78d Fix some warnings 2020-07-03 22:44:34 +02:00
Patrick Pelissier f03a4503eb Fix some warnings 2020-07-03 22:15:54 +02:00
Patrick Pelissier a6951fe5e3 Fix warnings for clang-cl 2020-07-03 21:59:25 +02:00
Patrick Pelissier 6def48a0d1 Fix clang-cl to target x64 mode 2020-07-03 21:30:19 +02:00
Patrick Pelissier 8b5d1e07ce Fix build with MSVC in 32 bits mode 2020-07-03 21:25:20 +02:00
Patrick Pelissier 3182c39280 Add clang-cl in the continuous Integration 2020-07-03 21:18:17 +02:00
Patrick Pelissier e0b5dc2f02 Add test for clang-cl 2020-07-03 20:59:42 +02:00
Patrick Pelissier 6e5181e405 Fix doc on B+TREE 2020-07-02 23:22:44 +02:00
Patrick Pelissier 75f4f23144 Add comments and fix Pn level 2020-07-02 21:41:57 +02:00
Patrick Pelissier bc1402f66a Udpate documentation 2020-07-02 10:40:41 +02:00
Patrick Pelissier fc5ffcb404 Update API 2020-07-02 10:39:22 +02:00
Patrick Pelissier bd20a021ce Update documentation 2020-07-02 10:39:15 +02:00
Patrick Pelissier dfd12107de Add new function _clear_ptr 2020-07-02 10:39:05 +02:00
Patrick Pelissier 6743cb9456 Add posibility for user to select Thread backend directly 2020-07-02 00:09:54 +02:00
Patrick Pelissier 4aa93325e9 Update documentation 2020-07-01 12:08:24 +02:00
Patrick Pelissier f2a06ede62 Add mechanism to disable temporary compiler warnings in a sequence of code. 2020-07-01 11:47:55 +02:00
Patrick Pelissier a36752b8ce Update documentation (Fix #66) 2020-07-01 11:45:24 +02:00
Patrick Pelissier 3b347f2ba5 Reduce some warnings using the atomic compatibility layer (cannot fix all) 2020-07-01 11:06:58 +02:00
Patrick Pelissier 47296e5c11 The user can define M_USE_C11_NO_THREADS to disable C11 header (Support for broken C11 implementation) 2020-06-29 21:53:09 +02:00
Patrick Pelissier a24c530ec6 Update documentation on _init_new method 2020-06-29 16:03:54 +02:00
Patrick Pelissier 7ebe0608ae Define _init_new method only if NEW method has not been disabled 2020-06-29 16:03:38 +02:00
Patrick Pelissier 2a3021c021 Adding more code generation. 2020-06-29 16:01:38 +02:00
Patrick Pelissier 4d313aa72b Fix warning about unused function 2020-06-29 15:16:37 +02:00
Patrick Pelissier 7906a39647 Fix warning about unused function 2020-06-29 15:16:03 +02:00
Patrick Pelissier 86254958f0 Add precision on C11 thread layer (#65) 2020-06-29 15:02:34 +02:00
Patrick Pelissier 0089c1af61 Remove clang-cl as it is not available 2020-06-28 23:08:44 +02:00
Patrick Pelissier 6b5a3ddef7 Add clang-cl version 2020-06-28 23:04:06 +02:00
PpHd 42c2fd69a2 Merge pull request #64 from vladipus/patch-2
Update m-core.h
2020-06-27 21:12:44 +02:00
Vladislav Dmitrievich Turbanov bcb9b831db Update m-core.h
A tiny typo. MSVS should be referred to as MSVC - that is the standard way.
2020-06-27 19:08:52 +03:00
Patrick Pelissier f6483cbb30 It seems GNUC is force to 4 for APPLE/CLANG 2020-06-27 01:00:46 +02:00
Patrick Pelissier f742707699 Always use atomic in C++ 2020-06-27 00:31:58 +02:00
Patrick Pelissier aee02d86ab Workaround issue with CLANG++ on MAC 2020-06-27 00:10:40 +02:00
Patrick Pelissier dfbf34daf6 Remove a warning with some compiler by encoding 0 as UINT_MAX+1 2020-06-26 23:48:59 +02:00
Patrick Pelissier 494cbbecf0 Try to make Apple Make working in C11 mode 2020-06-26 23:40:49 +02:00
Patrick Pelissier a1513777f1 Activate C++ build too 2020-06-26 23:38:54 +02:00
Patrick Pelissier 9784a16d47 Get ride of modular arithmetic 2020-06-26 00:25:15 +02:00
Patrick Pelissier a8648e0cc1 Fix variable name for conditional code 2020-06-25 23:49:28 +02:00
Patrick Pelissier 3f8e93ad7a Use of intrinsic for clz within MSVS 2020-06-25 23:45:39 +02:00
Patrick Pelissier b040bc411f Add tests for builtin core functions 2020-06-25 23:35:34 +02:00
Patrick Pelissier ae8c3e5300 Update documentation about array & mandatory operators 2020-06-25 22:49:54 +02:00
Patrick Pelissier 01d390c3e9 Test array without INIT_SET & SET 2020-06-25 22:49:36 +02:00
Patrick Pelissier 56e4cda76c Make INIT_SET & SET operators of arrays as optional 2020-06-25 22:49:25 +02:00
Patrick Pelissier c59d585c22 Add new macro to test method1 or method2 in oplist 2020-06-25 22:49:08 +02:00
PpHd 81c97682a7 Merge pull request #62 from vladipus/patch-1
Update README.md
2020-06-25 21:21:18 +02:00
Patrick Pelissier a432628df6 Fix warnings for CLANG/WINDOWS (#61) 2020-06-25 21:18:01 +02:00
Vladislav Dmitrievich Turbanov d16effb4c5 Update README.md
Fixed a small typo in the ALGO_DEF example, that features an ARRAY_OPLIST with `int` instead of `array_int`
2020-06-25 22:13:53 +03:00
Patrick Pelissier 6279f98bb5 Run also in C11 mode for CI 2020-06-24 21:15:51 +02:00
Patrick Pelissier 3cbc474e76 Document M_ENUM_OPLIST 2020-06-24 21:14:00 +02:00
Patrick Pelissier c80fb7bebe Add test for M_ENUM_OPLIST (in particular I/O tests) 2020-06-24 21:13:43 +02:00
Patrick Pelissier 68788a6fb8 Add M_ENUM_OPLIST 2020-06-24 21:13:13 +02:00
Patrick Pelissier fd3cb50249 Remove temporary file 2020-06-22 00:38:19 +02:00
Patrick Pelissier 7e0bd8414d Fix warnings for mingw 2020-06-22 00:33:10 +02:00
Patrick Pelissier 70de571dc8 Fix warnings in test suite. 2020-06-22 00:14:55 +02:00
Patrick Pelissier cc6da8941c * Fix wanings for reduce precision on integers.
* Add wrapper for strncat
2020-06-22 00:14:37 +02:00
Patrick Pelissier d27c448a94 Fix some warnings with MSVS
for the test suite.
2020-06-21 23:52:12 +02:00
Patrick Pelissier 06a1590645 Add missing assertion. 2020-06-21 23:51:49 +02:00
Patrick Pelissier 652653af0b Fix some warnings by casting
for compilers which cannot detect the affectations as ok.
2020-06-21 23:50:49 +02:00
Patrick Pelissier c520b7d0be Enable Annex K for MSVS 2020-06-21 23:36:47 +02:00
Patrick Pelissier 4f4605befb Use of Annex K for MSVS to reduce warnings. 2020-06-21 23:36:34 +02:00
Patrick Pelissier 3f84f54d65 Add casts to avoid some compiler warnings
if the compiler is not able to detect the cast if safe.
2020-06-21 23:03:40 +02:00
Patrick Pelissier bf49b8e933 Enable warnings for MSVS 2020-06-21 22:43:06 +02:00
Patrick Pelissier 1edb204ec6 Update documentation 2020-06-19 21:14:46 +02:00
Patrick Pelissier dd5c9ac8ad Fix corner case of string_fget_word when it doesn't end with a separator 2020-06-19 21:11:05 +02:00
Patrick Pelissier 32b6f82249 Add corner case for string_fget_word when it doesn't end with a separator 2020-06-19 21:10:46 +02:00
Patrick Pelissier 44b3895698 Fix m_core_fscan_* in case of EOF 2020-06-19 21:02:17 +02:00
Patrick Pelissier 5ce6ccde3d Add bench for deque 2020-06-18 22:04:56 +02:00
Patrick Pelissier ee64e068f9 Add bench for rapidjson 2020-06-14 21:12:02 +02:00
Patrick Pelissier 8d89e7c958 Add leak sanitizer to sanitize target. 2020-06-14 11:33:01 +02:00
Patrick Pelissier ef74f8eb55 Fix other warnings about conversion but in C++ 2020-06-14 01:10:37 +02:00
Patrick Pelissier a7749e944f Fix strange warning with gcc 2020-06-14 00:48:58 +02:00
Patrick Pelissier 18bf06ff5f Add m_core_serial_fail for make debugging easier for serialization
Fix issue in saving size_t for 32 bits system
2020-06-14 00:40:11 +02:00
Patrick Pelissier b27f490acb Fix typing 2020-06-14 00:18:26 +02:00
Patrick Pelissier e84fa859c6 Fix implicit conversion. 2020-06-14 00:17:44 +02:00
Patrick Pelissier 4c57ca69bc Support for 32 bits system. 2020-06-14 00:17:22 +02:00
Patrick Pelissier b0d2557ea1 string_fgets:
Fix buffer overflow for very big string
2020-06-14 00:17:09 +02:00
Patrick Pelissier 82906e03e9 Add warning also for GCC. 2020-06-13 20:02:29 +02:00
Patrick Pelissier 1859868838 Fix sign conversion for algorithm tests. 2020-06-13 20:02:14 +02:00
Patrick Pelissier 4ab3a3605b Fix -Wsign-conversion warnings in tests. 2020-06-13 19:43:52 +02:00
Patrick Pelissier 279b46b4e2 Fix -Wsign-conversion warnings. 2020-06-13 19:43:38 +02:00
Patrick Pelissier 17950c5fe5 Fix corner cases for string_reserve 2020-06-13 18:57:53 +02:00
Patrick Pelissier 45b94c8abc Add corner cases for string_reserve 2020-06-13 18:57:39 +02:00
Patrick Pelissier a98ebd3b20 Fix test. 2020-06-13 18:53:40 +02:00
Patrick Pelissier cb7cd1ac67 Simplify code 2020-06-13 18:53:28 +02:00
Patrick Pelissier 9a41faf40a Fix -Wsign-conversion warning for strings. 2020-06-13 18:41:23 +02:00
Patrick Pelissier 8c44362f74 More test case. 2020-06-13 18:41:06 +02:00
Patrick Pelissier 548c0c0c61 Fix -Wsign-conversion warning 2020-06-13 18:37:10 +02:00
Patrick Pelissier 607221f480 Fix expected result due to change in list + INIT_WITH 2020-06-13 18:19:29 +02:00
Patrick Pelissier 160c76361b Add -Wsign-conversion when checking with clang 2020-06-13 18:15:53 +02:00
Patrick Pelissier 2fadad0c8d Fix warnings raised by -Wsign-conversion of clang
in m-core.h
2020-06-13 18:15:26 +02:00
Patrick Pelissier 4d4973abcc Fix warning 2020-06-13 17:57:31 +02:00
Patrick Pelissier f8ae9eb677 Add bench of serialization of integers 2020-06-13 17:38:14 +02:00
Patrick Pelissier de825203cf Ignore other temporary files 2020-06-13 17:37:54 +02:00
Patrick Pelissier 4f865176d3 Add bench for serialization. 2020-06-13 17:30:58 +02:00
Patrick Pelissier cb4b43e2e8 * Add length param for seralization write_string
to increase a little bit the performance for big strings.
* Change the format of storing strings for serial-bin.
2020-06-13 17:26:07 +02:00
Patrick Pelissier 89b6e1aac0 Adding serialization for bounded string 2020-06-13 11:30:52 +02:00
Patrick Pelissier daeaa242b8 Add new types to be used for M_LET:
* m_serial_bin_write_t
* m_serial_bin_read_t
2020-06-13 11:21:33 +02:00
Patrick Pelissier 100af17328 Make copyright notice explicit 2020-06-13 10:44:47 +02:00
Patrick Pelissier 7527bfec85 Update comments 2020-06-13 00:17:35 +02:00
Patrick Pelissier f73d25c92d Update documentation after renaming 2020-06-12 20:00:20 +02:00
Patrick Pelissier 9080f5d52f Add basic tests for M_KEEP_ARGS / M_SKIP_ARGS / M_MID_ARGS 2020-06-12 20:00:04 +02:00
Patrick Pelissier 6beb142bbe Fix conflict with SVID2/XPG mallopt options #53 2020-06-12 19:58:18 +02:00
PpHd 9b8b93288a Merge pull request #51 from vladipus/patch-1
Update README.md
2020-06-12 19:42:51 +02:00
Vladislav Dmitrievich Turbanov 6a2a549ec5 Update README.md
Fixed a M_IPTR missing *
2020-06-11 19:46:40 +03:00
Patrick Pelissier 468b7e7a0c Add bench for CMC 2020-06-10 22:29:59 +02:00
Patrick Pelissier fd640e9232 Update change of behaviors 2020-06-08 22:58:52 +02:00
Patrick Pelissier d13d7feae3 Update test as per new behavior 2020-06-08 22:58:41 +02:00
Patrick Pelissier 17f69326e2 Reverse order of a list initialized with M_LET to match the behavior of array 2020-06-08 22:58:30 +02:00
Patrick Pelissier 273fcd51b6 Add bench for rigtorp MPMCQueue 2020-06-06 12:00:52 +02:00
Patrick Pelissier f4b9185ceb Update documentation on QUEUE_MPMC 2020-06-06 11:09:55 +02:00
Patrick Pelissier b722227b39 Update comment 2020-06-05 21:06:06 +02:00
Patrick Pelissier 3d7e2f5c6b Fix m*lib version 2020-06-05 21:01:11 +02:00
Patrick Pelissier 9369530068 Comments & formating 2020-06-05 20:50:34 +02:00
Patrick Pelissier 4e968c3777 Comment the exponential backoff object. 2020-06-05 20:39:16 +02:00
Patrick Pelissier 9a5302ac19 Rename internal backoff
to avoid consummign too much namespace
2020-06-05 20:34:31 +02:00
Patrick Pelissier 8216ef0f7b Factorization of check of index
So that it can be reused for other modules.
2020-06-05 20:30:07 +02:00
Patrick Pelissier b897027021 Add user customizable ARRAY macro
for checking if index is within the allowedd bounds even in release mode
2020-06-05 00:11:22 +02:00
Patrick Pelissier 6095cf8610 Reindent file. 2020-06-04 23:51:17 +02:00
Patrick Pelissier e917ac5663 Update comments and simplify 2020-06-02 22:57:38 +02:00
Patrick Pelissier 2b44892aad Add more comments 2020-05-31 00:36:47 +02:00
Patrick Pelissier 294e45c7e1 Add comments 2020-05-31 00:15:46 +02:00
Patrick Pelissier 467acfdd10 Use of M_BOOL_OPLIST
to avoid warnings.
2020-05-30 23:45:46 +02:00
Patrick Pelissier d3823951b5 Add M_BOOL_OPLIST 2020-05-30 23:45:29 +02:00
Patrick Pelissier cc33079d43 Add comments 2020-05-30 23:38:31 +02:00
Patrick Pelissier 78d0bfb286 Port new error oplist format to all containers. 2020-05-30 18:00:43 +02:00
Patrick Pelissier b2f5ae6917 Proper generation. 2020-05-30 17:54:58 +02:00
Patrick Pelissier 9c723da768 Change format of errror on oplist
This is to enable M_GLOBAL_OPLIST_OR_DEF to properly expand the erroneous oplist to the backend generator, that will report the error.
As such the erreneous oplist is surrounded by two pairs of brackets (())
2020-05-30 17:54:22 +02:00
Patrick Pelissier 70c3932f6e Add new test on proper error checking 2020-05-30 17:52:31 +02:00
Patrick Pelissier 92bddcaab4 Fix preprocessing issue
in case of recursive tuple or variant.
2020-05-30 12:13:43 +02:00
Patrick Pelissier 79a8401d75 Fix oplist definiiton
Improve test suite
2020-05-30 12:07:21 +02:00
Patrick Pelissier 570473e465 Improve test suite. 2020-05-30 11:33:37 +02:00
Patrick Pelissier 990b7b02d7 Update list of expected failures 2020-05-30 11:23:53 +02:00
Patrick Pelissier 0b301d1cea Fix oplist definition. 2020-05-30 11:12:15 +02:00
Patrick Pelissier f35db79792 Work around C++ warnings 2020-05-30 10:46:17 +02:00
Patrick Pelissier dc1f163716 Fix option name with new cl 2020-05-30 10:41:51 +02:00
Patrick Pelissier 4d6bb407ee Reenable MSVC test suite with new compiler version (16.6) 2020-05-30 10:34:02 +02:00
Patrick Pelissier 37cef298c6 Update format 2020-05-29 21:49:03 +02:00
Patrick Pelissier 0396d1f648 Go to next development version 2020-05-29 21:07:43 +02:00
Patrick Pelissier e694d83cc4 V0.4.0 2020-05-27 21:50:03 +02:00
Patrick Pelissier 19fc150763 Discard warning with clang++ 2020-05-27 21:41:31 +02:00
Patrick Pelissier 3784f653d9 Fix warning with CLANG 2020-05-27 21:41:11 +02:00
Patrick Pelissier eb40cff6a1 Improve checkall target to stop on warning 2020-05-27 21:09:07 +02:00
Patrick Pelissier b7f84236d3 * Update comments
* Micro optimization
2020-05-25 21:41:16 +02:00
Patrick Pelissier 65e3f1049b * Update comments.
* Fix position of const for some prototypes.
2020-05-25 00:23:12 +02:00
Patrick Pelissier cc45b9c1fe Fix issue in test suite. 2020-05-24 20:39:20 +02:00
Patrick Pelissier 9340c2e55c Fix memory leak for _parse_str in case of error. 2020-05-24 19:50:32 +02:00
Patrick Pelissier 9710e014f2 Reindent function 2020-05-24 19:19:19 +02:00
Patrick Pelissier 7761fb6bf1 Add contract for tuple & variant. 2020-05-24 19:08:18 +02:00
Patrick Pelissier 2f4df5f67c Fix potential read before init in test. 2020-05-24 19:07:29 +02:00
Patrick Pelissier b841f81416 Fix package name for MS Windows
The filesystem doesn't support '*'
2020-05-24 18:14:25 +02:00
Patrick Pelissier 72fd53ab44 Update comments 2020-05-24 12:01:56 +02:00
Patrick Pelissier 8335bc525b Add comments 2020-05-23 16:09:18 +02:00
Patrick Pelissier 9e5d14ce36 Factorization & add tests 2020-05-21 13:10:50 +02:00
Patrick Pelissier 3bafede8b7 * Make the test more pertinent 2020-05-21 12:32:33 +02:00
Patrick Pelissier 3f2904ab0d * Add comment 2020-05-21 12:32:20 +02:00
Patrick Pelissier 933b495ed1 * Optimization for M_LET for a string_t in case of constant non formatted string
* Support for string_t in M_LET for string_t in C11 mode.
* Adding associate test
2020-05-21 12:19:17 +02:00
Patrick Pelissier 77813adc00 Add example of formatted C string for string in M_LET 2020-05-21 11:55:35 +02:00
Patrick Pelissier ce2adea6c0 Update documentation 2020-05-21 09:54:08 +02:00
Patrick Pelissier 3ecdfff8f0 Remove more cleanly generated configuration file. 2020-05-21 00:54:24 +02:00
Patrick Pelissier a103ceb850 Add new example of array of string. 2020-05-21 00:36:35 +02:00
Patrick Pelissier 9f24b89487 Add debug flag for example 2020-05-21 00:36:13 +02:00
Patrick Pelissier 8be06cadb3 Add comments on description. 2020-05-20 23:21:27 +02:00
Patrick Pelissier c488d979cf Ignore Visual Code directory if any. 2020-05-20 23:05:28 +02:00
Patrick Pelissier f4c24f07af Update comment description of macros and functions 2020-05-20 22:36:36 +02:00
Patrick Pelissier 3d2ce63d63 Fix performance issue in benchmarks 2020-05-19 23:21:00 +02:00
Patrick Pelissier 0ac2c62ffe Port to new API 2020-05-19 22:57:08 +02:00
Patrick Pelissier 6001781e68 Cleanup namespace, add comments, and remove dead code 2020-05-17 21:39:24 +02:00
Patrick Pelissier d90cb7caf3 Update doc 2020-05-17 12:11:10 +02:00
Patrick Pelissier 88a4835025 Fix issue when defining algorithm with same prefix than container 2020-05-17 12:11:04 +02:00
Patrick Pelissier 75ae7a06e5 Add missing tests 2020-05-17 11:53:43 +02:00
Patrick Pelissier 3885cb29a2 Add control of type and oplists 2020-05-17 11:53:27 +02:00
Patrick Pelissier bf3ffd1766 Add test cases for new control 2020-05-17 11:10:06 +02:00
Patrick Pelissier d884d257bb Export TYPE operator in oplist 2020-05-17 10:53:17 +02:00
Patrick Pelissier a87cac84dd Move up control so that it is the first error reported by the compiler. 2020-05-17 10:52:54 +02:00
Patrick Pelissier d1ae26f0fd * Add control than the type and the oplist are compatible 2020-05-17 10:27:30 +02:00
Patrick Pelissier 9c58e73c37 * Add M_CHECK_COMPATIBLE
* Fix issue in oplist
2020-05-17 10:26:40 +02:00
Patrick Pelissier 024b62a7a7 Add instance for M_CHECK_COMPATIBLE to be able to check multiple types within one container. 2020-05-17 10:26:08 +02:00
Patrick Pelissier c59731775e * Provide alternative for M_STATIC_ASSERT in GNUC + C11 with improved error messages
* Add internal macro M_CHECK_COMPATIBLE_OPLIST to check if a type and an oplist could match.
2020-05-17 09:36:50 +02:00
Patrick Pelissier 4668476c6a Fix issue with old version of ICC 2020-05-16 14:47:30 +02:00
Patrick Pelissier 743959ebde Fix micro performance issue 2020-05-16 14:09:49 +02:00
Patrick Pelissier dd27fa7e72 Add coverage for Function Object 2020-05-16 10:24:29 +02:00
Patrick Pelissier f2025f83d3 Fix help usage 2020-05-16 09:41:05 +02:00
Patrick Pelissier 8c06b43b2b Update tests for new controls 2020-05-15 21:46:18 +02:00
Patrick Pelissier 3cde7a1731 Add protection for use of oplist within a container oplist 2020-05-15 21:46:03 +02:00
Patrick Pelissier e9db1d28b8 Try to work around to print the oplist 2020-05-15 21:45:21 +02:00
Patrick Pelissier adffaf0e87 Fix illegal usage of oplist for function object 2020-05-15 21:45:02 +02:00
Patrick Pelissier 49a2e600c4 Add control of sub-oplist when creating a new oplist of a container
Add test case of this new control
Fix some corner bugs in some containers evolving their own oplists.
2020-05-15 21:19:39 +02:00
Patrick Pelissier 0bedcba32b Rewrite M_STATIC_ASSERT to include an error code and message
Add more control on the default expanded macros to check if arguments are compatible
2020-05-15 14:51:20 +02:00
Patrick Pelissier c531f805b0 Define _reduce only if SET method is properly set 2020-05-15 14:31:47 +02:00
Patrick Pelissier da0ab5ea98 Update failure tests as per latest checks 2020-05-11 20:55:16 +02:00
Patrick Pelissier 6774afd751 Add checks of missing oplist in the last _DEF macros 2020-05-11 20:54:50 +02:00
Patrick Pelissier 6d489136e7 Update help 2020-05-10 22:18:19 +02:00
Patrick Pelissier 4ea6dbc7fa Update makefile as per latest version of library 2020-05-10 20:21:03 +02:00
Patrick Pelissier defc58f6a3 Update bench code to latest version of the library. 2020-05-10 20:20:37 +02:00
Patrick Pelissier 006d0d16a5 Fix error 2020-05-10 20:20:03 +02:00
Patrick Pelissier b8af8bb344 Redisable MSVC testing with new version of compiler 2020-05-10 12:40:37 +02:00
Patrick Pelissier e249be1142 Reenable MSVC testing with new version of compiler 2020-05-10 12:38:36 +02:00
Patrick Pelissier 05fde6c3cf Display MSVC compiler full version 2020-05-10 12:06:31 +02:00
Patrick Pelissier aaa1d7dc4b Update description of test 2020-05-10 11:20:16 +02:00
Patrick Pelissier 8c479b2e5a Update tests 2020-05-10 11:17:25 +02:00
Patrick Pelissier 45d2a529b5 Add more validation of oplists before expanding data 2020-05-10 11:16:46 +02:00
Patrick Pelissier 7d17223332 Update comments 2020-05-10 11:15:56 +02:00
Patrick Pelissier 12bc65b6a8 Fix spelling 2020-05-10 11:15:28 +02:00
Patrick Pelissier a849d5c031 Make check-failure tests parallel 2020-05-09 21:39:01 +02:00
Patrick Pelissier f195b09657 Add more tests 2020-05-09 21:38:48 +02:00
Patrick Pelissier 439177ec71 Add protection against wrong oplist in more headers 2020-05-09 21:38:32 +02:00
Patrick Pelissier aadd4f11b1 Update tests as per new checks 2020-05-09 17:16:11 +02:00
Patrick Pelissier 113fdbf388 Add more controls on proper presence of oplist for _DEF macros 2020-05-09 17:16:00 +02:00
Patrick Pelissier 648406a99a Update tests as per new checks 2020-05-09 16:11:11 +02:00
Patrick Pelissier 055e74d350 Add more check for valid oplists before expanding further 2020-05-09 16:10:56 +02:00
Patrick Pelissier ac3d7568f2 Update test 2020-05-09 11:20:05 +02:00
Patrick Pelissier 6c222b9ad7 Raise proper failure if M_let is used without an oplist
Raise proper failure if a TYPE operator is used in an oplist that doesn't export it.
2020-05-09 11:15:44 +02:00
Patrick Pelissier 4426a60904 Add test for testing expected failures 2020-05-09 10:56:31 +02:00
Patrick Pelissier 34f70a031f Use M_STATIC_FAILURE to stop expanding methods in case of detected failure 2020-05-09 10:56:05 +02:00
Patrick Pelissier 79f2f396b9 Add macro M_STATIC_FAILURE to abort expansion in case of error 2020-05-09 10:55:25 +02:00
Patrick Pelissier 88143f7d52 Update ignore file 2020-05-09 10:54:30 +02:00
Patrick Pelissier c1261dd0f2 Fix doc 2020-05-08 21:47:19 +02:00
Patrick Pelissier 8f7a60ea73 Add documentation for function object 2020-05-08 21:43:35 +02:00
Patrick Pelissier 4758bbd6cc Add more tests 2020-05-08 21:23:48 +02:00
Patrick Pelissier 3f66325c19 Add new example for function object, json & algorithms 2020-05-08 17:50:07 +02:00
Patrick Pelissier 6f10d7deb9 Add synonym of serialisater with specialized oplists to be used in RAII 2020-05-08 17:49:44 +02:00
Patrick Pelissier 919900c90a Update documentation 2020-05-08 17:48:56 +02:00
Patrick Pelissier e6daaf429c Add some tests for function objects 2020-05-08 11:37:38 +02:00
Patrick Pelissier 1200f30695 * Add more Function Object support in algorithm
* Fix bug of selection sort
2020-05-08 11:35:22 +02:00
Patrick Pelissier fca1120990 No longer export IT_REF for map containers (See API changes) 2020-05-08 11:33:28 +02:00
Patrick Pelissier 3735704c95 Update new API change 2020-05-08 11:30:57 +02:00
Patrick Pelissier 8c0c1b3102 Update documentation of reduce if the container is empty 2020-05-08 11:30:38 +02:00
Patrick Pelissier db192993f1 Reduce constraint as the dictionnary iteration is not modifiable 2020-05-08 00:27:15 +02:00
Patrick Pelissier 4f44b3f60b Add CMP callback 2020-05-07 22:13:36 +02:00
Patrick Pelissier b196fcc3c0 Rename _cmp_cb_t into _eq_cb_t 2020-05-07 22:10:53 +02:00
Patrick Pelissier 395f1af19e Implement more function object algorithm 2020-05-07 22:09:07 +02:00
Patrick Pelissier d8f761e889 Update Makefile for dist 2020-05-05 23:44:27 +02:00
Patrick Pelissier 563ffb4275 Add first support for function object for certain algos (WIP) 2020-05-05 23:34:34 +02:00
Patrick Pelissier 9ba2de4b70 Add macro M_IF_FUNCOBJ to handle conditional expression if the function object is defined 2020-05-05 23:34:12 +02:00
Patrick Pelissier 0ac6a53fe9 Define callback types 2020-05-05 22:57:19 +02:00
Patrick Pelissier 4431e9f9ae Factorization / Split of the definition of the algorithm 2020-05-05 22:40:03 +02:00
Patrick Pelissier 48526ff5c7 Simplify logic due to fix of M_PARENTHESIS_P 2020-05-04 00:33:00 +02:00
Patrick Pelissier 4ee453025c Add comments 2020-05-04 00:32:40 +02:00
Patrick Pelissier 1e7b543c0f Fix issue with oplists with 3 arguments and fix warnings 2020-05-04 00:30:14 +02:00
Patrick Pelissier 8c2b4f8cf9 Add test cases for function object 2020-05-04 00:29:42 +02:00
Patrick Pelissier 13cadfa470 Update description of the list of headers 2020-05-03 18:00:46 +02:00
Patrick Pelissier deb595372b Add first version of Function Object 2020-05-03 17:49:02 +02:00
Patrick Pelissier 01fd5d929e * Fix M_RET_ARG so that it accepts also a list of the exact number of arguments (instead of one more) * Add more keywords for pattern recognation 2020-05-03 13:13:45 +02:00
Patrick Pelissier 2d60bd2c1b Fix a bug in M_PARENTHESIS_P 2020-05-02 10:19:31 +02:00
Patrick Pelissier 9655b13203 Add more corner cases for M_PARENTHESIS_P 2020-05-02 10:18:52 +02:00
Patrick Pelissier 6b97a7436d Add basic tests for dispathing init_with based on their number of args 2020-05-02 10:06:30 +02:00
Patrick Pelissier 1c792dd0a4 Add option for init_with to dispatch to different methods in function of the number of args 2020-05-02 10:06:08 +02:00
Patrick Pelissier dcbd9f496f Document NAME operator 2020-05-02 09:56:23 +02:00
Patrick Pelissier 9804120cde * Add simple test for registration of int global operator 2020-05-02 09:56:11 +02:00
Patrick Pelissier a9b06718f0 * Add simple test for NAME operator 2020-05-02 09:55:28 +02:00
Patrick Pelissier 963d819e22 * Add NAME operator. * Register default oplist for char,short,int,long,float,double 2020-05-02 09:55:10 +02:00
Patrick Pelissier 28847af43f Update constraints on MOVE & INIT_MOVE operators 2020-04-27 23:12:06 +02:00
Patrick Pelissier 130fa36970 Update iterator constraint 2020-04-27 22:55:53 +02:00
Patrick Pelissier ab99035291 Add another example 2020-04-20 23:50:05 +02:00
Patrick Pelissier 6de43d8a45 Add doc for ALGO_REDUCE with different type 2020-04-20 23:49:48 +02:00
Patrick Pelissier 7b46891622 Add test for ALGO_REDUCE with different type 2020-04-20 23:49:35 +02:00
Patrick Pelissier a0a32d8c6c ALGO_REDUCE accept dest with different type than the container 2020-04-20 23:49:16 +02:00
Patrick Pelissier 1ffd07dc6e Update format 2020-04-11 00:25:40 +02:00
Patrick Pelissier cb49cd7100 * Fix integer overflow in test of mul reduction 2020-04-10 08:35:44 +02:00
Patrick Pelissier 923b340a80 * Update documentation 2020-04-10 08:29:55 +02:00
Patrick Pelissier 5b8750ee2a * Add support for product in ALGO_REDUCE 2020-04-10 08:28:16 +02:00
Patrick Pelissier d438d089fb Add note on the provided oplists 2020-04-10 08:19:59 +02:00
Patrick Pelissier 843ddac3dd Proper prefix internal variables of macros by '_' 2020-04-01 23:40:41 +02:00
Patrick Pelissier c5238e0a4c Add new example for algorithm 2020-04-01 23:40:16 +02:00
Patrick Pelissier f99ee8aa40 Update documentation 2020-04-01 23:28:07 +02:00
Patrick Pelissier 18c7d0e11a Add test for SET_KEY only containers for ALGO_EXTRACT 2020-04-01 23:27:38 +02:00
Patrick Pelissier 4e67823593 Add support for SET_KEY only containers for ALGO_EXTRACT 2020-04-01 23:27:20 +02:00
Patrick Pelissier e7fcefb391 * Dict supports INIT_WITH method too. 2020-03-29 00:49:36 +01:00
Patrick Pelissier be06426783 Add documentation for ALGO_TRANSFORM 2020-03-28 17:41:29 +01:00
Patrick Pelissier e558e83be3 Add test case for ALGO_TRANSFORM 2020-03-28 17:41:16 +01:00
Patrick Pelissier d77a235b2a Add macro ALGO_TRANSFORM 2020-03-28 17:41:04 +01:00
Patrick Pelissier 3add6bb5bf Improve test suite 2020-03-28 17:17:43 +01:00
Patrick Pelissier 4367daaa00 Add documentation for _transform method. 2020-03-28 13:34:17 +01:00
Patrick Pelissier 4d46b3d126 Add basic test cases for _transform method. 2020-03-28 13:34:02 +01:00
Patrick Pelissier 548cd84a7f Add _transform method for algorithm. 2020-03-28 13:33:43 +01:00
Patrick Pelissier d87ffaa572 Improve documentation. 2020-03-28 13:07:35 +01:00
Patrick Pelissier 370cdb4e45 Add another example. 2020-03-28 13:05:15 +01:00
Patrick Pelissier 068d023917 Factorize in m-core.h the pattern recognication. 2020-03-28 11:36:51 +01:00
Patrick Pelissier 86b6ad54d5 Rename filln, filla, fillan into fill_n, fill_a, fill_an (same name as C++) 2020-03-28 11:10:02 +01:00
Patrick Pelissier bdf999a9fc Disable fully VC++ build as the build is fully broken due to regression in version 16.5 vs 16.4 2020-03-26 22:34:51 +01:00
Patrick Pelissier 39f8b6828b Try workaround against regression with new VisualC++ 2020-03-26 22:03:11 +01:00
Patrick Pelissier 11f84ab34b Document new algorithms 2020-03-26 21:49:04 +01:00
Patrick Pelissier c3a5306266 Add function _fill, _filln, _filla, _fillan as algorithms 2020-03-26 21:48:46 +01:00
Patrick Pelissier 1fe9e4c14c Export ADD / MUL / DIV / SUB for basic C types. 2020-03-26 21:44:19 +01:00
Patrick Pelissier e69203dc50 Remove exported PUSH / POP methods as they don't follow stricly the prototypes of such functions. 2020-03-26 21:43:44 +01:00
Patrick Pelissier 342954f272 Fix introduced build error for Mingw 2020-03-25 11:56:38 +01:00
Patrick Pelissier 741d6b8828 Test string + algorithm 2020-03-25 11:44:35 +01:00
Patrick Pelissier f1f41ef320 * Add missing iterator functions * Export iterators in oplist so that it is usable in algorithm 2020-03-25 11:43:55 +01:00
Patrick Pelissier 785792d1f4 Allow build of examples in C11 mode 2020-03-25 11:17:06 +01:00
Patrick Pelissier 9affe3106c Add example of ALGO_FOR_EACH and ALGO_REDUCE 2020-03-25 11:16:19 +01:00
Patrick Pelissier eb9fd14e2c Fix documentation. 2020-03-25 10:19:43 +01:00
Patrick Pelissier c281a2c339 Update CI script to include VC++ 2020-03-02 18:09:53 +01:00
Patrick Pelissier cb109eb479 Add proper progression for special script 2020-03-02 14:35:49 +01:00
Patrick Pelissier 3c6d194974 Add script to launch the test suite with VC++ 2020-03-02 14:25:42 +01:00
Patrick Pelissier 653a0d9734 Fix build issue for systems where double==long double 2020-03-02 14:23:59 +01:00
Patrick Pelissier a5fbd8405c Avoid C99 construct incompatible with strict C++ compiler 2020-02-24 22:27:43 +01:00
Patrick Pelissier 70994d4f60 Update doc 2020-02-16 11:06:43 +01:00
Patrick Pelissier f15203afb2 Comment a little bit more the examples 2020-02-10 06:47:24 +01:00
Patrick Pelissier 0a0d707afd Document bitset 2020-02-08 23:39:30 +01:00
Patrick Pelissier e206c3fe48 Document SPSC buffer 2020-01-23 23:18:33 +01:00
Patrick Pelissier 7f5704d321 Document MPMC buffer 2020-01-09 22:52:02 +01:00
Patrick Pelissier 4f7b0b9455 Happy new year 2020 2020-01-04 15:41:06 +01:00
Patrick Pelissier f5f16015df In quiet mode, if the result of the bench is not assumed to be reliable, display -1 instead of the result. 2020-01-04 15:12:59 +01:00
Patrick Pelissier 935325e0cb Add bench of emilib 2020-01-04 15:06:24 +01:00
Patrick Pelissier 7b9530ac58 Fix name of bench 2020-01-04 15:05:12 +01:00
Patrick Pelissier a9fc259420 ALGO_EXTRACT func argument is now optional 2019-12-30 14:31:21 +01:00
Patrick Pelissier 6f603b52df Update comments 2019-12-30 14:11:41 +01:00
Patrick Pelissier aeb2a47952 Add comments to example 2019-12-30 13:44:03 +01:00
Patrick Pelissier ca7cea3fe3 Use of linear probing and the same hash function as other libraries 2019-12-30 00:12:05 +01:00
Patrick Pelissier f14aca8808 Port to new UDB2 protocol 2019-12-29 23:51:30 +01:00
Patrick Pelissier f1e5e9d9db Simplify code to use get_at method with its get & create semantic 2019-12-29 23:45:17 +01:00
Patrick Pelissier cecba9777a Update documentation on buffer/queues 2019-12-27 16:42:54 +01:00
Patrick Pelissier 4352267034 Update deprecated API 2019-12-27 16:42:00 +01:00
Patrick Pelissier 0c3730d9a3 Migrate version to 0.3.1 2019-12-27 16:41:42 +01:00
Patrick Pelissier 5111b0c726 Deprecated some buffer options since the _blocking functions are much more usefull 2019-12-27 16:39:42 +01:00
Patrick Pelissier 8ecd3f1592 Add best_within and variance 2019-12-23 23:05:48 +01:00
Patrick Pelissier 0a6f8851c9 Update list of bench to launch automatically 2019-12-20 21:37:51 +01:00
Patrick Pelissier f0d3e93d9d Tune for Windows CI: C11 is broken, so switch to C99 and requests ISO C compatible printf function. 2019-12-16 12:44:56 +01:00
Patrick Pelissier e77ff2451b Try setup CCI for windows 2019-12-16 12:31:10 +01:00
Patrick Pelissier 142c224f84 Add another example on complex structure usage 2019-12-15 19:53:46 +01:00
Patrick Pelissier 29e8d9199d Update doc about new API 2019-12-15 19:43:38 +01:00
Patrick Pelissier 7128f5add2 * Add support for API_6 & API_7. * Fix issue for DO_INIT_MOVE that doesn't support API calls 2019-12-15 19:43:26 +01:00
Patrick Pelissier 1b7bcda4e1 Add quiet mode. Add usage 2019-12-15 10:30:40 +01:00
Patrick Pelissier 03b6146ef0 Add option to print only the best or only the average 2019-12-15 10:12:38 +01:00
Patrick Pelissier e99735d2b6 Add repeat option for bench 2019-12-15 10:01:32 +01:00
Patrick Pelissier 7263629c55 Add rigtop hashmap 2019-12-14 20:59:01 +01:00
Patrick Pelissier 605ce9b938 * Update version * Update comments * Improve robustness 2019-12-14 11:12:59 +01:00
Patrick Pelissier 049d8b6ca6 Port to new libdynamic API 2019-12-13 23:00:57 +01:00
Patrick Pelissier 90d3dda830 Clean up generated plot files too 2019-12-09 07:53:43 +01:00
Patrick Pelissier 2022a66db3 * Update makefile (missing coverage) * Refactor 2019-12-08 22:17:56 +01:00
Patrick Pelissier 78c786070e Add coverage support 2019-12-08 22:17:27 +01:00
Patrick Pelissier c5c72007af Update list of files to distribute 2019-12-08 21:53:20 +01:00
Patrick Pelissier c60d59cb7a Port all benchs to new infrastructure 2019-12-07 19:21:21 +01:00
Patrick Pelissier 00111e3e3c Port more bench to new infrzastructure 2019-12-07 14:45:06 +01:00
Patrick Pelissier 5cc2ac17d9 Add support for generating gnuplot graph 2019-12-07 12:22:33 +01:00
Patrick Pelissier d37ea84ab5 Cleanup redundant 'time' word 2019-12-07 11:59:23 +01:00
Patrick Pelissier 5e335bc8bd * Port to generic parser 2019-12-07 11:58:47 +01:00
Patrick Pelissier 65765763ae * Add generic parser for bench. * Factorization 2019-12-07 11:58:19 +01:00
Patrick Pelissier 90f248fbe8 Rename interface field of serial object into m_interface (WINDOWS compatibility as it defines a macro called interface) 2019-12-06 21:13:37 +01:00
Patrick Pelissier a39cf23697 Remove a warning (WINDOWS) 2019-12-06 21:10:00 +01:00
Patrick Pelissier 261776762c Update debugging documentation 2019-12-02 23:38:29 +01:00
Patrick Pelissier f207f9441c Remove linker warning for examples 2019-11-30 00:33:53 +01:00
Patrick Pelissier ffed880e0a Fix static assert for C++ (disable them totally as static_assert doesn't work -- It can't be used in expressions) 2019-11-30 00:08:59 +01:00
Patrick Pelissier a79b67cea2 Generate better error message in case of missing methods in OPLIST for GCC/CLANG 2019-11-29 23:45:48 +01:00
Patrick Pelissier bc3c8b5bcd Fix M_DO_INIT_MOVE / M_DO_MOVE to be more conservative. M_MOVE_DEFAULT doesn't work for all types ([1] structure). A MOVE operator should be defined however. 2019-11-29 23:23:27 +01:00
Patrick Pelissier 3489bb42bc Add static assertion and use it for move/copy/cmp default 2019-11-29 23:13:28 +01:00
Patrick Pelissier 7fe36f7bd7 Add test for M_MOVE_DEFAULT 2019-11-29 23:12:34 +01:00
Patrick Pelissier 82fd4c94db Update CI (Simplify CI tests) 2019-11-25 23:09:54 +01:00
Patrick Pelissier 4fc48b490e Update CI 2019-11-25 23:05:25 +01:00
Patrick Pelissier 750e5e6d95 Add target checkall at root Makefile 2019-11-25 22:50:50 +01:00
Patrick Pelissier cb564128e6 Update doc 2019-11-24 09:16:43 +01:00
PpHd 047fc986f2 Setup github workflows for Continuous Integration 2019-11-24 09:05:44 +01:00
Patrick Pelissier aca800ef8a Fix warning with lastest GCC about strict overflow 2019-11-24 08:50:55 +01:00
Patrick Pelissier dde090d4b0 Make GMP optional for the examples 2019-11-24 08:34:39 +01:00
Patrick Pelissier 87183573ce Ignore generated configuration 2019-11-24 08:27:40 +01:00
Patrick Pelissier baddcc3855 Avoid warning about variable being unused (C11) 2019-11-23 23:28:36 +01:00
Patrick Pelissier ba531774a0 Fix doc 2019-11-21 06:28:28 +01:00
Patrick Pelissier 708d17a4d2 Update README on details on OPLIST 2019-11-21 06:27:32 +01:00
Patrick Pelissier 7d802c03e5 Update README on details on OPLIST 2019-11-21 06:26:10 +01:00
Patrick Pelissier 787e1e9965 Merge branch 'master' of https://github.com/P-p-H-d/mlib 2019-11-05 19:56:09 +01:00
Patrick Pelissier 625691d279 Clarify doc on m-worker 2019-11-05 08:13:16 +01:00
Patrick Pelissier 4f0148dc77 Update doc with new container 2019-11-02 12:56:00 +01:00
Patrick Pelissier c78f2b992f Add support for set based on OA hashmap (DICT_OASET_DEF) 2019-11-02 08:40:24 +01:00
Patrick Pelissier 9857db0d15 Prepare integration of set based on OA hashmap for _ref and _cref 2019-11-02 08:29:44 +01:00
Patrick Pelissier 8b71064643 Simplify code for SET (since EQUAL returns TRUE as an EMPTY method) 2019-11-02 08:24:42 +01:00
Patrick Pelissier bc39034f6d Prepare integration of set based on OA hashmap 2019-11-02 08:17:44 +01:00
Patrick Pelissier e6a9b8fc8e Add M_EMPTY_OPLIST 2019-11-02 08:16:45 +01:00
Patrick Pelissier 3db43dc2db Update comments 2019-11-02 07:33:48 +01:00
Patrick Pelissier d384d5ad6c Always use INIT_MOVE when shrinking or enlarging the OA hashmap (Reversing the order of the last scanning) 2019-11-01 20:01:02 +01:00
Patrick Pelissier 7b2004caad Remove item 2019-10-29 12:32:51 +01:00
Patrick Pelissier 6754f88861 Update 2019-10-29 12:32:36 +01:00
Patrick Pelissier 9393809dfd Update todo 2019-10-26 19:22:33 +02:00
Patrick Pelissier 79ecacb6c0 Clarify what dict to use 2019-10-26 11:11:37 +02:00
Patrick Pelissier 853acbad4b Update doc 2019-10-21 23:13:37 +02:00
Patrick Pelissier e158eac10a Update doc 2019-10-21 22:56:28 +02:00
Patrick Pelissier 48ca2a2384 Add bench for OA for big objects (it confirms that OA dict is not suited for such object) 2019-10-21 22:56:15 +02:00
Patrick Pelissier d9d3d3cbe3 Update doc 2019-10-16 07:03:43 +02:00
Patrick Pelissier 6b4f10bf45 Prepare common macros for both hash tables 2019-10-15 07:33:31 +02:00
Patrick Pelissier 3b647b982f Add linear bench 2019-10-14 21:29:27 +02:00
Patrick Pelissier 00b875ea53 Add linear hash map bench 2019-10-14 20:57:29 +02:00
Patrick Pelissier 545fc4d93c Update doc 2019-10-11 07:50:26 +02:00
Patrick Pelissier c41342739a Reformulate 2019-10-02 08:12:09 +02:00
Patrick Pelissier ed99c5aaa3 Fix spelling 2019-09-28 17:17:14 +02:00
PpHd 08842811e8 Merge pull request #48 from taboege/string-clear-get-str-stack
Fix string_clear_get_str when stack allocated
2019-09-26 07:19:14 +02:00
Tobias Boege 3ea063d1e0 Fix string_clear_get_str when stack allocated
If a string_t is stack-allocated, string_clear_get_str would still try
to copy it from the NULL heap pointer, resulting in a failed assertion.
Copy from the stack instead. Also add a test for this.
2019-09-26 05:39:49 +02:00
Patrick Pelissier a905f12915 Document _cmp_order for tuple 2019-09-22 08:06:56 +02:00
Patrick Pelissier 5d8548b92b Update 2019-09-04 07:41:46 +02:00
Patrick Pelissier 99b63e9c77 Update 2019-08-26 08:04:06 +02:00
Patrick Pelissier 4002ef5aff Fix spelling 2019-08-23 06:42:47 +02:00
Patrick Pelissier d31ccfe8a4 Simplify example code 2019-08-11 10:43:35 +02:00
Patrick Pelissier c4ab76a330 More examples 2019-08-09 08:14:12 +02:00
Patrick Pelissier 84d4277be3 Add new example with basic types usage 2019-08-08 22:23:06 +02:00
Patrick Pelissier 0a99814ce2 Fix comments 2019-08-06 20:47:24 +02:00
Patrick Pelissier 11d695cb57 Update doc 2019-07-31 07:45:31 +02:00
Patrick Pelissier 13e2d6b473 Update issues 2019-07-25 07:10:45 +02:00
Patrick Pelissier e8137e4218 Fix spelling 2019-07-24 21:27:06 +02:00
Patrick Pelissier fe5df08d6e Update comments 2019-07-20 09:32:09 +02:00
Patrick Pelissier f77017f35f Update current limitation 2019-07-16 23:21:52 +02:00
Patrick Pelissier ce93c00a7b Workaround limitation of M_MOVE_DEFAULT for [1] structure (==> It supposes now that the destination parameter is **not** a type with [1] tricks or at least not a pointer to it, instead of having this constraint for both arguments). 2019-07-16 23:21:41 +02:00
Patrick Pelissier b8f44cc219 Fix bug (number of reader was too big, resulting in potential segfault) 2019-07-16 23:00:10 +02:00
Patrick Pelissier 2c921fdefe Improve test suite of snapshot to detect incorrect issues of INIT/CLEAR call by a container. 2019-07-16 23:00:10 +02:00
Patrick Pelissier 20eb95ba45 Update comments 2019-07-16 23:00:10 +02:00
Patrick Pelissier 7a6239912e Simplify code 2019-07-12 12:30:04 +02:00
Patrick Pelissier 9067311788 Update comment 2019-07-12 11:50:46 +02:00
Patrick Pelissier 23b2e07132 Add basic testing for _push_move method 2019-07-11 13:38:58 +02:00
Patrick Pelissier c8f2c0e06e Add _push_move method for SPSC 2019-07-11 13:38:40 +02:00
Patrick Pelissier 72c4eb80a2 Add doc on non documented operators 2019-07-11 12:56:00 +02:00
Patrick Pelissier 1f18e788e6 Update comments 2019-07-11 12:36:01 +02:00
Patrick Pelissier f855e24b56 Add description of operator INC_ALLOC 2019-07-11 12:29:00 +02:00
Patrick Pelissier 84d1b7ad50 Update doc 2019-07-08 21:35:59 +02:00
Patrick Pelissier 9f82649aa8 Add test for multiset 2019-07-08 21:25:19 +02:00
Patrick Pelissier 791f586c7e Add back contract support for multimap / multiset 2019-07-08 21:18:59 +02:00
Patrick Pelissier 8d3b0cc94b Prepare support in contract for multimap/multiset 2019-07-08 21:14:15 +02:00
Patrick Pelissier 70d1dfeb8b Add test case for multimap 2019-07-08 16:23:59 +02:00
Patrick Pelissier 9a4c6ba0d5 WIP for multimap / multiset. 2019-07-08 16:23:45 +02:00
Patrick Pelissier ef2dbf89ee Improve test 2019-07-08 11:36:09 +02:00
Patrick Pelissier d30b776fb0 Add more test 2019-07-08 11:33:42 +02:00
Patrick Pelissier 6408b28513 Update comments, function name and prepare for multimap / multiset 2019-07-08 11:17:08 +02:00
Patrick Pelissier 32b3e21564 Start supporting multimap/multiet 2019-07-07 21:18:34 +02:00
Patrick Pelissier 1ef28bedcb Rename internal functions for clarity 2019-07-07 21:16:04 +02:00
Patrick Pelissier 1356bb746e Add more tests 2019-07-06 10:44:49 +02:00
Patrick Pelissier 23240a44d5 Change how the keys are split. Before key[i] ==> node[i] has all keys < key[i], node[i+1] has all keys >= key[i]. After key[i] ==> node[i] has all keys <= key[i], node[i+1} has all keys > key[i]. 2019-07-06 00:03:26 +02:00
Patrick Pelissier 589c023622 Update test 2019-07-06 00:01:13 +02:00
Patrick Pelissier 047b6c5a58 Update 2019-07-04 21:10:38 +02:00
Patrick Pelissier 951425e963 Update comments 2019-07-04 10:42:24 +02:00
Patrick Pelissier e69cbfcab3 Add parameter isMulti 2019-07-04 09:53:58 +02:00
Patrick Pelissier 37f3cd6a72 Rename method _it_to_p into _it_until_p. Add method _it_while_p 2019-07-03 18:57:24 +02:00
Patrick Pelissier ec7b5dd120 Remove deprecated methods 2019-07-03 18:06:52 +02:00
Patrick Pelissier d50a78171f Bump to version 0.3.0 2019-07-03 18:06:39 +02:00
Patrick Pelissier b422aec2cd Add new example 2019-06-25 07:04:33 +02:00
Patrick Pelissier 7ba0e03b4f Add comments 2019-06-20 21:36:12 +02:00
Patrick Pelissier c535766c22 Update/Clean up basic type 2019-06-17 07:26:11 +02:00
Patrick Pelissier 289a3fdc71 Fix confusing position of { 2019-06-10 23:20:36 +02:00
Patrick Pelissier 7f0b6208a4 Propose a shorter version of the example. 2019-06-10 22:59:47 +02:00
Patrick Pelissier 60a10eb799 Uniformize the macro names 2019-06-09 12:02:38 +02:00
Patrick Pelissier 5321085856 Uniformize & add intermediary evaluation step for dict oplist
(like all other containers)
2019-06-09 11:39:15 +02:00
Patrick Pelissier 03be814a4d Uniformize macro names 2019-06-09 11:38:39 +02:00
Patrick Pelissier 6c3f7683a5 Uniformize API 2019-06-09 11:26:45 +02:00
Patrick Pelissier 06d6a90a21 Uniformize internal macros 2019-06-09 11:02:45 +02:00
Patrick Pelissier 747da27489 Uniformize 2019-06-09 10:49:18 +02:00
Patrick Pelissier 2869345920 Add test dor dual-push list for algo 2019-06-09 10:05:34 +02:00
Patrick Pelissier 6b8938cf76 Update comments.
Rename / Uniformize internal macros.
2019-06-09 10:01:50 +02:00
Patrick Pelissier 8e7eae5751 Update comments. 2019-06-09 09:32:35 +02:00
Patrick Pelissier 1882148a7c Add more assertions 2019-06-08 10:45:24 +02:00
Patrick Pelissier e46746ce01 Fix format string 2019-06-08 10:33:26 +02:00
Patrick Pelissier 32917e2cfa Add variant & prioqueue to tests then with concurrent 2019-06-08 10:07:03 +02:00
Patrick Pelissier 65a243fc13 Add missing const 2019-06-08 10:06:47 +02:00
Patrick Pelissier 1e011cb851 Add missing const in prototypes. 2019-06-08 09:59:16 +02:00
Patrick Pelissier 48f585a4ee Update comments 2019-06-08 09:47:49 +02:00
Patrick Pelissier bc10b616ae Update doc 2019-06-08 09:31:18 +02:00
Patrick Pelissier 851f08131d Update 2019-06-07 07:46:54 +02:00
Patrick Pelissier e294f4557e Update 2019-06-06 22:07:09 +02:00
Patrick Pelissier 9e5775fc16 Add example of serialization 2019-06-06 07:44:33 +02:00
Patrick Pelissier 8eb95d0cdc Update doc 2019-06-05 22:05:02 +02:00
Patrick Pelissier 42f807d64b Rename test file 2019-06-02 10:39:55 +02:00
Patrick Pelissier d1bb97ac52 Add new serializer 2019-06-02 10:39:24 +02:00
Patrick Pelissier f502b16b1d Fix bug 2019-06-02 10:31:25 +02:00
Patrick Pelissier 51e5764258 Add comment 2019-06-02 10:05:27 +02:00
Patrick Pelissier ec2281c29a Use of proper cast 2019-06-02 09:25:19 +02:00
Patrick Pelissier acfe1cb7e8 Update documentation for serialization 2019-05-28 22:50:16 +02:00
Patrick Pelissier 594aebd903 Fix comment 2019-05-28 22:50:06 +02:00
Patrick Pelissier 8bca63ac08 Fix MD syntax 2019-05-28 21:54:12 +02:00
Patrick Pelissier c02ec4f94c Update comments 2019-05-19 10:27:23 +02:00
Patrick Pelissier 797ac1f0da Fix for 32 bits system 2019-05-18 18:55:51 +02:00
Patrick Pelissier 058d3202ff Amend 2019-05-18 14:09:10 +02:00
Patrick Pelissier 62fcdac9cb Update list of headers 2019-05-18 14:08:17 +02:00
Patrick Pelissier b9131353b6 Add test 2019-05-18 11:17:15 +02:00
Patrick Pelissier a34deb2f3b Workaround warning. 2019-05-18 11:17:15 +02:00
Patrick Pelissier 9ef4b5c93f Fix cast 2019-05-18 11:17:14 +02:00
Patrick Pelissier 417b0295be Add C++ compatibility 2019-05-18 11:17:14 +02:00
Patrick Pelissier d11409bcc6 Add proper cast 2019-05-18 11:17:14 +02:00
Patrick Pelissier 928b81f454 Fix return value for in_serial/out_serial 2019-05-18 11:17:14 +02:00
Patrick Pelissier 05a68157bc Add local argument to serial interface to enable serial interface to create local parameters if needed (for example for serial binary) 2019-05-18 11:17:14 +02:00
Patrick Pelissier b6d5b5462b Update interface needed for serial 2019-05-18 11:17:14 +02:00
Patrick Pelissier 1c77082a29 Update comments 2019-05-18 11:17:14 +02:00
Patrick Pelissier 363c55668d Add in_serial / out_serial methods for several containers 2019-05-18 11:17:14 +02:00
Patrick Pelissier 7ed85fb97a Add in_serial / out_serial for concurrent containers 2019-05-18 11:17:14 +02:00
Patrick Pelissier 585ea1293d Add in_serial / out_serial for lists 2019-05-18 11:17:14 +02:00
Patrick Pelissier 448072555f Update comments 2019-05-18 11:17:14 +02:00
Patrick Pelissier 4701d5919b Fix serial import/export for variant 2019-05-18 11:17:14 +02:00
Patrick Pelissier 0997f59665 Update for variant 2019-05-18 11:17:14 +02:00
Patrick Pelissier dcf7a94728 Add in_serial / out_serial for variant 2019-05-18 11:17:14 +02:00
Patrick Pelissier 12ba563416 Add assertions 2019-05-18 11:17:14 +02:00
Patrick Pelissier f2fffb9219 Factor comment 2019-05-18 11:17:14 +02:00
Patrick Pelissier 3f03615ed2 Simplify code by factoring fscanf calls 2019-05-18 11:17:14 +02:00
Patrick Pelissier bc6bda057c Add in_serial / out_serial for array 2019-05-18 11:17:14 +02:00
Patrick Pelissier aeebe42bfb Fix issues for EOF & parsing arrays 2019-05-18 11:17:14 +02:00
Patrick Pelissier 5c4c93b62f Add missing export/import JSON interface 2019-05-18 11:17:14 +02:00
Patrick Pelissier c3ddd48d38 Simplify code 2019-05-18 11:17:14 +02:00
Patrick Pelissier 98f3c40ac5 add export/import of JSON string 2019-05-18 11:17:14 +02:00
Patrick Pelissier ada1b9861f Add size_of_type field for reading too 2019-05-18 11:17:13 +02:00
Patrick Pelissier 50cc8689bb Add serial methods for string_t 2019-05-18 11:17:13 +02:00
Patrick Pelissier 83da861a9c Simplify code by using more fscanf possibility 2019-05-18 11:17:13 +02:00
Patrick Pelissier 1cb1d16e77 Simplify code by using fscanf behvior on white space 2019-05-18 11:17:13 +02:00
Patrick Pelissier b525723084 Implement Serial Json Read tuple 2019-05-18 11:17:13 +02:00
Patrick Pelissier 4accdc994d Add JSON/read interface 2019-05-18 11:17:13 +02:00
Patrick Pelissier ad9bee0eec Add JSON serializer 2019-05-18 11:17:13 +02:00
Patrick Pelissier 6c7ff1c723 Update/fix bugs 2019-05-18 11:17:13 +02:00
Patrick Pelissier 3b2aad1b2e Export new methods for tuple 2019-05-18 11:17:13 +02:00
Patrick Pelissier 5222fabf02 Add tuple support for serial 2019-05-18 11:17:13 +02:00
Patrick Pelissier 44abead174 Update IN_SERIAL & OUT_SERIAL for default types. 2019-05-18 11:17:13 +02:00
Patrick Pelissier 492d5f0f9a Add IN_SERIAL & OUT_SERIAL for default types. 2019-05-18 11:17:13 +02:00
Patrick Pelissier 9bc5ac3df8 Start implementating generic serialization 2019-05-18 11:17:13 +02:00
Patrick Pelissier 5c726d63f4 Fix 2019-05-15 07:38:16 +02:00
Patrick Pelissier 2cd0a8db74 Uniformize the way of displaying the location of errors in the error message 2019-05-11 01:16:54 +02:00
Patrick Pelissier 0fa0445fa9 Fix C++ warning -Wclass-memaccess with G++ >= 8 2019-05-10 23:13:54 +02:00
Patrick Pelissier 1e171f9cc0 Increase NARGS support to 75 2019-05-10 21:39:18 +02:00
Patrick Pelissier 8d16ea4bf4 Increase maximum number of operators per oplist to 75 2019-05-10 21:26:18 +02:00
Patrick Pelissier a0c2ead91d Fix bug for M_AS_TYPE and small types 2019-05-10 10:20:38 +02:00
Patrick Pelissier b2875f6ba0 Add BSTRLIB for MASTER STRING BENCHMARK 2019-05-10 08:18:38 +02:00
Patrick Pelissier edb4ccf63e Add algo functions _remove_val & _remove_if 2019-05-07 16:35:39 +02:00
Patrick Pelissier 481009d18b Add function _end_with for strings. 2019-05-07 16:12:43 +02:00
Patrick Pelissier 6153383dab Update indent 2019-05-07 16:05:47 +02:00
Patrick Pelissier 74fed41818 Update version 2019-05-07 16:01:50 +02:00
143 changed files with 29353 additions and 14694 deletions

No files matched your search

+100
View File
@@ -0,0 +1,100 @@
name: C/C++ CI
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
platform: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v1
- name: make check C99
run: make clean check CC="cc -std=c99 -Wno-unknown-warning-option -Werror"
- name: make check C11
working-directory: ./tests
run: make clean check CC="cc -std=c11 -Wno-unknown-warning-option -Werror"
- name: make check C++
working-directory: ./tests
run: make clean check CC="c++ -std=c++11"
build_linux32:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: update package list
run: sudo apt-get update
- name: install multilib
run: sudo apt-get install gcc-multilib
- name: make check C99 (32bits)
working-directory: ./tests
run: make clean check CC="gcc -m32 -std=c99 -Wno-unknown-warning-option -Werror"
- name: make check C11 (32bits)
working-directory: ./tests
run: make clean check CC="gcc -m32 -std=c11 -Wno-unknown-warning-option -Werror"
build_linux_tcc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Clone TCC
shell: bash
run: git clone https://repo.or.cz/tinycc.git
- name: Configure, build & install TCC
shell: bash
run: cd tinycc && ./configure --prefix=/tmp/tcc && make && make install
- name: make depend
shell: bash
run: make depend
- name: make check
shell: bash
run: make CC="/tmp/tcc/bin/tcc -std=c99" check
build_windows_mingw:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: make check
shell: bash
run: mingw32-make CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
build_windows_msys2:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v2
- uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
update: true
install: git mingw-w64-x86_64-toolchain make
- name: make check
run: make CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
build_windows_visual:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: make check
shell: cmd
working-directory: ./tests
run: Make-check-cl.bat cl
build_windows_clang_cl:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: make check
shell: cmd
working-directory: ./tests
run: Make-check-cl.bat clang-cl
+58
View File
@@ -0,0 +1,58 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"
on:
push:
branches: [master]
pull_request:
# The branches below must be a subset of the branches above
branches: [master]
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['cpp']
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
- name: Autobuild
working-directory: ./tests
run: make exe
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
+5
View File
@@ -37,3 +37,8 @@ depend
# Others
other/
a*.dat
config
*.log
.vscode
.vs
tmp-serial.*
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 2-Clause License
Copyright (c) 2017-2019, Patrick Pelissier
Copyright (c) 2017-2021, Patrick Pelissier
All rights reserved.
Redistribution and use in source and binary forms, with or without
+42 -10
View File
@@ -1,24 +1,47 @@
# Copyright (c) 2017-2021, 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.
# Environnement variable. To customize if needed.
RM=rm -f
MKDIR=mkdir -p
RMDIR=rmdir
INSTALL=install
INSTALL_PROGRAM=${INSTALL}
INSTALL_DATA=${INSTALL} -m 644
# Installation directory
PREFIX=/usr/local
DESTDIR=
# Package name & version.
PACKAGE=m*lib-$(VERSION)
VERSION=0.2.2
PACKAGE=m_lib-$(VERSION)
VERSION=0.5.0
# Define the contain of the distribution tarball
# TODO: Get theses lists from GIT itself.
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-concurrent.h m-core.h m-deque.h m-dict.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-shared.h m-snapshot.h m-string.h m-tuple.h m-variant.h m-worker.h
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tuple.h m-variant.h m-worker.h
DOC1=LICENSE README.md
DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/DEV.md doc/ISSUES.org doc/depend.png doc/oplist.png
EXAMPLE=example/ex-array01.c example/ex-array04.c example/ex-dict02.c example/ex-grep01.c example/ex-multi01.c example/ex-rbtree01.c example/ex-array02.c example/ex-buffer01.c example/ex-dict03.c example/ex-list01.c example/ex-multi02.c example/Makefile example/ex-array03.c example/ex-dict01.c example/ex-dict04.c example/ex-mph.c example/ex-multi03.c
TEST=tests/coverage.h tests/test-malgo.c tests/test-mbptree.c tests/test-mdeque.c tests/test-milist.c tests/test-mmutex.c tests/test-mshared.c tests/test-mtuple.c tests/test-obj.h tests/tgen-mdict.c tests/tgen-openmp.c tests/wip-mregister.c tests/dict.txt tests/test-marray.c tests/test-mbuffer.c tests/test-mdict.c tests/test-mlist.c tests/test-mprioqueue.c tests/test-msnapshot.c tests/test-mvariant.c tests/tgen-bitset.c tests/tgen-mlist.c tests/tgen-queue.c tests/Makefile tests/test-mbitset.c tests/test-mcore.c tests/test-mgenint.c tests/test-mmempool.c tests/test-mrbtree.c tests/test-mstring.c tests/test-mworker.c tests/tgen-marray.c tests/tgen-mstring.c tests/tgen-shared.c
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
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/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt
.PHONY: all test check doc clean distclean depend install uninstall dist
@@ -31,6 +54,10 @@ check:
cd tests && $(MAKE) check
cd example && $(MAKE) all
checkall:
cd tests && $(MAKE) checkall
cd example && $(MAKE) all
html: doc
doc: README.md doc/depend.png
markdown < README.md > README.html
@@ -70,8 +97,13 @@ distcheck: dist
cd '$(PACKAGE)' && make check
install:
$(MKDIR) $(DESTDIR)$(PREFIX)/include
$(INSTALL_DATA) $(HEADER) $(DESTDIR)$(PREFIX)/include
$(MKDIR) $(DESTDIR)$(PREFIX)/include/m-lib
$(INSTALL_DATA) $(HEADER) $(DESTDIR)$(PREFIX)/include/m-lib
uninstall:
for i in $(HEADER) ; do $(RM) $(DESTDIR)$(PREFIX)/include/$$i ; done
for i in $(HEADER) ; do $(RM) $(DESTDIR)$(PREFIX)/include/m-lib/$$i ; done
$(RMDIR) $(DESTDIR)$(PREFIX)/include/m-lib/
format:
cd example && $(MAKE) ex-string01.exe
for i in $(HEADER) ; do ./example/ex-string01.exe $$i > tmp.h && mv tmp.h $$i ; done
+2186 -601
View File
File diff suppressed because it is too large. Load diff
+123 -47
View File
@@ -1,3 +1,25 @@
# Copyright (c) 2017-2021, Patrick Pelissier
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# + Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# + Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
CC=cc -std=c11
CXX=c++ -std=c++11
CFLAGS=-O2 -march=native -Wall
@@ -7,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-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain
.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
all: container queue mempool string plain
@@ -17,10 +39,10 @@ pgo:
#########################################################################
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-hopscotchmap
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
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-rigtorp-mpmc-queue
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
mempool: bench-mempool
@@ -38,7 +60,7 @@ plain: bench-plain
bench-mlib:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -pthread bench-mlib.c -o bench-mlib.exe
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -pthread bench-mlib.c common.c -o bench-mlib.exe
@./bench-mlib.exe 10
@./bench-mlib.exe 11
@./bench-mlib.exe 20
@@ -47,12 +69,14 @@ bench-mlib:
@./bench-mlib.exe 40
@./bench-mlib.exe 41
@./bench-mlib.exe 42
@./bench-mlib.exe 46
@./bench-mlib.exe 47
@./bench-mlib.exe 43
@./bench-mlib.exe 50
@./bench-mlib.exe 51
bench-mlib-mempool:
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c -DUSE_MEMPOOL -pthread -o bench-mlib-mempool.exe
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c common.c -DUSE_MEMPOOL -pthread -o bench-mlib-mempool.exe
@./bench-mlib-mempool.exe 10
@./bench-mlib-mempool.exe 11
@./bench-mlib-mempool.exe 20
@@ -61,12 +85,14 @@ bench-mlib-mempool:
@./bench-mlib-mempool.exe 40
@./bench-mlib-mempool.exe 41
@./bench-mlib-mempool.exe 42
@./bench-mlib-mempool.exe 46
@./bench-mlib-mempool.exe 47
@./bench-mlib-mempool.exe 43
@./bench-mlib-mempool.exe 50
@./bench-mlib-mempool.exe 51
bench-mlib-thread:
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c -DMULTI_THREAD_MEASURE -pthread -o bench-mlib-thread.exe
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c common.c -DMULTI_THREAD_MEASURE -pthread -o bench-mlib-thread.exe
@./bench-mlib-thread.exe 60
@./bench-mlib-thread.exe 61
@./bench-mlib-thread.exe 62
@@ -76,13 +102,14 @@ bench-mlib-thread:
@./bench-mlib-thread.exe 66
bench-stl:
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-stl.cpp -o bench-stl.exe
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-stl.cpp common.c -o bench-stl.exe
@./bench-stl.exe 10
@./bench-stl.exe 20
@./bench-stl.exe 30
@./bench-stl.exe 40
@./bench-stl.exe 41
@./bench-stl.exe 42
@./bench-stl.exe 46
@./bench-stl.exe 43
@./bench-stl.exe 50
@./bench-stl.exe 51
@@ -91,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 -o bench-qt.exe
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -fPIC `PKG_CONFIG_PATH="$${QT}" pkg-config --libs --cflags Qt5Core` bench-qt.cpp common.c -o bench-qt.exe
@./bench-qt.exe 10
@./bench-qt.exe 20
@./bench-qt.exe 30
@@ -104,7 +131,7 @@ bench-qt0:
bench-glib:
@if test -n "$${GLIB}" ; then $(MAKE) bench-glib0 ; else echo "Nothing to be done for GLIB." ; fi
bench-glib0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-glib.c -o bench-glib.exe `PKG_CONFIG_PATH="$${GLIB}" pkg-config --libs --cflags glib-2.0`
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-glib.c common.c -o bench-glib.exe `PKG_CONFIG_PATH="$${GLIB}" pkg-config --libs --cflags glib-2.0`
@./bench-glib.exe 10
@./bench-glib.exe 20
@./bench-glib.exe 30
@@ -117,7 +144,7 @@ bench-klib:
@if test -n "$${KLIB}" ; then $(MAKE) bench-klib0 ; else echo "Nothing to be done for KLIB." ; fi
bench-klib0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${KLIB} bench-klib.c -o bench-klib.exe
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${KLIB} bench-klib.c common.c -o bench-klib.exe
@./bench-klib.exe 10
@./bench-klib.exe 20
@./bench-klib.exe 30
@@ -125,25 +152,32 @@ bench-klib0:
@./bench-klib.exe 41
@./bench-klib.exe 50
# CMC shall point to the directory where the CMC main header is
bench-cmc:
@if test -n "$${CMC}" ; then $(MAKE) bench-cmc0 ; else echo "Nothing to be done for CMC." ; fi
bench-cmc0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${CMC} bench-cmc.c common.c -o bench-cmc.exe
@./bench-cmc.exe 20
@./bench-cmc.exe 30
@./bench-cmc.exe 40
# LIBDYNAMIC shall point to the the directory containing the file libdynamic.pc
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 -o bench-libdynamic.exe `PKG_CONFIG_PATH="$${LIBDYNAMIC}" pkg-config --libs --cflags libdynamic`
@./bench-libdynamic.exe 10
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-libdynamic.c common.c -o bench-libdynamic.exe `PKG_CONFIG_PATH="$${LIBDYNAMIC}" pkg-config --libs --cflags libdynamic`
@./bench-libdynamic.exe 20
@./bench-libdynamic.exe 30
@./bench-libdynamic.exe 40
@./bench-libdynamic.exe 41
@./bench-libdynamic.exe 50
# SPARSEPP shall point to the directory where the headers are
bench-sparsepp:
@if test -n "$${SPARSEPP}" ; then $(MAKE) bench-sparsepp0 ; else echo "Nothing to be done for SPARSEPP." ; fi
bench-sparsepp0:
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${SPARSEPP}" -I "$${SPARSEPP}/.." bench-sparsepp.cpp -o bench-sparsepp.exe
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${SPARSEPP}" -I "$${SPARSEPP}/.." bench-sparsepp.cpp common.c -o bench-sparsepp.exe
@./bench-sparsepp.exe 41
@./bench-sparsepp.exe 42
@./bench-sparsepp.exe 43
@@ -153,17 +187,17 @@ bench-densehashmap:
@if test -n "$${DENSEHASHMAP}" ; then $(MAKE) bench-densehashmap0 ; else echo "Nothing to be done Google DENSEHASHMAP." ; fi
bench-densehashmap0:
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${DENSEHASHMAP}" -I "$${DENSEHASHMAP}/.." bench-densehashmap.cpp -o bench-densehashmap.exe
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${DENSEHASHMAP}" -I "$${DENSEHASHMAP}/.." bench-densehashmap.cpp common.c -o bench-densehashmap.exe
@./bench-densehashmap.exe 41
@./bench-densehashmap.exe 42
@./bench-densehashmap.exe 43
# COLLECTIONC shall point to the directory where the 'src' directory is.
# COLLECTIONC shall point to the directory where it is installed
bench-collectionc:
@if test -n "$${COLLECTIONC}" ; then $(MAKE) bench-collectionc0 ; else echo "Nothing to be done for COLLECTIONC." ; fi
bench-collectionc0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${COLLECTIONC}/include" -L "$${COLLECTIONC}" -static bench-collectionc.c -lcollectc -o bench-collectionc.exe
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${COLLECTIONC}/include/collectc" bench-collectionc.c common.c "$${COLLECTIONC}/lib/libcollectc.a" -o bench-collectionc.exe
@./bench-collectionc.exe 10
@./bench-collectionc.exe 20
@./bench-collectionc.exe 30
@@ -176,7 +210,7 @@ bench-tommyds:
@if test -n "$${TOMMYDS}" ; then $(MAKE) bench-tommyds0 ; else echo "Nothing to be done for TOMMYDS." ; fi
bench-tommyds0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${TOMMYDS}" bench-tommyds.c $${TOMMYDS}/tommyds/tommyarray.c $${TOMMYDS}/tommyds/tommylist.c $${TOMMYDS}/tommyds/tommytree.c $${TOMMYDS}/tommyds/tommyhashlin.c -o bench-tommyds.exe
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${TOMMYDS}" bench-tommyds.c $${TOMMYDS}/tommyds/tommyarray.c $${TOMMYDS}/tommyds/tommylist.c $${TOMMYDS}/tommyds/tommytree.c $${TOMMYDS}/tommyds/tommyhashlin.c common.c -o bench-tommyds.exe
@./bench-tommyds.exe 10
@./bench-tommyds.exe 20
@./bench-tommyds.exe 30
@@ -188,17 +222,29 @@ bench-flathashmap:
@if test -n "$${FLATHASHMAP}" ; then $(MAKE) bench-flathashmap0 ; else echo "Nothing to be done for FLATHASHMAP." ; fi
bench-flathashmap0:
$(CXX) -std=c++14 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${FLATHASHMAP}" bench-flathashmap.cpp -o bench-flathashmap.exe
$(CXX) -std=c++14 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${FLATHASHMAP}" bench-flathashmap.cpp common.c -o bench-flathashmap.exe
@./bench-flathashmap.exe 41
@./bench-flathashmap.exe 42
@./bench-flathashmap.exe 46
@./bench-flathashmap.exe 43
# EMILIB shall point to the directory where the headers are
bench-emilib:
@if test -n "$${EMILIB}" ; then $(MAKE) bench-emilib0 ; else echo "Nothing to be done for EMILIB." ; fi
bench-emilib0:
$(CXX) -std=c++14 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${EMILIB}" bench-emilib.cpp common.c -o bench-emilib.exe
@./bench-emilib.exe 41
@./bench-emilib.exe 42
@./bench-emilib.exe 46
@./bench-emilib.exe 43
# HOPSCOTCHMAP shall point to the directory where the source are
bench-hopscotchmap:
@if test -n "$${HOPSCOTCHMAP}" ; then $(MAKE) bench-hopscotchmap0 ; else echo "Nothing to be done for HOPSCOTCHMAP." ; fi
bench-hopscotchmap0:
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${HOPSCOTCHMAP}" bench-hopscotchmap.cpp -o bench-hopscotchmap.exe
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${HOPSCOTCHMAP}/include/tsl" bench-hopscotchmap.cpp common.c -o bench-hopscotchmap.exe
@./bench-hopscotchmap.exe 41
@./bench-hopscotchmap.exe 42
@./bench-hopscotchmap.exe 43
@@ -208,12 +254,11 @@ bench-uthash:
@if test -n "$${UTHASH}" ; then $(MAKE) bench-uthash0 ; else echo "Nothing to be done for UTHASH." ; fi
bench-uthash0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${UTHASH}" bench-uthash.c -o bench-uthash.exe
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${UTHASH}" bench-uthash.c common.c -o bench-uthash.exe
@./bench-uthash.exe 10
@./bench-uthash.exe 20
@./bench-uthash.exe 40
@./bench-uthash.exe 41
@./bench-uthash.exe 42
@./bench-uthash.exe 43
@./bench-uthash.exe 50
# QLIBC shall point to the directory where the library is installed.
@@ -221,25 +266,18 @@ bench-qlibc:
@if test -n "$${QLIBC}" ; then $(MAKE) bench-qlibc0 ; else echo "Nothing to be done for QLIBC." ; fi
bench-qlibc0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${QLIBC}/include" -L "$${QLIBC}/lib" -lqlibc -pthread bench-qlibc.c -o bench-qlibc.exe
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${QLIBC}/include" -L "$${QLIBC}/lib" -lqlibc -pthread bench-qlibc.c common.c -o bench-qlibc.exe
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 10
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 20
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 30
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 42
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 41
# LIBSRT shall point to the directory where the source are
# The library shall be built.
# LIBSRT shall point to the directory where it is installed
bench-libsrt:
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-libsrt0 ; else echo "Nothing to be done for LIBSRT." ; fi
bench-libsrt0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/src" bench-libsrt.c -o bench-libsrt.exe $${LIBSRT}/libsrt.a
@./bench-libsrt.exe 10
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/include/libsrt" bench-libsrt.c common.c -o bench-libsrt.exe $${LIBSRT}/lib/libsrt.a
@./bench-libsrt.exe 20
@./bench-libsrt.exe 41
@./bench-libsrt.exe 42
@./bench-libsrt.exe 43
@./bench-libsrt.exe 50
@@ -248,7 +286,7 @@ bench-libsrt0:
bench-liblfds:
@if test -n "$${LIBLFDS}" ; then $(MAKE) bench-liblfds0 ; else echo "Nothing to be done for LIBLFDS." ; fi
bench-liblfds0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBLFDS}/inc" -Wno-unknown-pragmas bench-liblfds.c -o bench-liblfds.exe $${LIBLFDS}/bin/liblfds711.a -lpthread
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBLFDS}/inc" -Wno-unknown-pragmas bench-liblfds.c common.c -DMULTI_THREAD_MEASURE -o bench-liblfds.exe $${LIBLFDS}/bin/liblfds711.a -lpthread
@LD_LIBRARY_PATH="$${LIBLFDS}/bin:$${LD_LIBRARY_PATH}" ./bench-liblfds.exe 60
@@ -257,7 +295,7 @@ bench-liblfds0:
bench-concurrentqueue:
@if test -n "$${CONCURRENTQUEUE}" ; then $(MAKE) bench-concurrentqueue0 ; else echo "Nothing to be done for CONCURRENTQUEUE." ; fi
bench-concurrentqueue0:
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${CONCURRENTQUEUE}/" bench-concurrentqueue.cpp -o bench-concurrentqueue.exe -lpthread
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${CONCURRENTQUEUE}/" bench-concurrentqueue.cpp common.c -DMULTI_THREAD_MEASURE -o bench-concurrentqueue.exe -lpthread
@./bench-concurrentqueue.exe 60
@@ -266,24 +304,56 @@ bench-concurrentqueue0:
bench-xxhash:
@if test -n "$${XXHASH}" ; then $(MAKE) bench-xxhash0 ; else echo "Nothing to be done for XXHASH." ; fi
bench-xxhash0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${XXHASH}/" bench-xxhash.c "$${XXHASH}/libxxhash.a" -o bench-xxhash.exe
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${XXHASH}/" bench-xxhash.c common.c "$${XXHASH}/libxxhash.a" -o bench-xxhash.exe
@./bench-xxhash.exe 70
# BOOST shall point to the header location.
bench-boost:
@if test -n "$${BOOST}" ; then $(MAKE) bench-boost0 ; else echo "Nothing to be done for BOOST." ; fi
bench-boost0:
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${BOOST}" bench-boost.cpp -o bench-boost.exe -lpthread
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${BOOST}" bench-boost.cpp common.c -DMULTI_THREAD_MEASURE -o bench-boost.exe -lpthread
@./bench-boost.exe 60
# NEDTRIES shall point to the header location.
bench-nedtries:
@if test -n "$${NEDTRIES}" ; then $(MAKE) bench-nedtries0 ; else echo "Nothing to be done for NEDTRIES." ; fi
bench-nedtries0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${NEDTRIES}" bench-nedtries.c -o bench-nedtries.exe
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${NEDTRIES}" bench-nedtries.c common.c -o bench-nedtries.exe
@./bench-nedtries.exe 40
@./bench-nedtries.exe 45
# RIGTORP_HASHMAP shall point to the directory where the headers are
bench-rigtorp-hashmap:
@if test -n "$${RIGTORP_HASHMAP}" ; then $(MAKE) bench-rigtorp-hashmap0 ; else echo "Nothing to be done for RIGTORP_HASHMAP." ; fi
bench-rigtorp-hashmap0:
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RIGTORP_HASHMAP}/include" bench-rigtorp-hashmap.cpp common.c -o bench-rigtorp-hashmap.exe
@./bench-rigtorp-hashmap.exe 42
@./bench-rigtorp-hashmap.exe 41
@./bench-rigtorp-hashmap.exe 43
# RIGTORP_MPMC_QUEUE shall point to the directory where the headers are
bench-rigtorp-mpmc-queue:
@if test -n "$${RIGTORP_MPMC_QUEUE}" ; then $(MAKE) bench-rigtorp-mpmc-queue0 ; else echo "Nothing to be done for RIGTORP_MPMC_QUEUE." ; fi
bench-rigtorp-mpmc-queue0:
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RIGTORP_MPMC_QUEUE}" bench-rigtorp-mpmcqueue.cpp common.c -DMULTI_THREAD_MEASURE -o bench-mpmcqueue.exe -lpthread
@./bench-mpmcqueue.exe 60
############################################################################
bench-mlib-json: bench-mlib
@./bench-mlib.exe 110
@./bench-mlib.exe 111
@./bench-mlib.exe 112
bench-rapidjson:
@if test -n "$${RAPIDJSON}" ; then $(MAKE) bench-rapidjson0 ; else echo "Nothing to be done for RAPIDJSON." ; fi
bench-rapidjson0:
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RAPIDJSON}/" bench-rapidjson.cpp common.c -o bench-rapidjson.exe
@./bench-rapidjson.exe 110
@./bench-rapidjson.exe 111
@./bench-rapidjson.exe 112
############################################################################
bench-plain:
@@ -307,19 +377,16 @@ bench-maxdict:
############################################################################
# BSTRLIB shall point to the BSTRLIB sources
# LIBSRT shall point to the LIBSRT sources
# LIBSRT shall point to the LIBSRT install directory
bench-string:
@if test -n "$${BSTRLIB}" ; then $(MAKE) bench-string-step1 BENCH_DEF="-DBENCH_CAN_USE_BSTRLIB -I ${BSTRLIB} $${BSTRLIB}/obj/bstrlib.o $${BSTRLIB}/obj/bstraux.o $${BSTRLIB}/obj/bstrwrap.o" ; else $(MAKE) bench-string-step1 ; fi
bench-string-step1:
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/src $${LIBSRT}/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}/include/libsrt $${LIBSRT}/lib/libsrt.a" ; else $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF)"; fi
#NOTE: Need to build by hand sds.o since it is not build by default and sds.c is not compatible with C++
bench-string-step2:
@if test -n "$${SDS}" ; then $(MAKE) bench-string-step3 BENCH_DEF="$(BENCH_DEF) -fpermissive -DBENCH_CAN_USE_SDS -I$${SDS}/ $${SDS}/sds.o" ; else $(MAKE) bench-string-step3 BENCH_DEF="$(BENCH_DEF)"; fi
bench-string-step3:
@if test -n "$${RAPIDSTRING}" ; then $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_RAPIDSTRING -I$${RAPIDSTRING}/ " ; else $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF)"; fi
@if test -n "$${SDS}" ; then $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF) -fpermissive -DBENCH_CAN_USE_SDS -I$${SDS}/ $${SDS}/sds.o" ; else $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF)"; fi
bench-string-step4:
@if test -n "$${GLIB}" ; then $(MAKE) bench-string-step5 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_GLIB $$(pkg-config --cflags --libs glib-2.0)" ; else $(MAKE) bench-string-step5 BENCH_DEF="$(BENCH_DEF)"; fi
@@ -331,7 +398,7 @@ bench-string-step5:
@./bench-string-2.exe 2000000 0
@./bench-string-2.exe 2000000 1
@./bench-string-2.exe 2000000 2
@./bench-string-2.exe 2000000 3
@./bench-string-2.exe 2000000 4
bench-string-pgo:
$(MAKE) bench-string XCFLAGS="-fprofile-generate=pgo"
@@ -339,9 +406,18 @@ bench-string-pgo:
############################################################################
bench-find-sort:
g++ bench-find-sort.cpp -O2 -march=native -std=c++11 -I.. -g common.c -o bench-find-sort.exe
./bench-find-sort.exe 10000000
############################################################################
clean:
$(RM) *.o bench-*.exe bench-*.s *~ massif.out.*
$(RM) *.o bench-*.exe
$(RM) bench-*.s *~ massif.out.*
$(RM) plot-*.dat
$(RM) pgo
$(RM) tmp-serial.*
cd nucleotide && $(MAKE) clean
############################################################################
+6 -8
View File
@@ -6,11 +6,8 @@
#include <boost/lockfree/queue.hpp>
#include "m-mutex.h"
#define MULTI_THREAD_MEASURE
#include "common.h"
/********************************************************************************************/
boost::lockfree::queue<unsigned int, boost::lockfree::capacity<4*64>> g_buff;
boost::lockfree::queue<unsigned long long, boost::lockfree::capacity<4*64>> g_final;
@@ -51,7 +48,7 @@ static void prod(void *arg)
}
}
static void test_buffer(size_t n)
static void test_queue(size_t n)
{
const int cpu_count = get_cpu_count();
const int prod_count = cpu_count/2;
@@ -88,11 +85,12 @@ static void test_buffer(size_t n)
/********************************************************************************************/
const config_func_t table[] = {
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 60)
test_function("Buffer time", 1000000, test_buffer);
test("BOOST-LOCKFREE", numberof(table), table, argc, argv);
exit(0);
}
+204
View File
@@ -0,0 +1,204 @@
#define NDEBUG
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "macro_collections.h"
#include "common.h"
/********************************************************************************************/
// CMC list are dynamic array
#define MY_LIST_PARAMS (list_uint, list_uint_s, , , unsigned int)
C_MACRO_COLLECTIONS_EXTENDED(CMC, LIST, MY_LIST_PARAMS, (STR))
struct list_uint_s_fval list_fval = { .cmp = NULL,
.cpy = NULL,
.str = NULL,
.free = NULL,
.hash = NULL,
.pri = NULL };
static void test_array(size_t n)
{
struct list_uint_s *a1 = list_uint_new(1, &list_fval);
struct list_uint_s *a2 = list_uint_new(1, &list_fval);
for(size_t i = 0; i < n; i++) {
list_uint_push_back(a1, rand_get() );
list_uint_push_back(a2, rand_get() );
}
unsigned int s = 0;
for(unsigned long i = 0; i < n; i++) {
s += list_uint_get(a1, i ) * list_uint_get(a2, i );
}
g_result = s;
list_uint_free(a1);
list_uint_free(a2);
}
/********************************************************************************************/
#define my_cmp(a,b) ( (a) < (b) ? -1 : (a) > (b) )
#define MY_TMAP_PARAMS (tree_ulong, tree_ulong_s, , unsigned long, bool)
C_MACRO_COLLECTIONS_EXTENDED(CMC, TREEMAP, MY_TMAP_PARAMS, (STR))
int cmp_ulong(unsigned long a, unsigned long b) { return my_cmp(a,b); }
struct tree_ulong_s_fkey tree_fkey = { .cmp = cmp_ulong,
.cpy = NULL,
.str = NULL,
.free = NULL,
.hash = NULL,
.pri = NULL };
struct tree_ulong_s_fval tree_fval = { .cmp = NULL,
.cpy = NULL,
.str = NULL,
.free = NULL,
.hash = NULL,
.pri = NULL };
static void test_rbtree(size_t n)
{
struct tree_ulong_s *tree;
tree = tree_ulong_new(&tree_fkey, &tree_fval);
for (size_t i = 0; i < n; i++) {
unsigned long j = rand_get();
tree_ulong_insert(tree, j, true);
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
unsigned long j = rand_get();
if (tree_ulong_get_ref(tree, j) != 0)
s+= j;
}
g_result = s;
tree_ulong_free(tree);
}
/********************************************************************************************/
#define hash_func(a) kh_int64_hash_func(a)
size_t hash_ulong(unsigned long a)
{
return ( (a) >> 33 ) ^ (a) ^ ((a) << 11);
}
#define MY_DICT_PARAMS (hmap, hmap_s, , unsigned long, unsigned long)
C_MACRO_COLLECTIONS_EXTENDED(CMC, HASHMAP, MY_DICT_PARAMS, (STR))
struct hmap_s_fkey hmap_fkey = { .cmp = cmp_ulong,
.cpy = NULL,
.str = NULL,
.free = NULL,
.hash = hash_ulong,
.pri = NULL };
struct hmap_s_fval hmap_fval = { .cmp = NULL,
.cpy = NULL,
.str = NULL,
.free = NULL,
.hash = NULL,
.pri = NULL };
static void
test_dict(size_t n)
{
struct hmap_s *dict = hmap_new(16, 0.7, &hmap_fkey, &hmap_fval);
for (size_t i = 0; i < n; i++) {
hmap_insert(dict, rand_get(), rand_get());
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
unsigned long *val = hmap_get_ref(dict, rand_get());
if (val != 0)
s += *val;
}
g_result = s;
hmap_free(dict);
}
/********************************************************************************************/
#if 0 // Not working issue in using not integer types
typedef struct {
char a[256];
} char_array_t;
static inline int char_cmp (const char_array_t a, const char_array_t b) { return strcmp(a.a,b.a); }
static inline size_t char_hash(const char_array_t a) {
size_t hash = 0;
const char *s = a.a;
while (*s) hash = hash * 31421 + (*s++) + 6927;
return hash;
}
#define MY_DICTB_PARAMS (bhmap, bhmap_s, , char_array_t, char_array_t)
C_MACRO_COLLECTIONS_EXTENDED(CMC, HASHMAP, MY_DICT_PARAMS, (STR))
struct bhmap_s_fkey bhmap_fkey = { .cmp = char_cmp,
.cpy = NULL,
.str = NULL,
.free = NULL,
.hash = char_hash,
.pri = NULL };
struct bhmap_s_fval bhmap_fval = { .cmp = NULL,
.cpy = NULL,
.str = NULL,
.free = NULL,
.hash = NULL,
.pri = NULL };
static void
test_dict_big(size_t n)
{
struct bhmap_s *dict = bhmap_new(16, 0.7, &bhmap_fkey, &bhmap_fval);
for (size_t i = 0; i < n; i++) {
char_array_t s1, s2;
sprintf(s1.a, "%u", rand_get());
sprintf(s2.a, "%u", rand_get());
bhmap_insert(dict, s1, s2);
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
char_array_t s1;
sprintf(s1.a, "%u", rand_get() );
char_array_t *val = bhmap_get_ref(dict, s1);
if (val != 0)
s ++;
}
g_result = s;
bhmap_free(dict);
}
#endif
/********************************************************************************************/
const config_func_t table[] = {
{ 20, "Array", 100000000, 0, test_array, 0},
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
{ 40, "dict", 1000000, 0, test_dict, 0},
//{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
};
int main(int argc, const char *argv[])
{
test("CMC", numberof(table), table, argc, argv);
exit(0);
}
+10 -13
View File
@@ -250,20 +250,17 @@ static void test_sort(size_t n)
/********************************************************************************************/
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[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 10)
test_function("List time",10000000, test_list);
if (n == 20)
test_function("Array time", 100000000, test_array);
if (n == 30)
test_function("Rbtree time", 1000000, test_rbtree);
if (n == 40)
test_function("Dict time", 1000000, test_dict);
if (n == 41)
test_function("DictB time", 1000000, test_dict_big);
if (n == 50)
test_function("Sort time", 10000000, test_sort);
test("CollectionC", numberof(table), table, argc, argv);
exit(0);
}
+6 -8
View File
@@ -6,11 +6,8 @@
#include "concurrentqueue.h"
#include "m-mutex.h"
#define MULTI_THREAD_MEASURE
#include "common.h"
/********************************************************************************************/
moodycamel::ConcurrentQueue<unsigned int> g_buff;
moodycamel::ConcurrentQueue<unsigned long long> g_final;
@@ -51,7 +48,7 @@ static void prod(void *arg)
}
}
static void test_buffer(size_t n)
static void test_queue(size_t n)
{
const int cpu_count = get_cpu_count();
const int prod_count = cpu_count/2;
@@ -88,11 +85,12 @@ static void test_buffer(size_t n)
/********************************************************************************************/
const config_func_t table[] = {
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 60)
test_function("Buffer time", 1000000, test_buffer);
test("CONCURRENT-QUEUE", numberof(table), table, argc, argv);
exit(0);
}
+7 -7
View File
@@ -131,14 +131,14 @@ test_dict_str(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}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 42)
test_function("Dict(u)time", 1000000, test_dict2);
if (n == 41)
test_function("DictB time", 1000000, test_dict_big);
if (n == 43)
test_function("DictS(u) time", 1000000, test_dict_str);
test("DENSE-HASPMAP", numberof(table), table, argc, argv);
exit(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 "emilib/hash_map.hpp"
using namespace emilib;
using namespace std;
#include "common.h"
/********************************************************************************************/
static void
test_dict2(size_t n)
{
HashMap<unsigned long, unsigned long> dict;
for (size_t i = 0; i < n; i++) {
dict[rand_get()] = rand_get();
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
HashMap<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
if (it != dict.end())
s += it->second;
}
g_result = s;
}
static void
test_dict2_linear(size_t n)
{
HashMap<unsigned long, unsigned long> dict;
for (size_t i = 0; i < n; i++) {
dict[i] = rand_get();
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
HashMap<unsigned long, unsigned long>::iterator it = dict.find(i);
if (it != dict.end())
s += it->second;
}
g_result = s;
}
/********************************************************************************************/
struct char_array_s {
char a[256];
char_array_s () { a[0] = 0 ; }
char_array_s ( const char_array_s & other) { strcpy(a, other.a); }
bool operator==(const char_array_s &other) const { return strcmp(a, other.a) == 0; }
};
namespace std {
template <> struct hash<char_array_s> {
std::size_t operator()(const char_array_s &k) const {
size_t hash = 0;
const char *s = k.a;
while (*s) hash = hash * 31421 + (*s++) + 6927;
return hash;
};
};
}
static void
test_dict_big(size_t n)
{
HashMap<char_array_s, char_array_s> dict;
for (size_t i = 0; i < n; i++) {
char_array_s s1, s2;
sprintf(s1.a, "%u", rand_get());
sprintf(s2.a, "%u", rand_get());
dict[s1] = s2;
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
char_array_s s1;
sprintf(s1.a, "%u", rand_get());
HashMap<char_array_s, char_array_s>::iterator it = dict.find(s1);
if (it != dict.end())
s ++;
}
g_result = s;
}
/********************************************************************************************/
static void
test_dict_str(size_t n)
{
HashMap<string, string> dict;
for (size_t i = 0; i < n; i++) {
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
dict[s1] = s2;
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
HashMap<string, string>::iterator it = dict.find(s1);
if (it != dict.end())
s ++;
}
g_result = s;
}
/********************************************************************************************/
const config_func_t table[] = {
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
{ 42,"dict", 1000000, 0, test_dict2, 0},
{ 43, "DictStr", 1000000, 0, test_dict_str, 0},
{ 46, "DictLinear", 1000000, 0, test_dict2_linear, 0}
};
int main(int argc, const char *argv[])
{
test("EMILIB", numberof(table), table, argc, argv);
exit(0);
}
+101
View File
@@ -0,0 +1,101 @@
// program to find longest contiguous subsequence
// based on https://www.geeksforgeeks.org/longest-consecutive-subsequence/
#include <iostream>
#include <unordered_set>
using namespace std;
// Returns length of the longest contiguous subsequence
int cpp_find_longest(int arr[], int n)
{
unordered_set<int> S;
int ans = 0;
// Hash all the array elements
for (int i = 0; i < n; i++)
S.insert(arr[i]);
// check each possible sequence from
// the start then update optimal length
for (int i = 0; i < n; i++) {
// if current element is the starting
// element of a sequence
if (S.find(arr[i] - 1) == S.end()) {
// Then check for next elements
// in the sequence
int j = arr[i] + 1;
while (S.find(j) != S.end())
j++;
// update optimal length if
// this length is more
ans = max(ans, j - arr[i]);
}
}
return ans;
}
#include "m-dict.h"
static inline bool oor_equal_p(int a, unsigned char c) { return a == ((c == 0) ? INT_MIN : INT_MAX); }
static inline void oor_set(int *a, unsigned char c) { *a = ((c == 0) ? INT_MIN : INT_MAX); }
DICT_OASET_DEF(dict_int, int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)))
// Returns length of the longest contiguous subsequence
int mlib_find_longest(int arr[], int n)
{
dict_int_t S;
int ans = 0;
dict_int_init(S);
// Hash all the array elements
for (int i = 0; i < n; i++)
dict_int_push(S, arr[i]);
// check each possible sequence from
// the start then update optimal length
for (int i = 0; i < n; i++) {
// if current element is the starting
// element of a sequence
int *p = dict_int_get(S, arr[i]-1);
if (p == NULL) {
// Then check for next elements
// in the sequence
int j = arr[i] + 1;
while (dict_int_get(S, j) != NULL)
j++;
// update optimal length if
// this length is more
ans = M_MAX(ans, j - arr[i]);
}
}
dict_int_clear(S);
return ans;
}
#include "common.h"
int main(int argc, const char *argv[])
{
int n = argc == 1 ? 10000 : atoi(argv[1]);
int *arr = (int*) malloc(n * sizeof(int));
for(int i = 0; i < n; i++)
arr[i] = rand_get();
unsigned long long t0 = cputime();
cout << "Length of the Longest contiguous subsequence is "
<< cpp_find_longest(arr, n) << endl;
unsigned long long t1 = cputime();
cout << "Length of the Longest contiguous subsequence is "
<< mlib_find_longest(arr, n) << endl;
unsigned long long t2 = cputime();
cout << "Time C++: " << (t1-t0) << " Time M*LIB: " << (t2-t1) << endl;
return 0;
}
+25 -7
View File
@@ -42,6 +42,23 @@ test_dict2(size_t n)
g_result = s;
}
static void
test_dict2_linear(size_t n)
{
flat_hash_map<unsigned long, unsigned long> dict;
for (size_t i = 0; i < n; i++) {
dict[i] = rand_get();
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
flat_hash_map<unsigned long, unsigned long>::iterator it = dict.find(i);
if (it != dict.end())
s += it->second;
}
g_result = s;
}
/********************************************************************************************/
struct char_array_s {
char a[256];
@@ -108,14 +125,15 @@ test_dict_str(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}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 42)
test_function("Dict(u)time", 1000000, test_dict2);
if (n == 41)
test_function("DictB time", 1000000, test_dict_big);
if (n == 43)
test_function("DictS(u) time", 1000000, test_dict_str);
test("FLAT-HASPMAP", numberof(table), table, argc, argv);
exit(0);
}
+10 -13
View File
@@ -186,20 +186,17 @@ static void test_sort(size_t n)
/********************************************************************************************/
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[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 10)
test_function("List time",10000000, test_list);
if (n == 20)
test_function("Array time", 100000000, test_array);
if (n == 30)
test_function("Rbtree time", 1000000, test_rbtree);
if (n == 40)
test_function("Dict time", 1000000, test_dict);
if (n == 41)
test_function("DictB time", 1000000, test_dict_big);
if (n == 50)
test_function("Sort time", 10000000, test_sort);
test("GLIB", numberof(table), table, argc, argv);
exit(0);
}
+9 -8
View File
@@ -15,7 +15,7 @@
#include <stdbool.h>
#include <string.h>
#include "src/hopscotch_map.h"
#include "hopscotch_map.h"
using namespace tsl;
using namespace std;
@@ -109,14 +109,15 @@ test_dict_str(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}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 42)
test_function("Dict(u)time", 1000000, test_dict2);
if (n == 41)
test_function("DictB time", 1000000, test_dict_big);
if (n == 43)
test_function("DictS(u) time", 1000000, test_dict_str);
test("HOPSCOTCHMAP", numberof(table), table, argc, argv);
exit(0);
}
+10 -13
View File
@@ -185,21 +185,18 @@ static void test_sort(size_t n)
/********************************************************************************************/
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[])
{
int n = (argc > 1) ? atoi(argv[1]): 0;
if (n == 10)
test_function("List time",10000000, test_list);
if (n == 20)
test_function("Array time", 100000000, test_array);
if (n == 30)
test_function("B-tree time", 1000000, test_rbtree);
if (n == 40)
test_function("DictOA time", 1000000, test_dict);
if (n == 41)
test_function("DictB time", 1000000, test_dict_big);
if (n == 50)
test_function("Sort time", 10000000, test_sort);
test("KLIB", numberof(table), table, argc, argv);
exit(0);
}
+31 -18
View File
@@ -7,6 +7,9 @@
#include <stdint.h>
#include <unistd.h>
// Needed due to compilation error in pool.h
#include <pthread.h>
#include "dynamic.h"
#include "common.h"
@@ -45,6 +48,9 @@ static size_t hash_func (void *a)
static int equal_func(void *a, void *b)
{
const unsigned long *pa = a;
if (b == NULL) {
return *pa == -1U;
}
const unsigned long *pb = b;
return *pa == *pb;
}
@@ -52,8 +58,12 @@ static int equal_func(void *a, void *b)
static void set_func(void *a, void *b)
{
unsigned long *pa = a;
const unsigned long *pb = b;
*pa = *pb;
if (b == NULL) {
*pa = -1U;
} else {
const unsigned long *pb = b;
*pa = *pb;
}
}
typedef struct map_element map_element;
@@ -67,10 +77,10 @@ static void
test_dict(size_t n)
{
map dict;
map_construct(&dict, sizeof(map_element), (map_element[]) {{.key = -1}}, set_func);
map_construct(&dict, sizeof(map_element), set_func);
for (size_t i = 0; i < n; i++) {
map_insert(&dict, (map_element[]) {{.key = rand_get(), .value = rand_get()}}, hash_func, equal_func, set_func, NULL);
map_insert(&dict, (map_element[]) {{.key = rand_get(), .value = rand_get()}}, hash_func, set_func, equal_func, NULL);
}
rand_init();
unsigned int s = 0;
@@ -90,6 +100,8 @@ typedef char char_array_t[256];
static int char_equal (void *a, void *b)
{
const char_array_t *pa = (const char_array_t *)a;
if (b == NULL)
return strcmp(*pa, "") == 0;
const char_array_t *pb = (const char_array_t *)b;
return strcmp(*pa,*pb)==0;
}
@@ -103,8 +115,12 @@ static size_t char_hash(void *a)
static void char_set(void *a, void *b)
{
char_array_t *pa = (char_array_t *)a;
const char_array_t *pb = (const char_array_t *)b;
strcpy(*pa,*pb);
if (b == NULL) {
strcpy(*pa, "");
} else {
const char_array_t *pb = (const char_array_t *)b;
strcpy(*pa,*pb);
}
}
typedef struct big_map_element big_map_element;
@@ -118,16 +134,13 @@ static void
test_dict_big(size_t n)
{
map dict;
big_map_element empty;
strcpy(empty.key, "");
strcpy(empty.value, "");
map_construct(&dict, sizeof(big_map_element), &empty, char_set);
map_construct(&dict, sizeof(big_map_element), char_set);
for (size_t i = 0; i < n; i++) {
big_map_element el;
sprintf(el.key, "%u", rand_get());
sprintf(el.value, "%u", rand_get());
map_insert(&dict, &el, char_hash, char_equal, char_set, NULL);
map_insert(&dict, &el, char_hash, char_set, char_equal, NULL);
}
rand_init();
unsigned int s = 0;
@@ -144,14 +157,14 @@ test_dict_big(size_t n)
/********************************************************************************************/
const config_func_t table[] = {
{ 20, "Array", 100000000, 0, test_array, 0},
{ 40, "dict", 1000000, 0, test_dict, 0},
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 20)
test_function("Array time", 100000000, test_array);
if (n == 40)
test_function("Dict time", 1000000, test_dict);
if (n == 41)
test_function("Dict B time", 1000000, test_dict_big);
test("LIBDYNAMIC", numberof(table), table, argc, argv);
exit(0);
}
+14 -28
View File
@@ -6,11 +6,8 @@
#include "liblfds711.h"
#include "m-mutex.h"
#define MULTI_THREAD_MEASURE
#include "common.h"
/********************************************************************************************/
struct lfds711_queue_bmm_state g_buff;
@@ -23,12 +20,9 @@ static void final(void *arg)
unsigned long long j, s = 0;
LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
for(int i = 0; i < n;i++) {
int rv;
do {
void *p;
rv = lfds711_queue_bmm_dequeue(&g_final, &p, NULL);
j = (uintptr_t)p;
} while (rv == 0);
void *p;
while (0 == lfds711_queue_bmm_dequeue(&g_final, &p, NULL)) { m_thread_yield(); }
j = (uintptr_t)p;
s += j;
}
g_result = s;
@@ -42,18 +36,12 @@ static void conso(void *arg)
unsigned long long s = 0;
LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
for(int i = 0; i < n;i++) {
int rv;
do {
void *p;
rv = lfds711_queue_bmm_dequeue(&g_buff, &p, NULL);
j = (uintptr_t) p;
} while (rv == 0);
void *p;
while (0 == lfds711_queue_bmm_dequeue(&g_buff, &p, NULL)) { m_thread_yield(); }
j = (uintptr_t) p;
s += j;
}
int rv;
do {
rv = lfds711_queue_bmm_enqueue(&g_final, (void*)(uintptr_t)s, NULL);
} while (rv == 0);
while (0 == lfds711_queue_bmm_enqueue(&g_final, (void*)(uintptr_t)s, NULL)) { m_thread_yield(); }
}
static void prod(void *arg)
@@ -63,15 +51,12 @@ static void prod(void *arg)
size_t r = n;
LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
for(unsigned int i = 0; i < n;i++) {
int rv;
do {
rv = lfds711_queue_bmm_enqueue(&g_buff, (void*)(uintptr_t)r, NULL);
} while (rv == 0);
while (0 == lfds711_queue_bmm_enqueue(&g_buff, (void*)(uintptr_t)r, NULL)) { m_thread_yield(); }
r = r * 31421U + 6927U;
}
}
static void test_buffer(size_t n)
static void test_queue(size_t n)
{
const int cpu_count = get_cpu_count();
const int prod_count = cpu_count/2;
@@ -120,11 +105,12 @@ static void test_buffer(size_t n)
/********************************************************************************************/
const config_func_t table[] = {
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 60)
test_function("Buffer time", 1000000, test_buffer);
test("LIBLFDS", numberof(table), table, argc, argv);
exit(0);
}
+10 -8
View File
@@ -14,8 +14,8 @@
static void test_array(size_t n)
{
sv_t *a1 = sv_alloc ( sizeof (unsigned int), 16, NULL);
sv_t *a2 = sv_alloc ( sizeof (unsigned int), 16, NULL);
srt_vector *a1 = sv_alloc ( sizeof (unsigned int), 16, NULL);
srt_vector *a2 = sv_alloc ( sizeof (unsigned int), 16, NULL);
for(size_t i = 0; i < n; i++) {
unsigned int value = rand_get();
@@ -48,7 +48,7 @@ static int cmp_float (const void *a, const void *b)
static void test_sort(size_t n)
{
sv_t *a1 = sv_alloc(sizeof(float), 16, cmp_float);
srt_vector *a1 = sv_alloc(sizeof(float), 16, cmp_float);
for(size_t i = 0; i < n; i++) {
unsigned int value = rand_get();
sv_push(&a1, &value );
@@ -60,13 +60,15 @@ static void test_sort(size_t n)
/********************************************************************************************/
const config_func_t table[] = {
{ 20, "Array", 100000000, 0, test_array, 0},
{ 50, "sort", 10000000, 0, test_sort, 0}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 20)
test_function("Array time", 100000000, test_array);
if (n == 50)
test_function("Sort time", 10000000, test_sort);
test("LIBSRT", numberof(table), table, argc, argv);
exit(0);
}
+296 -55
View File
@@ -8,6 +8,7 @@
#include "m-list.h"
#include "m-rbtree.h"
#include "m-bptree.h"
#include "m-deque.h"
#include "m-dict.h"
#include "m-algo.h"
#include "m-mempool.h"
@@ -16,6 +17,9 @@
#include "m-mutex.h"
#include "m-deque.h"
#include "m-concurrent.h"
#include "m-tuple.h"
#include "m-serial-bin.h"
#include "m-serial-json.h"
#include "common.h"
@@ -40,6 +44,30 @@ static void test_array(size_t n)
/********************************************************************************************/
DEQUE_DEF(deque_uint, unsigned int)
static void test_deque(size_t n)
{
M_LET(a1, a2, DEQUE_OPLIST(deque_uint)) {
for(size_t i = 0; i < n; i++) {
deque_uint_push_back(a1, rand_get() );
deque_uint_push_back(a2, rand_get() );
}
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)) {
s += *deque_uint_cref(it1 ) * *deque_uint_cref(it2 );
deque_uint_next(it1);
deque_uint_next(it2);
}
g_result = s;
}
}
/********************************************************************************************/
// Two benched mode: with or without mempool
#ifdef USE_MEMPOOL
LIST_DEF(list_uint, unsigned int, (MEMPOOL( list_mpool), MEMPOOL_LINKAGE(static)))
@@ -220,14 +248,36 @@ test_dict_oa(size_t n)
}
}
/********************************************************************************************/
static void
test_dict_oa_linear(size_t n)
{
M_LET(dict, DICT_OPLIST(dict_oa_ulong)) {
for (size_t i = 0; i < n; i++) {
dict_oa_ulong_set_at(dict, i, rand_get() );
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
unsigned long *p = dict_oa_ulong_get(dict, i);
if (p)
s += *p;
}
g_result = s;
}
}
typedef char char_array_t[256];
/********************************************************************************************/
#ifndef CHAR_ARRAY_SIZE
#define CHAR_ARRAY_SIZE 256
#endif
typedef char char_array_t[CHAR_ARRAY_SIZE];
static void char_init (char_array_t a) { a[0] = 0; }
static void char_set (char_array_t a, const char_array_t b) { strcpy(a, b); }
static bool char_equal_p (const char_array_t a, const char_array_t b) { return strcmp(a,b)==0; }
static size_t char_hash(const char_array_t a) { return m_core_hash (a, strlen(a)); }
#define M_OPL_char_array_t() (INIT(char_init), INIT_SET(char_set), SET(char_set), CLEAR(char_init), HASH(char_hash), EQUAL(char_equal_p))
static bool char_oor_equal_p(const char_array_t a, unsigned char n) { return a[0] == 1+n; }
static void char_oor_set(char_array_t a, unsigned char n) { a[0] = 1+n; }
#define M_OPL_char_array_t() (INIT(char_init), INIT_SET(char_set), SET(char_set), CLEAR(char_init), HASH(char_hash), EQUAL(char_equal_p), OOR_EQUAL(char_oor_equal_p), OOR_SET(char_oor_set))
#ifdef USE_MEMPOOL
DICT_STOREHASH_DEF2(dict_char, char_array_t, M_OPEXTEND(M_OPL_char_array_t(),MEMPOOL(dict_mpool2), MEMPOOL_LINKAGE(static)), char_array_t, M_OPL_char_array_t())
@@ -235,6 +285,7 @@ DICT_STOREHASH_DEF2(dict_char, char_array_t, M_OPEXTEND(M_OPL_char_array_t(),MEM
DICT_STOREHASH_DEF2(dict_char, char_array_t, M_OPL_char_array_t(), char_array_t, M_OPL_char_array_t())
#endif
static void
test_dict_big(size_t n)
{
@@ -264,6 +315,31 @@ test_dict_big(size_t n)
#endif
}
DICT_OA_DEF2(dict_oa_char, char_array_t, char_array_t)
static void
test_dict_oa_big(size_t n)
{
M_LET(dict, DICT_OPLIST(dict_oa_char)) {
for (size_t i = 0; i < n; i++) {
char_array_t s1, s2;
sprintf(s1, "%u", rand_get());
sprintf(s2, "%u", rand_get());
dict_oa_char_set_at(dict, s1, s2);
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
char_array_t s1;
sprintf(s1, "%u", rand_get());
char_array_t *p = dict_oa_char_get(dict, s1);
if (p)
s ++;
}
g_result = s;
}
}
/********************************************************************************************/
#ifdef USE_MEMPOOL
@@ -671,7 +747,6 @@ static void test_queue_single_bulk(size_t n)
/********************************************************************************************/
DEQUE_DEF(deque_uint, unsigned int)
CONCURRENT_DEF(cdeque_uint, deque_uint_t, M_OPEXTEND(DEQUE_OPLIST(deque_uint, M_DEFAULT_OPLIST), PUSH(deque_uint_push_front)))
DEQUE_DEF(deque_ull, unsigned long long)
@@ -791,59 +866,225 @@ static void test_core_hash(size_t n)
/********************************************************************************************/
ARRAY_DEF(vector_string, string_t)
vector_string_t vstring;
vector_string_t vstring2;
static void
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) {
vector_string_push_back(vstring, s);
}
}
vector_string_init(vstring2);
}
static void
bench_vector_string_init_big(size_t n)
{
vector_string_init(vstring);
for(size_t i = 0; i < n; i++)
{
M_LET( (s, "%zu%zu%zu%zu%zu%zu", i, i, i, i, i, i), string_t) {
vector_string_push_back(vstring, s);
}
}
vector_string_init(vstring2);
}
static void
bench_vector_string_bin_run(size_t n)
{
if (vector_string_size(vstring) != n) {
printf("Size are different!\n");
abort();
}
FILE *f = fopen("tmp-serial.dat", "wb");
if (!f) abort();
M_LET( (serial, f), m_serial_bin_write_t) {
vector_string_out_serial(serial, vstring);
}
fclose(f);
f = fopen("tmp-serial.dat", "rb");
if (!f) abort();
M_LET( (serial, f), m_serial_bin_read_t) {
vector_string_in_serial(vstring2, serial);
}
fclose(f);
if (vector_string_size(vstring2) != n) {
printf("Size are different!\n");
abort();
}
}
static void
bench_vector_string_json_run(size_t n)
{
if (vector_string_size(vstring) != n) {
printf("Size are different!\n");
abort();
}
FILE *f = fopen("tmp-serial.json", "wt");
if (!f) abort();
M_LET( (serial, f), m_serial_json_write_t) {
vector_string_out_serial(serial, vstring);
}
fclose(f);
f = fopen("tmp-serial.json", "rt");
if (!f) abort();
M_LET( (serial, f), m_serial_json_read_t) {
vector_string_in_serial(vstring2, serial);
}
fclose(f);
if (vector_string_size(vstring2) != n) {
printf("Size are different!\n");
abort();
}
}
static void
bench_vector_string_clear(void)
{
if (!vector_string_equal_p(vstring, vstring2)) {
printf("Array are different!\n");
abort();
}
vector_string_clear(vstring);
vector_string_clear(vstring2);
}
/********************************************************************************************/
ARRAY_DEF(vector_ulong, unsigned long)
vector_ulong_t vulong;
vector_ulong_t vulong2;
static void
bench_vector_ulong_init(size_t n)
{
vector_ulong_init(vulong);
for(size_t i = 0; i < n; i++)
{
vector_ulong_push_back(vulong, i*i);
}
vector_ulong_init(vulong2);
}
static void
bench_vector_ulong_bin_run(size_t n)
{
if (vector_ulong_size(vulong) != n) {
printf("Size are different!\n");
abort();
}
FILE *f = fopen("tmp-serial.dat", "wb");
if (!f) abort();
M_LET( (serial, f), m_serial_bin_write_t) {
vector_ulong_out_serial(serial, vulong);
}
fclose(f);
f = fopen("tmp-serial.dat", "rb");
if (!f) abort();
M_LET( (serial, f), m_serial_bin_read_t) {
vector_ulong_in_serial(vulong2, serial);
}
fclose(f);
if (vector_ulong_size(vulong2) != n) {
printf("Size are different!\n");
abort();
}
}
static void
bench_vector_ulong_json_run(size_t n)
{
if (vector_ulong_size(vulong) != n) {
printf("Size are different!\n");
abort();
}
FILE *f = fopen("tmp-serial.json", "wt");
if (!f) abort();
M_LET( (serial, f), m_serial_json_write_t) {
vector_ulong_out_serial(serial, vulong);
}
fclose(f);
f = fopen("tmp-serial.json", "rt");
if (!f) abort();
M_LET( (serial, f), m_serial_json_read_t) {
vector_ulong_in_serial(vulong2, serial);
}
fclose(f);
if (vector_ulong_size(vulong2) != n) {
printf("Size are different!\n");
abort();
}
}
static void
bench_vector_ulong_clear(void)
{
if (!vector_ulong_equal_p(vulong, vulong2)) {
printf("Array are different!\n");
abort();
}
vector_ulong_clear(vulong);
vector_ulong_clear(vulong2);
}
/********************************************************************************************/
const config_func_t table[] = {
{ 10, "List", 10000000, 0, test_list, 0},
{ 11, "DPList", 10000000, 0, test_dlist, 0},
{ 20, "Array", 100000000, 0, test_array, 0},
{ 21, "Deque", 100000000, 0, test_deque, 0},
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
{ 31, "B+tree", 1000000, 0, test_bptree, 0},
{ 40, "dict", 1000000, 0, test_dict, 0},
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
{ 42,"dict(OA)", 1000000, 0, test_dict_oa, 0},
{ 43,"DictStr", 1000000, 0, test_dict_str, 0},
{ 46, "dictLinear(OA)", 1000000, 0, test_dict_oa_linear, 0},
{ 47, "dictBig(OA)", 1000000, 0, test_dict_oa_big, 0},
{ 50, "Sort",10000000, 0, test_sort, 0},
{ 51, "Stable Sort",10000000, 0, test_stable_sort, 0},
{ 60,"Buffer", 1000000, 0, test_buffer, 0},
{ 61,"Queue MPMC", 1000000, 0, test_queue, 0},
{ 62,"Buffer(P=2)", SIZE_LIMIT+1000000, 0, test_buffer, 0},
{ 63,"Queue MPMC (P=2)", SIZE_LIMIT+1000000, 0, test_queue, 0},
{ 64,"Queue SPSC (P=2)", 1000000, 0, test_queue_single, 0},
{ 65,"Queue Concurrent", 1000000, 0, test_queue_concurrent, 0},
{ 66,"Queue SPSC(Bulk)", 1000000, 0, test_queue_single_bulk, 0},
{ 70,"M_HASH", 100000000, test_hash_prepare, test_hash, test_hash_final},
{ 71,"Core Hash", 100000000, test_hash_prepare, test_core_hash, test_hash_final},
{100, "serial-bin STR", 10000000, bench_vector_string_init, bench_vector_string_bin_run, bench_vector_string_clear},
{101, "serial-bin STR.big", 10000000, bench_vector_string_init_big, bench_vector_string_bin_run, bench_vector_string_clear},
{102, "serial-bin INT", 10000000, bench_vector_ulong_init, bench_vector_ulong_bin_run, bench_vector_ulong_clear},
{110, "serial-json STR", 10000000, bench_vector_string_init, bench_vector_string_json_run, bench_vector_string_clear},
{111, "serial-json STR.big", 10000000, bench_vector_string_init_big, bench_vector_string_json_run, bench_vector_string_clear},
{112, "serial-json INT", 10000000, bench_vector_ulong_init, bench_vector_ulong_json_run, bench_vector_ulong_clear}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 10)
test_function("List time",10000000, test_list);
if (n == 11)
test_function("DPList time",10000000, test_dlist);
if (n == 20)
test_function("Array time", 100000000, test_array);
if (n == 30)
test_function("Rbtree time", 1000000, test_rbtree);
if (n == 31)
test_function("B+tree time", 1000000, test_bptree);
if (n == 40)
test_function("Dict time", 1000000, test_dict);
if (n == 42)
test_function("DictOA time", 1000000, test_dict_oa);
if (n == 41)
test_function("DictB time", 1000000, test_dict_big);
if (n == 43)
test_function("DictS time", 1000000, test_dict_str);
if (n == 50)
test_function("Sort time", 10000000, test_sort);
if (n == 51)
test_function("Stable Sort time", 10000000, test_stable_sort);
if (n == 60)
test_function("Buffer time", 1000000, test_buffer);
if (n == 61)
test_function("Queue MPMC time", 1000000, test_queue);
if (n == 62)
test_function("Buffer time (P2)", SIZE_LIMIT+1000000, test_buffer);
if (n == 63)
test_function("Queue MPMC time (P2)", SIZE_LIMIT+1000000, test_queue);
if (n == 64)
test_function("Queue SPSC time", 1000000, test_queue_single);
if (n == 65)
test_function("Queue CONCURRENT time", 1000000, test_queue_concurrent);
if (n == 66)
test_function("Queue SPSC BULK time", 1000000, test_queue_single_bulk);
if (n == 70) {
n = (argc > 2) ? atoi(argv[2]) : 100000000;
test_hash_prepare(n);
test_function("M_HASH time", n, test_hash);
test_hash_final();
}
if (n == 71) {
n = (argc > 2) ? atoi(argv[2]) : 100000000;
test_hash_prepare(n);
test_function("CORE_HASH time", n, test_core_hash);
test_hash_final();
}
test("M-LIB", numberof(table), table, argc, argv);
exit(0);
}
+5 -7
View File
@@ -87,15 +87,13 @@ test_dict_noalloc(size_t n)
/********************************************************************************************/
const config_func_t table[] = {
{ 40, "dict", 1000000, 0, test_dict, 0},
{ 45, "dict(noalloc)", 1000000, 0, test_dict_noalloc, 0}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 40)
test_function("Dict time", 1000000, test_dict);
if (n == 45)
test_function("Dict No Alloc time", 1000000, test_dict_noalloc);
test("NEDTRIES", numberof(table), table, argc, argv);
exit(0);
}
+9 -7
View File
@@ -98,14 +98,16 @@ static void test_rbtree(size_t n)
/* qlibc hash functions only accept a string as the key */
/********************************************************************************************/
const config_func_t table[] = {
{ 10, "List", 10000000, 0, test_list, 0},
{ 20, "Array", 100000000, 0, test_array, 0},
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 20)
test_function("Array time", 100000000, test_array);
if (n == 10)
test_function("List time",10000000, test_list);
if (n == 30)
test_function("Rbtree time", 1000000, test_rbtree);
test("QLIBC", numberof(table), table, argc, argv);
exit(0);
}
+11 -15
View File
@@ -162,22 +162,18 @@ static void test_sort(size_t n)
/********************************************************************************************/
const config_func_t table[] = {
{ 10, "List", 10000000, 0, test_list, 0},
{ 20, "Array", 100000000, 0, test_array, 0},
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
{ 40, "dict(m)", 1000000, 0, test_dict1, 0},
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
{ 42,"dict(u)", 1000000, 0, test_dict2, 0},
{ 50, "Sort",10000000, 0, test_sort, 0}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 10)
test_function("List time",10000000, test_list);
if (n == 20)
test_function("Array time", 100000000, test_array);
if (n == 30)
test_function("Rbtree time", 1000000, test_rbtree);
if (n == 40)
test_function("Dict(m)time", 1000000, test_dict1);
if (n == 42)
test_function("Dict(u)time", 1000000, test_dict2);
if (n == 41)
test_function("DictB time", 1000000, test_dict_big);
if (n == 50)
test_function("Sort time", 10000000, test_sort);
test("QT", numberof(table), table, argc, argv);
exit(0);
}
+185
View File
@@ -0,0 +1,185 @@
#define NDEBUG
#define RAPIDJSON_HAS_STDSTRING 1
#include "rapidjson/reader.h"
#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h"
#include "rapidjson/encodedstream.h"
#include "rapidjson/error/en.h"
#include <stdio.h>
#include <string>
#include <vector>
#include "common.h"
using namespace std;
/********************************************************************************************/
vector<string> vstring;
vector<string> vstring2;
static void
bench_vector_string_init(size_t n)
{
for(size_t i = 0; i < n; i++)
{
char buff[100];
snprintf(buff, sizeof(buff), "%zu", i);
std::string s(buff);
vstring.push_back(s);
}
}
static void
bench_vector_string_init_big(size_t n)
{
for(size_t i = 0; i < n; i++)
{
char buff[100];
snprintf(buff, sizeof(buff), "%zu%zu%zu%zu%zu%zu", i, i, i, i, i, i);
std::string s(buff);
vstring.push_back(s);
}
}
static void
bench_vector_string_json_run(size_t n)
{
if (vstring.size() != n) {
printf("Size are different!\n");
abort();
}
FILE *f = fopen("tmp-serial.json", "wt");
if (!f) abort();
{
// Prepare writer and output stream.
char writeBuffer[65536];
typedef rapidjson::AutoUTFOutputStream<unsigned, rapidjson::FileWriteStream> OutputStream;
rapidjson::FileWriteStream os(f, writeBuffer, sizeof(writeBuffer));
OutputStream eos(os, rapidjson::kUTF8, false);
rapidjson::PrettyWriter<OutputStream, rapidjson::UTF8<>, rapidjson::AutoUTF<unsigned> > writer(eos);
writer.StartArray();
for(size_t i = 0; i < n; i++){
writer.String(vstring[i]);
}
writer.EndArray();
}
fclose(f);
f = fopen("tmp-serial.json", "rt");
if (!f) abort();
{
char readBuffer[65536];
rapidjson::FileReadStream is(f, readBuffer, sizeof(readBuffer));
rapidjson::Document d;
d.ParseStream(is);
for(size_t i = 0; i < d.Size(); i++) {
rapidjson::Value& s = d[i];
vstring2.push_back(s.GetString());
}
}
fclose(f);
if (vstring2.size() != n) {
printf("Size are different!\n");
abort();
}
}
static void
bench_vector_string_clear(void)
{
if (vstring != vstring2) {
printf("Array are different!\n");
abort();
}
}
/********************************************************************************************/
vector<unsigned long> vulong;
vector<unsigned long> vulong2;
static void
bench_vector_ulong_init(size_t n)
{
for(size_t i = 0; i < n; i++)
{
vulong.push_back(i*i);
}
}
static void
bench_vector_ulong_json_run(size_t n)
{
if (vulong.size() != n) {
printf("Size are different!\n");
abort();
}
FILE *f = fopen("tmp-serial.json", "wt");
if (!f) abort();
{
// Prepare writer and output stream.
char writeBuffer[65536];
typedef rapidjson::AutoUTFOutputStream<unsigned, rapidjson::FileWriteStream> OutputStream;
rapidjson::FileWriteStream os(f, writeBuffer, sizeof(writeBuffer));
OutputStream eos(os, rapidjson::kUTF8, false);
rapidjson::PrettyWriter<OutputStream, rapidjson::UTF8<>, rapidjson::AutoUTF<unsigned> > writer(eos);
writer.StartArray();
for(size_t i = 0; i < n; i++){
writer.Int64(vulong[i]);
}
writer.EndArray();
}
fclose(f);
f = fopen("tmp-serial.json", "rt");
if (!f) abort();
{
char readBuffer[65536];
rapidjson::FileReadStream is(f, readBuffer, sizeof(readBuffer));
rapidjson::Document d;
d.ParseStream(is);
for(size_t i = 0; i < d.Size(); i++) {
rapidjson::Value& s = d[i];
vulong2.push_back(s.GetInt64());
}
}
fclose(f);
if (vulong2.size() != n) {
printf("Size are different!\n");
abort();
}
}
static void
bench_vector_ulong_clear(void)
{
if (vulong != vulong2) {
printf("Array are different!\n");
abort();
}
}
/********************************************************************************************/
const config_func_t table[] = {
{110, "serial-json STR", 10000000, bench_vector_string_init, bench_vector_string_json_run, bench_vector_string_clear},
{111, "serial-json STR.big", 10000000, bench_vector_string_init_big, bench_vector_string_json_run, bench_vector_string_clear},
{112, "serial-json INT", 10000000, bench_vector_ulong_init, bench_vector_ulong_json_run, bench_vector_ulong_clear}
};
int main(int argc, const char *argv[])
{
test("RAPIDJSON", numberof(table), table, argc, argv);
exit(0);
}
+159
View File
@@ -0,0 +1,159 @@
#define NDEBUG
#include <vector>
#include <list>
#include <iterator>
#include <map>
#include <set>
#include <unordered_map>
#include <algorithm>
#include <string>
#include <sstream>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "rigtorp/HashMap.h"
using namespace rigtorp;
using namespace std;
#include "common.h"
/********************************************************************************************/
// Hash for using unsigned long as lookup key
struct UL_Hash {
size_t operator()(const unsigned long v) { return v * 7; }
};
// Equal comparison for using unsigned long as lookup key
struct UL_Equal {
bool operator()(const unsigned long lhs, const unsigned long rhs) {
return lhs == rhs;
}
};
static void
test_dict2(size_t n)
{
HashMap<unsigned long, unsigned long, UL_Hash, UL_Equal> dict(16, -1UL);
for (size_t i = 0; i < n; i++) {
dict[rand_get()] = rand_get();
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
HashMap<unsigned long, unsigned long, UL_Hash, UL_Equal>::iterator it = dict.find(rand_get());
if (it != dict.end())
s += it->second;
}
g_result = s;
}
/********************************************************************************************/
struct char_array_s {
char a[256];
char_array_s () { a[0] = 0 ; }
char_array_s ( const char_array_s & other) { strcpy(a, other.a); }
bool operator==(const char_array_s &other) const { return strcmp(a, other.a) == 0; }
};
namespace std {
template <> struct hash<char_array_s> {
std::size_t operator()(const char_array_s &k) const {
size_t hash = 0;
const char *s = k.a;
while (*s) hash = hash * 31421 + (*s++) + 6927;
return hash;
};
};
}
struct BIG_Hash {
size_t operator()(const char_array_s v) { return hash<char_array_s>()(v); }
};
struct BIG_Equal {
bool operator()(const char_array_s lhs, const char_array_s rhs) {
return lhs == rhs;
}
};
static void
test_dict_big(size_t n)
{
char_array_s empty;
HashMap<char_array_s, char_array_s, BIG_Hash, BIG_Equal> dict(16, empty);
for (size_t i = 0; i < n; i++) {
char_array_s s1, s2;
sprintf(s1.a, "%u", rand_get());
sprintf(s2.a, "%u", rand_get());
dict[s1] = s2;
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
char_array_s s1;
sprintf(s1.a, "%u", rand_get());
HashMap<char_array_s, char_array_s, BIG_Hash, BIG_Equal>::iterator it = dict.find(s1);
if (it != dict.end())
s ++;
}
g_result = s;
}
/********************************************************************************************/
struct STR_Hash {
size_t operator()(const string v) { return hash<string>()(v); }
};
struct STR_Equal {
bool operator()(const string lhs, const string rhs) {
return lhs == rhs;
}
};
static void
test_dict_str(size_t n)
{
string empty;
HashMap<string, string, STR_Hash, STR_Equal> dict(16, empty);
for (size_t i = 0; i < n; i++) {
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
dict[s1] = s2;
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
HashMap<string, string, STR_Hash, STR_Equal>::iterator it = dict.find(s1);
if (it != dict.end())
s ++;
}
g_result = s;
}
/********************************************************************************************/
const config_func_t table[] = {
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
{ 42,"dict", 1000000, 0, test_dict2, 0},
{ 43, "DictStr", 1000000, 0, test_dict_str, 0}
};
int main(int argc, const char *argv[])
{
test("RIGTORP-HASHMAP", numberof(table), table, argc, argv);
exit(0);
}
+96
View File
@@ -0,0 +1,96 @@
#define NDEBUG
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <rigtorp/MPMCQueue.h>
#include "common.h"
/********************************************************************************************/
rigtorp::MPMCQueue<unsigned int> g_buff(4*64);
rigtorp::MPMCQueue<unsigned long long> g_final(4*64);
static void final(void *arg)
{
size_t *p_n = (size_t*) arg;
size_t n = *p_n;
unsigned long long j, s = 0;
for(unsigned int i = 0; i < n;i++) {
g_final.pop(j);
s += j;
}
g_result = s;
}
static void conso(void *arg)
{
unsigned int j;
size_t *p_n = (size_t*)arg;
size_t n = *p_n;
unsigned long long s = 0;
for(unsigned int i = 0; i < n;i++) {
g_buff.pop(j);
s += j;
}
g_final.push(s);
}
static void prod(void *arg)
{
size_t *p_n = (size_t*)arg;
size_t n = *p_n;
size_t r = n;
for(unsigned int i = 0; i < n;i++) {
g_buff.push(r);
r = r * 31421U + 6927U;
}
}
static void test_queue(size_t n)
{
const int cpu_count = get_cpu_count();
const int prod_count = cpu_count/2;
const int conso_count = cpu_count - prod_count;
if (cpu_count < 2) {
fprintf(stderr, "WARNING: Can not measure Buffer performance.\n");
return;
}
rand_get();
// Create thread
m_thread_t idx_p[prod_count];
m_thread_t idx_c[conso_count];
m_thread_t idx_final;
for(int i = 0; i < prod_count; i++) {
m_thread_create (idx_p[i], prod, &n);
}
for(int i = 0; i < conso_count; i++) {
m_thread_create (idx_c[i], conso, &n);
}
size_t n2 = conso_count;
m_thread_create(idx_final, final, &n2);
// Wait for jobs to be done.
for(int i = 0; i < prod_count; i++) {
m_thread_join(idx_p[i]);
}
for(int i = 0; i < conso_count; i++) {
m_thread_join(idx_c[i]);
}
m_thread_join(idx_final);
}
/********************************************************************************************/
const config_func_t table[] = {
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
};
int main(int argc, const char *argv[])
{
test("RIGTORP-MPMC-QUEUE", numberof(table), table, argc, argv);
exit(0);
}
+7 -7
View File
@@ -109,14 +109,14 @@ test_dict_str(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}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 42)
test_function("Dict(u)time", 1000000, test_dict2);
if (n == 41)
test_function("DictB time", 1000000, test_dict_big);
if (n == 43)
test_function("DictS(u) time", 1000000, test_dict_str);
test("SPARSEPP", numberof(table), table, argc, argv);
exit(0);
}
+52 -21
View File
@@ -1,6 +1,7 @@
#define NDEBUG
#include <vector>
#include <deque>
#include <list>
#include <iterator>
#include <map>
@@ -53,6 +54,23 @@ static void test_array(size_t n)
/********************************************************************************************/
static void test_deque(size_t n)
{
deque<unsigned int> a1, a2;
for(size_t i = 0; i < n; i++) {
a1.push_back(rand_get() );
a2.push_back(rand_get() );
}
unsigned int s = 0;
for(auto it1 = a1.cbegin(), it2 = a2.cbegin();
it1 != a1.cend() ;it1++, it2++) {
s += *it1 * *it2;
}
g_result = s;
}
/********************************************************************************************/
static void test_rbtree(size_t n)
{
set<unsigned long> tree;
@@ -110,6 +128,24 @@ test_dict2(size_t n)
g_result = s;
}
static void
test_dict2_linear(size_t n)
{
unordered_map<unsigned long, unsigned long> dict;
for (size_t i = 0; i < n; i++) {
dict[i] = rand_get();
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
unordered_map<unsigned long, unsigned long>::iterator it = dict.find(i);
if (it != dict.end())
s += it->second;
}
g_result = s;
}
/********************************************************************************************/
struct char_array_s {
@@ -220,28 +256,23 @@ static void test_stable_sort(size_t n)
/********************************************************************************************/
const config_func_t table[] = {
{ 10, "List", 10000000, 0, test_list, 0},
{ 20, "Array", 100000000, 0, test_array, 0},
{ 21, "Deque", 100000000, 0, test_deque, 0},
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
{ 40, "dict(m)", 1000000, 0, test_dict1, 0},
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
{ 42,"dict(u)", 1000000, 0, test_dict2, 0},
{ 43,"DictStr(u)", 1000000, 0, test_dict_str, 0},
{ 44,"DictStr(m)", 1000000, 0, test_dict_str2, 0},
{ 46, "dictLinear(u)", 1000000, 0, test_dict2_linear, 0},
{ 50, "Sort",10000000, 0, test_sort, 0},
{ 51, "Stable Sort",10000000, 0, test_stable_sort, 0}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 10)
test_function("List time",10000000, test_list);
if (n == 20)
test_function("Array time", 100000000, test_array);
if (n == 30)
test_function("Rbtree time", 1000000, test_rbtree);
if (n == 40)
test_function("Dict(m)time", 1000000, test_dict1);
if (n == 42)
test_function("Dict(u)time", 1000000, test_dict2);
if (n == 41)
test_function("DictB time", 1000000, test_dict_big);
if (n == 43)
test_function("DictS(u) time", 1000000, test_dict_str);
if (n == 44)
test_function("DictS(m) time", 1000000, test_dict_str2);
if (n == 50)
test_function("Sort time", 10000000, test_sort);
if (n == 51)
test_function("Stable Sort time", 10000000, test_stable_sort);
test("STL", numberof(table), table, argc, argv);
exit(0);
}
+79 -109
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - String Bench
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2021, 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,17 +27,20 @@
#include <string>
#include <vector>
#include "m-string.h"
#include "common.h"
#include "m-string.h"
#ifdef BENCH_CAN_USE_SDS
extern "C" {
#include "sds.h"
};
#endif
#ifdef BENCH_CAN_USE_RAPIDSTRING
#include "rapidstring.h"
#ifdef BENCH_CAN_USE_BSTRLIB
#include "bstrlib.h"
#include "bstrwrap.h"
#include "bstraux.h"
#endif
/*
@@ -70,6 +73,17 @@ void random_permutation(unsigned n)
using namespace std;
static void replace_all_stl(string &str, const char pattern[], const char replace[])
{
size_t pos = 0;
do {
pos = str.find(pattern, pos);
if (pos != string::npos) {
str.replace (pos, strlen(pattern), replace);
}
} while (pos != string::npos);
}
size_t bench_stl(unsigned n)
{
vector<string> tab;
@@ -82,25 +96,12 @@ size_t bench_stl(unsigned n)
str += tab[permutation_tab[i]];
}
size_t pos = 0;
do {
pos = str.find("1234", pos);
if (pos != string::npos) {
str.replace (pos, 4, "WELL");
}
} while (pos != string::npos);
pos = 0;
do {
pos = str.find("56789", pos);
if (pos != string::npos) {
str.replace (pos, 5, "DONE");
}
} while (pos != string::npos);
replace_all_stl(str, "1234", "WELL");
replace_all_stl(str, "56789", "DONE");
return str.length();
}
size_t bench_mlib(unsigned n)
{
string_t *tab = (string_t*) malloc (n * sizeof (string_t));
@@ -117,15 +118,8 @@ size_t bench_mlib(unsigned n)
string_cat(str, tab[permutation_tab[i]]);
}
// P3
size_t i = 0;
do {
i = string_replace_str(str, "1234", "WELL", i);
} while (i != STRING_FAILURE);
// P4
i = 0;
do {
i = string_replace_str(str, "56789", "DONE", i);
} while (i != STRING_FAILURE);
string_replace_all_str(str, "1234", "WELL");
string_replace_all_str(str, "56789", "DONE");
size_t length = string_size(str);
// Clean
string_clear(str);
@@ -136,6 +130,42 @@ size_t bench_mlib(unsigned n)
return length;
}
#ifdef BENCH_CAN_USE_BSTRLIB
static void replace_all_bstrlib(CBString &str, const char pattern[], const char replace[])
{
size_t pos = 0;
do {
pos = str.find(pattern, pos);
if (pos != string::npos) {
str.replace (pos, strlen(pattern), replace);
}
} while (pos != string::npos);
}
size_t bench_bstrlib(unsigned n)
{
vector<CBString> tab;
tab.resize(n);
for(unsigned i = 0; i < n; i++) {
char tmp[10];
sprintf(tmp, "%u", rand_get());
tab[i] = tmp;
}
CBString str;
for(unsigned i = 0; i < n; i++) {
str += tab[permutation_tab[i]];
}
replace_all_bstrlib(str, "1234", "WELL");
replace_all_bstrlib(str, "56789", "DONE");
return str.length();
}
#endif
#ifdef BENCH_CAN_USE_SDS
sds SDS_replace_at(sds str, size_t pos, size_t len, const char str2[])
{
@@ -147,6 +177,19 @@ sds SDS_replace_at(sds str, size_t pos, size_t len, const char str2[])
return a;
}
sds replace_all_sds(sds str, const char pattern[], const char replace[])
{
size_t pos = 0;
do {
char *p = strstr(&str[pos], pattern);
pos = p == NULL ? -1U : (p - str);
if (pos != -1U) {
str = SDS_replace_at(str, pos, strlen(pattern), replace);
}
} while (pos != -1U);
return str;
}
size_t bench_sds(unsigned n)
{
sds *tab = (sds*) malloc (n * sizeof (sds));
@@ -161,25 +204,10 @@ size_t bench_sds(unsigned n)
str = sdscat(str, tab[permutation_tab[i]]);
}
// P3
size_t pos = 0;
do {
char *p = strstr(&str[pos], "1234");
pos = p == NULL ? -1U : (p - str);
if (pos != -1U) {
str = SDS_replace_at(str, pos, 4, "WELL");
}
} while (pos != -1U);
// P4
pos = 0;
do {
char *p = strstr(&str[pos], "56789");
pos = p == NULL ? -1U : (p - str);
if (pos != -1U) {
str = SDS_replace_at(str, pos, 5, "DONE");
}
} while (pos != -1U);
size_t length = sdslen(str);
str = replace_all_sds(str, "1234", "WELL");
str = replace_all_sds(str, "56789", "DONE");
// Clean
size_t length = sdslen(str);
sdsfree(str);
for(unsigned i = 0; i < n; i++) {
sdsfree(tab[i]);
@@ -189,63 +217,6 @@ size_t bench_sds(unsigned n)
}
#endif
#ifdef BENCH_CAN_USE_RAPIDSTRING
void RAPIDSTRING_replace_at(rapidstring *str, size_t pos, size_t len, const char str2[])
{
// simple implementation as replace is not available
rapidstring a;
rs_init_w_n(&a, rs_data(str), pos);
rs_cat(&a, str2);
rs_cat(&a, &rs_data(str)[pos+len] );
rs_free(str);
*str = a;
}
size_t bench_rapidstring(unsigned n)
{
rapidstring *tab = (rapidstring*) malloc (n * sizeof (rapidstring));
assert (tab != 0);
// P1
for(unsigned i = 0; i < n; i++) {
char tmp[10];
sprintf(tmp, "%u", rand_get());
rs_init_w(&tab[i], tmp);
}
// P2
rapidstring str;
rs_init(&str);
for(unsigned i = 0; i < n; i++) {
rs_cat_rs(&str, &tab[permutation_tab[i]]);
}
// P3
size_t pos = 0;
do {
char *p = strstr(&rs_data(&str)[pos], "1234");
pos = p == NULL ? -1U : (p - rs_data(&str));
if (pos != -1U) {
RAPIDSTRING_replace_at(&str, pos, 4, "WELL");
}
} while (pos != -1U);
// P4
pos = 0;
do {
char *p = strstr(&rs_data(&str)[pos], "56789");
pos = p == NULL ? -1U : (p - rs_data(&str));
if (pos != -1U) {
RAPIDSTRING_replace_at(&str, pos, 5, "DONE");
}
} while (pos != -1U);
size_t length = rs_len(&str);
// Clean
rs_free(&str);
for(unsigned i = 0; i < n; i++) {
rs_free(&tab[i]);
}
free(tab);
return length;
}
#endif
int main(int argc, const char *argv[])
{
@@ -271,10 +242,10 @@ int main(int argc, const char *argv[])
name = "SDS";
break;
#endif
#ifdef BENCH_CAN_USE_RAPIDSTRING
case 3:
length = bench_rapidstring(n);
name = "RAPID";
#ifdef BENCH_CAN_USE_BSTRLIB
case 4:
length = bench_bstrlib(n);
name = "BSTRLIB";
break;
#endif
default:
@@ -285,4 +256,3 @@ int main(int argc, const char *argv[])
return 0;
}
+2 -153
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, RAPIDSTRING & GLIB
done by Patrick Pelissier
/* Update of integrating M*LIB, LIBSRT, SDS & GLIB
Copyright (c) 2018-2021 Patrick Pelissier
*/
/*
@@ -79,11 +79,6 @@ extern "C" {
#include <string>
#endif
#if defined (BENCH_CAN_USE_RAPIDSTRING)
#include "rapidstring.h"
#endif
#if defined(BENCH_CAN_USE_GLIB)
#include "gmodule.h"
#endif
@@ -682,121 +677,6 @@ int testSDS_replace (int count) {
#endif
#ifdef BENCH_CAN_USE_RAPIDSTRING
int testRAPIDSTRING_emptyCtor (int count) {
int i, c = 0;
for (c=i=0; i < count; i++) {
rapidstring b;
rs_init(&b);
BARRIER(&b);
c += rs_len(&b) ^i;
rs_free(&b);
}
return c;
}
int testRAPIDSTRING_nonemptyCtor (int count) {
int i, c = 0;
for (c=i=0; i < count; i++) {
rapidstring b;
rs_init_w(&b, TESTSTRING1);
BARRIER(&b);
c += rs_len(&b) ^i;
rs_free(&b);
}
return c;
}
int testRAPIDSTRING_smallnonemptyCtor (int count) {
int i, c = 0;
for (c=i=0; i < count; i++) {
rapidstring b;
rs_init_w(&b, SMALLTESTSTRING1);
BARRIER(&b);
c += rs_len(&b) ^i;
rs_free(&b);
}
return c;
}
int testRAPIDSTRING_cstrAssignment (int count) {
int i, c = 0;
rapidstring b;
rs_init(&b);
for (c=i=0; i < count; i++) {
rs_cpy(&b, TESTSTRING1);
BARRIER(&b);
c += rs_len(&b) ^i;
}
rs_free(&b);
return c;
}
int testRAPIDSTRING_extraction (int count) {
int i, c = 0;
rapidstring b;
rs_init_w(&b, TESTSTRING1);
for (c=i=0; i < count; i++) {
c += rs_data_c(&b)[i & 7];
c += rs_data_c(&b)[(i & 7) ^ 8];
c += rs_data_c(&b)[(i & 7) ^ 4] ^i;
BARRIER(&b);
}
rs_free(&b);
return c;
}
int testRAPIDSTRING_concat (int count) {
int i, j, c = 0;
rapidstring a, accum;
rs_init_w(&a, TESTSTRING1);
rs_init (&accum);
for (j=0; j < count; j++) {
rs_cpy(&accum, "");
for (i=0; i < 250; i++) {
rs_cat_rs(&accum, &a);
rs_cat(&accum, "!!");
BARRIER(&accum);
c += rs_len(&accum) ^i;
}
}
rs_free(&a);
rs_free(&accum);
return c;
}
void RAPIDSTRING_replace_at(rapidstring *str, size_t pos, size_t len, const char str2[])
{
// simple implementation as replace is not available
rapidstring a;
rs_init_w_n(&a, rs_data(str), pos);
rs_cat(&a, str2);
rs_cat(&a, &rs_data(str)[pos+len] );
rs_free(str);
*str = a;
}
int testRAPIDSTRING_replace (int count) {
int j, c = 0;
rapidstring a;
rs_init_w(&a, TESTSTRING1);
for (j=0; j < count; j++) {
RAPIDSTRING_replace_at(&a, 11, 4, "XXXXXX");
RAPIDSTRING_replace_at(&a, 23, 2, "XXXXXX");
RAPIDSTRING_replace_at(&a, 4, 8, "XX");
BARRIER(&a);
c += rs_len(&a) ^j;
}
rs_free(&a);
return c;
}
#endif
#ifdef BENCH_CAN_USE_GLIB
int testGLIB_emptyCtor (int count) {
@@ -1088,37 +968,6 @@ int benchTest (const struct flags * runflags) {
}
#endif
#ifdef BENCH_CAN_USE_RAPIDSTRING
if (runflags->runtest[0]) {
c += timeTest (cps, testRAPIDSTRING_emptyCtor, 100000);
print ("RAPIDSTRING", "empty constructor", cps);
}
if (runflags->runtest[1]) {
c += timeTest (cps, testRAPIDSTRING_nonemptyCtor, 100000);
print ("RAPIDSTRING", "non-empty constructor", cps);
}
if (runflags->runtest[2]) {
c += timeTest (cps, testRAPIDSTRING_smallnonemptyCtor, 100000);
print ("RAPIDSTRING", "small non-empty constructor", cps);
}
if (runflags->runtest[3]) {
c += timeTest (cps, testRAPIDSTRING_cstrAssignment, 100000);
print ("RAPIDSTRING", "char * assignment", cps);
}
if (runflags->runtest[4]) {
c += timeTest (cps, testRAPIDSTRING_extraction, 100000);
print ("RAPIDSTRING", "char extraction", cps);
}
if (runflags->runtest[6]) {
c += timeTest (cps, testRAPIDSTRING_concat, 10);
print ("RAPIDSTRING", "concatenation", cps * 250);
}
if (runflags->runtest[7]) {
c += timeTest (cps, testRAPIDSTRING_replace, 10);
print ("RAPIDSTRING", "replace", cps);
}
#endif
#ifdef BENCH_CAN_USE_GLIB
if (runflags->runtest[0]) {
c += timeTest (cps, testGLIB_emptyCtor, 100000);
+9 -11
View File
@@ -206,18 +206,16 @@ test_dict_big(size_t n)
/********************************************************************************************/
const config_func_t table[] = {
{ 10, "List", 10000000, 0, test_list, 0},
{ 20, "Array", 100000000, 0, test_array, 0},
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
{ 40, "dict", 1000000, 0, test_dict, 0},
{ 41, "dictBig", 1000000, 0, test_dict_big, 0}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 10)
test_function("List time",10000000, test_list);
if (n == 20)
test_function("Array time", 100000000, test_array);
if (n == 30)
test_function("Rbtree time", 1000000, test_rbtree);
if (n == 40)
test_function("Dict time", 1000000, test_dict);
if (n == 41)
test_function("DictB time", 1000000, test_dict_big);
test("TommyDS", numberof(table), table, argc, argv);
exit(0);
}
+10 -12
View File
@@ -1,4 +1,5 @@
#define NDEBUG
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
@@ -199,19 +200,16 @@ static void test_sort(size_t n)
/********************************************************************************************/
const config_func_t table[] = {
{ 10, "List", 10000000, 0, test_list, 0},
{ 20, "Array", 100000000, 0, test_array, 0},
{ 40, "dict", 1000000, 0, test_dict, 0},
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
{ 50, "sort", 10000000, 0, test_sort, 0}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]): 0;
if (n == 10)
test_function("List time",10000000, test_list);
if (n == 20)
test_function("Array time", 100000000, test_array);
if (n == 40 || n == 42)
test_function("Dict time", 1000000, test_dict);
if (n == 41)
test_function("DictB time", 1000000, test_dict_big);
if (n == 50)
test_function("Sort time", 10000000, test_sort);
test("UT-HASH", numberof(table), table, argc, argv);
exit(0);
}
+4 -9
View File
@@ -31,17 +31,12 @@ static void test_hash(size_t n)
/********************************************************************************************/
const config_func_t table[] = {
{ 70,"XXHASH64", 100000000, test_hash_prepare, test_hash, test_hash_final}
};
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 70) {
n = (argc > 2) ? atoi(argv[2]) : 100000000;
test_hash_prepare(n);
test_function("XXHASH64 time", n, test_hash);
test_hash_final();
}
test("XXHASH", numberof(table), table, argc, argv);
exit(0);
}
+271 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - common functions for bench module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2021, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -23,8 +23,21 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include "common.h"
// Maximum supported value for repeat argument
#define MAX_REPEAT 10000
// The global result
unsigned long g_result;
// The rand value
#if defined(MULTI_THREAD_MEASURE)
M_THREAD_ATTR
#endif
unsigned int randValue = 0;
void compiler_barrier(void *p)
{
// Do nothing, but let the compiler thinks that we did.
@@ -32,3 +45,260 @@ void compiler_barrier(void *p)
// Can be used for FLTO building
// asm volatile("": "+r" (p) : :"memory");
}
struct parse_opt_s {
int test_function;
double from, to, step, grow;
double within;
unsigned repeat;
bool graph, best, best_within, average, quiet;
};
static void
parse_config(struct parse_opt_s *opt, int argc, const char *argv[])
{
char *end;
opt->test_function = 0;
opt->from = 0.0;
opt->to = 0.0;
opt->step = 0.0;
opt->grow = 1.1;
opt->graph = false;
opt->best = false;
opt->best_within = false;
opt->average = false;
opt->quiet = false;
opt->repeat = 1;
opt->within = .05;
for(int i = 1; i < argc ; i++)
{
if (argv[i][0] == '-') {
if (strcmp(argv[i], "--from") == 0){
i++;
opt->from = strtod(argv[i], &end);
opt->to = opt->from;
} else if (strcmp(argv[i], "--to") == 0) {
i++;
opt->to = strtod(argv[i], &end);
opt->grow = 1.1;
} else if (strcmp(argv[i], "--step") == 0) {
i++;
opt->step = strtod(argv[i], &end);
opt->grow = 0;
} else if (strcmp(argv[i], "--grow") == 0) {
i++;
opt->grow = strtod(argv[i], &end);
opt->step = 0;
} else if (strcmp(argv[i], "--repeat") == 0) {
i++;
opt->repeat = strtol(argv[i], &end, 10);
opt->repeat = (opt->repeat > MAX_REPEAT) ? MAX_REPEAT : opt->repeat;
} else if (strcmp(argv[i], "--graph") == 0) {
opt->graph = true;
} else if (strcmp(argv[i], "--best") == 0) {
opt->best = true;
opt->average = false;
opt->best_within = false;
} else if (strcmp(argv[i], "--best-within") == 0) {
opt->best_within = true;
opt->best = false;
opt->average = false;
i++;
opt->within = strtod(argv[i], &end) / 100.0;
} else if (strcmp(argv[i], "--average") == 0) {
opt->average = true;
opt->best = false;
opt->best_within = false;
} else if (strcmp(argv[i], "--quiet") == 0) {
opt->quiet = true;
} else {
fprintf(stderr, "ERROR: Option unkown: %s.\n",
argv[i]);
exit(-1);
}
if (*end != 0) {
fprintf(stderr, "ERROR: Cannot parse %s. Expected float\n",
argv[i]);
exit(-1);
}
} else {
opt->test_function = strtol (argv[i], &end, 10);
if (*end != 0) {
fprintf(stderr, "ERROR: Cannot parse %s. Expected function number\n",
argv[i]);
exit(-1);
}
}
}
}
static int
select_config(int func, size_t n, const config_func_t functions[])
{
for(size_t i = 0; i < n;i++) {
if (functions[i].num == func)
return i;
}
fprintf(stderr, "ERROR: Function number %d not found. Available functions are:\n", func);
for(size_t i = 0; i < n;i++) {
fprintf(stderr, " %d: %s\n", functions[i].num, functions[i].funcname);
}
fprintf(stderr,
"USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--grapĥ]\n"
"[--repeat number] [--best|--average|--best-within] [--quiet]\n");
exit(-1);
}
// Utility function for qsort
static int cmp_double(const void *pa, const void *pb)
{
const double *a = (const double *) pa, *b = (const double *)pb;
return (*a < *b) ? -1 : *a > *b;
}
/* Get the longest sequence of values within 'f'% */
static int
get_sequence(int i, int n, double tab[], double f)
{
int j;
for(j = i + 1; j < n; j++) {
if (tab[j] > f * tab[i])
break;
}
return j-i;
}
/* Return the minimum of the longest sequence of values with 'f'% */
static double
get_best_within(int n, double tab[], double f)
{
qsort(tab, n, sizeof(double), cmp_double);
int best_i = 0;
int best_seq = get_sequence(0, n, tab, f);
for(int i = 1; i < n && (n-i) > best_seq ; i++) {
int seq = get_sequence(i, n, tab, f);
if (seq > best_seq) {
best_i = i;
best_seq = seq;
}
}
return tab[best_i];
}
// Integer sqrt function (to avoid depending on libm)
static unsigned integer_sqrt(unsigned n)
{
// Find greatest shift.
int shift = 2;
unsigned nShifted = n >> shift;
// We check for nShifted being n, since some implementations
// perform shift operations modulo the word size.
while (nShifted != 0 && nShifted != n){
shift += 2;
nShifted = n >> shift;
}
shift -= 2;
// Find digits of result.
unsigned result = 0;
while (shift >= 0) {
result = result << 1;
unsigned candidateResult = result + 1;
if (candidateResult*candidateResult <= n >> shift) {
result = candidateResult;
}
shift -= 2;
}
return result;
}
void
test(const char library[], size_t n, const config_func_t functions[], int argc, const char *argv[])
{
// Init & parse arguments
// NUMBER
// --from NUMBER --to NUMBER --step NUMBER --grow NUMBER
// --graph --best --average --quiet
// --repeat N
struct parse_opt_s arg;
parse_config(&arg, argc, argv);
int i = select_config(arg.test_function, n, functions);
double from = (arg.from == 0) ? functions[i].default_n : arg.from;
double to = (arg.to == 0) ? functions[i].default_n : arg.to;
// Open plot file if needed
FILE *graph_file = NULL;
if (arg.graph) {
char filename[100];
sprintf(filename, "plot-%s-%d.dat", library, arg.test_function);
graph_file = fopen(filename, "wt");
if (!graph_file) {
fprintf(stderr, "ERROR: Cannot create plot.dat\n");
exit(-2);
}
fprintf(graph_file, "# plotting %s-%d : %s\n# N T", library, arg.test_function, functions[i].funcname);
}
// Do the bench
for(double n = from; n <= to ; n = ((arg.grow == 0) ? n + arg.step : n * arg.grow))
{
double best = (1.0/0.0);
double avg = 0.0;
double variance = 0.0;
static double measure[MAX_REPEAT];
double ba = 0.0;
if (functions[i].init != NULL)
functions[i].init(n);
// Measure the time of the test_function
for(unsigned r = 0; r < arg.repeat; r++) {
double t0 = test_function( (arg.graph|arg.best|arg.average|arg.quiet) ? NULL : functions[i].funcname, (size_t) n, functions[i].func);
best = (t0 < best) ? t0 : best;
avg += t0;
variance += t0 * t0;
measure[r] = t0;
}
// Closure of the tests
if (functions[i].clear != NULL)
functions[i].clear();
// Finish computing the different times
if (arg.repeat > 1) {
avg /= arg.repeat;
variance = (variance - arg.repeat * avg * avg) / (arg.repeat - 1);
ba = get_best_within(arg.repeat, measure, 1. + arg.within);
}
// The average value shall be around best_within (and greater)
// otherwise the result doesn't seem reliable.
bool reliable = (ba <= avg && ba * (1.0+arg.within/2) + 0.5 > avg);
// Print the result
if (arg.graph) {
fprintf(graph_file, "%f %f\n", n, arg.average ? avg : arg.best ? best : ba);
} else if (arg.quiet) {
printf("%ld\n", (long)(arg.average ? avg : arg.best ? best : reliable ? ba : -1));
} else if (arg.repeat > 1) {
if (arg.average == false && arg.best_within == false)
printf ("%20.20s time %lu ms for n = %lu *** BEST ***\n", functions[i].funcname, (unsigned long) best, (unsigned long) n);
if (arg.best == false && arg.best_within == false)
printf ("%20.20s time %lu ms +/- %u ms for n = %lu *** AVERAGE ***\n", functions[i].funcname, (unsigned long) avg, 2*integer_sqrt(variance), (unsigned long) n);
if (arg.best == false && arg.average == false)
printf ("%20.20s time %lu ms for n = %lu *** BEST within %d%% *** %s\n", functions[i].funcname, (unsigned long) ba, (unsigned long) n, (int)(100*arg.within), reliable ? "" : "(unreliable result)");
}
}
// Close the FILE if needed
if (arg.graph) {
fclose(graph_file);
printf("File plot-%s-%d.dat generated.\n"
"Run in gnuplot the following command:\n"
"\tplot 'plot-%s-%d.dat' with linespoints linestyle 1\n",
library, arg.test_function, library, arg.test_function);
}
return;
}
+66 -30
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - common functions for bench module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2021, 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,36 +27,57 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// Needed for M_THREAD_ATTR
#if defined(MULTI_THREAD_MEASURE)
#include "m-mutex.h"
#endif
#if defined(_WIN32)
/* WINDOWS variant */
#include <windows.h>
# include <windows.h>
#elif (defined(__APPLE__) && defined(__MACH__)) \
|| defined(__DragonFly__) || defined(__FreeBSD__) \
|| defined(__NetBSD__) || defined(__OpenBSD__)
# include <sys/types.h>
# include <sys/resource.h>
# include <sys/time.h>
# include <sys/param.h>
# include <sys/sysctl.h>
# define USE_SYSCTL
#else
# include <sys/types.h>
# include <sys/resource.h>
# include <sys/time.h>
# include <unistd.h>
#endif
// Number of elements of a table
#define numberof(x) (sizeof(x)/sizeof(x[0]))
/* Get the current CPU time. */
#if defined(_WIN32)
/* WINDOWS variant */
static inline unsigned long long
cputime (void)
{
LARGE_INTEGER freq, val;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&val);
return (unsigned long long) (1000000. * (double) val.QuadPart / (double) freq.QuadPart);
LARGE_INTEGER freq, val;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&val);
return (unsigned long long) (1000000. * (double) val.QuadPart / (double) freq.QuadPart);
}
#else
/* UNIX variant */
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/time.h>
static inline unsigned long long
cputime (void)
{
#if defined(MULTI_THREAD_MEASURE)
// Multi thread
// Multi thread: Uses real time
struct timeval tv;
gettimeofday (&tv, NULL);
return tv.tv_sec * 1000000ULL + tv.tv_usec;
#else
// Single thread
// Single thread: Uses process usage time
struct rusage rus;
getrusage (0, &rus);
return rus.ru_utime.tv_sec * 1000000ULL + rus.ru_utime.tv_usec;
@@ -65,46 +86,61 @@ cputime (void)
#endif
static unsigned long g_result;
static
// The result of the bench
extern unsigned long g_result;
// The rand value
extern
#if defined(MULTI_THREAD_MEASURE)
M_THREAD_ATTR
#endif
unsigned int randValue = 0;
unsigned int randValue;
// Pseudo rand value generator.
// Not very random but sufficient and fast enough for the bench
static inline void rand_init(void)
{
randValue = 0;
}
static inline unsigned int rand_get(void)
{
randValue = randValue * 31421U + 6927U;
return randValue;
}
static inline void test_function(const char str[], size_t n, void (*func)(size_t))
// The function that performs the bench
static inline double
test_function(const char *str, size_t n, void (*func)(size_t))
{
double result;
unsigned long long start, end;
rand_init();
start = cputime();
(*func)(n);
end = cputime();
result = (double)(end-start) / 1000.0;
end = (end - start) / 1000U;
printf ("%s %lu ms for n = %lu [r=%lu]\n", str, (unsigned long) end, (unsigned long) n, g_result);
if (str != NULL) {
printf ("%20.20s time %lu ms for n = %lu [r=%lu]\n", str, (unsigned long) end, (unsigned long) n, g_result);
}
return result;
}
#if defined(_WIN32)
# include <windows.h>
#elif (defined(__APPLE__) && defined(__MACH__)) \
|| defined(__DragonFly__) || defined(__FreeBSD__) \
|| defined(__NetBSD__) || defined(__OpenBSD__)
# include <sys/param.h>
# include <sys/sysctl.h>
# define USE_SYSCTL
#else
# include <unistd.h>
// Configuration table
typedef struct {
int num;
const char *funcname;
size_t default_n;
void (*init)(size_t);
void (*func)(size_t);
void (*clear)(void);
} config_func_t;
// Perform a parsing of the given arguments and do the bench according to the table
#ifdef __cplusplus
extern "C"
#endif
void test(const char library[], size_t n, const config_func_t functions[], int argc, const char *argv[]);
/* Return the number of CPU of the system */
static inline int get_cpu_count(void)
+2 -2
View File
@@ -1,7 +1,7 @@
/*
* MLIB - TEST module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2021, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -59,7 +59,7 @@ static void find_max(void)
dict_int64_set_at (dict, get_rand(), get_rand());
n++;
if ((n & ((1<<20)-1)) == 0) {
printf ("n=%lu\n", n);
printf ("n=%zu\n", n);
}
}
dict_int64_clear(dict);
+2 -7
View File
@@ -1,8 +1,3 @@
#ifndef NDEBUG
#define NDEBUG
#endif
#undef NDEBUG
#include <string.h>
#include "benchmark.h"
@@ -48,7 +43,7 @@ int test_int(int N, const unsigned *data)
if (dict_int_get (h, data[i]) == NULL) {
dict_int_set_at (h, data[i], i);
} else {
dict_int_remove(h, data[i]);
dict_int_erase(h, data[i]);
}
}
ret = (int)dict_int_size(h);
@@ -64,7 +59,7 @@ int test_str(int N, char * const *data)
if (dict_str_get (h, data[i]) == NULL) {
dict_str_set_at (h, data[i], i);
} else {
dict_str_remove(h, data[i]);
dict_str_erase(h, data[i]);
}
}
ret = (int)dict_str_size(h);
+4 -4
View File
@@ -4,10 +4,10 @@
#include "m-dict.h"
#include "m-mempool.h"
DICT_DEF2(dict_int,
DICT_STOREHASH_DEF2(dict_int,
int, M_OPEXTEND(M_DEFAULT_OPLIST, MEMPOOL(mpool_int), MEMPOOL_LINKAGE(static)),
int, M_DEFAULT_OPLIST)
DICT_DEF2(dict_str,
DICT_STOREHASH_DEF2(dict_str,
const char *, M_OPEXTEND (M_CSTR_OPLIST, MEMPOOL(mpool_str), MEMPOOL_LINKAGE(static)),
int, M_DEFAULT_OPLIST)
@@ -20,7 +20,7 @@ int test_int(int N, const unsigned *data)
if (dict_int_get (h, data[i]) == NULL) {
dict_int_set_at (h, data[i], i);
} else {
dict_int_remove(h, data[i]);
dict_int_erase(h, data[i]);
}
}
ret = (int)dict_int_size(h);
@@ -38,7 +38,7 @@ int test_str(int N, char * const *data)
if (dict_str_get (h, data[i]) == NULL) {
dict_str_set_at (h, data[i], i);
} else {
dict_str_remove(h, data[i]);
dict_str_erase(h, data[i]);
}
}
ret = (int)dict_str_size(h);
+8 -5
View File
@@ -1,4 +1,5 @@
#include "../common.c"
#define DICTI_OA_PROBING(s) 1
#include "m-dict.h"
static inline bool oor_equal_p(unsigned int k, unsigned char n)
@@ -11,10 +12,10 @@ static inline void oor_set(unsigned int *k, unsigned char n)
}
DICT_OA_DEF2(dict_oa_uint,
unsigned int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
unsigned int, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(hash_fn), OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
unsigned int, M_DEFAULT_OPLIST)
void test_int(uint32_t n, uint32_t x0)
uint32_t test_int(uint32_t n, uint32_t x0)
{
uint32_t i, x, z = 0;
dict_oa_uint_t h;
@@ -22,10 +23,12 @@ void test_int(uint32_t n, uint32_t x0)
for (i = 0, x = x0; i < n; ++i) {
x = hash32(x);
unsigned int key = get_key(n, x);
unsigned int *ptr = dict_oa_uint_get(h, key);
if (ptr) { (*ptr)++; z+= *ptr; }
else { dict_oa_uint_set_at(h, key, 1); z+=1; }
unsigned int *ptr = dict_oa_uint_get_at(h, key);
(*ptr)++;
z += *ptr;
}
fprintf(stderr, "# unique keys: %d; checksum: %u\n", (int) dict_oa_uint_size(h), z);
z = dict_oa_uint_size(h);
dict_oa_uint_clear(h);
return z;
}
+22
View File
@@ -35,3 +35,25 @@ V0.2.*: * worker_start takes a 'worker_t' as an additional parameter
The provided _remove doesn't use an iterator but a 'key', incompatible with the one of array or list.
But is like the one provided by the priority queue.
V0.3.*: * Remove B+TREE _remove method as it has been deprecated (use _erase instead)
* Remove DICT _remove method as it has been deprecated (use _erase instead)
* Make _it_to_p method of B+TREE / RB-TREE as deprecated (uses _it_until_p instead ).
* Deprecated buffer options BUFFER_BLOCKING* and BUFFER_UNBLOCKING*
as the _push_blocking and _pop_blocking functions can do the same and are more versatil.
* Iteration over the items of a dictionnary/tree returns const iterators for access through
OPLIST (impact: algorithm & M_EACH) as the IT_REF operator is no longer exported.
The _it_ref method is still defined and can be used, so you can still modify the values
but it won't be automatically used anymore (as the keys CANNOT be modified).
(Previously it generates incorrect algorithm when used with m-dict).
V0.4.*: * The order of a list initialized using M_LET is reversed
to match what is done for ARRAY (and the C++ forward_list).
* Rename M_SKIP, M_KEEP & M_MID into M_SKIP_ARGS, M_KEEP_ARGS & M_MID_ARGS
due to conflict with glibc malloc.h (that defines M_KEEP for compatibility).
* Method write_string of m_serial expects a new argument (number of characters).
* Method _init_set2 of m-i-shared is removed.
* Operator _it_insert updates it_insertion iterator to reference the inserted element.
* Dereference Type of an iterator of a dict / B+Tree is suffixed by _itref_t instead of _type_t.
* Rename TUPLE _init_set2 in _init_emplace & _set2 in _emplace.
* Rename Priority Queue method _update_further in _update.
BIN
View File
Binary file not shown.
+47
View File
@@ -30,6 +30,16 @@ List of tested systems
* clang 3.8 on linux/armv7l
Atomic library
==============
For target, armel m68k mips mipsel powerpc powerpcspe sh4, you may need to run the test suite:
make check LDFLAGS="-pthread -latomic"
since 'atomic' library is not automatically included for 32 bits systems.
Cross compilation
=================
@@ -62,3 +72,40 @@ This will have the following gains:
Once one issue of ISSUES.org is taken into account,
its state shall be changed to DONE (the issue shall not be removed).
Debugging
===============
Debugging the library can be quite difficult
as it performs heavy preprocessing expansion
and expands all code in one line.
Different strategy for debugging the library itself are still possible:
1) Good old printf.
Add printf of interresting values in the debugged function.
2) Preprocess the library and then compile the preprocessed file:
cc -std=c99 -E test-file.c > test-file.i
perl -pi -e 's/;/;\n/g' test-file.i
cc -std=c99 -c -Wall test-file.i
The resulting executable can be debugged much more easily.
3) To debug the preprocessing itself, the Boot Wave library can be used
and in particular the [wave driver](https://www.boost.org/doc/libs/1_71_0/libs/wave/doc/wave_driver.html)
Add in the code the following pragmas around the code to debug:
#pragma wave trace(enable)
ARRAY_DEF (array_charp, char *)
#pragma wave trace(disable)
Run the wave driver:
./wave ex-array01.c -I .. --c99 -t test.trace
The different expansion performed by the library are described in test.trace
+148 -47
View File
@@ -1,11 +1,97 @@
*Long term issues*
------------------
* TODO #26 : Hash-Map for huge objects :ENHANCEMENT:
Specialize Hashmap for huge objects on supported hardware:
based on OA hash map with taggued pointer (needs space for tagging):
low bits = low bits of hash
pointer to object { key, hash, value }
Can detect collision without dereferencing object with 1/2^lowbits chances.
Reduce cache usage ==> Should be faster.
Use of pointer to avoid moving object on GC.
On AMD64, only 48 bits of 64 bits are really used for addressing data.
* TODO #25 : Support of error code 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".
In case of allocation failure, it shall return an error.
M_CALL macro shall stop its execution if the service returns an error code
and the error code represents an error (avoid rewritting everything)
and throw back the error code (stopping the execution flow).
Services returning already something shall not be modified.
This model should be applied at the container level only and not globally.
Different containers may need different levels of error handling.
4 combinaison to take into account:
==> ABORT on container / ABORT on used type: The current model
==> ABORT on container / RETCODE on used type: Needs to abort on reported error.
==> RETCODE on container / ABORT on used type: Nothing particular to note.
==> RETCODE on container / RETCODE on used type: Forward retcode to caller.
Find a way to make it while not making the code too complex
(try to keep as simple as possible).
Using a specialized oplist for such containers (_OPLIST_RETCODE)
using a specialized API for retcode:
API_RET_*: that expands to
if (func(args) == 0) goto handler_exit_failure;
Adding at the end of each service:
M_END_FUNCTION(cleanup_code) that expands to different cases:
M_END_FUNCTION_VALUE(cleanup_code, return_success, return_failure) that expands to different cases:
ABORT/ABORT:
handler_exit_success:
handler_exit_failure:
return;
ABORT/RETCODE:
handler_exit_success:
return;
handler_exit_failure:
RAISE_FATAL_ERROR
RETCODE/ABORT
handler_exit_success:
return SUCESS;
handler_exit_failure:
cleanup_code
return FAILURE;
RETCODE/RETCODE
handler_exit_success:
return SUCESS;
handler_exit_failure:
cleanup_code
return FAILURE;
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?
* TODO #24 : Add 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: Force MOVE semantic :ENHANCEMENT:
@@ -34,48 +120,12 @@ For example for tuple, it shall
- create an init_move operator if no one has disabled INIT_MOVE,
- export the init_move operator if at least one has exported a INIT_MOVE and no one has disabled INIT_MOVE.
* DONE #22: Enhanced services for SPSC Queue :ENHANCEMENT:
** DO_INIT_MOVE operator
Add services:
** DONE _push_bulk
Test the capacity of the queue and push as much as possible in the queue
with one check of the atomic structure.
** DONE _pop_bulk
Test the capacity of the queue and push as much as possible in the queue
with one check of the atomic structure.
** DONE _push_force:
If the capacity of the queue is full, pop one element and push it:
push always succeed and the queue always keep the youngest element.
* TODO #21: Generic Binary serialization :ENHANCEMENT:
Based on issue #26 of https://github.com/P-p-H-d/mlib/issues/26
Some kind of "binary serialization" on the model of get_str/parse_str
could be possible. It would be a great feature from the application
point-of-view: binary representation is more bandwidth-efficient if
used on network communications.
It will be good to have import/export methods to the
XML/JSON/MSGPACK/PROTOBUF/BINARY format.
However, adding all of them on by one in the M*LIB containers
doesn't seem satisfactory.
Instead, adding a generic interface for the serialization of data
that may be customized by the user to perform the import/export of
objects in whatever format they want into what they want (FILE/memory/...).
To simplify it, this interface could only support one kind of import/export
per compilation unit.
Problem:
the interface is either too high level (limiting too much what we can do)
or too low level (exporting too many internal things of the library).
DO_INIT_MOVE macro is not also fully working for structure
defined with [1] tricks but without an explicit INIT_MOVE / MOVE
operators as it uses MOVE_DEFAULT which is not (fully compatible).
==> Analyse limitation and possible constraint usages.
* TODO #20: Bucket priority queue :ENHANCEMENT:
@@ -98,6 +148,7 @@ implementation.
* TODO #19: 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:
@@ -154,7 +205,7 @@ http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Co
backoff has be used when using CAS.
Concurrent insertion / insertion and insertion / deletion and deletion / deletion shall be taken into account.
Concurrent insertion / insertion and insertion / deletion and deletion / deletion shall be crefully analyzed when taken into account.
Questions:
- singly or doubly or dual push?
@@ -162,10 +213,11 @@ http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Co
(NULL if not logically deleted) ? TBC
* TODO #15: Constructor / Destructor Prologue / Epilogue for Stack Exception Handling :ENHANCEMENT:
* 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 Stack Exception Handling so that exceptions throwing may work reliably.
This is in order to register the constructed object into a proper Exception
Handling Stack so that throwing exceptions may work reliably.
Proposal:
@@ -174,15 +226,19 @@ Proposal:
- 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 will recursively remove them).
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:
Enhancement of the memory allocation scheme to find way to deal properly with advance allocators:
Enhancement of the memory allocation scheme to find way to deal properly with advanced allocators:
- non-default alignment requirements for types,
- instance-based allocator (may need instance based variable access),
@@ -214,6 +270,7 @@ 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.
* TODO #12: Atomic shared pointer :ENHANCEMENT:
Add an extension to the SHARED_PTR API:
@@ -231,7 +288,10 @@ No _ref or direct _init: we need to init first a normal shared_ptr then the atom
** _atomic_set method:
It can be implemented by incrementing the non atomic shared pointer reference, then performs a compare_and_swap to the data of the atomic shared pointer, finally decrement and dec/free the swapped previous data of the atomic .
It can be implemented by incrementing the non atomic shared pointer reference,
then performs a compare_and_swap to the data of the atomic shared pointer,
finally decrement and dec/free the swapped previous data of the atomic like a normal shared pointer.
All 3 steps are safe.
** _set_atomic method:
@@ -338,3 +398,44 @@ Not sure it will really help. To analyse.
A good way maybe Open Addessing table used only for indirection and a freelist memory reclamation container for handle the entries
(like a transaction).
* DONE #22: Enhanced services for SPSC Queue :ENHANCEMENT:
Add services:
** DONE _push_bulk
Test the capacity of the queue and push as much as possible in the queue
with one check of the atomic structure.
** DONE _pop_bulk
Test the capacity of the queue and push as much as possible in the queue
with one check of the atomic structure.
** DONE _push_force:
If the capacity of the queue is full, pop one element and push it:
push always succeed and the queue always keep the youngest element.
* DONE #21: Generic Binary serialization :ENHANCEMENT:
Based on issue #26 of https://github.com/P-p-H-d/mlib/issues/26
Some kind of "binary serialization" on the model of get_str/parse_str
could be possible. It would be a great feature from the application
point-of-view: binary representation is more bandwidth-efficient if
used on network communications.
It will be good to have import/export methods to the
XML/JSON/MSGPACK/PROTOBUF/BINARY format.
However, adding all of them on by one in the M*LIB containers
doesn't seem satisfactory.
Instead, adding a generic interface for the serialization of data
that may be customized by the user to perform the import/export of
objects in whatever format they want into what they want (FILE/memory/...).
To simplify it, this interface could only support one kind of import/export
per compilation unit.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 102 KiB

BIN
View File
Binary file not shown.
+34 -5
View File
@@ -1,18 +1,47 @@
# Copyright (c) 2017-2021, Patrick Pelissier
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# + Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# + Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
CC=cc -std=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
CFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -g
GMP_DIR=
CPPFLAGS=-I..
LDFLAGS=-pthread -lgmp
LDFLAGS=-pthread
RM=rm -f
.SUFFIXES: .c .exe
.c.exe:
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) `cat config` $< -o $@
all:
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
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
$(RM) config-test.c config-test.exe
clean:
$(RM) *.exe *.s *~ *.o ./a.dat
$(RM) *.exe *.s *~ *.o ./a.dat config
+68
View File
@@ -0,0 +1,68 @@
#include <stdio.h>
#include "m-array.h"
#include "m-algo.h"
/* Define a dynamic array of int */
ARRAY_DEF(vector_int, int)
/* Register the oplist of this dynamic array globally */
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
/* Define some standards algorithms on this dynamic array */
ALGO_DEF(vector_int, vector_int_t)
/* Define a dynamic array of bool */
ARRAY_DEF(vector_bool, bool, M_BOOL_OPLIST)
/* 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 */
ALGO_DEF(vector_bool, vector_bool_t)
/* ID function */
static bool id(bool x) { return x ; }
int main(void)
{
// Define, init (& later clear) myvector & tmp as vector_int_t
M_LET(myvector, tmp, vector_int_t) {
// Fill myvector with 3 int equal to 20
vector_int_fill_n(myvector, 3, 20);
// Fill tmp with 3 int equal to 33
vector_int_fill_n(tmp, 3, 33);
// Append all tmp in myvector
vector_int_splice(myvector, tmp);
// Fill tmp with 2 int equal to 10
vector_int_fill_n(tmp, 2, 10);
// Append all tmp in myvector
vector_int_splice(myvector, tmp);
// Display the result
printf("myvector contains:");
// In C11, the for loop can be simplified as :
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
ALGO_FOR_EACH(myvector, vector_int_t, M_PRINT, " ");
#else
for M_EACH(it, myvector, vector_int_t) {
printf(" %d", *it);
}
#endif
printf("\n");
}
// Same thing but with booleans
M_LET(myvector, tmp, vector_bool_t) {
vector_bool_fill_n(myvector, 3, false);
vector_bool_fill_n(tmp, 3, true);
vector_bool_splice(myvector, tmp);
vector_bool_fill_n(tmp, 2, false);
vector_bool_splice(myvector, tmp);
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) );
}
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
#include "m-dict.h"
#include "m-array.h"
#include "m-algo.h"
#include "m-string.h"
/* Define a dictionnary (or hash_map or undordered_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 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 */
#define start_with(pattern, item) \
string_start_with_str_p((item).key, (pattern))
/* Micro macro to get the value of a pair of (key, value) */
#define get_value(out, item) ((out) = (item).value)
int main(void)
{
int s;
// 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' */
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);
/* Sum theses values */
ALGO_REDUCE(s, keys, vector_int_t, sum);
printf("Sum of elements starting with 'b' is: %d\n", s);
}
return 0;
}
+38
View File
@@ -0,0 +1,38 @@
#include "m-algo.h"
#include "m-array.h"
#include "m-string.h"
/* Define an array of int */
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.
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;
// Compute the sum of theses integers.
ALGO_REDUCE(sum, v, vector_int_t, add);
// Compute the product of theses integers.
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);
printf ("sum: %d\n"
"product: %d\n"
"dash str: %s\n", sum, product, string_get_cstr(s));
}
return 0;
}
+619
View File
@@ -0,0 +1,619 @@
/* Include M*LIB header */
#include "m-array.h"
#include "m-string.h"
#include "m-tuple.h"
/* Provide several examples of different types usage with array,
with the oplist to use for each case.
Each time it creates and initializes an array,
fills it with some number,
computes its sum,
and returns it.
This is done for several basic C types:
- integers,
- floats,
- pointers,
- structures,
- tuples
*/
/* 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.
*/
ARRAY_DEF(r_bool, bool)
/* Basic usage of the type */
static int
test_bool(int n)
{
r_bool_t array;
r_bool_init(array);
for(int i = 0; i < n; i++) {
r_bool_push_back(array, i & 1);
}
int s = 0;
for(int i = 0; i < n; i++) {
s += *r_bool_get(array, i);
}
r_bool_clear(array);
return s;
}
/* Same with type char */
ARRAY_DEF(r_char, char)
static int
test_char(int n)
{
r_char_t array;
r_char_init(array);
for(int i = 0; i < n; i++) {
r_char_push_back(array, i & 255);
}
int s = 0;
for(int i = 0; i < n; i++) {
s += *r_char_get(array, i);
}
r_char_clear(array);
return s;
}
/* Same with type signed int. */
ARRAY_DEF(r_int, signed int)
static int
test_int(int n)
{
r_int_t array;
r_int_init(array);
for(int i = 0; i < n; i++) {
r_int_push_back(array, i);
}
int s = 0;
for(int i = 0; i < n; i++) {
s += *r_int_get(array, i);
}
r_int_clear(array);
return s;
}
/* Same with type signed int.
But with an explicit oplist.
This generates exactly the same code than r_int
*/
ARRAY_DEF(r_int2, signed int, M_DEFAULT_OPLIST)
static int
test_int2(int n)
{
r_int2_t array;
r_int2_init(array);
for(int i = 0; i < n; i++) {
r_int2_push_back(array, i);
}
int s = 0;
for(int i = 0; i < n; i++) {
s += *r_int2_get(array, i);
}
r_int2_clear(array);
return s;
}
/* Same with type unsigned long long */
ARRAY_DEF(r_ullong, unsigned long long)
static int
test_ullong(int n)
{
r_ullong_t array;
r_ullong_init(array);
for(int i = 0; i < n; i++) {
r_ullong_push_back(array, i);
}
int s = 0;
for(int i = 0; i < n; i++) {
s += *r_ullong_get(array, i);
}
r_ullong_clear(array);
return s;
}
/* Same with type float */
ARRAY_DEF(r_float, float)
static int
test_float(int n)
{
r_float_t array;
r_float_init(array);
for(int i = 0; i < n; i++) {
r_float_push_back(array, i/4.0);
}
float s = 0;
for(int i = 0; i < n; i++) {
s += *r_float_get(array, i);
}
r_float_clear(array);
return s;
}
/* Same with type double and an explicit oplist*/
ARRAY_DEF(r_double, double, M_DEFAULT_OPLIST)
static int
test_double(int n)
{
r_double_t array;
r_double_init(array);
for(int i = 0; i < n; i++) {
r_double_push_back(array, i/4.0);
}
float s = 0;
for(int i = 0; i < n; i++) {
s += *r_double_get(array, i);
}
r_double_clear(array);
return s;
}
/* Helper function strdup */
static char *my_strdup(const char *p)
{
size_t s = strlen(p);
char *d= malloc(s+1);
if(!d) abort();
strcpy(d, p);
return d;
}
/* Same with type const char *, representing a contant string.
We *** need *** an explicit oplist to tell M*LIB
to consider the type as a constant 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
string equality.
*/
ARRAY_DEF(r_cstring, const char *, M_CSTR_OPLIST)
static int
test_cstring(int n)
{
r_cstring_t array;
r_cstring_init(array);
for(int i = 0; i < n; i++) {
char buffer[10];
// Create a string from the integer
sprintf(buffer, "%d", i);
// We need to make an explicit copy of the string
// since it is not supported by the basic type.
char *p = my_strdup(buffer);
// Push the copy in the container.
r_cstring_push_back(array, p);
}
int s = 0;
for(int i = 0; i < n; i++) {
// Get back the string
const char *p = *r_cstring_get(array, i);
// Convert it to integer
int j = atoi(p);
s += j;
}
// We also need a special unalloc pass
// to free all constant strings we have allocated.
for(int i = 0; i < n; i++) {
const char *p = *r_cstring_get(array, i);
free((void*)(uintptr_t)p);
}
r_cstring_clear(array);
return s;
}
/* Same with type string_t of M*LIB, representing a variable 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
give it to array_def! */
ARRAY_DEF(r_string, string_t)
static int
test_string(int n)
{
r_string_t array;
string_t str;
r_string_init(array);
string_init (str);
for(int i = 0; i < n; i++) {
// create a string from an integer
string_printf(str, "%d", i);
// No need to make a copy in the container!
r_string_push_back(array, str);
}
int s = 0;
for(int i = 0; i < n; i++) {
// Get back the string and convert it back to an integer
int j = atoi(string_get_cstr(*r_string_get(array, i)));
s += j;
}
// No need to explicit dealloc !
string_clear(str);
r_string_clear(array);
return s;
}
/* Same with type string_t of M*LIB, representing a variable string
and its explicit oplist. And said above, it generates exactly the
same code. */
ARRAY_DEF(r_string2, string_t, STRING_OPLIST)
/* Same with type 'volatile unsigned int *'
The array stores pointers to another integer,
allocated somewhere else.
We need to tell M*LIB to handle the basic type
as pointers without caring for what the value of
the pointer is.
So here, we **need** to specify the oplist of the type
as M_PTR_OPLIST.
*/
ARRAY_DEF(r_vintptr, volatile unsigned int *, M_PTR_OPLIST)
static int
test_vintptr(int n)
{
r_vintptr_t array;
// Allocate a secondary table to store the value.
unsigned *tab = calloc(n, sizeof(volatile unsigned int));
if (!tab) abort();
r_vintptr_init(array);
for(int i = 0; i < n; i++) {
tab[i] = i*i - i;
// Push the pointer to this integer in the array
r_vintptr_push_back(array, &tab[i]);
}
int s = 0;
for(int i = 0; i < n; i++) {
// Get the pointer to the integer.
volatile unsigned *p = *r_vintptr_get(array, i);
s += *p;
}
r_vintptr_clear(array);
free(tab);
return s;
}
/* Same with a structure type.
We need to tell M*LIB to handle the basic type
as POD;
So here, we **need** to specify the oplist of the type
as M_POD_OPLIST.
*/
struct rock_me_out {
int n;
float other;
};
ARRAY_DEF(r_rockme, struct rock_me_out, M_POD_OPLIST)
static int
test_rockme(int n)
{
r_rockme_t array;
r_rockme_init(array);
for(int i = 0; i < n; i++) {
struct rock_me_out rock;
rock.n = i*i - i;
// Push the struct in the array
r_rockme_push_back(array, rock);
}
int s = 0;
for(int i = 0; i < n; i++) {
// Get the pointer to the struct
struct rock_me_out *p = r_rockme_get(array, i);
s += p->n;
}
r_rockme_clear(array);
return s;
}
/* Same with a structure type defined with [1]:
We need to tell M*LIB to handle the basic type
as a special array;
So here, we **need** to specify the oplist of the type
as M_A1_OPLIST.
*/
typedef struct rock_me_in {
int n;
float other;
} rock_me_in[1];
ARRAY_DEF(r_rockme2, rock_me_in, M_A1_OPLIST)
static int
test_rockme2(int n)
{
r_rockme2_t array;
r_rockme2_init(array);
for(int i = 0; i < n; i++) {
rock_me_in rock;
rock->n = i*i - i;
r_rockme2_push_back(array, rock);
}
int s = 0;
for(int i = 0; i < n; i++) {
// Get the pointer to the struct.
rock_me_in *p = r_rockme2_get(array, i);
s += (*p)->n;
}
r_rockme2_clear(array);
return s;
}
/* Same with a structure type defined with [1] and a global registeration.
We need to tell M*LIB to handle the basic type
as a special array.
To do so, 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.
Then we define the array, giving it only the type.
M*LIB will look at the global registered oplist of the type, we don't
need to give it explictly.
Global registeration makes easier code.
Registeration should be done when the type is defined.
*/
#define M_OPL_rock_me_in() M_A1_OPLIST
ARRAY_DEF(r_rockme2b, rock_me_in)
static int
test_rockme2b(int n)
{
r_rockme2b_t array;
r_rockme2b_init(array);
for(int i = 0; i < n; i++) {
rock_me_in rock;
rock->n = i*i - i;
r_rockme2b_push_back(array, rock);
}
int s = 0;
for(int i = 0; i < n; i++) {
// Get the pointer to the struct.
rock_me_in *p = r_rockme2b_get(array, i);
s += (*p)->n;
}
r_rockme2b_clear(array);
return s;
}
/* 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.
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.
*/
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))
static int
test_rockme3(int n)
{
r_rockme3_t array;
rock_you_t x;
r_rockme3_init(array);
rock_you_init(x);
for(int i = 0; i < n; i++) {
rock_you_set_n(x, i*i - i);
r_rockme3_push_back(array, x);
}
int s = 0;
for(int i = 0; i < n; i++) {
// Get the pointer to the structure containing the integer.
rock_you_t *p = r_rockme3_get(array, i);
s += (*p)->n;
}
r_rockme3_clear(array);
rock_you_clear(x);
return s;
}
/* 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.
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.
Then we define the array, giving it only the type.
M*LIB will look at the global registered oplist of the type, we don't
need to give it explictly.
Global registeration makes easier code.
*/
TUPLE_DEF2(rock_us, (n, int), (other, float))
#define M_OPL_rock_us_t() TUPLE_OPLIST(rock_us, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
ARRAY_DEF(r_rockme4, rock_us_t)
static int
test_rockme4(int n)
{
r_rockme4_t array;
rock_us_t x;
r_rockme4_init(array);
rock_us_init(x);
for(int i = 0; i < n; i++) {
rock_us_set_n(x, i*i - i);
r_rockme4_push_back(array, x);
}
int s = 0;
for(int i = 0; i < n; i++) {
// Get the pointer to the structure containing the integer.
rock_us_t *p = r_rockme4_get(array, i);
s += (*p)->n;
}
r_rockme4_clear(array);
rock_us_clear(x);
return s;
}
int main (int argc, const char *argv[])
{
int n = argc == 1 ? 10 : atoi(argv[1]);
int s;
s = test_bool(n);
printf ("S[bool] = %d\n", s);
s = test_char(n);
printf ("S[char] = %d\n", s);
s = test_int(n);
printf ("S[int] = %d\n", s);
s = test_int2(n);
printf ("S[int2] = %d\n", s);
s = test_ullong(n);
printf ("S[ullong] = %d\n", s);
s = test_float(n);
printf ("S[float] = %d\n", s);
s = test_double(n);
printf ("S[double] = %d\n", s);
s = test_cstring(n);
printf ("S[cstring] = %d\n", s);
s = test_string(n);
printf ("S[string] = %d\n", s);
s = test_vintptr(n);
printf ("S[vintptr] = %d\n", s);
s = test_rockme(n);
printf ("S[rockme] = %d\n", s);
s = test_rockme2(n);
printf ("S[rockme2] = %d\n", s);
s = test_rockme2b(n);
printf ("S[rockme2b] = %d\n", s);
s = test_rockme3(n);
printf ("S[rockme3] = %d\n", s);
s = test_rockme3(n);
printf ("S[rockme4] = %d\n", s);
exit(0);
}
+2 -2
View File
@@ -1,14 +1,14 @@
#include <stdlib.h>
#include "m-array.h"
// Let's define an array of 'int' named 'int'
// Let's define an array of 'int' named 'array_int'
ARRAY_DEF(array_int, int)
const int n = 100000;
int main(void)
{
// Declare and initilize the array
// Declare and initialize the array
array_int_t x;
array_int_init(x);
+13 -1
View File
@@ -1,9 +1,13 @@
#if HAVE_GMP
#include <gmp.h>
#include "m-array.h"
#include "m-algo.h"
/* Define an array of mpz_t */
ARRAY_DEF(array_mpz, mpz_t, M_CLASSIC_OPLIST(mpz))
/* Define some algorithm functions on array_mpz_t */
ALGO_DEF(array_mpz, ARRAY_OPLIST(array_mpz, M_CLASSIC_OPLIST(mpz)))
static inline void my_mpz_inc(mpz_t *d, const mpz_t a){
@@ -19,14 +23,22 @@ int main(void)
mpz_init_set_ui(z, 1);
array_mpz_t a;
array_mpz_init(a);
array_mpz_push_back(a, z);
for(size_t i = 2 ; i < 1000; i++) {
mpz_mul_ui(z, z, i);
array_mpz_push_back(a, z);
}
/* z = sum (a[i]^2) */
/* Compute z = sum (a[i]^2) */
array_mpz_map_reduce (&z, a, my_mpz_inc, my_mpz_sqr);
gmp_printf ("Z=%Zd\n", z);
array_mpz_clear(a);
mpz_clear(z);
}
#else
// Nothing to do
int main(void) { return 0; }
#endif
+116
View File
@@ -0,0 +1,116 @@
#include "m-array.h"
#include "m-string.h"
/* This example show how to use complex structure with array
embedding another library */
/* This is a typical trivial library with its interface */
typedef struct lib_ext_struct {
int id;
// Other data may be added
} lib_ext_struct;
/* Method to create a duplicate of the object.
The new object is heap allocated */
static lib_ext_struct *lib_ext_struct_Duplicate(const lib_ext_struct *obj)
{
lib_ext_struct *p = malloc(sizeof(lib_ext_struct));
if (!p) abort();
p->id = obj->id;
return p;
}
/* Method to delete any object */
static void lib_ext_struct_Delete(lib_ext_struct *obj)
{
free(obj);
}
/* This is the complex structure */
typedef struct {
uint32_t id;
string_t type;
lib_ext_struct* properties;
} data_node;
/* This method shall initialize the object data_node to
the init state.
It takes as first argument the object to initialize,
and since it takes by reference through a pointer,
it is compatible with 'API_2' convention for oplist */
static void data_node_init(data_node *obj)
{
obj->id = 0;
string_init(obj->type);
obj->properties = NULL;
}
/* This method shall initialize the object data_node to
the same state as the 'src' object (creating a copy, a duplicate) .
It takes as first argument the object to initialize,
and as second argument the source object.
It takes both object by reference through pointers,
as such it is compatible with 'API_6' convention for oplist */
static void data_node_init_set(data_node *obj, const data_node *src)
{
obj->id = src->id;
string_init_set(obj->type, src->type);
if (src->properties)
obj->properties = lib_ext_struct_Duplicate(src->properties);
else
obj->properties = NULL;
}
/* This method shall set the object data_node to
the same state as the 'src' object (creating a copy, a duplicate) .
THe object was already initialized.
It takes as first argument the object to initialize,
and as second argument the source object.
It takes both object by reference through pointers,
as such it is compatible with 'API_6' convention for oplist */
static void data_node_set(data_node *obj, const data_node *src)
{
obj->id = src->id;
string_set(obj->type, src->type);
if (obj->properties)
lib_ext_struct_Delete(obj->properties);
if (src->properties)
obj->properties = lib_ext_struct_Duplicate(src->properties);
else
obj->properties = NULL;
}
/* This method shall clear the object data_node to
the cleared state (aka it shall free any resource).
It takes as first argument the object to initialize,
and since it takes by reference through a pointer,
it is compatible with 'API_2' convention for oplist */
static void data_node_clear(data_node *obj)
{
string_clear(obj->type);
if (obj->properties)
lib_ext_struct_Delete(obj->properties);
}
/* Create a dynamic array of 'data_node' named array_data_node_t
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.
*/
ARRAY_DEF(/* the array prefix */ array_data_node,
/* the object type */ data_node,
/* the object oplist */ (INIT(API_2(data_node_init)),
SET(API_6(data_node_set)),
INIT_SET(API_6(data_node_init_set)),
CLEAR(API_2(data_node_clear))))
/* Define a global array with the created type */
array_data_node_t global_array;
int main(void)
{
/* Call the created method */
array_data_node_init(global_array);
/* Do stuff... */
array_data_node_clear(global_array);
}
+65
View File
@@ -0,0 +1,65 @@
#include "m-bptree.h"
#include "m-string.h"
// Define a map int -> string named map_employee_id
// 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 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)
int main(void)
{
map_employee_id_t Employees;
map_employee_id_init(Employees);
// Assign the map with some data
map_employee_id_set_at(Employees, 17425, STRING_CTE("Mike"));
map_employee_id_set_at(Employees, 7147, STRING_CTE("Tango"));
map_employee_id_set_at(Employees, 841, STRING_CTE("Charlie"));
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"));
printf("Number of employees: %zu\n", map_employee_id_size(Employees));
// Iterate over the employee list
printf("\nList of employees (sorted by id):\n");
map_employee_id_it_t it;
for(map_employee_id_it(it, Employees); !map_employee_id_end_p(it); map_employee_id_next(it)) {
// Get a pointer to this employee from the iterator
const map_employee_id_itref_t *e = map_employee_id_cref(it);
// Print it
printf ("%d: %s\n", *(e->key_ptr), string_get_cstr(*(e->value_ptr)));
}
// Now, let's go using some macros!
// Let's create a reverse map
M_LET(Employees_r, map_employee_name_t) {
// Let's fill in the reverse map with each employee
// (using macro M_EACH)
for M_EACH(e, Employees, map_employee_id_t) {
map_employee_name_set_at(Employees_r, *(e->value_ptr), *(e->key_ptr));
}
// Iterate over the employee list
printf("\nList of employees (sorted by name):\n");
for M_EACH(e, Employees_r, map_employee_name_t) {
printf ("%d: %s\n", *(e->value_ptr), string_get_cstr(*(e->key_ptr)));
}
// Print
printf("\nElisabeth has id = %d\n", *map_employee_name_get(Employees_r, STRING_CTE("Elisabeth")));
} /* Employees_r is cleared beyond this point */
map_employee_id_clear(Employees);
return 0;
}
+36
View File
@@ -0,0 +1,36 @@
#include "m-core.h"
// Stubs defined for the example. Real code will use soundio library.
struct SoundIo { int x; };
struct SoundIoDevice { int x; };
struct SoundIoOutStream { int x; };
static struct SoundIo *soundio_create(void) { return (struct SoundIo *) malloc(sizeof(struct SoundIo)); }
static void soundio_destroy(struct SoundIo *s) { free(s); }
static struct SoundIoDevice *soundio_get_device(struct SoundIo *io, int def) { (void) io; (void) def; return (struct SoundIoDevice *) malloc(sizeof(struct SoundIoDevice)); }
static void soundio_device_unref(struct SoundIoDevice *s) { free(s); }
static struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device) { (void) device ; return (struct SoundIoOutStream *) malloc(sizeof(struct SoundIoOutStream)); }
static void soundio_outstream_destroy(struct SoundIoOutStream *s) { free(s); }
static bool soundio_wait_events(struct SoundIo *s) { (void) s; return false; }
// End of stubs
int main(void)
{
int err = 1;
/* Example of using M_LET_IF macro to simplify writing error handling code.
The following code creates some object, test if the object creation succeeds, register the destructor, and print an error if something went wrong
*/
M_LET_IF( struct SoundIo *soundio = soundio_create(), soundio != 0 , soundio_destroy(soundio) , fprintf(stderr, "out of memory for soundio\n") )
M_LET_IF(struct SoundIoDevice *device = soundio_get_device(soundio, -1), device != 0, soundio_device_unref(device), fprintf(stderr, "out of memory for device\n"))
M_LET_IF(struct SoundIoOutStream *outstream = soundio_outstream_create(device), outstream != 0, soundio_outstream_destroy(outstream), fprintf(stderr, "out of memory for stream\n")) {
err = 0;
bool cont = true;
while (cont)
cont = soundio_wait_events(soundio);
}
return err;
}
+1 -1
View File
@@ -5,7 +5,7 @@
#include "m-string.h"
// Define a dictionnary of string --> int
// named 'str'
// named 'dict_str'
DICT_DEF2(dict_str, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
int main(void)
+5 -4
View File
@@ -5,8 +5,9 @@
#include "m-dict.h"
#include "m-string.h"
DICT_DEF2(dict_map, char, M_DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
// Define a dictionary (hashmap) from 'char' to 'int'
DICT_DEF2(dict_map, char, int)
int main(void)
{
dict_map_t mp;
@@ -81,7 +82,7 @@ int main(void)
}
break;
case 7:
case 6:
dict_map_clear(mp);
string_clear (str);
exit(0);
@@ -89,7 +90,7 @@ int main(void)
default:
printf("Wrong Choice\n");
break;
}
}
}
+11 -2
View File
@@ -5,14 +5,23 @@
/* program that reads text from standard-input,
and prints the total number of distinct words found in the text.
*/
/* Definition of a set (hashset) of unique string_t */
DICT_SET_DEF(dict_str, string_t, STRING_OPLIST)
int main(void)
{
// Define word as a string_t
M_LET(word, STRING_OPLIST)
M_LET(wordcount, DICT_SET_OPLIST(dict_str, STRING_OPLIST)) {
while (string_fget_word(word, " \t\n,.!;:?", stdin))
// Define wordcount as a set of string_t
M_LET(wordcount, DICT_SET_OPLIST(dict_str, STRING_OPLIST)) {
// Read a word from the standard input
while (string_fget_word(word, " \t\n,.!;:?", stdin)) {
// Push this word in the set.
// Do nothing if it already exists.
dict_str_push(wordcount, word);
}
// Print the number of words of the standard input.
printf ("Words: %zu\n", dict_str_size(wordcount));
}
}
+42 -18
View File
@@ -3,30 +3,54 @@
#include "m-array.h"
#include "m-dict.h"
// Define an array of size_t
ARRAY_DEF(array_size, size_t)
// Register the oplist of this array globaly
#define M_OPL_array_size_t() ARRAY_OPLIST(array_size)
// Define a dictionary (hashmap) of string_t to array of size_t
DICT_DEF2(map_pos, string_t, array_size_t)
// Register the oplist of this dictionary (hashmap)
#define M_OPL_map_pos_t() DICT_OPLIST(map_pos, STRING_OPLIST, ARRAY_OPLIST(array_size))
int main(int argc, const char *argv[])
{
if (argc == 2) {
M_LET(word, string_t)
M_LET(positions, map_pos_t) {
FILE *f = fopen(argv[1], "rt");
if (!f) return 1;
while (string_fget_word(word, " \t\n\r\"(),=", f)) {
array_size_t *array = map_pos_get_at(positions, word);
array_size_push_back(*array, (size_t)ftell(f) - string_size(word));
}
fclose(f);
for M_EACH(pair, positions, map_pos_t) {
string_fputs(stdout, pair->key);
for M_EACH(pos, pair->value, array_size_t)
printf(" %zu", *pos);
printf("\n");
}
}
if (argc != 2) {
printf("USAGE: %s filename\n", argv[0]);
exit(0);
}
// Define word as a string_t
M_LET(word, string_t)
// Define positions as a map of string_t-->array of size_t
M_LET(positions, map_pos_t) {
// Open the file
FILE *f = fopen(argv[1], "rt");
if (!f) {
fprintf(stderr, "ERROR: Cannot open %s.\n", argv[1]);
return 1;
}
// While it reads some word from the file
while (string_fget_word(word, " \t\n\r\"(),=", f)) {
// Get the reference to the array of this word in the dictionnary (or create it if needed)
array_size_t *array = map_pos_get_at(positions, word);
// Push the new offset to this word in the associated array
array_size_push_back(*array, (size_t)ftell(f) - string_size(word));
}
// Close the file
fclose(f);
// Print the words and where they are:
for M_EACH(pair, positions, map_pos_t) {
string_fputs(stdout, pair->key);
for M_EACH(pos, pair->value, array_size_t) {
printf(" %zu", *pos);
}
printf("\n");
}
} // All created objects are destroyed beyond this point
return 0;
}
+17 -8
View File
@@ -24,22 +24,25 @@
/* Define the needed data structure : */
// Define a dictionnary of constant string --> integer
// 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)
// Defin an array of integer
// Define an array of integer to store the value and register it.
ARRAY_DEF(array_value, uint32_t) // Start from 1. 0 is 'None'
#define M_OPL_array_value_t() ARRAY_OPLIST(array_value)
// Defin an array of integer
// Define an array of integer to store the seed and register it.
ARRAY_DEF(array_seed, int32_t)
#define M_OPL_array_seed_t() ARRAY_OPLIST(array_seed)
// Define algorithms on array_seed
ALGO_DEF(array_seed, array_seed_t)
// Define an array of constant string that are ordered by their size.
ARRAY_DEF(array_cstr, const char *, M_CSTR_OPLIST)
// Register it globally but with a custom CMP operator
static inline int array_cstr_cmp(const array_cstr_t a, const array_cstr_t b) {
// We compare only the size
size_t sa = array_cstr_size(a);
size_t sb = array_cstr_size(b);
return (sa > sb) ? -1 : (sa < sb);
@@ -191,7 +194,11 @@ static void
dict_read_from_file(dict_mph_t dict, array_string_t arr, const char filename[])
{
FILE *f = fopen(filename, "rt");
if (!f) abort();
if (!f) {
fprintf(stderr, "ERROR: Cannot open %s\n", filename);
exit(2);
}
uint32_t line = 1;
M_LET(str, string_t) {
while (!feof(f) && !ferror(f)) {
@@ -234,12 +241,14 @@ test(array_seed_t seed, array_value_t value, dict_mph_t dict)
int main(int argc, const char *argv[])
{
// Create arr as array_string_t, dict as dist_mph_t and seed as array_seed_t
M_LET(arr, array_string_t) M_LET(dict, dict_mph_t) M_LET(seed, array_seed_t)
// and value as array_value_t
M_LET(value, array_value_t) {
const char *filename = (argc > 1) ? argv[1] :"/usr/share/dict/words";
dict_read_from_file(dict, arr, filename);
CreateMinimalPerfectHash(seed, value, dict);
test(seed, value, dict);
const char *filename = (argc > 1) ? argv[1] :"/usr/share/dict/words";
dict_read_from_file(dict, arr, filename);
CreateMinimalPerfectHash(seed, value, dict);
test(seed, value, dict);
}
return 0;
+7 -2
View File
@@ -4,6 +4,7 @@
#include "m-array.h"
#include "m-string.h"
// Define an array of integer
ARRAY_DEF(array_int, int)
typedef struct {
@@ -25,7 +26,7 @@ static void tape_devance(tape_t tape) { if (tape->pos > 0) tape->pos--; }
typedef struct {
string_t code;
array_int_t bracket_map; // Should use map when possible.
array_int_t bracket_map;
} program_t[1];
static void program_init(program_t p, string_t text) {
@@ -98,7 +99,11 @@ static void program_run(program_t p){
static void read_file(string_t str, const string_t filename) {
FILE *f = fopen(string_get_cstr(filename), "rt");
if (!f) abort();
if (!f) {
fprintf(stderr, "ERROR: Cannot open %s\n", string_get_cstr(filename));
exit(2);
}
// Read the full FILE in the string
string_fgets (str, f, STRING_READ_FILE);
fclose(f);
}
+9 -2
View File
@@ -1,3 +1,5 @@
#if HAVE_GMP
#include <stdio.h>
#include <gmp.h>
@@ -50,14 +52,19 @@ int main(void)
// Dictionary iterator are pair (key,value)
if (my_integer_n_p(p->value)) {
printf ("It is a long long, value = %lld\n",
*my_integer_get_n(p->value));
*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_get_z(p->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
+4
View File
@@ -51,6 +51,9 @@ TUPLE_DEF2(mlib_points, (first_ref, mlib_point_ptr, M_PTR_OPLIST),
static void let2(void)
{
// Initialize p1 as mlib_point_t with (4,4)
// and p2 as mlib_point_t with (5,5)
// and pair as mlib_point_t with default value
M_LET((p1, 4, 4), (p2, 5, 5), mlib_point_t) {
M_LET(pair, mlib_points_t) {
pair->first_ref = p1;
@@ -68,6 +71,7 @@ static void let2(void)
static void let(void)
{
// Let's initialize all the declared types
M_LET(s, symbol_t)
M_LET(l, symbol_list_t)
M_LET(r,record_t)
+31
View File
@@ -0,0 +1,31 @@
#include <stdio.h>
#include "m-array.h"
#include "m-string.h"
// Let's create an array of string_t and register it globaly
ARRAY_DEF(vector_string, string_t)
#define M_OPL_vector_string_t() ARRAY_OPLIST(vector_string, STRING_OPLIST)
int main(void)
{
// Let's define a new string named str
M_LET(str, string_t)
// Let's define msg as a vector_array_t
M_LET( (msg, STRING_CTE("Hello"), STRING_CTE("C"), STRING_CTE("World!"), STRING_CTE("Let's"), STRING_CTE("discover"), STRING_CTE("M*LIB!")), vector_string_t) {
// Iterate over all words of the array msg
for M_EACH(word, msg, vector_string_t) {
// Cat the current word into the target string
string_cat(str, *word);
// Also add a space character
string_push_back(str, ' ');
}
// Let's define another string and set it to a formatted value.
M_LET( (count, "\nTo display this it uses \"vector\" of %zu strings!", vector_string_size(msg)), string_t) {
string_cat(str, count);
}
// Print the result
printf("%s\n", string_get_cstr(str) );
}
return 0;
}
+10 -8
View File
@@ -4,6 +4,15 @@
#include "m-rbtree.h"
// Let's define one utility function.
void *xmalloc(size_t n);
void *xmalloc(size_t n)
{
void *p = malloc (n);
if (!p) abort();
return p;
}
// Let's define a new type.
typedef struct {
int key;
@@ -12,7 +21,7 @@ typedef struct {
#define SIZE 256
void *xmalloc(size_t n);
// Let's define the prototypes of the methods of this new type.
void my_type_init(my_type_t x);
void my_type_clear(my_type_t x);
void my_type_init_set(my_type_t x, const my_type_t y);
@@ -24,13 +33,6 @@ void my_type_out_str(FILE *f, const my_type_t x);
bool my_type_in_str(my_type_t x, FILE *f);
void my_type_rand(my_type_t x);
void *xmalloc(size_t n)
{
void *p = malloc (n);
if (!p) abort();
return p;
}
// Let's define its constructor
void my_type_init(my_type_t x)
{
+53
View File
@@ -0,0 +1,53 @@
#include <stdio.h>
#include <string.h>
#include "m-string.h"
#define MAX_COLUMN 80
static void format(FILE *f)
{
string_t s;
string_init(s);
while (string_fgets(s, f, STRING_READ_PURE_LINE) == true)
{
size_t n = string_size(s);
if (n > 0 && string_get_char(s, n-1) == '\\' && n < MAX_COLUMN) {
string_left(s, n-1);
while (n < MAX_COLUMN-1) {
string_push_back(s, ' ');
n++;
}
string_push_back(s, '\\');
}
if (n >= MAX_COLUMN && string_get_char(s, n-1) == '\\') {
n--;
string_left(s, n);
while (n >= MAX_COLUMN-2 && string_get_char(s, n-1) == ' ') {
n--;
string_left(s, n);
}
string_push_back(s, ' ');
string_push_back(s, '\\');
}
printf("%s\n", string_get_cstr(s));
}
string_clear(s);
}
int main(int argc, const char *argv[])
{
if (argc < 2)
{
fprintf(stderr, "ERROR: Missing argument filename.\nUSAGE: %s filename.h\n", argv[0]);
exit(1);
}
FILE *f = fopen(argv[1], "rt");
if (!f) {
fprintf(stderr, "ERROR: Cannot open filename '%s' .h\n", argv[1]);
exit(2);
}
format(f);
fclose(f);
exit(0);
}
+91
View File
@@ -0,0 +1,91 @@
#include "m-array.h"
#include "m-string.h"
// Define an array of string_t. Since the oplist of string_t is registered globaly
// there is no need to give it to this definition.
ARRAY_DEF(str_array, string_t)
// First the verbose way and (nearly) macro free:
static void main_macrofree(void)
{
str_array_t tab_name;
str_array_init(tab_name);
// Push some elements in the array (long way)
str_array_push_back(tab_name, STRING_CTE("My"));
str_array_push_back(tab_name, STRING_CTE("CD"));
str_array_push_back(tab_name, STRING_CTE("IS"));
str_array_push_back(tab_name, STRING_CTE("OUT"));
// Overwrite element 1 of the array.
str_array_set_at(tab_name, 1, STRING_CTE("DVD"));
// Format some strings and push them back in the array
string_t format;
string_init_printf(format, "There are %d elements", str_array_size(tab_name));
str_array_push_back(tab_name, format);
string_printf(format, "There is a capacty of %d", str_array_capacity(tab_name));
string_replace_all_str(format, "capacty", "capacity");
str_array_push_back(tab_name, format);
string_printf(format, "The third element is '%s'", string_get_cstr(*str_array_get(tab_name, 2)));
str_array_push_back(tab_name, format);
string_clear(format);
// Display the content of the array.
str_array_it_t it;
int i = 0;
for (str_array_it(it, tab_name) ; !str_array_end_p(it); str_array_next(it)) {
printf("item[%d] = '%s'\n", i, string_get_cstr(*str_array_cref(it)) );
i++;
}
// Clear the array
str_array_clear(tab_name);
}
// Then the short version with macros.
// For this we need to register the oplist of the array of string globally.
#define M_OPL_str_array_t() ARRAY_OPLIST(str_array, STRING_OPLIST)
static void main_macro(void)
{
// Define and fill an array of string with some elements in it:
M_LET( (tab_name, STRING_CTE("My"), STRING_CTE("CD"), STRING_CTE("IS"), STRING_CTE("OUT")), str_array_t) {
// Overwrite element 1 of the array.
str_array_set_at(tab_name, 1, STRING_CTE("DVD"));
// Format some strings and push them back in the array
M_LET(format, string_t) {
string_printf(format, "There are %d elements", str_array_size(tab_name));
str_array_push_back(tab_name, format);
string_printf(format, "There is a capacty of %d", str_array_capacity(tab_name));
string_replace_all_str(format, "capacty", "capacity");
str_array_push_back(tab_name, format);
string_printf(format, "The third element is '%s'", string_get_cstr(*str_array_get(tab_name, 2)));
str_array_push_back(tab_name, format);
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
// Set format to a formated string
// In C11, we can mix string_t and char *.
// We can also use M_CSTR to create a printf formated string.
string_sets(format, "FILE=", getenv("PWD"), "/", *str_array_get(tab_name, 2), M_CSTR("-%d.txt", str_array_size(tab_name) ));
str_array_push_back(tab_name, format);
#endif
} // beyond this point format is cleared
// Display the content of the array.
int i = 0;
for M_EACH(item, tab_name, str_array_t) {
printf("item[%d] = '%s'\n", i, string_get_cstr(*item) );
i++;
}
} // beyond this point tab_name is cleared
}
int main(void)
{
printf("Version macrofree:\n");
main_macrofree();
printf("Version macro:\n");
main_macro();
return 0;
}
+37
View File
@@ -0,0 +1,37 @@
/* Based on https://en.cppreference.com/w/cpp/algorithm/for_each
Need to be built in C11 mode */
#include <stdio.h>
#include "m-array.h"
#include "m-algo.h"
/* Define a dynamic array of int */
ARRAY_DEF(vector_int, int)
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
/* Define operator increment on int */
#define INC(n) (n)++
int main(void)
{
M_LET( (nums, 3, 4, 2, 8, 15, 267), vector_int_t) {
// Print the array before
printf ("before:");
ALGO_FOR_EACH(nums, vector_int_t, M_PRINT, " ");
printf ("\n");
// Increment each element of the array
ALGO_FOR_EACH(nums, vector_int_t, INC);
// Print the array after
printf ("after: ");
ALGO_FOR_EACH(nums, vector_int_t, M_PRINT, " ");
printf ("\n");
// Sum the elements of the array
int sum = 0;
ALGO_REDUCE(sum, nums, vector_int_t, add);
M_PRINT("sum = ", sum, "\n");
}
return 0;
}
+91
View File
@@ -0,0 +1,91 @@
#include "m-tuple.h"
#include "m-array.h"
#include "m-algo.h"
#include "m-funcobj.h"
#include "m-serial-json.h"
#include "m-string.h"
/* Define the employee */
TUPLE_DEF2(employee,
(name, string_t),
(age, int),
(idnum, int))
#define M_OPL_employee_t() TUPLE_OPLIST(employee, STRING_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
/* Define an array of employee and some algorithms on it */
ARRAY_DEF(vector_employee, employee_t)
#define M_OPL_vector_employee_t() ARRAY_OPLIST(vector_employee, M_OPL_employee_t())
ALGO_DEF(vector_employee, vector_employee_t)
/* Define the function object to select the sort order
* named 'compare_by' which is an instance of the interface
* 'vector_employee_cmp_obj' created by ALGO_DEF.
*/
FUNC_OBJ_INS_DEF(compare_by /* name of the instance */,
vector_employee_cmp_obj /* name of the interface */,
(a, b) /* name of the input parameters of the function like object. The type are inherited from the interface. */, {
/* code of the function object */
if (string_equal_str_p(self->sort_field, "name"))
return string_cmp(a->name, b->name);
else if (string_equal_str_p(self->sort_field, "age"))
return a->age < b->age ? -1 : a->age > b->age;
else
return a->idnum < b->idnum ? -1 : a->idnum > b->idnum;
},
/* Additional fields stored in the function object */
(sort_field, string_t) )
#define M_OPL_compare_by_t() FUNC_OBJ_INS_OPLIST(compare_by, STRING_OPLIST)
// Let's read an array of person from the given JSON file
static void read(vector_employee_t base, const char filename[])
{
m_serial_return_code_t ret;
// Open the file
FILE *f = fopen(filename, "rt");
if (!f) {
// Handle errors
fprintf(stderr, "ERROR: Cannot open file '%s'.\n", filename);
exit(2);
}
// Initialize the JSON serializer with this file
M_LET( (in,f), m_serial_json_read_t)
// Read the JSON file and fill in 'base' with it.
ret = vector_employee_in_serial(base, in);
// Let's handle serialization error
if (ret != M_SERIAL_OK_DONE) {
fprintf(stderr, "ERROR: Cannot read JSON data from file '%s'.\nParsing stops at:\n", filename);
while (!feof(f)) { fputc(fgetc(f), stdout); }
fclose(f);
exit(2);
}
// Close the FILE
fclose(f);
}
int main(void)
{
M_LET(emps, vector_employee_t) {
/* Code to populate database from JSON */
read(emps, "ex11-algo02.json");
// Sort the database by employee ID number
M_LET( (cmp, STRING_CTE("idnum")), compare_by_t )
vector_employee_sort_fo(emps, compare_by_as_interface(cmp));
printf("Employees sorted by idnum are: ");
vector_employee_out_str(stdout, emps);
// Sort the database by employee name
M_LET( (cmp, STRING_CTE("name")), compare_by_t )
vector_employee_sort_fo(emps, compare_by_as_interface(cmp));
printf("\nEmployees sorted by name are: ");
vector_employee_out_str(stdout, emps);
printf("\n");
// End
}
return 0;
}
+9
View File
@@ -0,0 +1,9 @@
[
{ "name": "John Doe", "age": 32, "idnum": 14528},
{ "name": "Clint Smith", "age": 31, "idnum": 14529},
{ "name": "Linda Cameron", "age": 20, "idnum": 14527},
{ "name": "Cameron Carrey", "age": 25, "idnum": 14526},
{ "name": "Marty Brown", "age": 26, "idnum": 14525},
{ "name": "Donald Cow", "age": 45, "idnum": 14520}
]
+60
View File
@@ -0,0 +1,60 @@
#include "m-serial-json.h"
#include "m-tuple.h"
#include "m-array.h"
// Let's define a 'person' composed of several fields.
TUPLE_DEF2(person,
(surname, string_t),
(age, int),
(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 )
// Let's define an array of person
ARRAY_DEF(base, person_t)
// Register the oplist of this array globaly
#define M_OPL_base_t() ARRAY_OPLIST(base, M_OPL_person_t())
// Let's read an array of person from the given JSON file
static void read(base_t base, const char filename[])
{
m_serial_read_t in;
m_serial_return_code_t ret;
// Open the file
FILE *f = fopen(filename, "rt");
if (!f) {
fprintf(stderr, "ERROR: Cannot open file '%s'.\n", filename);
exit(2);
}
// Initialize the serializer with the file
m_serial_json_read_init(in, f);
// Read the array
ret = base_in_serial(base, in);
if (ret != M_SERIAL_OK_DONE) {
fprintf(stderr, "ERROR: Cannot read JSON data from file '%s'.\n", filename);
exit(2);
}
// Let's close & clear all
m_serial_json_read_clear(in);
fclose(f);
}
int main(void)
{
// Let's have base as a base_t
M_LET(base, base_t) {
// Read the JSON file and fill-in base
read(base, "ex11-json01.json");
// Print the contents of base:
printf ("List of presents:\n");
for M_EACH(el, base, base_t) {
if ((*el)->present) {
printf("%s\n", string_get_cstr((*el)->surname));
}
}
}
exit(0);
}
+7
View File
@@ -0,0 +1,7 @@
[
{ "surname": "Angel", "age": 1, "present": false},
{ "surname": "Snake", "age": 2, "present": true},
{ "surname": "BallOfBase", "age": 5, "present": true}
]
@@ -1,5 +1,3 @@
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#include <stdio.h>
#include "m-array.h"
@@ -7,12 +5,15 @@
#include "m-dict.h"
#include "m-string.h"
// 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)
// Let's define an array of such tuple and register it
ARRAY_DEF(array_symbol, symbol_t)
#define M_OPL_array_symbol_t() ARRAY_OPLIST(array_symbol, M_OPL_symbol_t())
// Let's define a dictionnary associating a string_t to such an array and register it
DICT_DEF2(sections, string_t, array_symbol_t)
#define M_OPL_sections_t() DICT_OPLIST(sections, STRING_OPLIST, M_OPL_array_symbol_t())
@@ -20,13 +21,21 @@ int main(int argc, const char *argv[])
{
if (argc < 2) abort();
FILE *f = fopen(argv[1], "rt");
if (!f) abort();
if (!f) {
fprintf(stderr, "ERROR: Cannot open %s\n", argv[1]);
return 2;
}
// Create & initialize sc as sections_t
M_LET(sc, sections_t) {
// Read the section from the FILE
sections_in_str(sc, f);
// Get the section named .text
array_symbol_t *a = sections_get(sc, STRING_CTE(".text"));
if (a == NULL) {
printf("There is no .text section.");
} else {
// Print its content
printf("Section .text is :");
array_symbol_out_str(stdout, *a);
printf("\n");
@@ -34,7 +43,3 @@ int main(int argc, const char *argv[])
}
return 0;
}
#else
int main(void) { return 0; }
#endif
+1119 -752
View File
File diff suppressed because it is too large. Load diff
+1048 -910
View File
File diff suppressed because it is too large. Load diff
+115 -60
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Thin stdatomic wrapper for C++ compatibility
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2021, 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:
@@ -26,14 +26,17 @@
#define MSTARLIB_ATOMIC_H
/* NOTE: Due to the C++ not having recognized stdatomic.h officialy,
it is hard to use this header directly with a C++ compiler like
g++ or MSVC.
(See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932 ).
clang has no issue with this header.
GCC 4.9 doesn't have a working implementation of 'atomic'
it is hard to use this header directly with a C++ compiler.
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932
clang++ has no issue with this header but if someone includes
atomic from C++, there is incompatibility between atomic & stdatomic.
Moreover some compilers lack a working stdatomic header.
GCC 4.9 doesn't have a working implementation of 'atomic'.
APPLE Clang defines __GNUC__ to be only 4 despite having full support
for atomic.
*/
#if defined(__cplusplus) && __cplusplus >= 201103L \
&& !defined(__clang__) && !(defined(__GNUC__) && __GNUC__ < 5)
#if defined(__cplusplus) && __cplusplus >= 201103L \
&& !(defined(__GNUC__) && __GNUC__ < 5 && !defined(__APPLE__))
/* NOTE: This is what the stdatomic.h header shall do in C++ mode. */
#include <atomic>
@@ -96,14 +99,38 @@ using std::memory_order_release;
using std::memory_order_acq_rel;
using std::memory_order_seq_cst;
/* CLANG provides a warning on defining _Atomic as it sees it
* as a reserved system macro. It is true. However, the goal of this
* header is to provide stdatomic semantic, so it needs to define
* _Atomic macro.
*
* So, this warning has to be ignored.
*
* It cannot use M_BEGIN_PROTECTED_CODE as this header is normally
* independent of m-core.h
*/
#if defined(__clang__) && __clang_major__ >= 4
_Pragma("clang diagnostic push")
_Pragma("clang diagnostic ignored \"-Wreserved-id-macro\"")
#endif
#define _Atomic(T) std::atomic< T >
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
|| ( defined(__GNUC__) && !defined(__clang__) && !defined(__cplusplus) && (__GNUC__*100 + __GNUC_MINOR__) >= 409) \
|| (defined(__clang__) && __clang_major__ >= 4)
#if defined(__clang__) && __clang_major__ >= 4
_Pragma("clang diagnostic pop")
#endif
/* C11 with working stdatomic
STDATOMIC doesn't work with C++ except for clang but is incompatible with atomic.
GCC < 4.9 doesn't provide a compliant stdatomic.h
CLANG 3.5 has issues with GCC's stdatomic.h and doesn't provide its own
ICC < 18 doesn't provide a compliant stdatomic.h
*/
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) ) \
|| (defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__cplusplus) && (__GNUC__*100 + __GNUC_MINOR__) >= 409) \
|| (defined(__clang__) && (__clang_major__ * 100 + __clang_minor__) >= 308) \
|| (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1800)
/* CLANG 3.5 has issues with GCC's stdatomic.h
and doesn't provide its own stdatomic.h */
#include <stdatomic.h>
/* MSYS2 has a conflict between cdefs.h which defines a _Atomic macro (if not C11)
@@ -118,32 +145,38 @@ using std::memory_order_seq_cst;
# undef _Atomic
#endif
#else
/* Non working atomic.h, nor working stdatomic.h found.
/* Non working C++ atomic header, nor working stdatomic.h found.
Write a compatible layer using mutex as slin as possible.
Supports only up to 64-bits atomic (sizeof long long to be more precise).
The locks are never properly cleared and remain active until
the end of the program.
We also assume that the call to the atomic_* interface is "clean".
We also assume that the call to the atomic_* interface is "macro clean".
*/
#include "m-mutex.h"
#else
/* The structure is quite large:
#include "m-mutex.h"
#include "m-core.h"
M_BEGIN_PROTECTED_CODE
/* _Atomic qualifier for a type (emulation).
The structure is quite large:
_val : value of the atomic type,
_zero : zero value of the atomic type (constant),
_previous: temporary value used within the mutex lock,
_lock : the mutex lock.
Support up to sizeof (long long) type.
*/
#define _Atomic(T) \
struct { \
T volatile _val; \
T _zero; \
T _previous; \
m_mutex_t _lock; \
#define _Atomic(T) \
struct { \
T volatile _val; \
T _zero; \
T _previous; \
m_mutex_t _lock; \
}
/* Even if memory order is defined, only the strongest constraint is used */
/* Define the supported memory order.
Even if memory order is defined, only the strongest constraint is used */
typedef enum {
memory_order_relaxed,
memory_order_consume,
@@ -184,76 +217,96 @@ typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
#endif
/* Detect if stdint.h was included */
#if (defined (INTMAX_C) && defined (UINTMAX_C) && !defined(__cplusplus)) || \
defined (_STDINT_H) || defined (_STDINT_H_) || defined (_STDINT) || \
#if (defined (INTMAX_C) && defined (UINTMAX_C) && !defined(__cplusplus)) || \
defined (_STDINT_H) || defined (_STDINT_H_) || defined (_STDINT) || \
defined (_SYS_STDINT_H_)
/* Define additional atomic types */
typedef _Atomic(intmax_t) atomic_intmax_t;
typedef _Atomic(uintmax_t) atomic_uintmax_t;
#endif
/* Unlock the mutex and return the given value */
/* (INTERNAL) Unlock the mutex and return the given value */
static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
{
m_mutex_unlock (*lock);
return val;
}
/* This is the heart of the wrapper:
/* (INTERNAL) This is the heart of the wrapper:
lock the atomic value, read it and returns the value.
In order to avoid any compiler extension, we need to transform the
atomic type into 'long long' then convert it back to its value.
This is because _previous can't be read after the lock, and we can't
generate temporary variable within a macro.
The trick is computing _val - _zero within the lock, then
returns retvalue + _zero after the lock.
returns retvalue + _zero after the release of the lock.
*/
#define atomic_fetch_op(ptr, val, op) \
(m_mutex_lock((ptr)->_lock), \
(ptr)->_previous = (ptr)->_val, \
(ptr)->_val op (val), \
atomic_fetch_unlock(&(ptr)->_lock, (ptr)->_previous-(ptr)->_zero)+(ptr)->_zero)
#define atomic_fetch_op(ptr, val, op) \
(m_mutex_lock((ptr)->_lock), \
(ptr)->_previous = (ptr)->_val, \
(ptr)->_val op (val), \
atomic_fetch_unlock(&(ptr)->_lock, (long long)((ptr)->_previous-(ptr)->_zero))+(ptr)->_zero)
/* Perform an atomic add (EMULATION) */
#define atomic_fetch_add(ptr, val) atomic_fetch_op(ptr, val, +=)
/* Perform an atomic sub (EMULATION) */
#define atomic_fetch_sub(ptr, val) atomic_fetch_op(ptr, val, -=)
/* Perform an atomic or (EMULATION) */
#define atomic_fetch_or(ptr, val) atomic_fetch_op(ptr, val, |=)
/* Perform an atomic xor (EMULATION) */
#define atomic_fetch_xor(ptr, val) atomic_fetch_op(ptr, val, ^=)
/* Perform an atomic and (EMULATION) */
#define atomic_fetch_and(ptr, val) atomic_fetch_op(ptr, val, &=)
/* Perform an atomic exchange (EMULATION) */
#define atomic_exchange(ptr, val) atomic_fetch_op(ptr, val, =)
/* Initialize an atomic GLOBAL variable */
#define ATOMIC_VAR_INIT(val) { val, 0, 0, M_MUTEXI_INIT_VALUE }
#define atomic_init(ptr, val) \
/* Initialize an atomic variable */
#define atomic_init(ptr, val) \
(m_mutex_init((ptr)->_lock), (ptr)->_val = val, (ptr)->_zero = 0)
#define atomic_load_lock(ptr) \
(m_mutex_lock((ptr)->_lock), \
(ptr)->_previous = (ptr)->_val, \
atomic_fetch_unlock(&(ptr)->_lock, (ptr)->_previous-(ptr)->_zero)+(ptr)->_zero)
/* (INTERNAL) Load an atomic variable within a lock
(needed for variable greater than CPU atomic size) */
#define atomic_load_lock(ptr) \
(m_mutex_lock((ptr)->_lock), \
(ptr)->_previous = (ptr)->_val, \
atomic_fetch_unlock(&(ptr)->_lock, (long long) ((ptr)->_previous-(ptr)->_zero))+(ptr)->_zero)
#define atomic_store_lock(ptr, val) \
(m_mutex_lock((ptr)->_lock), \
(ptr)->_val = (val), \
/* (INTERNAL) Store an atomic variable within a lock
(needed for variable greater than CPU atomic size) */
#define atomic_store_lock(ptr, val) \
(m_mutex_lock((ptr)->_lock), \
(ptr)->_val = (val), \
m_mutex_unlock((ptr)->_lock))
#define atomic_load(ptr) \
( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE \
? (ptr)->_val \
/* Atomic load of a variable (EMULATION)
If the atomic type size is not greater than the CPU atomic size,
we can perform a direct read of the variable (much faster) */
#define atomic_load(ptr) \
( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE \
? (ptr)->_val \
: atomic_load_lock(ptr))
#define atomic_store(ptr, val) do { \
if ( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE) { \
(ptr)->_val = (val); \
} else { \
long long _offset = (val) - (ptr)->_zero; \
atomic_store_lock(ptr, (ptr)->_zero + _offset); \
} \
/* Atomic store of a variable (EMULATION)
If the atomic type size is not greater than the CPU atomic size,
we can perform a direct write of the variable (much faster) */
#define atomic_store(ptr, val) do { \
if ( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE) { \
(ptr)->_val = (val); \
} else { \
long long _offset = (long long) ((val) - (ptr)->_zero); \
atomic_store_lock(ptr, (ptr)->_zero + _offset); \
} \
} while (0)
#define atomic_compare_exchange_strong(ptr, exp, val) \
(m_mutex_lock((ptr)->_lock), \
atomic_fetch_unlock(&(ptr)->_lock, \
(ptr)->_val == *(exp) \
? ((ptr)->_val = (val), true) \
/* Perform a CAS (Compare and swap) operation (EMULATION) */
#define atomic_compare_exchange_strong(ptr, exp, val) \
(m_mutex_lock((ptr)->_lock), \
atomic_fetch_unlock(&(ptr)->_lock, \
(ptr)->_val == *(exp) \
? ((ptr)->_val = (val), true) \
: (*(exp) = (ptr)->_val, false)))
@@ -273,7 +326,9 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
#define atomic_compare_exchange_weak_explicit(ptr, exp, val, mem1, mem2) atomic_compare_exchange_strong(ptr, exp, val)
#define atomic_compare_exchange_weak(ptr, exp, val) atomic_compare_exchange_strong(ptr, exp, val)
/* TODO: Missing atomic_flag. Problem: it needs to be lock free! */
/* TODO: Missing atomic_flag. Problem: it is supposed to be lock free! */
M_END_PROTECTED_CODE
#endif
+200 -114
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - BITSET module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2021, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -30,10 +30,12 @@
/********************************** INTERNAL ************************************/
// Define the limb of a bitset
typedef uint64_t bitset_limb;
// And its size
#define BITSET_LIMB_BIT (sizeof(bitset_limb) * CHAR_BIT)
M_BEGIN_PROTECTED_CODE
// Define the basic limb of a bitset
typedef uint64_t bitset_limb_ct;
// And its size in bits
#define BITSET_LIMB_BIT (sizeof(bitset_limb_ct) * CHAR_BIT)
// bitset grow policy. n is limb size
#define BITSETI_INC_ALLOC_SIZE(n) ((n) < 4 ? 4 : (n) * 2)
@@ -45,43 +47,51 @@ typedef uint64_t bitset_limb;
#define BITSETI_FROM_ALLOC(n) ((n) * BITSET_LIMB_BIT)
// Contract of a bitset
#define BITSETI_CONTRACT(t) do { \
assert (t != NULL); \
assert (t->size <= BITSETI_FROM_ALLOC (t->alloc)); \
assert (t->alloc <= ((size_t)-1) / BITSET_LIMB_BIT); \
assert (t->size < ((size_t)-1) - BITSET_LIMB_BIT); \
assert (t->size == 0 || t->ptr != NULL); \
#define BITSETI_CONTRACT(t) do { \
M_ASSERT (t != NULL); \
M_ASSERT (t->size <= BITSETI_FROM_ALLOC (t->alloc)); \
M_ASSERT (t->alloc <= ((size_t)-1) / BITSET_LIMB_BIT); \
M_ASSERT (t->size < ((size_t)-1) - BITSET_LIMB_BIT); \
M_ASSERT (t->size == 0 || t->ptr != NULL); \
M_ASSERT (t->alloc == 0 || t->ptr != NULL); \
} while (0)
/********************************** EXTERNAL ************************************/
/* Define a type of variable 'bits' or array of packed booleans */
typedef struct bitset_s {
size_t size; // Size is the number of bits
size_t alloc; // Alloc is the number of allocated limbs
bitset_limb *ptr; // Pointer to the allocated limbs
bitset_limb_ct *ptr; // Pointer to the allocated limbs
} bitset_t[1];
/* Pointer to a bitset_t */
typedef struct bitset_s *bitset_ptr;
/* Constant Pointer to a bitset_t */
typedef const struct bitset_s *bitset_srcptr;
/* Iterator on a bitset */
typedef struct bitset_it_s {
size_t index; // index to the array of bit
bool value; // value used for _ref & _cref to store the value
struct bitset_s *set; // the associated bitset
} bitset_it_t[1];
/* Initialize a bitset (CONSTRUCTOR) */
static inline void
bitset_init(bitset_t t)
{
assert (t != NULL);
assert (M_POWEROF2_P(BITSET_LIMB_BIT));
M_ASSERT (t != NULL);
M_STATIC_ASSERT (M_POWEROF2_P(BITSET_LIMB_BIT), MLIB_INTERNAL, "M*LIB: BITSET LIMB shall be a power of 2.");
t->size = 0;
t->alloc = 0;
t->ptr = NULL;
BITSETI_CONTRACT(t);
}
/* Clean a bitset */
static inline void
bitset_clean(bitset_t t)
{
@@ -89,16 +99,20 @@ bitset_clean(bitset_t t)
t->size = 0;
}
/* Clear a bitset (DESTRUCTOR) */
static inline void
bitset_clear(bitset_t t)
{
bitset_clean(t);
M_MEMORY_FREE(t->ptr);
// This is not really needed, but is safer
t->alloc = 0;
// This representation is invalid and will be detected by the contract.
// A C compiler should be able to optimize out theses initializations.
t->alloc = 1;
t->ptr = NULL;
}
/* Set a bitset to another one */
static inline void
bitset_set(bitset_t d, const bitset_t s)
{
@@ -107,7 +121,7 @@ bitset_set(bitset_t d, const bitset_t s)
if (M_UNLIKELY (d == s)) return;
const size_t needAlloc = BITSETI_TO_ALLOC (s->size);
if (s->size > BITSETI_FROM_ALLOC (d->alloc)) {
bitset_limb *ptr = M_MEMORY_REALLOC (bitset_limb, d->ptr, needAlloc);
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, d->ptr, needAlloc);
if (M_UNLIKELY (ptr == NULL)) {
M_MEMORY_FULL(needAlloc);
return ;
@@ -115,19 +129,21 @@ bitset_set(bitset_t d, const bitset_t s)
d->ptr = ptr;
d->alloc = needAlloc;
}
memcpy (d->ptr, s->ptr, needAlloc * sizeof(bitset_limb) );
memcpy (d->ptr, s->ptr, needAlloc * sizeof(bitset_limb_ct) );
d->size = s->size;
BITSETI_CONTRACT(d);
}
/* Initialize & set a bitset to another one (CONSTRUCTOR) */
static inline void
bitset_init_set(bitset_t d, const bitset_t s)
{
assert (d != s);
M_ASSERT (d != s);
bitset_init(d);
bitset_set(d, s);
}
/* Initialize & move a bitset (CONSTRUCTOR) from another one (DESTRUCTOR) */
static inline void
bitset_init_move(bitset_t d, bitset_t s)
{
@@ -140,6 +156,7 @@ bitset_init_move(bitset_t d, bitset_t s)
BITSETI_CONTRACT(d);
}
/* Move a bitset from another one (DESTRUCTOR) */
static inline void
bitset_move(bitset_t d, bitset_t s)
{
@@ -147,46 +164,52 @@ bitset_move(bitset_t d, bitset_t s)
bitset_init_move (d, s);
}
/* Set the bit 'i' in the bitset to the value 'x' */
static inline void
bitset_set_at(bitset_t v, size_t i, bool x)
{
BITSETI_CONTRACT(v);
assert (i < v->size && v->ptr != NULL);
M_ASSERT (v->ptr != NULL);
M_ASSERT_INDEX(i, v->size);
const size_t offset = i / BITSET_LIMB_BIT;
const size_t index = i % BITSET_LIMB_BIT;
// This is a branchless version as x can only be 0 or 1 with only one variable shift.
const bitset_limb mask = ((bitset_limb)1)<<index;
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (-(bitset_limb)x));
const bitset_limb_ct mask = ((bitset_limb_ct)1)<<index;
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (0-(bitset_limb_ct)x));
BITSETI_CONTRACT (v);
}
/* Flip the bit 'i' in the bitset */
static inline void
bitset_flip_at(bitset_t v, size_t i)
{
BITSETI_CONTRACT(v);
assert (i < v->size && v->ptr != NULL);
M_ASSERT (v->ptr != NULL);
M_ASSERT_INDEX(i, v->size);
size_t offset = i / BITSET_LIMB_BIT;
size_t index = i % BITSET_LIMB_BIT;
v->ptr[offset] ^= ((bitset_limb)1)<<index;
v->ptr[offset] ^= ((bitset_limb_ct)1)<<index;
BITSETI_CONTRACT (v);
}
/* Push back the boolean 'x' in the bitset (increasing the bitset) */
static inline void
bitset_push_back (bitset_t v, bool x)
{
BITSETI_CONTRACT (v);
if (v->size >= BITSETI_FROM_ALLOC (v->alloc)) {
// Compute the needed allocation.
const size_t needAlloc = BITSETI_INC_ALLOC_SIZE(v->alloc);
// Check for integer overflow
if (M_UNLIKELY (needAlloc <= v->alloc)) {
M_MEMORY_FULL(needAlloc * sizeof(bitset_limb));
M_MEMORY_FULL(needAlloc * sizeof(bitset_limb_ct));
return;
}
// Alloc memory
bitset_limb *ptr = M_MEMORY_REALLOC (bitset_limb, v->ptr, needAlloc);
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, v->ptr, needAlloc);
// Check if success
if (M_UNLIKELY (ptr == NULL) ) {
M_MEMORY_FULL(needAlloc * sizeof(bitset_limb));
M_MEMORY_FULL(needAlloc * sizeof(bitset_limb_ct));
return;
}
// Clear allocated memory
@@ -196,11 +219,12 @@ bitset_push_back (bitset_t v, bool x)
v->ptr = ptr;
v->alloc = needAlloc;
}
assert(v->ptr != NULL);
M_ASSERT(v->ptr != NULL);
v->size ++;
bitset_set_at (v, v->size - 1, x);
}
/* Resize the bitset to have exactly 'size' bits */
static inline void
bitset_resize (bitset_t v, size_t size)
{
@@ -210,18 +234,19 @@ bitset_resize (bitset_t v, size_t size)
M_MEMORY_FULL((size_t) -1);
return;
}
// Compute the needed allocation.
size_t newAlloc = BITSETI_TO_ALLOC (size);
if (newAlloc > v->alloc) {
bitset_limb *ptr = M_MEMORY_REALLOC (bitset_limb, v->ptr, newAlloc);
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, v->ptr, newAlloc);
if (M_UNLIKELY (ptr == NULL) ) {
M_MEMORY_FULL(newAlloc * sizeof(bitset_limb));
M_MEMORY_FULL(newAlloc * sizeof(bitset_limb_ct));
return;
}
v->ptr = ptr;
v->alloc = newAlloc;
}
//FIXME: Last bit are not cleared. if new size is lower than org size
//TODO: More efficient!
//FIXME: Last bit are not cleared if new size is lower than org size. Needed?
//TODO: Implement a more efficient version when needed.
size_t i = v->size;
v->size = size;
for( ; i < size; i++)
@@ -229,6 +254,7 @@ bitset_resize (bitset_t v, size_t size)
BITSETI_CONTRACT (v);
}
/* Reserve allocation in the bitset to accomodate at least 'size' bits without reallocation */
static inline void
bitset_reserve (bitset_t v, size_t size)
{
@@ -243,9 +269,9 @@ bitset_reserve (bitset_t v, size_t size)
v->size = v->alloc = 0;
v->ptr = NULL;
} else {
bitset_limb *ptr = M_MEMORY_REALLOC (bitset_limb, v->ptr, newAlloc);
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, v->ptr, newAlloc);
if (M_UNLIKELY (ptr == NULL) ) {
M_MEMORY_FULL(newAlloc * sizeof(bitset_limb));
M_MEMORY_FULL(newAlloc * sizeof(bitset_limb_ct));
return;
}
v->ptr = ptr;
@@ -254,24 +280,30 @@ bitset_reserve (bitset_t v, size_t size)
BITSETI_CONTRACT (v);
}
// NOTE: Interface is a little bit different:
// It doesn't return a pointer to the data, but the data itself.
/* Return the value of the boolean at index 'i'.
* NOTE: Interface is a little bit different:
* It doesn't return a pointer to the data, but the data itself.
*/
static inline bool
bitset_get(const bitset_t v, size_t i)
{
BITSETI_CONTRACT(v);
assert (v->ptr != NULL && i < v->size);
M_ASSERT (v->ptr != NULL);
M_ASSERT_INDEX(i, v->size);
size_t offset = i / BITSET_LIMB_BIT;
size_t index = i % BITSET_LIMB_BIT;
return ( v->ptr[offset] & (((bitset_limb)1) << index) ) != 0;
return ( v->ptr[offset] & (((bitset_limb_ct)1) << index) ) != 0;
}
/* bitset_cget is the exact same service than bitset_get */
#define bitset_cget bitset_get
/* Pop back the last bit in the bitset */
static inline void
bitset_pop_back(bool *dest, bitset_t v)
{
BITSETI_CONTRACT (v);
assert (v->size > 0);
M_ASSERT_INDEX (0, v->size);
if (dest) {
*dest = bitset_get (v, v->size - 1);
}
@@ -280,22 +312,25 @@ bitset_pop_back(bool *dest, bitset_t v)
BITSETI_CONTRACT (v);
}
/* Return the front bit value in the bitset */
static inline bool
bitset_front(bitset_t v)
{
BITSETI_CONTRACT (v);
assert(v->size > 0);
M_ASSERT_INDEX (0, v->size);
return bitset_get(v, 0);
}
/* Return the back bit value in the bitset */
static inline bool
bitset_back(bitset_t v)
{
BITSETI_CONTRACT (v);
assert(v->size > 0);
M_ASSERT_INDEX (0, v->size);
return bitset_get(v, v->size-1);
}
/* Test if the bitset is empty (no bits stored)*/
static inline bool
bitset_empty_p(bitset_t v)
{
@@ -303,6 +338,7 @@ bitset_empty_p(bitset_t v)
return v->size == 0;
}
/* Return the number of bits of the bitset */
static inline size_t
bitset_size(bitset_t v)
{
@@ -310,6 +346,7 @@ bitset_size(bitset_t v)
return v->size;
}
/* Return the capacity in limbs of the bitset */
static inline size_t
bitset_capacity(bitset_t v)
{
@@ -317,11 +354,14 @@ bitset_capacity(bitset_t v)
return BITSETI_FROM_ALLOC (v->alloc);
}
/* Swap the bit at index i and j of the bitset */
static inline void
bitset_swap_at (bitset_t v, size_t i, size_t j)
{
BITSETI_CONTRACT (v);
assert (i < v->size && j < v->size);
M_ASSERT_INDEX(i, v->size);
M_ASSERT_INDEX(j, v->size);
bool i_val = bitset_get(v, i);
bool j_val = bitset_get(v, j);
bitset_set_at (v, i, j_val);
@@ -329,6 +369,7 @@ bitset_swap_at (bitset_t v, size_t i, size_t j)
BITSETI_CONTRACT (v);
}
/* Swap the bitsets */
static inline void
bitset_swap (bitset_t v1, bitset_t v2)
{
@@ -336,59 +377,74 @@ bitset_swap (bitset_t v1, bitset_t v2)
BITSETI_CONTRACT (v2);
M_SWAP (size_t, v1->size, v2->size);
M_SWAP (size_t, v1->alloc, v2->alloc);
M_SWAP (bitset_limb *, v1->ptr, v2->ptr);
M_SWAP (bitset_limb_ct *, v1->ptr, v2->ptr);
}
static inline bitset_limb
bitseti_lshift(bitset_limb ptr[], size_t n, bitset_limb carry)
/* (INTERNAL) Left shift of the bitset (ptr+size) by 1 bit,
* integrating the carry in the lowest position.
* Return the new carry.
*/
static inline bitset_limb_ct
bitseti_lshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
{
for(size_t i = 0; i < n; i++) {
bitset_limb v = ptr[i];
bitset_limb_ct v = ptr[i];
ptr[i] = (v << 1) | carry;
carry = (v >> (BITSET_LIMB_BIT-1) );
}
return carry;
}
static inline bitset_limb
bitseti_rshift(bitset_limb ptr[], size_t n, bitset_limb carry)
/* (INTERNAL) Right shift of the bitset (ptr+size) by 1 bit,
* integrating the carry in the lowest position.
* Return the new carry.
*/
static inline bitset_limb_ct
bitseti_rshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
{
for(size_t i = n - 1; i < n; i--) {
bitset_limb v = ptr[i];
bitset_limb_ct v = ptr[i];
v = (v >> 1) | (carry << (BITSET_LIMB_BIT-1) );
carry = v & 1;
}
return carry;
}
/* Insert a new bit at position 'key' of value 'value' in the bitset */
static inline void
bitset_push_at(bitset_t set, size_t key, bool value)
{
BITSETI_CONTRACT (set);
// First push another value to extend the array to the right size
bitset_push_back(set, false);
assert (set->ptr != NULL && key < set->size);
M_ASSERT (set->ptr != NULL);
M_ASSERT_INDEX(key, set->size);
// Then shift it
size_t offset = key / BITSET_LIMB_BIT;
size_t index = key % BITSET_LIMB_BIT;
bitset_limb v = set->ptr[offset];
bitset_limb mask = (((bitset_limb)1)<<index)-1;
bitset_limb carry = (v >> (BITSET_LIMB_BIT-1) );
v = (v & mask) | (value << index) | ((v & ~mask) << 1);
bitset_limb_ct v = set->ptr[offset];
bitset_limb_ct mask = (((bitset_limb_ct)1)<<index)-1;
bitset_limb_ct carry = (v >> (BITSET_LIMB_BIT-1) );
v = (v & mask) | ((unsigned int) value << index) | ((v & ~mask) << 1);
set->ptr[offset] = v;
size_t size = (set->size + BITSET_LIMB_BIT - 1) / BITSET_LIMB_BIT;
assert (size >= offset + 1);
M_ASSERT (size >= offset + 1);
v = bitseti_lshift(&set->ptr[offset+1], size - offset - 1, carry);
// v is unused.
(void) v;
BITSETI_CONTRACT (set);
}
/* Pop a new bit at position 'key' in the bitset
* and return in *dest its value if *dest exists */
static inline void
bitset_pop_at(bool *dest, bitset_t set, size_t key)
{
BITSETI_CONTRACT (set);
assert (set->ptr != NULL && key < set->size);
M_ASSERT (set->ptr != NULL);
M_ASSERT_INDEX(key, set->size);
if (dest) {
*dest = bitset_get (set, key);
}
@@ -396,10 +452,10 @@ bitset_pop_at(bool *dest, bitset_t set, size_t key)
size_t offset = key / BITSET_LIMB_BIT;
size_t index = key % BITSET_LIMB_BIT;
size_t size = (set->size + BITSET_LIMB_BIT - 1) / BITSET_LIMB_BIT;
bitset_limb v, mask, carry;
bitset_limb_ct v, mask, carry;
carry = bitseti_rshift(&set->ptr[offset+1], size - offset - 1, false);
v = set->ptr[offset];
mask = (((bitset_limb)1)<<index)-1;
mask = (((bitset_limb_ct)1)<<index)-1;
v = (v & mask) | ((v>>1) & ~mask) | (carry << (BITSET_LIMB_BIT-1)) ;
set->ptr[offset] = v;
// Decrease size
@@ -407,6 +463,7 @@ bitset_pop_at(bool *dest, bitset_t set, size_t key)
BITSETI_CONTRACT (set);
}
/* Test if two bitsets are equal */
static inline bool
bitset_equal_p (const bitset_t set1, const bitset_t set2)
{
@@ -423,13 +480,14 @@ bitset_equal_p (const bitset_t set1, const bitset_t set2)
/* Compare the last limb if needed */
const size_t index = set1->size % BITSET_LIMB_BIT;
if (index > 0) {
const bitset_limb mask = (((bitset_limb)1) << index) - 1;
const bitset_limb_ct mask = (((bitset_limb_ct)1) << index) - 1;
if ((set1->ptr[limbSize] & mask) != (set2->ptr[limbSize] & mask))
return false;
}
return true;
}
/* Initialize an iterator to the first bit of the biset */
static inline void
bitset_it(bitset_it_t it, bitset_t set)
{
@@ -438,14 +496,16 @@ bitset_it(bitset_it_t it, bitset_t set)
it->set = set;
}
/* Initialize an iterator to reference the same bit as the given one*/
static inline void
bitset_it_set(bitset_it_t it, const bitset_it_t itorg)
{
assert (it != NULL && itorg != NULL);
M_ASSERT (it != NULL && itorg != NULL);
it->index = itorg->index;
it->set = itorg->set;
}
/* Initialize an iterator to reference the last bit of the bitset*/
static inline void
bitset_it_last(bitset_it_t it, bitset_t set)
{
@@ -454,6 +514,7 @@ bitset_it_last(bitset_it_t it, bitset_t set)
it->set = set;
}
/* Initialize an iterator to reference no valid bit of the bitset*/
static inline void
bitset_it_end(bitset_it_t it, bitset_t set)
{
@@ -462,55 +523,66 @@ bitset_it_end(bitset_it_t it, bitset_t set)
it->set = set;
}
/* Test if an iterator references no valid bit of the bitset anymore */
static inline bool
bitset_end_p(const bitset_it_t it)
{
assert (it != NULL && it->set != NULL);
M_ASSERT (it != NULL && it->set != NULL);
return (it->index) >= (it->set->size);
}
/* Test if an iterator references the last (or end) bit of the bitset anymore */
static inline bool
bitset_last_p(const bitset_it_t it)
{
assert (it != NULL && it->set != NULL);
return (it->index) >= (it->set->size)-1;
M_ASSERT (it != NULL && it->set != NULL);
/* NOTE: Can not compute 'size-1' due to potential overflow
if size is 0 */
return (it->index+1) >= (it->set->size);
}
/* Test if both iterators reference the same bit */
static inline bool
bitset_it_equal_p(const bitset_it_t it1, const bitset_it_t it2)
{
assert (it1 != NULL && it2 != NULL);
M_ASSERT (it1 != NULL && it2 != NULL);
return it1->index == it2->index && it1->set == it2->set;
}
/* Move the iterator to the next bit */
static inline void
bitset_next(bitset_it_t it)
{
assert (it != NULL && it->set != NULL);
M_ASSERT (it != NULL && it->set != NULL);
it->index++;
}
/* Move the iterator to the previous bit */
static inline void
bitset_previous(bitset_it_t it)
{
assert (it != NULL && it->set != NULL);
M_ASSERT (it != NULL && it->set != NULL);
it->index--;
}
// There is no _ref as it is not possible to modify the value using the IT interface
/* Return a pointer to the bit referenced by the iterator
* Only one reference is possible at a time per iterator */
static inline const bool *
bitset_cref(bitset_it_t it)
{
assert (it != NULL && it->set != NULL);
M_ASSERT (it != NULL && it->set != NULL);
it->value = bitset_get(it->set, it->index);
return &it->value;
}
/* Output the bitset as a formatted text in a FILE */
static inline void
bitset_out_str(FILE *file, const bitset_t set)
{
BITSETI_CONTRACT (set);
assert(file != NULL);
M_ASSERT(file != NULL);
fputc ('[', file);
for(size_t i = 0; i < set->size; i++) {
const bool b = bitset_get (set, i);
@@ -520,11 +592,12 @@ bitset_out_str(FILE *file, const bitset_t set)
fputc (']', file);
}
/* Input the bitset from a formatted text in a FILE */
static inline bool
bitset_in_str(bitset_t set, FILE *file)
{
BITSETI_CONTRACT (set);
assert(file != NULL);
M_ASSERT(file != NULL);
bitset_clean(set);
int c = fgetc(file);
if (c != '[') return false;
@@ -538,11 +611,12 @@ bitset_in_str(bitset_t set, FILE *file)
return c == ']';
}
/* Parse the bitset from a formatted text in a C string */
static inline bool
bitset_parse_str(bitset_t set, const char str[], const char **endptr)
{
BITSETI_CONTRACT (set);
assert(str != NULL);
M_ASSERT(str != NULL);
bool success = false;
bitset_clean(set);
char c = *str++;
@@ -561,12 +635,15 @@ bitset_parse_str(bitset_t set, const char str[], const char **endptr)
return success;
}
/* Set the bitset from a formatted text in a C string */
static inline bool
bitset_set_str(bitset_t dest, const char str[])
{
return bitset_parse_str(dest, str, NULL);
}
/* Perform an AND operation between the bitsets,
* up to the minimum size of both bitsets */
static inline void
bitset_and(bitset_t dest, const bitset_t src)
{
@@ -578,13 +655,15 @@ bitset_and(bitset_t dest, const bitset_t src)
for(size_t i = 0 ; i < n; i++)
dest->ptr[i] &= src->ptr[i];
if (m) {
bitset_limb mask = (((bitset_limb)1) << m) - 1;
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
dest->ptr[n] = (dest->ptr[n] & src->ptr[n]) & mask;
}
dest->size = s;
BITSETI_CONTRACT(dest);
}
/* Perform an OR operation between the bitsets,
* up to the minimum size of both bitsets */
static inline void
bitset_or(bitset_t dest, const bitset_t src)
{
@@ -596,13 +675,15 @@ bitset_or(bitset_t dest, const bitset_t src)
for(size_t i = 0 ; i < n; i++)
dest->ptr[i] |= src->ptr[i];
if (m) {
bitset_limb mask = (((bitset_limb)1) << m) - 1;
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
dest->ptr[n] = (dest->ptr[n] | src->ptr[n]) & mask;
}
dest->size = s;
BITSETI_CONTRACT(dest);
}
/* Perform an XOR operation between the bitsets,
* up to the minimum size of both bitsets */
static inline void
bitset_xor(bitset_t dest, const bitset_t src)
{
@@ -614,13 +695,14 @@ bitset_xor(bitset_t dest, const bitset_t src)
for(size_t i = 0 ; i < n; i++)
dest->ptr[i] ^= src->ptr[i];
if (m) {
bitset_limb mask = (((bitset_limb)1) << m) - 1;
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
dest->ptr[n] = (dest->ptr[n] ^ src->ptr[n]) & mask;
}
dest->size = s;
BITSETI_CONTRACT(dest);
}
/* Perform a NOT operation of the bitset */
static inline void
bitset_not(bitset_t dest)
{
@@ -631,13 +713,14 @@ bitset_not(bitset_t dest)
for(size_t i = 0 ; i < n; i++)
dest->ptr[i] = ~ (dest->ptr[i]);
if (m) {
bitset_limb mask = (((bitset_limb)1) << m) - 1;
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
dest->ptr[n] = (~ dest->ptr[n]) & mask;
}
dest->size = s;
BITSETI_CONTRACT(dest);
}
/* Copute a hash of the bitset */
static inline size_t
bitset_hash(const bitset_t set)
{
@@ -649,23 +732,24 @@ bitset_hash(const bitset_t set)
for(size_t i = 0 ; i < n; i++)
M_HASH_UP(hash, set->ptr[i]);
if (m) {
bitset_limb mask = (((bitset_limb)1) << m) - 1;
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
M_HASH_UP(hash, (set->ptr[n] & mask));
}
return M_HASH_FINAL (hash);
}
/* Count the number of leading zero */
static inline size_t
bitset_clz(const bitset_t set)
{
BITSETI_CONTRACT(set);
size_t s = set->size;
assert (s > 0);
M_ASSERT_INDEX (0, s); // TBC: Special case to handle?
size_t n = (s -1) / BITSET_LIMB_BIT;
size_t m = s % BITSET_LIMB_BIT;
bitset_limb limb = set->ptr[n];
bitset_limb_ct limb = set->ptr[n];
if (m) {
bitset_limb mask = (((bitset_limb)1) << m) - 1;
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
limb &= mask;
} else {
m = BITSET_LIMB_BIT;
@@ -680,39 +764,40 @@ bitset_clz(const bitset_t set)
return s;
}
#define BITSET_OPLIST \
(INIT(bitset_init) \
,INIT_SET(bitset_init_set) \
,INIT_WITH(API_1(M_INIT_VAI)) \
,SET(bitset_set) \
,CLEAR(bitset_clear) \
,INIT_MOVE(bitset_init_move) \
,MOVE(bitset_move) \
,SWAP(bitset_swap) \
,TYPE(bitset_t) \
,SUBTYPE(bool) \
,TEST_EMPTY(bitset_empty_p), \
,GET_SIZE(bitset_size) \
,IT_TYPE(bitset_it_t) \
,IT_FIRST(bitset_it) \
,IT_SET(bitset_it_set) \
,IT_LAST(bitset_it_last) \
,IT_END(bitset_it_end) \
,IT_END_P(bitset_end_p) \
,IT_LAST_P(bitset_last_p) \
,IT_EQUAL_P(bitset_it_equal_p) \
,IT_NEXT(bitset_next) \
,IT_PREVIOUS(bitset_previous) \
,IT_CREF(bitset_cref) \
,CLEAN(bitset_clean) \
,PUSH(bitset_push_back) \
,POP(bitset_pop_back) \
,HASH(bitset_hash) \
,GET_STR(bitset_get_str) \
,OUT_STR(bitset_out_str) \
,PARSE_STR(bitset_parse_str) \
,IN_STR(bitset_in_str) \
,EQUAL(bitset_equal_p) \
/* Oplist for a bitset */
#define BITSET_OPLIST \
(INIT(bitset_init) \
,INIT_SET(bitset_init_set) \
,INIT_WITH(API_1(M_INIT_VAI)) \
,SET(bitset_set) \
,CLEAR(bitset_clear) \
,INIT_MOVE(bitset_init_move) \
,MOVE(bitset_move) \
,SWAP(bitset_swap) \
,TYPE(bitset_t) \
,SUBTYPE(bool) \
,EMPTY_P(bitset_empty_p), \
,GET_SIZE(bitset_size) \
,IT_TYPE(bitset_it_t) \
,IT_FIRST(bitset_it) \
,IT_SET(bitset_it_set) \
,IT_LAST(bitset_it_last) \
,IT_END(bitset_it_end) \
,IT_END_P(bitset_end_p) \
,IT_LAST_P(bitset_last_p) \
,IT_EQUAL_P(bitset_it_equal_p) \
,IT_NEXT(bitset_next) \
,IT_PREVIOUS(bitset_previous) \
,IT_CREF(bitset_cref) \
,CLEAN(bitset_clean) \
,PUSH(bitset_push_back) \
,POP(bitset_pop_back) \
,HASH(bitset_hash) \
,GET_STR(bitset_get_str) \
,OUT_STR(bitset_out_str) \
,PARSE_STR(bitset_parse_str) \
,IN_STR(bitset_in_str) \
,EQUAL(bitset_equal_p) \
)
/* Register the OPLIST as a global one */
@@ -723,15 +808,15 @@ bitset_clz(const bitset_t set)
#endif
// NOTE: Define this function only if m-string has been included
#ifndef MSTARLIB_BITSET_STRING_H
#ifdef MSTARLIB_STRING_H
#if !defined(MSTARLIB_BITSET_STRING_H) && defined(MSTARLIB_STRING_H)
#define MSTARLIB_BITSET_STRING_H
/* Output to a string_t the formatted text representation of a bitset */
static inline void
bitset_get_str(string_t str, const bitset_t set, bool append)
{
BITSETI_CONTRACT (set);
assert(str != NULL);
M_ASSERT(str != NULL);
(append ? string_cat_str : string_set_str) (str, "[");
for(size_t i = 0; i < set->size; i++) {
const bool b = bitset_get (set, i);
@@ -741,5 +826,6 @@ bitset_get_str(string_t str, const bitset_t set, bool append)
string_push_back (str, ']');
}
#endif
M_END_PROTECTED_CODE
#endif
+1397 -1061
View File
File diff suppressed because it is too large. Load diff
+1038 -892
View File
File diff suppressed because it is too large. Load diff
+471 -463
View File
File diff suppressed because it is too large. Load diff
+831 -660
View File
File diff suppressed because it is too large. Load diff
+1574 -422
View File
File diff suppressed because it is too large. Load diff
+978 -847
View File
File diff suppressed because it is too large. Load diff
+1836 -1512
View File
File diff suppressed because it is too large. Load diff
+402
View File
@@ -0,0 +1,402 @@
/*
* M*LIB - Function Object module
*
* Copyright (c) 2017-2021, 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_FUNCOBJ_H
#define MSTARLIB_FUNCOBJ_H
#include "m-core.h"
/* Define a function object interface of name 'name'
* with a function like retcode, type of param1, type of param 2, ...
* USAGE:
* FUNC_OBJ_ITF_DEF(name, retcode type, type of param1, type of param 2, ...)
*/
#define FUNC_OBJ_ITF_DEF(name, ...) \
M_BEGIN_PROTECTED_CODE \
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_ITF_NO_PARAM_DEF, FUNCOBJI_ITF_PARAM_DEF)(name, M_C(name, _t), __VA_ARGS__) \
M_END_PROTECTED_CODE
/* Define a function object interface of name 'name'
* as the given name name_t
* 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, ...) \
M_BEGIN_PROTECTED_CODE \
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_ITF_NO_PARAM_DEF, FUNCOBJI_ITF_PARAM_DEF)(name, name_t, __VA_ARGS__) \
M_END_PROTECTED_CODE
/* Define a function object instance of name 'name' based on the interface 'base_name'
* The function is defined using:
* - the prototype of the inherited interface
* - the parameters of the function are named as per the list param_list
* - the core of the function given in 'callback_core'
* - optionals member attributes of the function object can be defined after the core
* (just like for tuple & variant: (name, type [, oplist])
*
* In the core of the function, parameters are accessible just like a normal function.
* A special variable named 'self' that refers to the function object itself
* can be used to access member attributes using the syntax self->param1, ...
*
* There shall be **exactly** the same number of parameters in 'param_list' than
* the number of parameters of the interface 'base_name'
*
* 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, ...) \
M_BEGIN_PROTECTED_CODE \
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_DEF, FUNCOBJI_INS_ATTR_DEF)(name, M_C(name, _t), base_name, param_list, __VA_ARGS__) \
M_END_PROTECTED_CODE
/* Define a function object instance of name 'name' based on the interface 'base_name'
* as the given name name_t.
* See FUNC_OBJ_INS_DEF for additional details.
*
* 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, ...) \
M_BEGIN_PROTECTED_CODE \
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_DEF, FUNCOBJI_INS_ATTR_DEF)(name, name_t, base_name, param_list, __VA_ARGS__) \
M_END_PROTECTED_CODE
/* OPLIST of the instanced function object
* USAGE:
* FUNC_OBJ_INS_OPLIST(name, oplist of the attr1, ...)
*/
#define FUNC_OBJ_INS_OPLIST(...) \
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_OPLIST, FUNCOBJI_INS_ATTR_OPLIST_P1)( __VA_ARGS__)
/********************************************************************************/
/********************************** 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
/* Design Constraints:
* callback SHALL be the first member of the structures in all the definitions.
*
* Structure definitions are specialized in function of the presence or not
* of parameters and/or attributes
* FIXME: How to factorize reasonnably well between the definitions?
*/
/* Specialization of the OPLIST in function if there is at least one member or not */
#define FUNCOBJI_INS_NO_ATTR_OPLIST(name) ( \
NAME(name), \
TYPE(M_C(name, _ct)), \
CLEAR(M_C(name, _clear)), \
INIT(M_C(name,_init)) \
)
/* Validate the oplist before going further */
#define FUNCOBJI_INS_ATTR_OPLIST_P1(name, ...) \
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(FUNCOBJI_INS_ATTR_OPLIST_P3, FUNCOBJI_INS_ATTR_OPLIST_FAILURE)(name, __VA_ARGS__)
/* Prepare a clean compilation failure */
#define FUNCOBJI_INS_ATTR_OPLIST_FAILURE(name, ...) \
((M_LIB_ERROR(ONE_ARGUMENT_OF_FUNC_OBJ_INS_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)))
/* Define the oplist of the instance */
#define FUNCOBJI_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)),), \
)
/* 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.
*/
#define FUNCOBJI_ITF_NO_PARAM_DEF(name, interface_t, retcode) \
\
/* Forward declaration */ \
struct M_C(name, _s); \
\
/* Internal type for instance */ \
typedef retcode M_C(name, _retcode_ct); \
/* No parameters to the callback */ \
typedef retcode(*M_C(name, _callback_ct))(struct M_C(name, _s) *); \
\
typedef struct M_C(name, _s) { \
M_C(name, _callback_ct) callback; \
} interface_t[1]; \
\
/* Internal type for oplist & instance */ \
typedef interface_t M_C(name, _ct); \
\
static inline retcode \
M_C(name, _call)(interface_t funcobj) \
{ \
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
funcobj->callback(funcobj); \
}
/* Specialization of the definition a function object interface of name 'name'
* 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_C4(name, _param_, num, _ct) for each parameter defined
* - M_C(name, _ct): synonym of main type used by oplist.
*/
#define FUNCOBJI_ITF_PARAM_DEF(name, interface_t, retcode, ...) \
\
/* Forward declaration */ \
struct M_C(name, _s); \
\
/* Internal types for instance */ \
typedef retcode M_C(name, _retcode_ct); \
/* Define types for all parameters */ \
M_MAP3(FUNCOBJI_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 struct M_C(name, _s) { \
M_C(name, _callback_ct) callback; \
} interface_t[1]; \
\
/* Internal type for oplist & instance */ \
typedef interface_t M_C(name, _ct); \
\
static inline retcode \
M_C(name, _call)(interface_t funcobj \
M_MAP3(FUNCOBJI_BASE_ARGLIST, name, __VA_ARGS__) ) \
{ \
/* If the retcode is 'void', don't return the value of the callback */ \
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
funcobj->callback(funcobj M_MAP3(FUNCOBJI_BASE_ARGCALL, name, __VA_ARGS__) ); \
}
/* Specialization of the definition a function object instance of name 'name'
* with no member attribute.
*/
#define FUNCOBJI_INS_NO_ATTR_DEF(name, instance_t, base_name, param_list, callback_core) \
typedef struct M_C(name, _s) { \
M_C(base_name, _callback_ct) callback; \
} instance_t[1]; \
\
/* Internal type for oplist */ \
typedef instance_t M_C(name, _ct); \
\
static inline M_C(base_name, _retcode_ct) \
M_C(name, _callback)(M_C(base_name, _ct) _self \
M_IF_EMPTY(M_OPFLAT param_list)( \
/* No param */, \
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list) \
) \
) \
{ \
struct M_C(name, _s) *self = (struct M_C(name, _s) *)_self; \
(void) self; /* maybe unused */ \
callback_core; \
} \
\
static inline void \
M_C(name, _init_with)(instance_t obj) \
{ \
obj->callback = M_C(name, _callback); \
} \
\
static inline void \
M_C(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) \
{ \
return (struct M_C(base_name, _s) *) obj; \
} \
\
static inline void \
M_C(name, _init)(instance_t obj) \
{ \
obj->callback = M_C(name, _callback); \
} \
/* Specialization of the definition a function object instance of name 'name'
* with mandatory member attribute.
* First inject oplist in member attributes.
*/
#define FUNCOBJI_INS_ATTR_DEF(name, instance_t, base_name, param_list, callback_core, ...) \
FUNCOBJI_INS_ATTR_DEF_P2(name, instance_t, base_name, param_list, callback_core, FUNCOBJI_INJECT_GLOBAL(__VA_ARGS__) )
/* Inject the oplist within the list of arguments */
#define FUNCOBJI_INJECT_GLOBAL(...) \
M_MAP_C(FUNCOBJI_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 keep (x, type, oplist) if oplist was already present */
#define FUNCOBJI_INJECT_OPLIST_A( duo_or_trio ) \
FUNCOBJI_INJECT_OPLIST_B duo_or_trio
#define FUNCOBJI_INJECT_OPLIST_B( f, ... ) \
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
// Test if all third argument of all arguments is an oplist
#define FUNCOBJI_IF_ALL_OPLIST(...) \
M_IF(M_REDUCE(FUNCOBJI_IS_OPLIST_P, M_AND, __VA_ARGS__))
// Test if the third argument is an oplist. a is a trio (name, type, oplist)
#define FUNCOBJI_IS_OPLIST_P(a) \
M_OPLIST_P(M_RET_ARG3 a)
/* Validate the oplist before going further */
#define FUNCOBJI_INS_ATTR_DEF_P2(name, instance_t, base_name, param_list, callback_core, ...) \
FUNCOBJI_IF_ALL_OPLIST(__VA_ARGS__)(FUNCOBJI_INS_ATTR_DEF_P3, FUNCOBJI_INS_ATTR_DEF_FAILURE)(name, instance_t, base_name, param_list, callback_core, __VA_ARGS__)
/* Stop processing with a compilation failure */
#define FUNCOBJI_INS_ATTR_DEF_FAILURE(name, instance_t, base_name, param_list, callback_core, ...) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(FUNC_OBJ_INS_DEF): at least one of the given argument is not a valid oplist: " #__VA_ARGS__)
/* Expand the Function Object with members */
#define FUNCOBJI_INS_ATTR_DEF_P3(name, instance_t, base_name, param_list, callback_core, ...) \
typedef struct M_C(name, _s) { \
/* Callback is the mandatory first argument */ \
M_C(base_name, _callback_ct) callback; \
/* All the member attribute of the Function Object */ \
M_MAP(FUNCOBJI_INS_ATTR_STRUCT, __VA_ARGS__) \
} instance_t[1]; \
\
/* Internal type for oplist */ \
typedef instance_t M_C(name, _ct); \
\
FUNCOBJI_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_IF_EMPTY(M_OPFLAT param_list)( \
/* No param */, \
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list) \
) \
) \
{ \
struct M_C(name, _s) *self = (struct M_C(name, _s) *)(void*)_self; \
(void) self; /* maybe unused */ \
callback_core; \
} \
\
static inline void \
M_C(name, _init_with)(instance_t obj M_MAP(FUNCOBJI_INS_ATTR_LIST, __VA_ARGS__)) \
{ \
obj->callback = M_C(name, _callback); \
M_MAP(FUNCOBJI_INS_ATTR_INIT_SET, __VA_ARGS__); \
} \
\
static inline void \
M_C(name, _clear)(instance_t obj) \
{ \
M_MAP(FUNCOBJI_INS_ATTR_CLEAR, __VA_ARGS__); \
} \
\
static inline struct M_C(base_name, _s) * \
M_C(name, _as_interface)(instance_t obj) \
{ \
return (struct M_C(base_name, _s) *) obj; \
} \
\
M_IF(FUNCOBJI_TEST_METHOD_P(INIT, __VA_ARGS)) \
( \
static inline void \
M_C(name, _init)(instance_t obj) \
{ \
obj->callback = M_C(name, _callback); \
M_MAP(FUNCOBJI_INS_ATTR_INIT, __VA_ARGS__); \
} \
, /* END OF INIT METHOD */ ) \
/* Define a numbered type of a parameter of the callback*/
#define FUNCOBJI_BASE_TYPE(name, num, type) \
typedef type M_C4(name, _param_, num, _ct);
/* Define a list of the type of arguments for a function definition */
#define FUNCOBJI_BASE_ARGLIST(name, num, type) \
M_DEFERRED_COMMA type M_C(param_, num)
/* Define a list of arguments for a function call */
#define FUNCOBJI_BASE_ARGCALL(name, num, type) \
M_DEFERRED_COMMA M_C(param_, num)
/* Helper macros */
/* arg = (name, type [, oplist]) */
#define FUNCOBJI_INS_ATTR_STRUCT(arg) \
M_RET_ARG2 arg M_RET_ARG1 arg;
#define FUNCOBJI_INS_ATTR_LIST(arg) \
M_DEFERRED_COMMA M_RET_ARG2 arg const M_RET_ARG1 arg
#define FUNCOBJI_INS_ATTR_INIT(arg) \
M_CALL_INIT(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg);
#define FUNCOBJI_INS_ATTR_INIT_SET(arg) \
M_CALL_INIT_SET(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg, M_RET_ARG1 arg);
#define FUNCOBJI_INS_ATTR_CLEAR(arg) \
M_CALL_CLEAR(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg);
/* Define the list of arguments of the instance of the callback */
#define FUNCOBJI_INS_ARGLIST(name, num, param) \
M_DEFERRED_COMMA M_C4(name, _param_, num, _ct) param
/* Macros for testing for a method presence in all the attributes */
#define FUNCOBJI_TEST_METHOD2_P(method, op) \
M_TEST_METHOD_P(method, op)
#define FUNCOBJI_TEST_METHOD1_P(method, arg) \
M_APPLY(FUNCOBJI_TEST_METHOD2_P, method, M_RET_ARG3 arg)
#define FUNCOBJI_TEST_METHOD_P(method, ...) \
M_IF(M_REDUCE2(FUNCOBJI_TEST_METHOD1_P, M_AND, method, __VA_ARGS__))
/* Macro for checking compatible type and oplist for all the attributes */
#define FUNCOBJI_CONTROL_ALL_OPLIST(name, ...) \
M_MAP2(FUNCOBJI_CONTROL_OPLIST, name, __VA_ARGS__)
#define FUNCOBJI_CONTROL_OPLIST(name, a) \
M_CHECK_COMPATIBLE_OPLIST(name, M_RET_ARG1 a, M_RET_ARG2 a, M_RET_ARG3 a)
#endif
+83 -56
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - GENINT module
* M*LIB - Integer Generator (GENINT) module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2021, 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,70 +28,87 @@
#include "m-core.h"
#include "m-atomic.h"
/* GENINT is a container of integers with the following properties:
M_BEGIN_PROTECTED_CODE
/* GENINT is a container providing unique integers.
It has the following properties:
- it stores integer from [0..N) (N is fixed).
- an integer can have only one occurrence in the container.
- you can atomically push in / pop out integer from this container
provided that they were not already in the container.
provided that it is not already in the container.
- there are no order (like FIFO or stack)
This can be used to map integers to index of resources in a table.
At most we can support N = GENINT_LIMBSIZE * GENINT_LIMBSIZE >= 4096
due to the master trick. For the typical usage of this container
At most we can support N = 2048 with the master limb usage.
For the typical usage of this container
(mapping hardware or software limited resources), this should be
enough.
*/
// TO DO: We may want a specialization with constant N value.
// Define the limb size
typedef unsigned long long genint_limb_t;
// Define the limb size used by genint
typedef unsigned long long 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_t mask0; // mask of the last limb
genint_limb_t mask_master; // mask of master
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
atomic_ullong *data; // the bitfield which informs if an integer is used or not
} genint_t[1];
// Define the max supported value
// Define the max absolute supported value
#define GENINT_MAX_ALLOC (GENINT_LIMBSIZE * (GENINT_LIMBSIZE - GENINT_ABA_CPT))
// Define the size of a limb in bits.
#define GENINT_LIMBSIZE (sizeof(genint_limb_t) * CHAR_BIT)
#define GENINT_LIMBSIZE ((unsigned)(sizeof(genint_limb_ct) * CHAR_BIT))
#define GENINT_CONTRACT(s) do { \
assert (s != NULL); \
assert (s->n > 0 && s->n <= GENINT_MAX_ALLOC); \
assert ((s->max+1) * GENINT_LIMBSIZE >= s->n); \
assert (s->data != NULL); \
// Define the contract of a genint
#define GENINT_CONTRACT(s) do { \
M_ASSERT (s != NULL); \
M_ASSERT (s->n > 0 && s->n <= GENINT_MAX_ALLOC); \
M_ASSERT ((s->max+1) * GENINT_LIMBSIZE >= s->n); \
M_ASSERT (s->data != NULL); \
} while (0)
#define GENINT_ONE ((genint_limb_t)1)
// Define the limb one
#define GENINT_ONE ((genint_limb_ct)1)
// Value returned in case of error.
#define GENINT_ERROR (-1U)
#define GENINT_FULL_MASK ULLONG_MAX
// 32 bits of master are kept for handling the ABA problems.
// Value returned in case of error (not integer available).
#define 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
*/
#define GENINT_ABA_CPT 32
#define GENINT_ABA_CPT_T uint32_t
// Set the bit i of master
#define GENINT_MASTER_SET(master, i) \
// Set the bit 'i' of the master limb, and increase ABA counter.
#define GENINT_MASTER_SET(master, i) \
((((master)& (~((GENINT_ONE<< GENINT_ABA_CPT)-1))) | (GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \
|((GENINT_ABA_CPT_T)((master) + 1)))
// Reset the bit i of master
#define GENINT_MASTER_RESET(master, i) \
(((master) & (~((GENINT_ONE<< GENINT_ABA_CPT)-1)) & ~(GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \
// Reset the bit i of the master limb, and increase ABA counter.
#define GENINT_MASTER_RESET(master, i) \
(((master) & (~((GENINT_ONE<< GENINT_ABA_CPT)-1)) & ~(GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \
|((GENINT_ABA_CPT_T)((master) + 1)))
static inline void genint_init(genint_t s, unsigned int n)
/* Initialize an integer generator (CONSTRUCTOR).
* Initialy, the container is full of all the integers up to 'n-1'
* The typical sequence is to initialize the container, and pop
* the integer from it. Each pop integer is **unique** for all threads,
* meaning it can be used to index global unique resources shared
* for all threads.
*/
static inline void
genint_init(genint_t s, unsigned int n)
{
assert (s != NULL && n > 0 && n <= GENINT_MAX_ALLOC);
M_ASSERT (s != NULL && n > 0 && n <= GENINT_MAX_ALLOC);
const size_t alloc = (n + GENINT_LIMBSIZE - 1) / GENINT_LIMBSIZE;
const unsigned int index = n % GENINT_LIMBSIZE;
atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, alloc);
@@ -101,55 +118,61 @@ static inline void genint_init(genint_t s, unsigned int n)
}
s->n = n;
s->data = ptr;
s->max = alloc-1;
s->mask0 = (index == 0) ? -GENINT_ONE : ~((GENINT_ONE<<(GENINT_LIMBSIZE-index))-1);
s->max = (unsigned int) (alloc-1);
s->mask0 = (index == 0) ? GENINT_FULL_MASK : ~((GENINT_ONE<<(GENINT_LIMBSIZE-index))-1);
s->mask_master = (((GENINT_ONE << alloc) - 1) << (GENINT_LIMBSIZE-alloc)) >> GENINT_ABA_CPT;
atomic_init (&s->master, (genint_limb_t)0);
atomic_init (&s->master, (genint_limb_ct)0);
for(unsigned int i = 0; i < alloc; i++)
atomic_init(&s->data[i], (genint_limb_t)0);
atomic_init(&s->data[i], (genint_limb_ct)0);
GENINT_CONTRACT(s);
}
static inline void genint_clear(genint_t s)
/* Clear an integer generator (Destructor) */
static inline void
genint_clear(genint_t s)
{
GENINT_CONTRACT(s);
M_MEMORY_FREE(s->data);
s->data = NULL;
}
static inline size_t genint_size(genint_t s)
/* Return the maximum integer that the generator will provide */
static inline size_t
genint_size(genint_t s)
{
GENINT_CONTRACT(s);
return s->n;
}
// For a typical case, the amortized cost is one CAS per pop.
static inline unsigned int genint_pop(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)
{
GENINT_CONTRACT(s);
// First read master to see which limb is not full.
genint_limb_t master = atomic_load(&s->master);
genint_limb_ct master = atomic_load(&s->master);
// While master is not full
while ((master >> GENINT_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);
assert (i < GENINT_LIMBSIZE);
M_ASSERT (i < GENINT_LIMBSIZE);
// Let's compute the mask of this limb representing the limb as being full
genint_limb_t mask = s->mask0;
mask = (i == s->max) ? mask : -GENINT_ONE;
genint_limb_ct mask = s->mask0;
mask = (i == s->max) ? mask : GENINT_FULL_MASK;
unsigned int bit;
// Let's load this limb,
genint_limb_t next, org = atomic_load(&s->data[i]);
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))
goto next_element;
assert (org != -GENINT_ONE);
M_ASSERT (org != GENINT_FULL_MASK);
// At least one bit is free in the limb. Find one.
bit = GENINT_LIMBSIZE - 1 - m_core_clz64(~org);
assert (bit < GENINT_LIMBSIZE);
assert ((org & (GENINT_ONE<<bit)) == 0);
assert (i * GENINT_LIMBSIZE + GENINT_LIMBSIZE - 1 - bit < s->n);
M_ASSERT (bit < GENINT_LIMBSIZE);
M_ASSERT ((org & (GENINT_ONE<<bit)) == 0);
M_ASSERT (i * GENINT_LIMBSIZE + GENINT_LIMBSIZE - 1 - bit < s->n);
// Set the integer as being used.
next = org | (GENINT_ONE << bit);
// Try to reserve the integer
@@ -158,7 +181,7 @@ static inline unsigned int genint_pop(genint_t s)
// If the limb is now full, try to update master
if (M_UNLIKELY(next == mask)) {
while (true) {
genint_limb_t newMaster;
genint_limb_ct newMaster;
if (next == mask) {
newMaster = GENINT_MASTER_SET(master, i);
} else {
@@ -181,30 +204,32 @@ static inline unsigned int genint_pop(genint_t s)
return GENINT_ERROR; // No more resource available
}
// For a typical case, the amortized cost is one CAS per pop.
static inline void genint_push(genint_t s, unsigned int n)
/* 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)
{
GENINT_CONTRACT(s);
assert (n < s->n);
M_ASSERT (n < s->n);
const unsigned int i = n / GENINT_LIMBSIZE;
const unsigned int bit = GENINT_LIMBSIZE - 1 - (n % GENINT_LIMBSIZE);
genint_limb_t master = atomic_load(&s->master);
genint_limb_ct master = atomic_load(&s->master);
// Load the limb
genint_limb_t next, org = atomic_load(&s->data[i]);
genint_limb_ct next, org = atomic_load(&s->data[i]);
do {
assert ((org & (GENINT_ONE << bit)) != 0);
M_ASSERT ((org & (GENINT_ONE << bit)) != 0);
// Reset it
next = org & (~(GENINT_ONE << bit));
// 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_t mask = s->mask0;
mask = (i == s->max) ? mask : -GENINT_ONE;
genint_limb_ct mask = s->mask0;
mask = (i == s->max) ? mask : GENINT_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_t newMaster;
genint_limb_ct newMaster;
if (next == mask) {
newMaster = GENINT_MASTER_SET(master, i);
} else {
@@ -219,4 +244,6 @@ static inline void genint_push(genint_t s, unsigned int n)
GENINT_CONTRACT(s);
}
M_END_PROTECTED_CODE
#endif
+582 -516
View File
File diff suppressed because it is too large. Load diff
+189 -97
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - INTRUSIVE SHARED PTR Module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2021, 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,119 +28,211 @@
#include "m-core.h"
#include "m-atomic.h"
M_BEGIN_PROTECTED_CODE
/* Define the oplist of a intrusive shared pointer.
USAGE: ISHARED_OPLIST(name [, oplist_of_the_type]) */
#define ISHARED_PTR_OPLIST(...) \
ISHAREDI_PTR_OPLIST(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
(__VA_ARGS__ )))
#define ISHARED_PTR_OPLIST(...) \
ISHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
(__VA_ARGS__ )))
/* Interface to add to a structure to allow intrusive support.
name: name of the intrusive shared pointer.
type: name of the type of the structure (aka. struct test_s) - not used currently.
NOTE: There can be only one interface of this kind in a type! */
#define ISHARED_PTR_INTERFACE(name, type) \
#define ISHARED_PTR_INTERFACE(name, type) \
atomic_int M_C(name, _cpt)
/* Value of the interface field for static intialization (Uses C99 designated element). */
#define ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
.M_C(name, _cpt) = ATOMIC_VAR_INIT(0)
/* Value of the interface field for static intialization (Uses C89 designated element). */
#define ISHARED_PTR_STATIC_INIT(name, type) \
ATOMIC_VAR_INIT(0)
/* Define the intrusive shared pointer type and its static inline functions.
USAGE: ISHARED_PTR_DEF(name[, oplist]) */
#define ISHARED_PTR_DEF(name, ...) \
ISHAREDI_PTR_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
(name, __VA_ARGS__ )))
USAGE: ISHARED_PTR_DEF(name, type, [, oplist]) */
#define ISHARED_PTR_DEF(name, ...) \
M_BEGIN_PROTECTED_CODE \
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t) ), \
(name, __VA_ARGS__ , M_C(name, _t) ))) \
M_END_PROTECTED_CODE
/* Define the intrusive shared pointer type and its static inline functions
as the name name_t
USAGE: ISHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
#define ISHARED_PTR_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
(name, __VA_ARGS__ , name_t ))) \
M_END_PROTECTED_CODE
/********************************** INTERNAL ************************************/
#define ISHAREDI_PTR_OPLIST(arg) ISHAREDI_PTR_OPLIST2 arg
// Deferred evaluation
#define ISHAREDI_PTR_OPLIST_P1(arg) ISHAREDI_PTR_OPLIST_P2 arg
#define ISHAREDI_PTR_OPLIST2(name, oplist) ( \
INIT(M_INIT_DEFAULT), \
INIT_SET(M_C(name, _init_set2) M_IPTR), \
SET(M_C(name, _set) M_IPTR), \
CLEAR(M_C(name, _clear)), \
CLEAN(M_C(name, _clean) M_IPTR), \
TYPE(M_C(name, _type_t)), \
OPLIST(oplist), \
SUBTYPE(M_C(name, _type_t)) \
,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),) \
/* Validation of the given oplist */
#define ISHAREDI_PTR_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(ISHAREDI_PTR_OPLIST_P3, ISHAREDI_PTR_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define ISHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
((M_LIB_ERROR(ARGUMENT_OF_ISHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
// Define the oplist
#define ISHAREDI_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)), \
CLEAN(M_C(name, _clean) M_IPTR), \
TYPE(M_C(name, _ct)), \
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),) \
)
#define ISHAREDI_PTR_DEF(arg) ISHAREDI_PTR_DEF2 arg
// Deferred evaluatioin
#define ISHAREDI_PTR_DEF_P1(arg) ISHAREDI_PTR_DEF_P2 arg
#define ISHAREDI_PTR_DEF2(name, type, oplist) \
\
typedef type *M_C(name,_t); \
typedef type M_C(name, _type_t); \
\
static inline M_C(name,_t) \
M_C(name, _init)(type *ptr) \
{ \
if (M_LIKELY (ptr != NULL)) \
atomic_init(&ptr->M_C(name, _cpt), 1); \
return ptr; \
} \
\
static inline M_C(name,_t) \
M_C(name, _init_set)(M_C(name,_t) shared) \
{ \
if (M_LIKELY (shared != NULL)) { \
int n = atomic_fetch_add(&(shared->M_C(name, _cpt)), 1); \
(void) n; \
} \
return shared; \
} \
\
static inline void \
M_C(name, _init_set2)(M_C(name,_t) *ptr, M_C(name,_t) shared) \
{ \
assert (ptr != NULL); \
*ptr = M_C(name, _init_set)(shared); \
} \
\
static inline M_C(name,_t) \
M_C(name, _init_new)(void) \
{ \
type *ptr = M_CALL_NEW(oplist, type); \
if (ptr == NULL) { \
M_MEMORY_FULL(sizeof(type)); \
return NULL; \
} \
M_CALL_INIT(oplist, *ptr); \
atomic_init (&ptr->M_C(name, _cpt), 1); \
return ptr; \
} \
\
static inline void \
M_C(name, _clear)(M_C(name,_t) shared) \
{ \
if (shared != NULL) { \
if (atomic_fetch_sub(&(shared->M_C(name, _cpt)), 1) == 1) { \
M_CALL_CLEAR(oplist, *shared); \
M_IF_DISABLED_METHOD(DEL, oplist)(, M_CALL_DEL(oplist, shared);) \
} \
} \
} \
\
static inline void \
M_C(name, _clean)(M_C(name,_t) *shared) \
{ \
M_C(name, _clear)(*shared); \
*shared = NULL; \
} \
\
static inline void \
M_C(name, _set)(M_C(name,_t) *ptr, M_C(name,_t)shared) \
{ \
assert (ptr != NULL); \
if (M_LIKELY (*ptr != shared)) { \
M_C(name, _clear)(*ptr); \
*ptr = M_C(name, _init_set)(shared); \
} \
} \
\
/* Validate the oplist before going further */
#define ISHAREDI_PTR_DEF_P2(name, type, oplist, shared_t) \
M_IF_OPLIST(oplist)(ISHAREDI_PTR_DEF_P3, ISHAREDI_PTR_DEF_FAILURE)(name, type, oplist, shared_t)
/* Stop processing with a compilation failure */
#define ISHAREDI_PTR_DEF_FAILURE(name, type, oplist, shared_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ISHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
#define ISHAREDI_PTR_DEF_P3(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); \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline shared_t \
M_C(name, _init)(type *ptr) \
{ \
/* Initialize the type referenced by the pointer */ \
if (M_LIKELY (ptr != NULL)) { \
atomic_init(&ptr->M_C(name, _cpt), 2); \
} \
return ptr; \
} \
\
static inline shared_t \
M_C(name, _init_set)(shared_t shared) \
{ \
if (M_LIKELY (shared != NULL)) { \
int n = atomic_fetch_add(&(shared->M_C(name, _cpt)), 2); \
(void) n; \
} \
return shared; \
} \
\
M_IF_METHOD(INIT, oplist)( \
M_IF_DISABLED_METHOD(NEW, oplist) \
( \
/* This function is only for static object */ \
static inline shared_t \
M_C(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 n; \
do { \
n = o + 1 + (o != 0); \
} while (!atomic_compare_exchange_strong(&(shared->M_C(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); \
} 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 ) { \
m_core_backoff_wait(bkoff); \
} \
} \
M_ASSERT( (atomic_load(&(shared->M_C(name, _cpt)))&1) == 0); \
} \
return shared; \
} \
, \
/* This function is only for dynamic object */ \
static inline shared_t \
M_C(name, _init_new)(void) \
{ \
type *ptr = M_CALL_NEW(oplist, type); \
if (ptr == NULL) { \
M_MEMORY_FULL(sizeof(type)); \
return NULL; \
} \
M_CALL_INIT(oplist, *ptr); \
atomic_init (&ptr->M_C(name, _cpt), 2); \
return ptr; \
} \
/* End of NEW */) \
, /* End of INIT */) \
\
static inline void \
M_C(name, _clear)(shared_t shared) \
{ \
if (shared != NULL) { \
if (atomic_fetch_sub(&(shared->M_C(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_ASSERT(shared != NULL); \
M_C(name, _clear)(*shared); \
*shared = NULL; \
} \
\
static inline void \
M_C(name, _clean)(shared_t *shared) \
{ \
M_C(name, _clear)(*shared); \
*shared = NULL; \
} \
\
static inline void \
M_C(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_END_PROTECTED_CODE
#endif
+1403 -1224
View File
File diff suppressed because it is too large. Load diff
+127 -95
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - MEMPOOL module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2021, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -37,113 +37,145 @@
*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
*/
// NOTE: Can not use m-list since it may be expanded from LIST_DEF
#define MEMPOOL_DEF(name, type) \
M_BEGIN_PROTECTED_CODE \
MEMPOOL_DEF_P2(name, type, M_C(name, _t) ) \
M_END_PROTECTED_CODE
/* Fast Fixed Size thread unsafe allocator based on memory region.
USAGE:
MEMPOOL_DEF_AS(memppol_uint, name_t, unsigned int)
*/
#define MEMPOOL_DEF_AS(name, name_t, type) \
M_BEGIN_PROTECTED_CODE \
MEMPOOL_DEF_P2(name, type, name_t ) \
M_END_PROTECTED_CODE
#define MEMPOOL_DEF(name, type) \
\
typedef union M_C(name,_union_s) { \
type t; \
union M_C(name,_union_s) *next; \
} M_C(name,_union_t); \
\
typedef struct M_C(name,_segment_s) { \
unsigned int count; \
struct M_C(name,_segment_s) *next; \
M_C(name,_union_t) tab[MEMPOOL_MAX_PER_SEGMENT(type)]; \
} M_C(name,_segment_t); \
\
typedef struct M_C(name, _s) { \
M_C(name,_union_t) *free_list; \
M_C(name,_segment_t) *current_segment; \
} M_C(name,_t)[1]; \
\
static inline void \
M_C(name,_init)(M_C(name,_t) mem) \
{ \
mem->free_list = NULL; \
mem->current_segment = M_MEMORY_ALLOC(M_C(name,_segment_t)); \
if (mem->current_segment == NULL) { \
M_MEMORY_FULL(sizeof (M_C(name,_segment_t))); \
return; \
} \
mem->current_segment->next = NULL; \
mem->current_segment->count = 0; \
MEMPOOLI_CONTRACT(mem, type); \
} \
\
static inline void \
M_C(name,_clear)(M_C(name,_t) mem) \
{ \
MEMPOOLI_CONTRACT(mem, type); \
M_C(name,_segment_t) *segment = mem->current_segment; \
while (segment != NULL) { \
M_C(name,_segment_t) *next = segment->next; \
M_MEMORY_DEL (segment); \
segment = next; \
} \
/* Clean pointers to be safer */ \
mem->free_list = NULL; \
mem->current_segment = NULL; \
} \
\
static inline type * \
M_C(name,_alloc)(M_C(name,_t) mem) \
{ \
MEMPOOLI_CONTRACT(mem, type); \
M_C(name,_union_t) *ret = mem->free_list; \
if (ret != NULL) { \
mem->free_list = ret->next; \
return &ret->t; \
} \
M_C(name,_segment_t) *segment = mem->current_segment; \
assert(segment != NULL); \
unsigned int count = segment->count; \
if (M_UNLIKELY (count >= MEMPOOL_MAX_PER_SEGMENT(type))) { \
M_C(name,_segment_t) *new_segment = M_MEMORY_ALLOC (M_C(name,_segment_t)); \
if (M_UNLIKELY (new_segment == NULL)) { \
M_MEMORY_FULL(sizeof (M_C(name,_segment_t))); \
return NULL; \
} \
new_segment->next = segment; \
new_segment->count = 0; \
mem->current_segment = new_segment; \
segment = new_segment; \
count = 0; \
} \
ret = &segment->tab[count]; \
segment->count = count + 1; \
MEMPOOLI_CONTRACT(mem, type); \
return &ret->t; \
} \
\
static inline void \
M_C(name,_free)(M_C(name,_t) mem, type *ptr) \
{ \
MEMPOOLI_CONTRACT(mem, type); \
/* NOTE: Unsafe cast: suppose that the given pointer \
was allocated by the previous alloc function. */ \
M_C(name,_union_t) *ret = (M_C(name,_union_t) *)(uintptr_t)ptr; \
ret->next = mem->free_list; \
mem->free_list = ret; \
MEMPOOLI_CONTRACT(mem, type); \
} \
/* User shall be able to cutomize the size of the segment and/or
the minimun number of elements.
The default is the number of elements that fits in 16KB.
*/
#ifndef MEMPOOL_MAX_PER_SEGMENT
#define MEMPOOL_MAX_PER_SEGMENT(type) \
#define MEMPOOL_MAX_PER_SEGMENT(type) \
M_MAX((16*1024-sizeof(unsigned int) - 2*sizeof(void*)) / sizeof (type), 256U)
#endif
/********************************** INTERNAL ************************************/
#define MEMPOOL_DEF_P2(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) { \
type t; \
union M_C(name,_union_s) *next; \
} M_C(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) { \
unsigned int count; \
struct M_C(name,_segment_s) *next; \
M_C(name,_union_ct) tab[MEMPOOL_MAX_PER_SEGMENT(type)]; \
} M_C(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; \
} name_t[1]; \
\
static inline void \
M_C(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))); \
return; \
} \
mem->current_segment->next = NULL; \
mem->current_segment->count = 0; \
MEMPOOLI_CONTRACT(mem, type); \
} \
\
static inline void \
M_C(name,_clear)(name_t mem) \
{ \
MEMPOOLI_CONTRACT(mem, type); \
M_C(name,_segment_ct) *segment = mem->current_segment; \
while (segment != NULL) { \
M_C(name,_segment_ct) *next = segment->next; \
M_MEMORY_DEL (segment); \
segment = next; \
} \
/* Clean pointers to be safer */ \
mem->free_list = NULL; \
mem->current_segment = NULL; \
} \
\
static inline type * \
M_C(name,_alloc)(name_t mem) \
{ \
MEMPOOLI_CONTRACT(mem, type); \
/* Test if one object is in the free list */ \
M_C(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_ASSERT(segment != NULL); \
unsigned int count = segment->count; \
/* If segment is full, allocate a new one from the system */ \
if (M_UNLIKELY (count >= 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))); \
return NULL; \
} \
new_segment->next = segment; \
new_segment->count = 0; \
mem->current_segment = new_segment; \
segment = new_segment; \
count = 0; \
} \
/* Return the object as the last element of the current segment */ \
ret = &segment->tab[count]; \
segment->count = count + 1; \
MEMPOOLI_CONTRACT(mem, type); \
return &ret->t; \
} \
\
static inline void \
M_C(name,_free)(name_t mem, type *ptr) \
{ \
MEMPOOLI_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; \
/* Add the object back in the free list */ \
ret->next = mem->free_list; \
mem->free_list = ret; \
/* NOTE: the objects are NOT given back to the system until the mempool \
is fully cleared */ \
MEMPOOLI_CONTRACT(mem, type); \
} \
#define MEMPOOLI_CONTRACT(mempool, type) do { \
assert((mempool) != NULL); \
assert((mempool)->current_segment != NULL); \
assert((mempool)->current_segment->count <= MEMPOOL_MAX_PER_SEGMENT(type)); \
/* MEMPOOL contract */
#define MEMPOOLI_CONTRACT(mempool, type) do { \
M_ASSERT((mempool) != NULL); \
M_ASSERT((mempool)->current_segment != NULL); \
M_ASSERT((mempool)->current_segment->count <= MEMPOOL_MAX_PER_SEGMENT(type)); \
} while (0)
#endif
+162 -34
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Thin Mutex & Thread wrapper
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2021, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -25,108 +25,173 @@
#ifndef MSTARLIB_MUTEX_H
#define MSTARLIB_MUTEX_H
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \
/* 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);
assert (rc == thrd_success);
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 = usec / 1000000ULL;
tv.tv_nsec = (usec % 1000000ULL) * 1000UL;
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_oncei_t[1];
typedef once_flag m_once_ct[1];
// Initial value for m_once_ct
#define M_ONCEI_INIT_VALUE { ONCE_FLAG_INIT }
static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
// 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
// MSYS2 doesn't define _WIN32 by default.
#elif defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
/****************************** 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
@@ -135,83 +200,112 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
#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) func, arg, 0, NULL);
*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;
assert (dwWaitResult == WAIT_OBJECT_0);
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;
ft.QuadPart = -(10ULL*usec);
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);
@@ -222,7 +316,7 @@ static inline bool m_thread_sleep(unsigned long long usec)
// Internal type, not exported.
typedef INIT_ONCE m_oncei_t[1];
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)
{
@@ -233,20 +327,24 @@ static inline BOOL CALLBACK m_oncei_callback( PINIT_ONCE InitOnce, PVOID Paramet
(*func)();
return TRUE;
}
static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
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
#else
M_END_PROTECTED_CODE
/**************************** PTHREAD version ******************************/
#else
#include <pthread.h>
#ifdef _POSIX_PRIORITY_SCHEDULING
@@ -259,76 +357,103 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
#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.
assert (_rc == 0);
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
@@ -336,30 +461,33 @@ static inline void m_thread_yield(void)
#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 = usec / 1000000ULL;
tv.tv_usec = usec % 1000000ULL;
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_oncei_t[1];
typedef pthread_once_t m_once_ct[1];
#define M_ONCEI_INIT_VALUE { PTHREAD_ONCE_INIT }
static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
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: m_thread_sleep doesn't yield thread during waiting, making it a poor choice for active waiting.
// TODO: Obsolete M_LOCK macro.
/* M_LOCK macro. Allow simple locking encapsulation.
@@ -375,25 +503,25 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
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) \
# 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_oncei_t 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)), \
# 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) \
# 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); \
#define M_LOCKI_DO(name, cont, lock_func, unlock_func) \
for(bool cont = true \
; cont && (lock_func (name), true); \
(unlock_func (name), cont = false))
#endif
+392 -302
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - dynamic priority queue module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2021, 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:
@@ -26,323 +26,413 @@
#define MSTARLIB_PRIOQUEUE_H
#include "m-core.h"
#include "m-array.h"
#include "m-array.h" /* Priority queue are built upon array */
/* Priority queue based on binary heap implementation */
/* Define a prioqueue of a given type and its associated functions.
USAGE: PRIOQUEUE_DEF(name, type [, oplist_of_the_type]) */
#define PRIOQUEUE_DEF(name, ...) \
PRIOQUEUEI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name,_it_t) ), \
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t))))
#define PRIOQUEUE_DEF(name, ...) \
M_BEGIN_PROTECTED_CODE \
PRIOQUEUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name,_it_t) ), \
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t)))) \
M_END_PROTECTED_CODE
/* 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, ...) \
M_BEGIN_PROTECTED_CODE \
PRIOQUEUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
(name, __VA_ARGS__, name_t, it_t ))) \
M_END_PROTECTED_CODE
/* Define the oplist of a prioqueue of type.
USAGE: PRIOQUEUE_OPLIST(name[, oplist of the type]) */
#define PRIOQUEUE_OPLIST(...) \
PRIOQUEUEI_OPLIST(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
(__VA_ARGS__ )))
#define PRIOQUEUE_OPLIST(...) \
PRIOQUEUEI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
(__VA_ARGS__ )))
/********************************** INTERNAL ************************************/
#define PRIOQUEUEI_OPLIST(arg) PRIOQUEUEI_OPLIST2 arg
#define PRIOQUEUEI_DEF(arg) PRIOQUEUEI_DEF2 arg
/* Deferred evaluation for the definition,
so that all arguments are evaluated before further expansion */
#define PRIOQUEUEI_OPLIST_P1(arg) PRIOQUEUEI_OPLIST_P2 arg
#define PRIOQUEUEI_OPLIST2(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)) \
,TYPE(M_C(name,_t)) \
,SUBTYPE(M_C(name, _type_t)) \
,CLEAN(M_C(name,_clean)) \
,PUSH(M_C(name,_push)) \
,POP(M_C(name,_pop)) \
,OPLIST(oplist) \
,TEST_EMPTY(M_C(name, _empty_p)), \
,GET_SIZE(M_C(name, _size)) \
/* Validation of the given oplist */
#define PRIOQUEUEI_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(PRIOQUEUEI_OPLIST_P3, PRIOQUEUEI_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define PRIOQUEUEI_OPLIST_FAILURE(name, oplist) \
((M_LIB_ERROR(ARGUMENT_OF_PRIOQUEUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
/* Define oplist of a priority queue */
#define PRIOQUEUEI_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)) \
,TYPE(M_C(name,_ct)) \
,SUBTYPE(M_C(name, _subtype_ct)) \
,CLEAN(M_C(name,_clean)) \
,PUSH(M_C(name,_push)) \
,POP(M_C(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)), \
)
#define PRIOQUEUEI_DEF2(name, type, oplist, prioqueue_t, it_t) \
ARRAY_DEF(M_C(name, _array), type, oplist) \
\
typedef type M_C(name, _type_t); \
\
typedef struct M_C(name, _s) { \
M_C(name, _array_t) array; \
} prioqueue_t[1]; \
typedef struct M_C(name, _s) *M_C(name, _ptr); \
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
\
typedef M_C(name, _array_it_t) it_t; \
\
static inline void \
M_C(name, _init)(prioqueue_t p) \
{ \
M_C(name, _array_init)(p->array); \
} \
\
static inline void \
M_C(name, _init_set)(prioqueue_t p, prioqueue_t o) \
{ \
M_C(name, _array_init_set)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _set)(prioqueue_t p, prioqueue_t o) \
{ \
M_C(name, _array_set)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _clear)(prioqueue_t p) \
{ \
M_C(name, _array_clear)(p->array); \
} \
\
static inline void \
M_C(name, _init_move)(prioqueue_t p, prioqueue_t o) \
{ \
M_C(name, _array_init_move)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _move)(prioqueue_t p, prioqueue_t o) \
{ \
M_C(name, _array_move)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _swap)(prioqueue_t p, prioqueue_t o) \
{ \
M_C(name, _array_swap)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _clean)(prioqueue_t p) \
{ \
M_C(name, _array_clean)(p->array); \
} \
\
static inline size_t \
M_C(name, _i_parent)(size_t i) \
{ \
assert (i > 0); \
return (i - 1) / 2; \
} \
\
static inline size_t \
M_C(name, _i_lchild)(size_t i) \
{ \
assert(i <= ((-(size_t)1)-2)/2); \
return 2*i + 1; \
} \
\
static inline size_t \
M_C(name, _i_rchild)(size_t i) \
{ \
assert(i <= ((-(size_t)1)-2)/2); \
return 2*i + 2; \
} \
\
static inline int \
M_C(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)); \
} \
\
static inline bool \
M_C(name, _empty_p)(const prioqueue_t p) \
{ \
return M_C(name, _array_empty_p)(p->array); \
} \
\
static inline size_t \
M_C(name, _size)(const prioqueue_t p) \
{ \
return M_C(name, _array_size)(p->array); \
} \
\
static inline void \
M_C(name, _push)(prioqueue_t p, type const x) \
{ \
M_C(name, _array_push_back)(p->array, x); \
\
size_t i = M_C(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) \
break; \
M_C(name, _array_swap_at) (p->array, i, j); \
i = j; \
} \
} \
\
static inline type const * \
M_C(name, _front)(prioqueue_t p) \
{ \
return M_C(name, _array_cget)(p->array, 0); \
} \
\
static inline void \
M_C(name, _pop)(type *x, prioqueue_t p) \
{ \
size_t size = M_C(name, _array_size)(p->array)-1; \
M_C(name, _array_swap_at) (p->array, 0, size); \
M_C(name, _array_pop_back)(x, p->array); \
\
size_t i = 0; \
while (true) { \
size_t child = M_C(name, _i_lchild)(i); \
if (child >= size) break; \
size_t otherChild = M_C(name, _i_rchild)(i); \
if (otherChild < size \
&& M_C(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); \
i = child; \
} \
} \
\
static inline void \
M_C(name, _it)(it_t it, const prioqueue_t v) \
{ \
M_C(name, _array_it)(it, v->array); \
} \
\
static inline void \
M_C(name, _it_last)(it_t it, const prioqueue_t v) \
{ \
M_C(name, _array_it_last)(it, v->array); \
} \
\
static inline void \
M_C(name, _it_end)(it_t it, const prioqueue_t 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, _erase)(prioqueue_t p, type x) \
{ \
/* 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), x)) \
break; \
} \
/* 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); \
/* Deferred evaluation for the definition,
so that all arguments are evaluated before further expansion */
#define PRIOQUEUEI_DEF_P1(arg) PRIOQUEUEI_DEF_P2 arg
/* Validate the oplist before going further */
#define PRIOQUEUEI_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
M_IF_OPLIST(oplist)(PRIOQUEUEI_DEF_P3, PRIOQUEUEI_DEF_FAILURE)(name, type, oplist, prioqueue_t, it_t)
/* Stop processing with a compilation failure */
#define PRIOQUEUEI_DEF_FAILURE(name, type, oplist, prioqueue_t, it_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(PRIOQUEUE_DEF): the given argument is not a valid oplist: " #oplist)
/* Define the priority queue:
- name: prefix to use,
- type: type of the contained objects,
- oplist: oplist of the contained objects,
- prioqueue_t: type of the container,
- it_t: iterator of the container
*/
#define PRIOQUEUEI_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) \
\
/* Define the priority queue over the defined array */ \
typedef struct M_C(name, _s) { \
M_C(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); \
\
/* The iterator is the same one as the one of the internal array */ \
typedef M_C(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); \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void \
M_C(name, _init)(prioqueue_t p) \
{ \
M_C(name, _array_init)(p->array); \
} \
\
static inline void \
M_C(name, _init_set)(prioqueue_t p, prioqueue_t const o) \
{ \
M_C(name, _array_init_set)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _set)(prioqueue_t p, prioqueue_t const o) \
{ \
M_C(name, _array_set)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _clear)(prioqueue_t p) \
{ \
M_C(name, _array_clear)(p->array); \
} \
\
static inline void \
M_C(name, _init_move)(prioqueue_t p, prioqueue_t o) \
{ \
M_C(name, _array_init_move)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _move)(prioqueue_t p, prioqueue_t o) \
{ \
M_C(name, _array_move)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _swap)(prioqueue_t p, prioqueue_t o) \
{ \
M_C(name, _array_swap)(p->array, o->array); \
} \
\
static inline void \
M_C(name, _clean)(prioqueue_t p) \
{ \
M_C(name, _array_clean)(p->array); \
} \
\
static inline size_t \
M_C(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_ASSERT(i <= ((SIZE_MAX)-2)/2); \
return 2*i + 1; \
} \
\
static inline size_t \
M_C(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) \
{ \
return M_CALL_CMP(oplist, *M_C(name, _array_cget)(p->array, i), \
*M_C(name, _array_cget)(p->array, j)); \
} \
\
static inline bool \
M_C(name, _empty_p)(prioqueue_t const p) \
{ \
return M_C(name, _array_empty_p)(p->array); \
} \
\
static inline size_t \
M_C(name, _size)(prioqueue_t const p) \
{ \
return M_C(name, _array_size)(p->array); \
} \
\
static inline void \
M_C(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); \
\
/* 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; \
while (i > 0) { \
size_t j = M_C(name, _i_parent)(i); \
if (M_C(name, _i_cmp)(p, j, i) <= 0) \
break; \
M_C(name, _array_swap_at) (p->array, i, j); \
i = j; \
} \
} \
\
static inline type const * \
M_C(name, _front)(prioqueue_t const p) \
{ \
return M_C(name, _array_cget)(p->array, 0); \
} \
\
static inline void \
M_C(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); \
/* Swap the new last element */ \
M_C(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); \
if (child >= size) \
break; \
size_t otherChild = M_C(name, _i_rchild)(i); \
if (otherChild < size \
&& M_C(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); \
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) \
{ \
return M_C(name, _array_equal_p)(p->array, q->array); \
} \
\
static inline bool \
M_C(name, _erase)(prioqueue_t p, type 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 i = 0; \
for(i = 0; i < size; i++) { \
if (M_CALL_EQUAL(oplist, *M_C(name, _array_cget)(p->array, i), x)) \
break; \
} \
/* 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); \
/* Move back the last swapped element to its right position in the heap */ \
while (true) { \
size_t child = M_C(name, _i_lchild)(i); \
if (child >= size) break; \
size_t otherChild = M_C(name, _i_rchild)(i); \
if (otherChild < size \
&& M_C(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); \
i = child; \
} \
return true; \
} \
\
static inline void \
M_C(name, _update_further)(prioqueue_t p, type xold, type xnew) \
{ \
/* This update assumes that the new position is further in the heap */ \
assert (M_CALL_CMP(oplist, xold, xnew) > 0); \
/* 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; \
} \
/* We shall have found the item */ \
assert (i < size); \
/* Set the found item to the new element */ \
M_C(name, _array_set_at) (p->array, i, xnew); \
/* Move back the updated element to its right position in the heap */ \
while (true) { \
size_t child = M_C(name, _i_lchild)(i); \
if (child >= size) break; \
size_t otherChild = M_C(name, _i_rchild)(i); \
if (otherChild < size \
&& M_C(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); \
i = child; \
} \
} \
\
, /* No EQUAL */ \) \
while (true) { \
size_t child = M_C(name, _i_lchild)(i); \
if (child >= size) break; \
size_t otherChild = M_C(name, _i_rchild)(i); \
if (otherChild < size \
&& M_C(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); \
i = child; \
} \
return true; \
} \
\
static inline void \
M_C(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; \
} \
/* 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); \
/* Set the found item to the new element */ \
M_C(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); \
if (child >= size) break; \
size_t otherChild = M_C(name, _i_rchild)(i); \
if (otherChild < size \
&& M_C(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); \
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); \
i = parent; \
} \
} \
} \
, /* No EQUAL */ ) \
// TODO: set all & remove all function
+1077 -920
View File
File diff suppressed because it is too large. Load diff
+593
View File
@@ -0,0 +1,593 @@
/*
* M*LIB - Serial BIN
*
* Copyright (c) 2017-2021, 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_SERIAL_BIN_H
#define MSTARLIB_SERIAL_BIN_H
#include <stdint.h>
#include "m-core.h"
#include "m-string.h"
M_BEGIN_PROTECTED_CODE
/* 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)
{
bool b;
if (M_LIKELY(size < 253))
{
b = EOF != fputc((unsigned char) size, f);
} else if (size < 1ULL << 16) {
b = EOF != fputc(253, f); // Save 16 bits encoding
b &= EOF != fputc((unsigned char) (size >> 8), f);
b &= EOF != fputc((unsigned char) size, f);
}
// For 32 bits systems, don't encode a 64 bits size_t
#if SIZE_MAX < 1ULL<< 32
else {
b = EOF != fputc(254, f); // Save 32 bits encoding
b &= EOF != fputc((unsigned char) (size >> 24), f);
b &= EOF != fputc((unsigned char) (size >> 16), f);
b &= EOF != fputc((unsigned char) (size >> 8), f);
b &= EOF != fputc((unsigned char) size, f);
}
#else
else if (size < 1ULL<< 32) {
b = EOF != fputc(254, f); // Save 32 bits encoding
b &= EOF != fputc((unsigned char) (size >> 24), f);
b &= EOF != fputc((unsigned char) (size >> 16), f);
b &= EOF != fputc((unsigned char) (size >> 8), f);
b &= EOF != fputc((unsigned char) size, f);
} else {
b = EOF != fputc(255, f); // Save 64 bits encoding
b &= EOF != fputc((unsigned char) (size >> 56), f);
b &= EOF != fputc((unsigned char) (size >> 48), f);
b &= EOF != fputc((unsigned char) (size >> 40), f);
b &= EOF != fputc((unsigned char) (size >> 32), f);
b &= EOF != fputc((unsigned char) (size >> 24), f);
b &= EOF != fputc((unsigned char) (size >> 16), f);
b &= EOF != fputc((unsigned char) (size >> 8), f);
b &= EOF != fputc((unsigned char) size, f);
}
#endif
return b;
}
/* Internal service:
* 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)
{
int c;
c = fgetc(f);
if (M_UNLIKELY(c == EOF)) return false;
if (M_LIKELY(c < 253)) {
*size = (size_t) c;
return true;
}
size_t s = 0;
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;
s = (s << 8) | (size_t) c;
}
*size = s;
return true;
}
/* 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)
{
FILE *f = (FILE *)serial->data[0].p;
size_t n = fwrite (M_ASSIGN_CAST(const void*, &data), sizeof (bool), 1, f);
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_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;
n = fwrite (M_ASSIGN_CAST(const void*, &i8), sizeof i8, 1, f);
break;
case 2:
i16 = (int16_t) data;
n = fwrite (M_ASSIGN_CAST(const void*, &i16), sizeof i16, 1, f);
break;
case 4:
i32 = (int32_t) data;
n = fwrite (M_ASSIGN_CAST(const void*, &i32), sizeof i32, 1, f);
break;
case 8:
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)
{
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;
n = fwrite (M_ASSIGN_CAST(const void*, &f1), sizeof f1, 1, f);
} else if (size_of_type == sizeof f2) {
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");
}
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_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();
// 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);
return (n == length) ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Start writing an array of 'number_of_elements' objects into the serial stream 'serial'.
If 'number_of_elements' is 0, then either the array has no data,
or the number of elements of the array is unkown.
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)
{
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)
{
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;
}
}
/* 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)
{
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;
}
}
/* 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)
{
(void) local; // argument not used
(void) serial;
return M_SERIAL_OK_CONTINUE;
}
/* Start writing a tuple into the serial stream '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)
{
(void) local; // argument not used
(void) serial;
return M_SERIAL_OK_CONTINUE;
}
/* Start writing the field named field_name[index] of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_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;
(void) field_name;
(void) max;
(void) index; // Assume index are write in order from 0 to max.
return M_SERIAL_OK_CONTINUE;
}
/* 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)
{
(void) local; // argument not used
(void) serial;
return M_SERIAL_OK_DONE;
}
/* Start writing a variant into the serial stream 'serial'.
If index <= 0, the variant is empty.
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)
{
(void) field_name;
(void) max;
(void) local;
FILE *f = (FILE *)serial->data[0].p;
size_t n = fwrite (M_ASSIGN_CAST(const void*, &index), sizeof index, 1, f);
return n == 1 ? ((index < 0) ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE) : m_core_serial_fail();
}
/* 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)
{
(void) local; // argument not used
(void) serial;
return M_SERIAL_OK_DONE;
}
/* 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 inline void m_serial_bin_write_init(m_serial_write_t serial, FILE *f)
{
serial->m_interface = &m_serial_write_bin_interface;
serial->data[0].p = M_ASSIGN_CAST(void*, f);
}
static inline void m_serial_bin_write_clear(m_serial_write_t serial)
{
(void) serial; // Nothing to do
}
/* 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) )
/* 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){
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();
}
/* 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){
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:
n = fread (M_ASSIGN_CAST(void*, &i8), sizeof i8, 1, f);
*i = i8;
break;
case 2:
n = fread (M_ASSIGN_CAST(void*, &i16), sizeof i16, 1, f);
*i = i16;
break;
case 4:
n = fread (M_ASSIGN_CAST(void*, &i32), sizeof i32, 1, f);
*i = i32;
break;
case 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();
}
/* 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){
float f1;
double f2;
long double f3;
size_t n;
FILE *f = (FILE *)serial->data[0].p;
if (size_of_type == sizeof f1) {
n = fread (M_ASSIGN_CAST(void*, &f1), sizeof f1, 1, f);
*r = f1;
} 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) {
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();
}
/* 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){
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();
// Use of internal string interface to dimension the string
char *p = stringi_fit2size(s, length + 1);
stringi_set_size(s, length);
// Read the characters excluding the final null one.
// NOTE: fread supports length == 0.
size_t n = fread(M_ASSIGN_CAST(void*, p), 1, length, f);
// Force the final null character
p[length] = 0;
return (n == length) ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Start reading from the stream 'serial' an array.
Set '*num' with the number of elements, or 0 if it is not known.
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 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)
{
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;
}
/* 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)
{
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;
}
}
/* 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)
{
(void) local; // argument not used
(void) serial;
return M_SERIAL_OK_CONTINUE;
}
/* 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)
{
(void) serial;
local->data[1].i = 0;
return M_SERIAL_OK_CONTINUE;
}
/* Continue reading a tuple from the stream 'serial'.
Set '*id' with the corresponding index of the table 'field_name[max]'
associated to the parsed field in the stream.
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)
{
(void) serial;
(void) field_name;
(void) max;
*id = local->data[1].i;
local->data[1].i ++;
return (*id == max) ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE;
}
/* Start reading a variant from the stream 'serial'.
Set '*id' with the corresponding index of the table 'field_name[max]'
associated to the parsed field in the stream.
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)
{
(void) field_name;
(void) max;
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
size_t n = fread (M_ASSIGN_CAST(void*, id), sizeof *id, 1, f);
return n == 1 ? ((*id < 0) ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE) : m_core_serial_fail();
}
/* 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)
{
(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 inline void m_serial_bin_read_init(m_serial_read_t serial, FILE *f)
{
serial->m_interface = &m_serial_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)
{
(void) serial; // Nothing to do
}
/* Define a synonym of m_serial_read_t to the BIN serializer with its proper OPLIST */
typedef m_serial_read_t m_serial_bin_read_t;
#define M_OPL_m_serial_bin_read_t() \
(INIT_WITH(m_serial_bin_read_init), CLEAR(m_serial_bin_read_clear), TYPE(m_serial_bin_read_t) )
M_END_PROTECTED_CODE
#endif
+580
View File
@@ -0,0 +1,580 @@
/*
* M*LIB - Serial JSON
*
* Copyright (c) 2017-2021, 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_SERIAL_JSON_H
#define MSTARLIB_SERIAL_JSON_H
#include "m-core.h"
#include "m-string.h"
M_BEGIN_PROTECTED_CODE
/* Write the boolean 'data' into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_boolean(m_serial_write_t serial, const bool data)
{
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "%s", data ? "true" : "false");
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
{
(void) size_of_type; // Ignored
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "%lld", data);
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Write the float 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
{
(void) size_of_type; // Ignored
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "%Lf", data);
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Write the null-terminated string 'data'into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_string(m_serial_write_t serial, const char data[], size_t length)
{
M_ASSERT_SLOW(length == strlen(data) );
FILE *f = (FILE *)serial->data[0].p;
M_ASSERT(f != NULL && data != NULL);
/* HACK: Build dummy string to reuse string_out_str */
string_t v2;
uintptr_t ptr = (uintptr_t) data;
v2->u.heap.size = length;
v2->u.heap.alloc = length + 1;
v2->ptr = (char*)ptr;
string_out_str(f, v2);
return M_SERIAL_OK_DONE;
}
/* Start writing an array of 'number_of_elements' objects into the serial stream 'serial'.
If 'number_of_elements' is 0, then either the array has no data,
or the number of elements of the array is unkown.
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_json_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
{
(void) local; // argument not used
(void) number_of_elements; // Ignored
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "[");
return n > 0 ? 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_json_write_array_next(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, ",");
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
/* End the writing of an array into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_array_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "]");
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Start writing a map of 'number_of_elements' pairs of objects into the serial stream 'serial'.
If 'number_of_elements' is 0, then either the map has no data,
or the number of elements is unkown.
Initialize 'local' so that it can be used to serialize the map
(local is an unique serialization object of the map).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
{
(void) local; // argument not used
(void) number_of_elements; // Ignored
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "{");
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
/* Write a value separator between element of the same pair of a map into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_map_value(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, ":");
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
/* Write a map separator between elements of a map into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_map_next(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, ",");
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
/* End the writing of a map into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "}");
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Start writing a tuple into the serial stream '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_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "{");
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
/* Start writing the field named field_name[index] of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
{
(void) local; // argument not used
(void) max; // Ignored
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "%c\"%s\":", index == 0 ? ' ' : ',', field_name[index]);
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
/* End the write of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "}");
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Start writing a variant into the serial stream 'serial'.
If index <= 0, the variant is empty.
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_json_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
{
(void) local; // argument not used
(void) max; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n;
if (index >= 0) {
M_ASSERT (index < max);
n = fprintf(f, "{\"%s\":", field_name[index]);
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
} else {
n = fprintf(f, "{}");
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
}
/* End Writing a variant into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "}");
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* The internal exported interface of m_serial_write_json. */
static const m_serial_write_interface_t m_serial_write_json_interface = {
m_serial_json_write_boolean,
m_serial_json_write_integer,
m_serial_json_write_float,
m_serial_json_write_string,
m_serial_json_write_array_start,
m_serial_json_write_array_next,
m_serial_json_write_array_end,
m_serial_json_write_map_start,
m_serial_json_write_map_value,
m_serial_json_write_map_next,
m_serial_json_write_map_end,
m_serial_json_write_tuple_start,
m_serial_json_write_tuple_id,
m_serial_json_write_tuple_end,
m_serial_json_write_variant_start,
m_serial_json_write_variant_end
};
/* Initialize the JSON serial object for writing any object to JSON format in the given FILE */
static inline void m_serial_json_write_init(m_serial_write_t serial, FILE *f)
{
serial->m_interface = &m_serial_write_json_interface;
serial->data[0].p = M_ASSIGN_CAST(void*, f);
}
/* CLear the JSON serial object for writing*/
static inline void m_serial_json_write_clear(m_serial_write_t serial)
{
(void) serial; // Nothing to do
}
/* Define a synonym to the JSON serializer with a proper OPLIST */
typedef m_serial_write_t m_serial_json_write_t;
#define M_OPL_m_serial_json_write_t() \
(INIT_WITH(m_serial_json_write_init), CLEAR(m_serial_json_write_clear), TYPE(m_serial_json_write_t) )
/* Helper function to skip a space */
static inline int
m_serial_json_read_skip (FILE *f)
{
int c;
do {
c = fgetc(f);
} while (isspace(c));
return c;
}
/* Read from the stream 'serial' a boolean.
Set '*b' with the boolean value if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_read_boolean(m_serial_read_t serial, bool *b){
FILE *f = (FILE*) serial->data[0].p;
int c = m_serial_json_read_skip(f);
if (c == 't') {
*b = true;
c = fgetc(f);
if (c != 'r') return m_core_serial_fail();
c = fgetc(f);
if (c != 'u') return m_core_serial_fail();
c = fgetc(f);
if (c != 'e') return m_core_serial_fail();
return M_SERIAL_OK_DONE;
} else if (c == 'f') {
*b = false;
c = fgetc(f);
if (c != 'a') return m_core_serial_fail();
c = fgetc(f);
if (c != 'l') return m_core_serial_fail();
c = fgetc(f);
if (c != 's') return m_core_serial_fail();
c = fgetc(f);
if (c != 'e') return m_core_serial_fail();
return M_SERIAL_OK_DONE;
} else {
return m_core_serial_fail();
}
}
/* 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_json_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
(void) size_of_type; // Ignored
FILE *f = (FILE*) serial->data[0].p;
return m_core_fscanf(f, " %lld", i) == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* 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_json_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
(void) size_of_type; // Ignored
FILE *f = (FILE*) serial->data[0].p;
return m_core_fscanf(f, " %Lf", r) == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* 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_json_read_string(m_serial_read_t serial, struct string_s *s){
FILE *f = (FILE*) serial->data[0].p;
int n = m_core_fscanf(f, " "); // Skip any leading spaces.
(void) n; // Unused return value.
return string_in_str(s, f) ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Start reading from the stream 'serial' an array.
Set '*num' with the number of elements, or 0 if it is not known.
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 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_json_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
int final1 = -1, final2 = -1;
int n = m_core_fscanf(f, " [%n ]%n", &final1, &final2);
(void) n; // Unused. Parsing is checked through c (more robust)
*num = 0; // don't know the size of the array.
// Test how much the parsing succeed.
if (final1 < 0) m_core_serial_fail();
return (final2 < 0) ? M_SERIAL_OK_CONTINUE : M_SERIAL_OK_DONE;
}
/* 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_json_read_array_next(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
char c = 0;
int n = m_core_fscanf(f, " %c", m_core_arg_size(&c, 1) );
(void) n; // Unused. Parsing is checked through c (more robust)
return c == ',' ? M_SERIAL_OK_CONTINUE : c == ']' ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Start reading from the stream 'serial' a map.
Set '*num' with the number of elements, or 0 if it is not known.
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 and the map continue,
M_SERIAL_OK_DONE if it succeeds and the map ends (the map is empty),
m_core_serial_fail() otherwise */
static inline m_serial_return_code_t
m_serial_json_read_map_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
int final1 = -1, final2 = -1;
int n = m_core_fscanf(f, " {%n }%n", &final1, &final2);
(void) n; // Unused. Parsing is checked through final (more robust)
*num = 0; // don't know the size of the map.
// Test how much the parsing succeed.
if (final1 < 0) m_core_serial_fail();
return (final2 < 0) ? M_SERIAL_OK_CONTINUE : M_SERIAL_OK_DONE;
}
/* 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_json_read_map_value(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
int final = -1;
int n = m_core_fscanf(f, " :%n", &final);
(void) n; // Unused. Parsing is checked through final (more robust)
return final > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
/* Continue reading from the stream 'serial' a map.
Return M_SERIAL_OK_CONTINUE if it succeeds and the map continue,
M_SERIAL_OK_DONE if it succeeds and the map ends,
M_SERIAL_FAIL otherwise */
static inline m_serial_return_code_t
m_serial_json_read_map_next(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
char c = 0;
int n = m_core_fscanf(f, " %c", m_core_arg_size(&c, 1) );
(void) n; // Unused. Parsing is checked through c (more robust)
return c == ',' ? M_SERIAL_OK_CONTINUE : c == '}' ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* 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_json_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
int final = -1;
int n = m_core_fscanf(f, " {%n", &final);
(void) n; // Unused. Parsing is checked through final (more robust)
return final > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
/* Continue reading a tuple from the stream 'serial'.
Set '*id' with the corresponding index of the table 'field_name[max]'
associated to the parsed field in the stream.
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_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const char *const field_name [], const int max, int *id)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
int c = m_serial_json_read_skip(f);
if (c == EOF) return m_core_serial_fail();
if (c == '}') return M_SERIAL_OK_DONE;
if (c == ',') {
// If first call of read_tuple_id, it is a failure
if (*id == -1) return m_core_serial_fail();
} else {
// c should be \" but let fscanf parse it.
ungetc(c, f);
}
/* Read the field in the JSON */
c = -1;
char field[M_MAX_IDENTIFIER_LENGTH+1];
int nn = m_core_fscanf(f, " \"%" M_APPLY(M_AS_STR, M_MAX_IDENTIFIER_LENGTH) "[^ \t\n\"]\":%n",
m_core_arg_size(field, M_MAX_IDENTIFIER_LENGTH+1), &c);
(void) nn ; // Unused. Check is done through 'c' (more robust).
if (c <= 0)
return m_core_serial_fail();
/* Search for field in field_name */
for(int n = 0; n < max; n++) {
if (strcmp(field, field_name[n]) == 0) {
*id = n;
return M_SERIAL_OK_CONTINUE;
}
}
return m_core_serial_fail();
}
/* Start reading a variant from the stream 'serial'.
Set '*id' with the corresponding index of the table 'field_name[max]'
associated to the parsed field in the stream.
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_json_read_variant_start(m_serial_local_t local, m_serial_read_t serial, const char *const field_name[], const int max, int*id)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
int final1 = -1, final2 = -1;
int nn = m_core_fscanf(f, " {%n }%n", &final1, &final2);
(void) nn ; // Unused. Check is done through final (more robust).
// Test how much the parsing succeed.
if (final1 <= 0) return m_core_serial_fail();
if (final2 > 0) return M_SERIAL_OK_DONE;
/* Read the field in the JSON */
char field[M_MAX_IDENTIFIER_LENGTH+1];
nn = m_core_fscanf(f, " \"%" M_APPLY(M_AS_STR, M_MAX_IDENTIFIER_LENGTH) "[^ \t\n\"]\":%n",
m_core_arg_size(field, M_MAX_IDENTIFIER_LENGTH+1), &final2);
(void) nn ; // Unused. Check is done through final (more robust).
if (final2 <= 0) return m_core_serial_fail();
/* Linear Search for field in field_name */
for(int n = 0; n < max; n++) {
if (strcmp(field, field_name[n]) == 0) {
*id = n;
return M_SERIAL_OK_CONTINUE;
}
}
// Field not found
return m_core_serial_fail();
}
/* 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_json_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
{
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
int final = -1;
int n = m_core_fscanf(f, " }%n", &final);
(void) n ; // Unused. Check is done through final (more robust).
return final > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
static const m_serial_read_interface_t m_serial_json_read_interface = {
m_serial_json_read_boolean,
m_serial_json_read_integer,
m_serial_json_read_float,
m_serial_json_read_string,
m_serial_json_read_array_start,
m_serial_json_read_array_next,
m_serial_json_read_map_start,
m_serial_json_read_map_value,
m_serial_json_read_map_next,
m_serial_json_read_tuple_start,
m_serial_json_read_tuple_id,
m_serial_json_read_variant_start,
m_serial_json_read_variant_end
};
/* Initialize the JSON serial object for reading any object from JSON format in the given FILE */
static inline void m_serial_json_read_init(m_serial_read_t serial, FILE *f)
{
serial->m_interface = &m_serial_json_read_interface;
serial->data[0].p = M_ASSIGN_CAST(void*, f);
}
/* Clear the JSON serial object for reading from the FILE */
static inline void m_serial_json_read_clear(m_serial_read_t serial)
{
(void) serial; // Nothing to do
}
/* Define a synonym of m_serial_read_t
to the JSON serializer with its proper OPLIST */
typedef m_serial_read_t m_serial_json_read_t;
#define M_OPL_m_serial_json_read_t() \
(INIT_WITH(m_serial_json_read_init), CLEAR(m_serial_json_read_clear), TYPE(m_serial_json_read_t) )
M_END_PROTECTED_CODE
#endif
+435 -349
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - SHARED Module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2021, 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,392 +29,478 @@
#include "m-atomic.h"
#include "m-genint.h"
M_BEGIN_PROTECTED_CODE
/* Define the oplist of a shared pointer.
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
#define SHARED_PTR_OPLIST(...) \
SHAREDI_PTR_OPLIST(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
_OPLIST(__VA_ARGS__ )))
#define SHARED_PTR_OPLIST(...) \
SHAREDI_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, ...) \
SHAREDI_PTR_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_ATOMIC_OPLIST ), \
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST)))
#define SHARED_PTR_DEF(name, ...) \
M_BEGIN_PROTECTED_CODE \
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_ATOMIC_OPLIST, M_C(name, _t) ), \
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST, M_C(name, _t) ))) \
M_END_PROTECTED_CODE
/* 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, ...) \
M_BEGIN_PROTECTED_CODE \
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_ATOMIC_OPLIST, name_t ), \
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST, name_t ))) \
M_END_PROTECTED_CODE
/* Define relaxed shared pointer and its function (thread unsafe).
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
#define SHARED_PTR_RELAXED_DEF(name, ...) \
SHAREDI_PTR_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_INTEGER_OPLIST ), \
(name, __VA_ARGS__ , SHAREDI_INTEGER_OPLIST)))
#define SHARED_PTR_RELAXED_DEF(name, ...) \
M_BEGIN_PROTECTED_CODE \
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_INTEGER_OPLIST, M_C(name, _t) ), \
(name, __VA_ARGS__, SHAREDI_INTEGER_OPLIST, M_C(name, _t) ))) \
M_END_PROTECTED_CODE
/* 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, ...) \
M_BEGIN_PROTECTED_CODE \
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_INTEGER_OPLIST, name_t ), \
(name, __VA_ARGS__, SHAREDI_INTEGER_OPLIST, name_t ))) \
M_END_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, ...) \
SHAREDI_RESOURCE_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
(name, __VA_ARGS__)))
#define SHARED_RESOURCE_DEF(name, ...) \
M_BEGIN_PROTECTED_CODE \
SHAREDI_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t), M_C(name, _it_t) ), \
(name, __VA_ARGS__, M_C(name, _t), M_C(name, _it_t) ))) \
M_END_PROTECTED_CODE
/* 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, ...) \
M_BEGIN_PROTECTED_CODE \
SHAREDI_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
(name, __VA_ARGS__, name_t, it_t ))) \
M_END_PROTECTED_CODE
/********************************** INTERNAL ************************************/
// deferred
#define SHAREDI_PTR_OPLIST(arg) SHAREDI_PTR_OPLIST2 arg
// deferred evaluation
#define SHAREDI_PTR_OPLIST_P1(arg) SHAREDI_PTR_OPLIST_P2 arg
#define SHAREDI_PTR_OPLIST2(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)), \
CLEAN(M_C(name, _clean)), \
MOVE(M_C(name, _move)), \
SWAP(M_C(name, _swap)) \
,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),) \
/* Validation of the given, shared_t oplist */
#define SHAREDI_PTR_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(SHAREDI_PTR_OPLIST_P3, SHAREDI_PTR_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define SHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
((M_LIB_ERROR(ARGUMENT_OF_SHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
#define SHAREDI_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)), \
CLEAN(M_C(name, _clean)), \
MOVE(M_C(name, _move)), \
SWAP(M_C(name, _swap)) \
,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),) \
)
// deferred
#define SHAREDI_PTR_DEF(arg) SHAREDI_PTR_DEF2 arg
// OPLIST to handle a counter of atomic type
#define SHAREDI_ATOMIC_OPLIST (TYPE(atomic_int), \
INIT_SET(atomic_init), \
ADD(atomic_fetch_add), \
SUB(atomic_fetch_sub), \
#define SHAREDI_ATOMIC_OPLIST (TYPE(atomic_int), \
INIT_SET(atomic_init), \
ADD(atomic_fetch_add), \
SUB(atomic_fetch_sub), \
IT_CREF(atomic_load))
// OPLIST to handle a counter of non-atomic type with its helper functions.
#define SHAREDI_INTEGER_OPLIST (TYPE(int), \
INIT_SET(sharedi_integer_init_set), \
ADD(sharedi_integer_add), \
SUB(sharedi_integer_sub), \
// OPLIST to handle a counter of non-atomic type
#define SHAREDI_INTEGER_OPLIST (TYPE(int), \
INIT_SET(sharedi_integer_init_set), \
ADD(sharedi_integer_add), \
SUB(sharedi_integer_sub), \
IT_CREF(sharedi_integer_cref))
/* Atomic like interface for basic integers */
static inline void sharedi_integer_init_set(int *p, int val) { *p = val; }
static inline int sharedi_integer_add(int *p, int val) { int r = *p; *p += val; return r; }
static inline int sharedi_integer_sub(int *p, int val) { int r = *p; *p -= val; return r; }
static inline int sharedi_integer_cref(int *p) { return *p; }
#define SHAREDI_CONTRACT(shared, cpt_oplist) do { \
assert(shared != NULL); \
assert(*shared == NULL || M_CALL_IT_CREF(cpt_oplist, &(*shared)->cpt) >= 1); \
/* Contract of a shared pointer */
#define SHAREDI_CONTRACT(shared, cpt_oplist) do { \
M_ASSERT(shared != NULL); \
M_ASSERT(*shared == NULL || M_CALL_IT_CREF(cpt_oplist, &(*shared)->cpt) >= 1); \
} while (0)
#define SHAREDI_PTR_DEF2(name, type, oplist, cpt_oplist) \
\
typedef struct M_C(name, _s){ \
type *data; /* Pointer to the data */ \
M_GET_TYPE cpt_oplist cpt; /* Counter of how many points to the data */ \
bool combineAlloc; /* Does the data and the ptr share the slot? */ \
} *M_C(name, _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_C(name, combine_s) { \
type data; \
struct M_C(name, _s) ptr; \
} M_C(name, combine_t)[1]; \
\
static inline void \
M_C(name, _init)(M_C(name, _t) shared) \
{ \
*shared = NULL; \
} \
\
static inline void \
M_C(name, _init2)(M_C(name, _t) shared, type *data) \
{ \
assert (shared != NULL); \
/* The shared ptr get exclusive access to data */ \
struct M_C(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))); \
return; \
} \
ptr->data = data; \
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
ptr->combineAlloc = false; \
*shared = ptr; \
SHAREDI_CONTRACT(shared, cpt_oplist); \
} \
\
static inline void \
M_C(name, _init_new)(M_C(name, _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))); \
return; \
} \
struct M_C(name, _s) *ptr = &p->ptr; \
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; \
SHAREDI_CONTRACT(shared, cpt_oplist); \
} \
\
static inline bool \
M_C(name, _NULL_p)(const M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(shared, cpt_oplist); \
return *shared == NULL; \
} \
\
static inline void \
M_C(name, _init_set)(M_C(name, _t) dest, \
const M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(shared, cpt_oplist); \
assert (dest != shared); \
*dest = *shared; \
if (*dest != NULL) { \
int n = M_CALL_ADD(cpt_oplist, &((*dest)->cpt), 1); \
(void) n; /* unused return value */ \
} \
SHAREDI_CONTRACT(dest, cpt_oplist); \
} \
\
static inline void \
M_C(name, _clear)(M_C(name, _t) dest) \
{ \
SHAREDI_CONTRACT(dest, cpt_oplist); \
if (*dest != NULL) { \
if (M_CALL_SUB(cpt_oplist, &((*dest)->cpt), 1) == 1) { \
bool combineAlloc = (*dest)->combineAlloc; \
/* Note: if combineAlloc is true, the address of the slot \
combining both data & ptr is the same as the address of the \
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); \
} \
*dest = NULL; \
} \
SHAREDI_CONTRACT(dest, cpt_oplist); \
} \
\
static inline void \
M_C(name, _clean)(M_C(name, _t) dest) \
{ \
/* NOTE: Clear will also set dest to NULL */ \
M_C(name, _clear)(dest); \
} \
\
static inline void \
M_C(name, _set)(M_C(name, _t) dest, \
const M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(dest, cpt_oplist); \
SHAREDI_CONTRACT(shared, cpt_oplist); \
M_C(name, _clear)(dest); \
M_C(name, _init_set)(dest, shared); \
} \
\
static inline void \
M_C(name, _init_move)(M_C(name, _t) dest, \
M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(shared, cpt_oplist); \
assert (dest != NULL && dest != shared); \
*dest = *shared; \
*shared = NULL; \
SHAREDI_CONTRACT(dest, cpt_oplist); \
} \
\
static inline void \
M_C(name, _move)(M_C(name, _t) dest, \
M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(dest, cpt_oplist); \
SHAREDI_CONTRACT(shared, cpt_oplist); \
assert (dest != shared); \
M_C(name, _clear)(dest); \
M_C(name, _init_move)(dest, shared); \
} \
\
static inline void \
M_C(name, _swap)(M_C(name, _t) p1, \
M_C(name, _t) p2) \
{ \
SHAREDI_CONTRACT(p1, cpt_oplist); \
SHAREDI_CONTRACT(p2, cpt_oplist); \
M_SWAP (struct M_C(name, _s)*, *p1, *p2); \
SHAREDI_CONTRACT(p1, cpt_oplist); \
SHAREDI_CONTRACT(p2, cpt_oplist); \
} \
\
static inline bool \
M_C(name, _equal_p)(const M_C(name, _t) p1, \
const M_C(name, _t) p2) \
{ \
SHAREDI_CONTRACT(p1, cpt_oplist); \
SHAREDI_CONTRACT(p2, cpt_oplist); \
return *p1 == *p2; \
} \
\
static inline type const * \
M_C(name, _cref)(const M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(shared, cpt_oplist); \
assert(*shared != NULL); \
type *data = (*shared)->data; \
assert (data != NULL); \
return M_CONST_CAST (type, data); \
} \
\
static inline type * \
M_C(name, _ref)(M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(shared, cpt_oplist); \
assert(*shared != NULL); \
type *data = (*shared)->data; \
assert (data != NULL); \
return data; \
} \
// deferred evaluation
#define SHAREDI_PTR_DEF_P1(arg) SHAREDI_PTR_DEF_P2 arg
/* Validate the oplist before going further */
#define SHAREDI_PTR_DEF_P2(name, type, oplist, cpt_oplist, shared_t) \
M_IF_OPLIST(oplist)(SHAREDI_PTR_DEF_P3, SHAREDI_PTR_DEF_FAILURE)(name, type, oplist, cpt_oplist, shared_t)
/* Stop processing with a compilation failure */
#define SHAREDI_PTR_DEF_FAILURE(name, type, oplist, cpt_oplist, shared_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
/* Code generation */
#define SHAREDI_PTR_DEF_P3(name, type, oplist, cpt_oplist, shared_t) \
\
typedef struct M_C(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); \
\
/* Internal type for oplist */ \
typedef shared_t M_C(name, _ct); \
\
typedef struct M_C(name, combine_s) { \
type data; \
struct M_C(name, _s) ptr; \
} M_C(name, combine_ct)[1]; \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void \
M_C(name, _init)(shared_t shared) \
{ \
*shared = NULL; \
} \
\
static inline void \
M_C(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; \
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))); \
return; \
} \
ptr->data = data; \
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
ptr->combineAlloc = false; \
*shared = ptr; \
SHAREDI_CONTRACT(shared, cpt_oplist); \
} \
\
static inline void \
M_C(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))); \
return; \
} \
struct M_C(name, _s) *ptr = &p->ptr; \
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; \
SHAREDI_CONTRACT(shared, cpt_oplist); \
} \
\
static inline bool \
M_C(name, _NULL_p)(const shared_t shared) \
{ \
SHAREDI_CONTRACT(shared, cpt_oplist); \
return *shared == NULL; \
} \
\
static inline void \
M_C(name, _init_set)(shared_t dest, \
const shared_t shared) \
{ \
SHAREDI_CONTRACT(shared, cpt_oplist); \
M_ASSERT (dest != shared); \
*dest = *shared; \
if (*dest != NULL) { \
int n = M_CALL_ADD(cpt_oplist, &((*dest)->cpt), 1); \
(void) n; /* unused return value */ \
} \
SHAREDI_CONTRACT(dest, cpt_oplist); \
} \
\
static inline void \
M_C(name, _clear)(shared_t dest) \
{ \
SHAREDI_CONTRACT(dest, cpt_oplist); \
if (*dest != NULL) { \
if (M_CALL_SUB(cpt_oplist, &((*dest)->cpt), 1) == 1) { \
bool combineAlloc = (*dest)->combineAlloc; \
/* Note: if combineAlloc is true, the address of the slot \
combining both data & ptr is the same as the address of the \
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); \
} \
*dest = NULL; \
} \
SHAREDI_CONTRACT(dest, cpt_oplist); \
} \
\
static inline void \
M_C(name, _clean)(shared_t dest) \
{ \
/* NOTE: Clear will also set dest to NULL */ \
M_C(name, _clear)(dest); \
} \
\
static inline void \
M_C(name, _set)(shared_t dest, \
const shared_t shared) \
{ \
SHAREDI_CONTRACT(dest, cpt_oplist); \
SHAREDI_CONTRACT(shared, cpt_oplist); \
M_C(name, _clear)(dest); \
M_C(name, _init_set)(dest, shared); \
} \
\
static inline void \
M_C(name, _init_move)(shared_t dest, \
shared_t shared) \
{ \
SHAREDI_CONTRACT(shared, cpt_oplist); \
M_ASSERT (dest != NULL && dest != shared); \
*dest = *shared; \
*shared = NULL; \
SHAREDI_CONTRACT(dest, cpt_oplist); \
} \
\
static inline void \
M_C(name, _move)(shared_t dest, \
shared_t shared) \
{ \
SHAREDI_CONTRACT(dest, cpt_oplist); \
SHAREDI_CONTRACT(shared, cpt_oplist); \
M_ASSERT (dest != shared); \
M_C(name, _clear)(dest); \
M_C(name, _init_move)(dest, shared); \
} \
\
static inline void \
M_C(name, _swap)(shared_t p1, \
shared_t p2) \
{ \
SHAREDI_CONTRACT(p1, cpt_oplist); \
SHAREDI_CONTRACT(p2, cpt_oplist); \
/* NOTE: SWAP is not atomic */ \
M_SWAP (struct M_C(name, _s)*, *p1, *p2); \
SHAREDI_CONTRACT(p1, cpt_oplist); \
SHAREDI_CONTRACT(p2, cpt_oplist); \
} \
\
static inline bool \
M_C(name, _equal_p)(const shared_t p1, \
const shared_t p2) \
{ \
SHAREDI_CONTRACT(p1, cpt_oplist); \
SHAREDI_CONTRACT(p2, cpt_oplist); \
return *p1 == *p2; \
} \
\
static inline type const * \
M_C(name, _cref)(const shared_t shared) \
{ \
SHAREDI_CONTRACT(shared, cpt_oplist); \
M_ASSERT(*shared != NULL); \
type *data = (*shared)->data; \
M_ASSERT (data != NULL); \
return M_CONST_CAST (type, data); \
} \
\
static inline type * \
M_C(name, _ref)(shared_t shared) \
{ \
SHAREDI_CONTRACT(shared, cpt_oplist); \
M_ASSERT(*shared != NULL); \
type *data = (*shared)->data; \
M_ASSERT (data != NULL); \
return data; \
} \
/********************************** SHARED RESOURCE ************************************/
#define SHAREDI_RESOURCE_CONTRACT(s) do { \
assert (s != NULL); \
assert (s->buffer != NULL); \
#define SHAREDI_RESOURCE_CONTRACT(s) do { \
M_ASSERT (s != NULL); \
M_ASSERT (s->buffer != NULL); \
} while (0)
// deferred
#define SHAREDI_RESOURCE_DEF(arg) SHAREDI_RESOURCE_DEF2 arg
#define SHAREDI_RESOURCE_DEF_P1(arg) SHAREDI_RESOURCE_DEF_P2 arg
#define SHAREDI_RESOURCE_DEF2(name, type, oplist) \
\
/* Create an aligned type to avoid false sharing between threads */ \
typedef struct M_C(name, _atype_s) { \
atomic_uint cpt; \
type x; \
M_CACHELINE_ALIGN(align, type, atomic_uint); \
} M_C(name, _atype_t); \
\
typedef struct M_C(name, _s) { \
genint_t core; \
M_C(name, _atype_t) *buffer; \
} M_C(name, _t)[1]; \
\
typedef struct M_C(name, _it_s) { \
unsigned int idx; \
struct M_C(name, _s) *ref; \
} M_C(name, _it_t)[1]; \
\
static inline void \
M_C(name, _init)(M_C(name, _t) s, size_t n) \
{ \
assert(s != NULL); \
assert (n > 0); \
s->buffer = M_CALL_REALLOC(oplist, M_C(name, _atype_t), NULL, n); \
if (M_UNLIKELY (s->buffer == NULL)) { \
M_MEMORY_FULL(sizeof(M_C(name, _atype_t)) * 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, n); \
SHAREDI_RESOURCE_CONTRACT(s); \
} \
\
static inline void \
M_C(name, _clear)(M_C(name, _t) s) \
{ \
SHAREDI_RESOURCE_CONTRACT(s); \
size_t n = 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); \
} \
\
static inline void \
M_C(name, _it)(M_C(name, _it_t) it, M_C(name, _t) s) \
{ \
SHAREDI_RESOURCE_CONTRACT(s); \
assert (it != NULL); \
unsigned int idx = genint_pop(s->core); \
it->idx = idx; \
it->ref = s; \
if (M_LIKELY (idx != GENINT_ERROR)) { \
assert(atomic_load(&s->buffer[idx].cpt) == 0); \
atomic_store(&s->buffer[idx].cpt, 1U); \
} \
} \
\
static inline bool \
M_C(name, _end_p)(M_C(name, _it_t) it) \
{ \
assert (it != NULL); \
return it->idx == GENINT_ERROR; \
} \
\
static inline type * \
M_C(name, _ref)(M_C(name, _it_t) it) \
{ \
assert (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
SHAREDI_RESOURCE_CONTRACT(it->ref); \
return &it->ref->buffer[it->idx].x; \
} \
\
static inline type const * \
M_C(name, _cref)(M_C(name, _it_t) it) \
{ \
assert (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
SHAREDI_RESOURCE_CONTRACT(it->ref); \
return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \
} \
\
static inline void \
M_C(name, _end)(M_C(name, _it_t) it, M_C(name, _t) s) \
{ \
SHAREDI_RESOURCE_CONTRACT(s); \
assert (it != NULL); \
assert (it->ref == s); \
unsigned int idx = it->idx; \
if (M_LIKELY (idx != GENINT_ERROR)) { \
unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \
if (c == 1) { \
genint_push(it->ref->core, idx); \
} \
it->idx = GENINT_ERROR; \
} \
} \
\
static inline void \
M_C(name, _it_set)(M_C(name, _it_t) itd, M_C(name, _it_t) its) \
{ \
assert (itd != NULL && its != NULL); \
SHAREDI_RESOURCE_CONTRACT(its->ref); \
itd->ref = its->ref; \
unsigned int idx = its->idx; \
itd->idx = idx; \
if (M_LIKELY (idx != GENINT_ERROR)) { \
unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \
assert (c >= 1); \
} \
} \
/* Validate the oplist before going further */
#define SHAREDI_RESOURCE_DEF_P2(name, type, oplist, shared_t, it_t) \
M_IF_OPLIST(oplist)(SHAREDI_RESOURCE_DEF_P3, SHAREDI_RESOURCE_DEF_FAILURE)(name, type, oplist, shared_t, it_t)
/* Stop processing with a compilation failure */
#define SHAREDI_RESOURCE_DEF_FAILURE(name, type, oplist, shared_t, it_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_RESOURCE_DEF): the given argument is not a valid oplist: " #oplist)
#define SHAREDI_RESOURCE_DEF_P3(name, type, oplist, shared_t, it_t) \
\
/* Create an aligned type to avoid false sharing between threads */ \
typedef struct M_C(name, _atype_s) { \
atomic_uint cpt; \
type x; \
M_CACHELINE_ALIGN(align, type, atomic_uint); \
} M_C(name, _atype_ct); \
\
typedef struct M_C(name, _s) { \
genint_t core; \
M_C(name, _atype_ct) *buffer; \
} shared_t[1]; \
\
typedef struct M_C(name, _it_s) { \
unsigned int idx; \
struct M_C(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) \
{ \
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); \
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); \
SHAREDI_RESOURCE_CONTRACT(s); \
} \
\
static inline void \
M_C(name, _clear)(shared_t s) \
{ \
SHAREDI_RESOURCE_CONTRACT(s); \
size_t n = 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); \
} \
\
static inline void \
M_C(name, _it)(it_t it, shared_t s) \
{ \
SHAREDI_RESOURCE_CONTRACT(s); \
M_ASSERT (it != NULL); \
unsigned int idx = genint_pop(s->core); \
it->idx = idx; \
it->ref = s; \
if (M_LIKELY (idx != 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_ASSERT (it != NULL); \
return it->idx == GENINT_ERROR; \
} \
\
static inline type * \
M_C(name, _ref)(it_t it) \
{ \
M_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
SHAREDI_RESOURCE_CONTRACT(it->ref); \
return &it->ref->buffer[it->idx].x; \
} \
\
static inline type const * \
M_C(name, _cref)(it_t it) \
{ \
M_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
SHAREDI_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) \
{ \
SHAREDI_RESOURCE_CONTRACT(s); \
M_ASSERT (it != NULL); \
M_ASSERT (it->ref == s); \
unsigned int idx = it->idx; \
if (M_LIKELY (idx != GENINT_ERROR)) { \
unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \
if (c == 1) { \
genint_push(it->ref->core, idx); \
} \
it->idx = GENINT_ERROR; \
} \
} \
\
static inline void \
M_C(name, _it_set)(it_t itd, it_t its) \
{ \
M_ASSERT (itd != NULL && its != NULL); \
SHAREDI_RESOURCE_CONTRACT(its->ref); \
itd->ref = its->ref; \
unsigned int idx = its->idx; \
itd->idx = idx; \
if (M_LIKELY (idx != GENINT_ERROR)) { \
unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \
M_ASSERT (c >= 1); \
} \
} \
M_END_PROTECTED_CODE
#endif
+544 -379
View File
File diff suppressed because it is too large. Load diff
+1088 -567
View File
File diff suppressed because it is too large. Load diff
Loaded 100 of 143 files, more files were not shown because too many files have changed in this diff. Show more