380 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
111 changed files with 20879 additions and 15522 deletions

No files matched your search

+71 -16
View File
@@ -1,6 +1,6 @@
name: C/C++ CI
on: [push]
on: [push, pull_request]
jobs:
build:
@@ -11,35 +11,90 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: make
run: make
- name: make check
run: make check
- 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:
strategy:
matrix:
platform: [windows-latest]
runs-on: ${{ matrix.platform }}
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: Install MINGW
run: choco install mingw --no-progress
- 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:
strategy:
matrix:
platform: [windows-latest]
runs-on: ${{ matrix.platform }}
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: make check
shell: cmd
working-directory: ./tests
run: Make-check-cl.bat
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
+3 -1
View File
@@ -38,5 +38,7 @@ depend
other/
a*.dat
config
fail*.log
*.log
.vscode
.vs
tmp-serial.*
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 2-Clause License
Copyright (c) 2017-2020, Patrick Pelissier
Copyright (c) 2017-2021, Patrick Pelissier
All rights reserved.
Redistribution and use in source and binary forms, with or without
+34 -6
View File
@@ -1,6 +1,29 @@
# 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
@@ -11,14 +34,14 @@ DESTDIR=
# Package name & version.
PACKAGE=m_lib-$(VERSION)
VERSION=0.4.0
VERSION=0.5.0
# Define the contain of the distribution tarball
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tuple.h m-variant.h m-worker.h
DOC1=LICENSE README.md
DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/depend.png doc/DEV.md doc/ISSUES.org doc/oplist.odp doc/oplist.png
EXAMPLE=example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.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-json01.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-rbtree01.c example/ex-section.c 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/wip-mregister.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt
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
@@ -74,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
+844 -415
View File
File diff suppressed because it is too large. Load diff
+65 -8
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-emilib 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-densehashmap bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-uthash bench-qlibc bench-libsrt bench-nedtries bench-rigtorp-hashmap
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
@@ -130,6 +152,16 @@ 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
@@ -300,6 +332,28 @@ bench-rigtorp-hashmap0:
@./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:
@@ -332,10 +386,7 @@ bench-string-step1:
#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
@@ -347,7 +398,6 @@ 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:
@@ -356,11 +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
$(RM) bench-*.s *~ massif.out.*
$(RM) plot-*.dat
$(RM) pgo
$(RM) tmp-serial.*
cd nucleotide && $(MAKE) clean
############################################################################
+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);
}
+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;
}
+221 -2
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)))
@@ -719,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)
@@ -837,12 +864,198 @@ 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},
@@ -861,7 +1074,13 @@ const config_func_t table[] = {
{ 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}
{ 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[])
+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);
}
+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);
}
+19
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;
@@ -241,6 +259,7 @@ 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},
+46 -126
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - String Bench
*
* Copyright (c) 2017-2020, 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,10 +37,6 @@ extern "C" {
};
#endif
#ifdef BENCH_CAN_USE_RAPIDSTRING
#include "rapidstring.h"
#endif
#ifdef BENCH_CAN_USE_BSTRLIB
#include "bstrlib.h"
#include "bstrwrap.h"
@@ -77,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;
@@ -89,21 +96,8 @@ 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();
}
@@ -124,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);
@@ -145,6 +132,18 @@ size_t bench_mlib(unsigned n)
#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;
@@ -160,21 +159,8 @@ size_t bench_bstrlib(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_bstrlib(str, "1234", "WELL");
replace_all_bstrlib(str, "56789", "DONE");
return str.length();
}
@@ -191,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));
@@ -205,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]);
@@ -233,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[])
{
@@ -315,12 +242,6 @@ int main(int argc, const char *argv[])
name = "SDS";
break;
#endif
#ifdef BENCH_CAN_USE_RAPIDSTRING
case 3:
length = bench_rapidstring(n);
name = "RAPID";
break;
#endif
#ifdef BENCH_CAN_USE_BSTRLIB
case 4:
length = bench_bstrlib(n);
@@ -335,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
Copyright (c) 2018-2019 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);
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - common functions for bench module
*
* Copyright (c) 2017-2020, 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:
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - common functions for bench module
*
* Copyright (c) 2017-2020, 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:
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* MLIB - TEST module
*
* Copyright (c) 2017-2020, 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:
+12
View File
@@ -45,3 +45,15 @@ V0.3.*: * Remove B+TREE _remove method as it has been deprecated (use _erase ins
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.
+10
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
=================
+58 -12
View File
@@ -1,4 +1,3 @@
*Long term issues*
------------------
@@ -6,39 +5,85 @@
Specialize Hashmap for huge objects on supported hardware:
based on OA hash map of taggued pointer (needs space for tagging)
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 ==> Shall be faster.
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
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.
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:
New operator: ERROR_MODEL which value is 0 (abort on error), 1 (throw on error)
or 2 (return code on error).
==> 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:
@@ -186,8 +231,9 @@ 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 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:
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 102 KiB

+22
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=c99
CFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -g
GMP_DIR=
+20 -5
View File
@@ -4,33 +4,49 @@
/* 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)
#define M_OPL_vector_bool_t() ARRAY_OPLIST(vector_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 :
// ALGO_FOR_EACH(myvector, vector_int_t, M_PRINT, " ");
#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);
@@ -38,8 +54,6 @@ int main(void)
vector_bool_fill_n(tmp, 2, false);
vector_bool_splice(myvector, tmp);
printf("myvector contains:");
// In C11, the for loop can be simplified as :
// ALGO_FOR_EACH(myvector, vector_bool_t, M_PRINT, " ");
for M_EACH(it, myvector, vector_bool_t) {
printf(" %d", (int)*it);
}
@@ -49,5 +63,6 @@ int main(void)
vector_bool_any_of_p(myvector, id),
vector_bool_none_of_p(myvector, id) );
}
return 0;
}
+11
View File
@@ -3,20 +3,31 @@
#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' */
+11
View File
@@ -2,20 +2,31 @@
#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);
+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);
+12 -7
View File
@@ -1,12 +1,16 @@
#include "m-bptree.h"
#include "m-string.h"
// Define a map int -> string
// 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
// 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)
@@ -14,7 +18,7 @@ int main(void)
map_employee_id_t Employees;
map_employee_id_init(Employees);
// Assign
// 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"));
@@ -30,11 +34,13 @@ int main(void)
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_type_t *e = map_employee_id_cref(it);
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) {
@@ -51,9 +57,8 @@ int main(void)
}
// Print
printf("\nElisabeth has id = %d\n", *map_employee_name_get(Employees_r, STRING_CTE("Elisabeth")));
}
printf("\nElisabeth has id = %d\n", *map_employee_name_get(Employees_r, STRING_CTE("Elisabeth")));
} /* 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);
}
+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)
+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;
}
+19 -5
View File
@@ -17,10 +17,14 @@ 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 */
FUNC_OBJ_INS_DEF(compare_by,
vector_employee_cmp_obj,
(a, b), {
/* 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"))
@@ -28,6 +32,7 @@ FUNC_OBJ_INS_DEF(compare_by,
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)
@@ -39,19 +44,25 @@ static void read(vector_employee_t base, const char filename[])
// 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 errors
// 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);
}
@@ -67,11 +78,14 @@ int main(void)
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;
}
+10 -14
View File
@@ -2,19 +2,18 @@
#include "m-tuple.h"
#include "m-array.h"
// Serial json is not supported for standard types if not C11
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
// 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
@@ -29,6 +28,7 @@ static void read(base_t base, const char filename[])
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
@@ -44,21 +44,17 @@ static void read(base_t base, const char filename[])
int main(void)
{
// Let's have base as a base_t
M_LET(base, base_t) {
read(base, "ex-json01.json");
// 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));
}
if ((*el)->present) {
printf("%s\n", string_get_cstr((*el)->surname));
}
}
}
exit(0);
}
#else
int main(void)
{
exit(0);
}
#endif
File renamed without changes.
@@ -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
+1010 -924
View File
File diff suppressed because it is too large. Load diff
+1020 -957
View File
File diff suppressed because it is too large. Load diff
+82 -56
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Thin stdatomic wrapper for C++ compatibility
*
* Copyright (c) 2017-2020, 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,20 +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(__INTEL_COMPILER) && !defined(__cplusplus) && (__GNUC__*100 + __GNUC_MINOR__) >= 409) \
|| (defined(__clang__) && __clang_major__ >= 4) \
|| (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1800)
#if defined(__clang__) && __clang_major__ >= 4
_Pragma("clang diagnostic pop")
#endif
/* C11 has mandatory working stdatomic
STDATOMIC doesn't work with C++ except for clang
/* 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 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)
#include <stdatomic.h>
/* MSYS2 has a conflict between cdefs.h which defines a _Atomic macro (if not C11)
@@ -124,16 +145,19 @@ 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".
*/
#else
#include "m-mutex.h"
#include "m-core.h"
M_BEGIN_PROTECTED_CODE
/* _Atomic qualifier for a type (emulation).
The structure is quite large:
@@ -143,12 +167,12 @@ using std::memory_order_seq_cst;
_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; \
}
/* Define the supported memory order.
@@ -193,8 +217,8 @@ 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;
@@ -217,11 +241,11 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
The trick is computing _val - _zero within the lock, then
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, +=)
@@ -240,49 +264,49 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
#define ATOMIC_VAR_INIT(val) { val, 0, 0, M_MUTEXI_INIT_VALUE }
/* Initialize an atomic variable */
#define atomic_init(ptr, val) \
#define atomic_init(ptr, val) \
(m_mutex_init((ptr)->_lock), (ptr)->_val = val, (ptr)->_zero = 0)
/* (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, (ptr)->_previous-(ptr)->_zero)+(ptr)->_zero)
#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)
/* (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), \
#define atomic_store_lock(ptr, val) \
(m_mutex_lock((ptr)->_lock), \
(ptr)->_val = (val), \
m_mutex_unlock((ptr)->_lock))
/* 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 \
#define atomic_load(ptr) \
( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE \
? (ptr)->_val \
: atomic_load_lock(ptr))
/* 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 = (val) - (ptr)->_zero; \
atomic_store_lock(ptr, (ptr)->_zero + _offset); \
} \
#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)
/* 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) \
#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)))
@@ -304,6 +328,8 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
/* TODO: Missing atomic_flag. Problem: it is supposed to be lock free! */
M_END_PROTECTED_CODE
#endif
#endif
+200 -114
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - BITSET module
*
* Copyright (c) 2017-2020, 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
+1314 -1228
View File
File diff suppressed because it is too large. Load diff
+993 -911
View File
File diff suppressed because it is too large. Load diff
+471 -466
View File
File diff suppressed because it is too large. Load diff
+781 -685
View File
File diff suppressed because it is too large. Load diff
+1070 -468
View File
File diff suppressed because it is too large. Load diff
+949 -928
View File
File diff suppressed because it is too large. Load diff
+1724 -1621
View File
File diff suppressed because it is too large. Load diff
+240 -183
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Function Object module
*
* Copyright (c) 2017-2020, 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:
@@ -32,21 +32,34 @@
* USAGE:
* FUNC_OBJ_ITF_DEF(name, retcode type, type of param1, type of param 2, ...)
*/
#define FUNC_OBJ_ITF_DEF(name, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_ITF_NO_PARAM_DEF, FUNCOBJI_ITF_PARAM_DEF)(name, __VA_ARGS__)
#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 as per :
* 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 shall be defined in callback_core
* - 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 like
* and a special variable 'self' which refers to the function object itself
* can be used to access member attributes.
* 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'
@@ -54,15 +67,30 @@
* 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_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_DEF, FUNCOBJI_INS_ATTR_DEF)(name, base_name, param_list, __VA_ARGS__)
#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(...) \
#define FUNC_OBJ_INS_OPLIST(...) \
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_OPLIST, FUNCOBJI_INS_ATTR_OPLIST_P1)( __VA_ARGS__)
@@ -71,7 +99,7 @@
/********************************** INTERNAL ************************************/
/********************************************************************************/
/* To be used by M_IF_FUNCOBJ macro.
/* 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
@@ -85,75 +113,97 @@
*/
/* 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, _t)), \
CLEAR(M_C(name, _clear)), \
INIT(M_C(name,_init)) \
)
#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, ...) \
#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 FUNCOBJI_INS_ATTR_OPLIST_FAILURE(name, ...) \
((M_LIB_ERROR(ONE_ARGUMENT_OF_FUNC_OBJ_INS_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)))
/* Define at least the oplist */
#define FUNCOBJI_INS_ATTR_OPLIST_P3(name, ...) \
(NAME(name), TYPE(M_C(name, _t)), \
INIT_WITH(M_C(name, _init_with)), \
CLEAR(M_C(name, _clear)), \
M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
)
/* 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 () that doesn't have any input parameters.
* 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, retcode) \
typedef retcode M_C(name, _retcode_t); \
\
struct M_C(name, _s); \
\
/* No parameters to the callback */ \
typedef retcode(*M_C(name, _callback_t))(struct M_C(name, _s) *); \
\
typedef struct M_C(name, _s) { \
M_C(name, _callback_t) callback; \
} M_C(name, _t)[1]; \
\
static inline retcode \
M_C(name, _call)(M_C(name, _t) funcobj) \
{ \
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
funcobj->callback(funcobj); \
#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, retcode, ...) \
typedef retcode M_C(name, _retcode_t); \
\
/* Define types for all paremeters */ \
M_MAP3(FUNCOBJI_BASE_TYPE, name, __VA_ARGS__) \
\
struct M_C(name, _s); \
\
typedef retcode(*M_C(name, _callback_t))(struct M_C(name, _s) *, __VA_ARGS__); \
\
typedef struct M_C(name, _s) { \
M_C(name, _callback_t) callback; \
} M_C(name, _t)[1]; \
\
static inline retcode \
M_C(name, _call)(M_C(name, _t) funcobj \
M_MAP3(FUNCOBJI_BASE_ARGLIST, name, __VA_ARGS__) ) \
{ \
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
#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__) ); \
}
@@ -161,184 +211,191 @@
/* Specialization of the definition a function object instance of name 'name'
* with no member attribute.
*/
#define FUNCOBJI_INS_NO_ATTR_DEF(name, base_name, param_list, callback_core) \
typedef struct M_C(name, _s) { \
M_C(base_name, _callback_t) callback; \
} M_C(name, _t)[1]; \
\
static inline M_C(base_name, _retcode_t) \
M_C(name, _callback)(M_C(base_name, _t) _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)(M_C(name, _t) obj) \
{ \
obj->callback = M_C(name, _callback); \
} \
\
static inline void \
M_C(name, _clear)(M_C(name, _t) obj) \
{ \
(void) obj; /* nothing to do */ \
} \
\
static inline struct M_C(base_name, _s) * \
M_C(name, _as_interface)(M_C(name, _t) obj) \
{ \
return (struct M_C(base_name, _s) *) obj; \
} \
\
static inline void \
M_C(name, _init)(M_C(name, _t) obj) \
{ \
obj->callback = M_C(name, _callback); \
} \
#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, base_name, param_list, callback_core, ...) \
FUNCOBJI_INS_ATTR_DEF_P2(name, base_name, param_list, callback_core, FUNCOBJI_INJECT_GLOBAL(__VA_ARGS__) )
#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(...) \
#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 ) \
#define FUNCOBJI_INJECT_OPLIST_A( duo_or_trio ) \
FUNCOBJI_INJECT_OPLIST_B duo_or_trio
#define FUNCOBJI_INJECT_OPLIST_B( f, ... ) \
#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(...) \
#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
#define FUNCOBJI_IS_OPLIST_P(a) \
// 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, base_name, param_list, callback_core, ...) \
FUNCOBJI_IF_ALL_OPLIST(__VA_ARGS__)(FUNCOBJI_INS_ATTR_DEF_P3, FUNCOBJI_INS_ATTR_DEF_FAILURE)(name, base_name, param_list, callback_core, __VA_ARGS__)
#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, base_name, param_list, callback_core, ...) \
#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, base_name, param_list, callback_core, ...) \
typedef struct M_C(name, _s) { \
/* Callback is the mandatory first argument */ \
M_C(base_name, _callback_t) callback; \
/* All the member attribute of the Function Object */ \
M_MAP(FUNCOBJI_INS_ATTR_STRUCT, __VA_ARGS__) \
} M_C(name, _t)[1]; \
\
FUNCOBJI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
\
static inline M_C(base_name, _retcode_t) \
M_C(name, _callback)(M_C(base_name, _t) _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)(M_C(name, _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)(M_C(name, _t) obj) \
{ \
M_MAP(FUNCOBJI_INS_ATTR_CLEAR, __VA_ARGS__); \
} \
\
static inline struct M_C(base_name, _s) * \
M_C(name, _as_interface)(M_C(name, _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)(M_C(name, _t) obj) \
{ \
obj->callback = M_C(name, _callback); \
M_MAP(FUNCOBJI_INS_ATTR_INIT, __VA_ARGS__); \
} \
, /* END OF INIT METHOD */ ) \
#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, _t);
#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) \
#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) \
#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) \
#define FUNCOBJI_INS_ATTR_STRUCT(arg) \
M_RET_ARG2 arg M_RET_ARG1 arg;
#define FUNCOBJI_INS_ATTR_LIST(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) \
#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) \
#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) \
#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, _t) param
#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) \
#define FUNCOBJI_TEST_METHOD2_P(method, op) \
M_TEST_METHOD_P(method, op)
#define FUNCOBJI_TEST_METHOD1_P(method, arg) \
#define FUNCOBJI_TEST_METHOD1_P(method, arg) \
M_APPLY(FUNCOBJI_TEST_METHOD2_P, method, M_RET_ARG3 arg)
#define FUNCOBJI_TEST_METHOD_P(method, ...) \
#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, ...) \
#define FUNCOBJI_CONTROL_ALL_OPLIST(name, ...) \
M_MAP2(FUNCOBJI_CONTROL_OPLIST, name, __VA_ARGS__)
#define FUNCOBJI_CONTROL_OPLIST(name, a) \
#define FUNCOBJI_CONTROL_OPLIST(name, a) \
M_CHECK_COMPATIBLE_OPLIST(name, M_RET_ARG1 a, M_RET_ARG2 a, M_RET_ARG3 a)
+83 -56
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - GENINT module
* M*LIB - Integer Generator (GENINT) module
*
* Copyright (c) 2017-2020, 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
+566 -516
View File
File diff suppressed because it is too large. Load diff
+171 -103
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - INTRUSIVE SHARED PTR Module
*
* Copyright (c) 2017-2020, 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,27 +28,52 @@
#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_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
#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, type, [, oplist]) */
#define ISHARED_PTR_DEF(name, ...) \
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
(name, __VA_ARGS__ )))
#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 ************************************/
@@ -57,114 +82,157 @@
#define ISHAREDI_PTR_OPLIST_P1(arg) ISHAREDI_PTR_OPLIST_P2 arg
/* Validation of the given oplist */
#define ISHAREDI_PTR_OPLIST_P2(name, 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 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(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, _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),) \
#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),) \
)
// Deferred evaluatioin
#define ISHAREDI_PTR_DEF_P1(arg) ISHAREDI_PTR_DEF_P2 arg
/* Validate the oplist before going further */
#define ISHAREDI_PTR_DEF_P2(name, type, oplist) \
M_IF_OPLIST(oplist)(ISHAREDI_PTR_DEF_P3, ISHAREDI_PTR_DEF_FAILURE)(name, type, oplist)
#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) \
#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) \
\
typedef type *M_C(name,_t); \
typedef type M_C(name, _type_t); \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
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); \
} \
\
M_IF_METHOD2(INIT, NEW, oplist)( \
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; \
} \
, /* End of INIT/NEW */) \
\
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); \
} \
} \
\
#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
+1325 -1286
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-2020, 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
+81 -34
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Thin Mutex & Thread wrapper
*
* Copyright (c) 2017-2020, 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,16 +25,29 @@
#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];
@@ -116,7 +129,7 @@ static inline void m_thread_create(m_thread_t t, void (*func)(void*), void* arg)
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;
}
@@ -133,20 +146,20 @@ static inline void m_thread_yield(void)
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_oncei_t
// Initial value for m_once_ct
#define M_ONCEI_INIT_VALUE { ONCE_FLAG_INIT }
// Call the function exactly once
static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
{
call_once(o,func);
}
@@ -154,11 +167,31 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
// 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
@@ -167,11 +200,19 @@ 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];
@@ -247,7 +288,7 @@ 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);
}
@@ -263,7 +304,8 @@ static inline void m_thread_yield(void)
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);
@@ -274,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)
{
@@ -285,7 +327,7 @@ 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);
}
@@ -298,9 +340,11 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
# define M_THREAD_ATTR __thread
#endif
#else
M_END_PROTECTED_CODE
/**************************** PTHREAD version ******************************/
#else
#include <pthread.h>
#ifdef _POSIX_PRIORITY_SCHEDULING
@@ -313,6 +357,8 @@ 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];
@@ -403,7 +449,7 @@ 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.
@@ -422,25 +468,26 @@ 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.
@@ -456,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
+361 -306
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - dynamic priority queue module
*
* Copyright (c) 2017-2020, 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,23 +26,36 @@
#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_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
#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))))
(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_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
#define PRIOQUEUE_OPLIST(...) \
PRIOQUEUEI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
(__VA_ARGS__ )))
@@ -54,31 +67,40 @@
#define PRIOQUEUEI_OPLIST_P1(arg) PRIOQUEUEI_OPLIST_P2 arg
/* Validation of the given oplist */
#define PRIOQUEUEI_OPLIST_P2(name, 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 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,_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)) \
#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)), \
)
@@ -87,11 +109,11 @@
#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) \
#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) \
#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:
@@ -101,283 +123,316 @@
- prioqueue_t: type of the container,
- it_t: iterator of the container
*/
#define PRIOQUEUEI_DEF_P3(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; \
\
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) \
{ \
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)(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) \
{ \
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 const 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, 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, _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); \
#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
+1043 -1027
View File
File diff suppressed because it is too large. Load diff
+138 -41
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Serial BIN
*
* Copyright (c) 2017-2020, 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,6 +30,80 @@
#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
@@ -37,7 +111,7 @@ 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_SERIAL_FAIL;
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'.
@@ -54,26 +128,26 @@ m_serial_bin_write_integer(m_serial_write_t serial,const long long data, const s
FILE *f = (FILE *)serial->data[0].p;
switch (size_of_type) {
case 1:
i8 = data;
i8 = (int8_t) data;
n = fwrite (M_ASSIGN_CAST(const void*, &i8), sizeof i8, 1, f);
break;
case 2:
i16 = data;
i16 = (int16_t) data;
n = fwrite (M_ASSIGN_CAST(const void*, &i16), sizeof i16, 1, f);
break;
case 4:
i32 = data;
i32 = (int32_t) data;
n = fwrite (M_ASSIGN_CAST(const void*, &i32), sizeof i32, 1, f);
break;
case 8:
i64 = data;
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");
M_ASSERT_INIT(false, "an integer of suitable size (8/16/32/64)");
break;
}
return n == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
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'.
@@ -88,29 +162,34 @@ m_serial_bin_write_float(m_serial_write_t serial, const long double data, const
FILE *f = (FILE *)serial->data[0].p;
if (size_of_type == sizeof f1) {
f1 = data;
f1 = (float) data;
n = fwrite (M_ASSIGN_CAST(const void*, &f1), sizeof f1, 1, f);
} else if (size_of_type == sizeof f2) {
f2 = data;
f2 = (double) data;
n = fwrite (M_ASSIGN_CAST(const void*, &f2), sizeof f2, 1, f);
} else if (size_of_type == sizeof f3) {
f3 = data;
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_SERIAL_FAIL;
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[])
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;
size_t l = strlen(data);
size_t n = fwrite (M_ASSIGN_CAST(const void*, data), 1, l+1, f);
return n == l+1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
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'.
@@ -125,7 +204,7 @@ m_serial_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial,
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_SERIAL_FAIL;
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.
@@ -138,7 +217,7 @@ m_serial_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial)
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_SERIAL_FAIL;
return n == 1 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
} else {
return M_SERIAL_OK_CONTINUE;
}
@@ -154,7 +233,7 @@ m_serial_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial)
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_SERIAL_FAIL;
return n == 1 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
} else {
return M_SERIAL_OK_CONTINUE;
}
@@ -218,7 +297,7 @@ m_serial_bin_write_variant_start(m_serial_local_t local, m_serial_write_t serial
(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_SERIAL_FAIL;
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'.
@@ -263,6 +342,12 @@ static inline void m_serial_bin_write_clear(m_serial_write_t serial)
}
/* Define a synonym of m_serial_read_t to the BIN serializer with its proper OPLIST */
typedef m_serial_write_t m_serial_bin_write_t;
#define M_OPL_m_serial_bin_write_t() \
(INIT_WITH(m_serial_bin_write_init), CLEAR(m_serial_bin_write_clear), TYPE(m_serial_bin_write_t) )
/* 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 */
@@ -270,7 +355,7 @@ 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_SERIAL_FAIL;
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.
@@ -305,7 +390,7 @@ m_serial_bin_read_integer(m_serial_read_t serial, long long *i, const size_t siz
M_ASSERT_INIT(false, "an integer of suitable size");
break;
}
return n == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
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.
@@ -330,7 +415,7 @@ m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
} else {
M_ASSERT_INIT(false, "a float of suitable size");
}
return n == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Read from the stream 'serial' a string.
@@ -339,14 +424,19 @@ m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
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;
string_clean(s);
int c;
c = fgetc(f);
while (c != 0 && c != EOF) {
string_push_back(s, c);
c = fgetc(f);
}
return c != EOF ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
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.
@@ -362,7 +452,7 @@ m_serial_bin_read_array_start(m_serial_local_t local, m_serial_read_t serial, si
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_SERIAL_FAIL;
return m_core_serial_fail();
local->data[0].b = (*num == 0);
local->data[1].s = *num;
if (local->data[0].b) {
@@ -370,8 +460,8 @@ m_serial_bin_read_array_start(m_serial_local_t local, m_serial_read_t serial, si
size_t p;
n = fread (M_ASSIGN_CAST(void*, &p), sizeof p, 1, f);
if (n != 1)
return M_SERIAL_FAIL;
return p == 0xABCDEF ? M_SERIAL_OK_CONTINUE : p == 0x12345678 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
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;
}
@@ -389,10 +479,10 @@ m_serial_bin_read_array_next(m_serial_local_t local, m_serial_read_t serial)
size_t p, n;
n = fread (M_ASSIGN_CAST(void*, &p), sizeof p, 1, f);
if (n != 1)
return M_SERIAL_FAIL;
return p == 0xABCDEF ? M_SERIAL_OK_CONTINUE : p == 0x12345678 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
return m_core_serial_fail();
return p == 0xABCDEF ? M_SERIAL_OK_CONTINUE : p == 0x12345678 ? M_SERIAL_OK_DONE : m_core_serial_fail();
} else {
assert(local->data[1].s > 0);
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;
}
@@ -417,7 +507,7 @@ 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].s = 0;
local->data[1].i = 0;
return M_SERIAL_OK_CONTINUE;
}
@@ -433,8 +523,8 @@ m_serial_bin_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const
(void) serial;
(void) field_name;
(void) max;
*id = local->data[1].s;
local->data[1].s ++;
*id = local->data[1].i;
local->data[1].i ++;
return (*id == max) ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE;
}
@@ -452,7 +542,7 @@ m_serial_bin_read_variant_start(m_serial_local_t local, m_serial_read_t serial,
(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_SERIAL_FAIL;
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'.
@@ -493,4 +583,11 @@ 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
+85 -63
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Serial JSON
*
* Copyright (c) 2017-2020, 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,6 +28,8 @@
#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
@@ -35,7 +37,7 @@ 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_SERIAL_FAIL;
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'.
@@ -46,7 +48,7 @@ m_serial_json_write_integer(m_serial_write_t serial,const long long data, const
(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_SERIAL_FAIL;
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'.
@@ -57,20 +59,22 @@ m_serial_json_write_float(m_serial_write_t serial, const long double data, const
(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_SERIAL_FAIL;
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[])
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;
/* Build dummy string to reuse string_out_str */
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 = strlen(data);
v2->u.heap.alloc = v2->u.heap.size + 1;
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;
@@ -89,7 +93,7 @@ m_serial_json_write_array_start(m_serial_local_t local, m_serial_write_t serial,
(void) number_of_elements; // Ignored
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "[");
return n > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
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.
@@ -100,7 +104,7 @@ 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_SERIAL_FAIL;
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
/* End the writing of an array into the serial stream 'serial'.
@@ -111,7 +115,7 @@ 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_SERIAL_FAIL;
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'.
@@ -127,7 +131,7 @@ m_serial_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, c
(void) number_of_elements; // Ignored
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "{");
return n > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
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.
@@ -138,7 +142,7 @@ 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_SERIAL_FAIL;
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.
@@ -149,7 +153,7 @@ 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_SERIAL_FAIL;
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
/* End the writing of a map into the serial stream 'serial'.
@@ -160,7 +164,7 @@ 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_SERIAL_FAIL;
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Start writing a tuple into the serial stream 'serial'.
@@ -173,7 +177,7 @@ 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_SERIAL_FAIL;
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'.
@@ -185,7 +189,7 @@ m_serial_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, co
(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_SERIAL_FAIL;
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
/* End the write of a tuple into the serial stream 'serial'.
@@ -196,7 +200,7 @@ 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_SERIAL_FAIL;
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Start writing a variant into the serial stream 'serial'.
@@ -212,12 +216,12 @@ m_serial_json_write_variant_start(m_serial_local_t local, m_serial_write_t seria
FILE *f = (FILE *)serial->data[0].p;
int n;
if (index >= 0) {
assert (index < max);
M_ASSERT (index < max);
n = fprintf(f, "{\"%s\":", field_name[index]);
return n > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
} else {
n = fprintf(f, "{}");
return n > 0 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
}
@@ -229,7 +233,7 @@ 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_SERIAL_FAIL;
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* The internal exported interface of m_serial_write_json. */
@@ -267,7 +271,7 @@ static inline void m_serial_json_write_clear(m_serial_write_t serial)
/* 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() \
#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) )
@@ -293,25 +297,25 @@ m_serial_json_read_boolean(m_serial_read_t serial, bool *b){
if (c == 't') {
*b = true;
c = fgetc(f);
if (c != 'r') return M_SERIAL_FAIL;
if (c != 'r') return m_core_serial_fail();
c = fgetc(f);
if (c != 'u') return M_SERIAL_FAIL;
if (c != 'u') return m_core_serial_fail();
c = fgetc(f);
if (c != 'e') return M_SERIAL_FAIL;
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_SERIAL_FAIL;
if (c != 'a') return m_core_serial_fail();
c = fgetc(f);
if (c != 'l') return M_SERIAL_FAIL;
if (c != 'l') return m_core_serial_fail();
c = fgetc(f);
if (c != 's') return M_SERIAL_FAIL;
if (c != 's') return m_core_serial_fail();
c = fgetc(f);
if (c != 'e') return M_SERIAL_FAIL;
if (c != 'e') return m_core_serial_fail();
return M_SERIAL_OK_DONE;
} else {
return M_SERIAL_FAIL;
return m_core_serial_fail();
}
}
@@ -322,7 +326,7 @@ 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 fscanf(f, " %lld", i) == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
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.
@@ -332,7 +336,7 @@ 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 fscanf(f, " %Lf", r) == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
return m_core_fscanf(f, " %Lf", r) == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Read from the stream 'serial' a string.
@@ -341,8 +345,9 @@ m_serial_json_read_float(m_serial_read_t serial, long double *r, const size_t si
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;
fscanf(f, " "); // Skip any leading spaces.
return string_in_str(s, f) ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
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.
@@ -358,10 +363,12 @@ m_serial_json_read_array_start(m_serial_local_t local, m_serial_read_t serial, s
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
int final1 = -1, final2 = -1;
fscanf(f, " [%n ]%n", &final1, &final2);
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.
return (final1 < 0) ? M_SERIAL_FAIL : (final2 < 0) ? M_SERIAL_OK_CONTINUE : M_SERIAL_OK_DONE;
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.
@@ -374,8 +381,9 @@ 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;
fscanf(f, " %c", &c);
return c == ',' ? M_SERIAL_OK_CONTINUE : c == ']' ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
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.
@@ -384,17 +392,19 @@ m_serial_json_read_array_next(m_serial_local_t local, m_serial_read_t serial)
(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_SERIAL_FAIL otherwise */
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;
fscanf(f, " {%n }%n", &final1, &final2);
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.
return (final1 < 0) ? M_SERIAL_FAIL : (final2 < 0) ? M_SERIAL_OK_CONTINUE : M_SERIAL_OK_DONE;
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
@@ -406,8 +416,9 @@ 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;
fscanf(f, " :%n", &final);
return final > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
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.
@@ -420,8 +431,9 @@ 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;
fscanf(f, " %c", &c);
return c == ',' ? M_SERIAL_OK_CONTINUE : c == '}' ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
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'.
@@ -433,8 +445,9 @@ 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;
fscanf(f, " {%n", &final);
return final > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
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'.
@@ -449,21 +462,23 @@ m_serial_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, cons
(void) local; // argument not used
FILE *f = (FILE*) serial->data[0].p;
int c = m_serial_json_read_skip(f);
if (c == EOF) return M_SERIAL_FAIL;
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_SERIAL_FAIL;
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]; // TODO: fix error detection below.
fscanf(f, " \"%" M_APPLY(M_AS_STR, M_MAX_IDENTIFIER_LENGTH) "[^ \t\n\"]\":%n", field, &c);
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_SERIAL_FAIL;
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) {
@@ -471,7 +486,7 @@ m_serial_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, cons
return M_SERIAL_OK_CONTINUE;
}
}
return M_SERIAL_FAIL;
return m_core_serial_fail();
}
/* Start reading a variant from the stream 'serial'.
@@ -487,24 +502,28 @@ m_serial_json_read_variant_start(m_serial_local_t local, m_serial_read_t serial,
FILE *f = (FILE*) serial->data[0].p;
int final1 = -1, final2 = -1;
fscanf(f, " {%n }%n", &final1, &final2);
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_SERIAL_FAIL;
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];
fscanf(f, " \"%" M_APPLY(M_AS_STR, M_MAX_IDENTIFIER_LENGTH) "[^ \t\n\"]\":%n", field, &final2);
if (final2 <= 0) return M_SERIAL_FAIL;
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();
/* Search for field in field_name */
/* 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;
}
}
return M_SERIAL_FAIL;
// Field not found
return m_core_serial_fail();
}
/* End reading a variant from the stream 'serial'.
@@ -516,8 +535,9 @@ 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;
fscanf(f, " }%n", &final);
return final > 0 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
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 = {
@@ -552,7 +572,9 @@ static inline void m_serial_json_read_clear(m_serial_read_t serial)
/* 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() \
#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
+406 -354
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - SHARED Module
*
* Copyright (c) 2017-2020, 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,37 +29,79 @@
#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_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
#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_P1(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_P1(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_P1(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
@@ -68,41 +110,41 @@
// deferred evaluation
#define SHAREDI_PTR_OPLIST_P1(arg) SHAREDI_PTR_OPLIST_P2 arg
/* Validation of the given oplist */
#define SHAREDI_PTR_OPLIST_P2(name, 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_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, _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),) \
#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),) \
)
// 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
#define SHAREDI_INTEGER_OPLIST (TYPE(int), \
INIT_SET(sharedi_integer_init_set), \
ADD(sharedi_integer_add), \
SUB(sharedi_integer_sub), \
#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 */
@@ -112,343 +154,353 @@ static inline int sharedi_integer_sub(int *p, int val) { int r = *p; *p -= val;
static inline int sharedi_integer_cref(int *p) { return *p; }
/* Contract of a shared pointer */
#define SHAREDI_CONTRACT(shared, cpt_oplist) do { \
assert(shared != NULL); \
assert(*shared == NULL || M_CALL_IT_CREF(cpt_oplist, &(*shared)->cpt) >= 1); \
#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)
// 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_t) \
M_IF_OPLIST(oplist)(SHAREDI_PTR_DEF_P3, SHAREDI_PTR_DEF_FAILURE)(name, type, oplist, cpt_oplist_t)
#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) \
#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) \
\
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]; \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
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; \
} \
#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_P1(arg) SHAREDI_RESOURCE_DEF_P2 arg
/* Validate the oplist before going further */
#define SHAREDI_RESOURCE_DEF_P2(name, type, oplist) \
M_IF_OPLIST(oplist)(SHAREDI_RESOURCE_DEF_P3, SHAREDI_RESOURCE_DEF_FAILURE)(name, type, oplist)
#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) \
#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) \
\
/* 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); \
} \
} \
#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
+505 -390
View File
File diff suppressed because it is too large. Load diff
+846 -587
View File
File diff suppressed because it is too large. Load diff
+490 -420
View File
File diff suppressed because it is too large. Load diff
+537 -464
View File
File diff suppressed because it is too large. Load diff
+83 -75
View File
@@ -1,7 +1,7 @@
/*
* M*LIB / WORKER - Extra worker interface
*
* Copyright (c) 2017-2020, 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:
@@ -43,8 +43,8 @@
/* Include needed system header for detection of how many core on the system */
#if defined(_WIN32)
# include <windows.h>
#elif (defined(__APPLE__) && defined(__MACH__)) \
|| defined(__DragonFly__) || defined(__FreeBSD__) \
#elif (defined(__APPLE__) && defined(__MACH__)) \
|| defined(__DragonFly__) || defined(__FreeBSD__) \
|| defined(__NetBSD__) || defined(__OpenBSD__)
# include <sys/param.h>
# include <sys/sysctl.h>
@@ -93,6 +93,8 @@
# error M_USE_WORKER_CPP_FUNCTION and M_USE_WORKER_CLANG_BLOCK are both defined. This is not supported.
#endif
M_BEGIN_PROTECTED_CODE
/* Definition of a work order */
typedef struct work_order_s {
struct worker_sync_s *block; // Reference to the shared Synchronization block
@@ -104,7 +106,7 @@ typedef struct work_order_s {
#if M_USE_WORKER_CPP_FUNCTION
std::function<void(void*)> function; // The work order function (for C++)
#endif
} worker_order_t;
} worker_order_ct;
/* Define the macros needed to initialize an order.
* * MACRO to be used to send an empty order to stop the thread
@@ -122,11 +124,11 @@ typedef struct work_order_s {
is not sufficient for initialization of the structure.
So let's use C++ constructor, destructor and copy constructor */
#if M_USE_WORKER_CPP_FUNCTION
# define WORKERI_CPP_INIT(x) (new (&(x)) worker_order_t())
# define WORKERI_CPP_INIT_SET(x, y) (new (&(x)) worker_order_t(y))
# define WORKERI_CPP_INIT(x) (new (&(x)) worker_order_ct())
# define WORKERI_CPP_INIT_SET(x, y) (new (&(x)) worker_order_ct(y))
# define WORKERI_CPP_SET(x, y) ((x) = (y))
# define WORKERI_CPP_CLEAR(x) ((&(x))->~worker_order_t())
# define WORKERI_CPP_INIT_MOVE(x,y) (new (&(x)) worker_order_t(y), ((&(y))->~worker_order_t()))
# define WORKERI_CPP_CLEAR(x) ((&(x))->~worker_order_ct())
# define WORKERI_CPP_INIT_MOVE(x,y) (new (&(x)) worker_order_ct(y), ((&(y))->~worker_order_ct()))
# define WORKER_OPLIST \
(INIT(WORKERI_CPP_INIT), INIT_SET(WORKERI_CPP_INIT_SET), \
SET(WORKERI_CPP_SET), CLEAR(WORKERI_CPP_CLEAR), INIT_MOVE(WORKERI_CPP_INIT_MOVE) )
@@ -137,19 +139,19 @@ typedef struct work_order_s {
/* Definition of a worker (implemented by a thread) */
typedef struct worker_thread_s {
m_thread_t id;
} worker_thread_t;
} worker_thread_ct;
/* Definition of the queue that will record the work orders */
BUFFER_DEF(worker_queue, worker_order_t, 0,
BUFFER_DEF_AS(worker_queue, m_worker_queue_ct, worker_order_ct, 0,
BUFFER_QUEUE|BUFFER_UNBLOCKING_PUSH|BUFFER_BLOCKING_POP|BUFFER_THREAD_SAFE|BUFFER_DEFERRED_POP, WORKER_OPLIST)
/* Definition the global pool of workers */
typedef struct worker_s {
/* The work order queue */
worker_queue_t queue_g;
m_worker_queue_ct queue_g;
/* The table of available workers */
worker_thread_t *worker;
worker_thread_ct *worker;
/* Number of workers in the table */
unsigned int numWorker_g;
@@ -161,7 +163,7 @@ typedef struct worker_s {
void (*clearFunc_g)(void);
m_mutex_t lock;
m_cond_t a_thread_ends; // A worker has ended
m_cond_t a_thread_ends; // EVENT: A worker has ended
} worker_t[1];
@@ -179,7 +181,8 @@ workeri_get_cpu_count(void)
#if defined(_WIN32)
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors;
M_ASSERT(sysinfo.dwNumberOfProcessors <= INT_MAX);
return (int) sysinfo.dwNumberOfProcessors;
#elif defined(M_USE_WORKER_SYSCTL)
int nm[2];
int count = 0;
@@ -189,7 +192,7 @@ workeri_get_cpu_count(void)
sysctl(nm, 2, &count, &len, NULL, 0);
return M_MAX(1, count);
#elif defined (_SC_NPROCESSORS_ONLN)
return sysconf(_SC_NPROCESSORS_ONLN);
return (int) sysconf(_SC_NPROCESSORS_ONLN);
#else
return 1;
#endif
@@ -204,9 +207,9 @@ workeri_get_cpu_count(void)
/* Execute the registered work order **synchronously** */
static inline void
workeri_exec(worker_order_t *w)
workeri_exec(worker_order_ct *w)
{
assert (w!= NULL && w->block != NULL);
M_ASSERT (w!= NULL && w->block != NULL);
WORKERI_DEBUG ("Starting thread with data %p\n", w->data);
#if M_USE_WORKER_CLANG_BLOCK
WORKERI_DEBUG ("Running %s f=%p b=%p\n", (w->func == NULL) ? "Blocks" : "Function", w->func, w->blockFunc);
@@ -233,7 +236,7 @@ workeri_thread(void *arg)
// Get back the given argument
struct worker_s *g = M_ASSIGN_CAST(struct worker_s *, arg);
while (true) {
worker_order_t w;
worker_order_ct w;
// If needed, reset the global state of the worker
if (g->resetFunc_g != NULL) {
g->resetFunc_g();
@@ -271,20 +274,22 @@ workeri_thread(void *arg)
static inline void
worker_init(worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
{
assert (numWorker >= -1);
M_ASSERT (numWorker >= -1);
// Auto compute number of workers if the argument is 0
if (numWorker <= 0)
numWorker = (1 + (numWorker == -1))*workeri_get_cpu_count()-1;
WORKERI_DEBUG ("Starting queue with: %d\n", numWorker + extraQueue);
// Initialization
size_t numWorker_st = numWorker;
g->worker = M_MEMORY_REALLOC(worker_thread_t, NULL, numWorker_st);
// numWorker can still be 0 if it is a single core cpu (no worker available)
M_ASSERT(numWorker >= 0);
size_t numWorker_st = (size_t) numWorker;
g->worker = M_MEMORY_REALLOC(worker_thread_ct, NULL, numWorker_st);
if (g->worker == NULL) {
M_MEMORY_FULL(sizeof (worker_thread_t) * numWorker_st);
M_MEMORY_FULL(sizeof (worker_thread_ct) * numWorker_st);
return;
}
worker_queue_init(g->queue_g, numWorker + extraQueue);
g->numWorker_g = numWorker_st;
worker_queue_init(g->queue_g, numWorker_st + extraQueue);
g->numWorker_g = (unsigned int) numWorker_st;
g->resetFunc_g = resetFunc;
g->clearFunc_g = clearFunc;
m_mutex_init(g->lock);
@@ -308,10 +313,10 @@ worker_init(worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc
static inline void
worker_clear(worker_t g)
{
assert (worker_queue_empty_p (g->queue_g));
M_ASSERT (worker_queue_empty_p (g->queue_g));
// Push the terminate order on the queue
for(unsigned int i = 0; i < g->numWorker_g; i++) {
worker_order_t w = WORKERI_EMPTY_ORDER;
worker_order_ct w = WORKERI_EMPTY_ORDER;
// Normaly all worker threads shall be waiting at this
// stage, so all push won't block as the queue is empty.
// But for robustness, let's wait.
@@ -346,7 +351,7 @@ worker_start(worker_sync_t block, worker_t g)
static inline void
worker_spawn(worker_sync_t block, void (*func)(void *data), void *data)
{
const worker_order_t w = { block, data, func WORKERI_EXTRA_ORDER };
const worker_order_ct w = { block, data, func WORKERI_EXTRA_ORDER };
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
&& worker_queue_push (block->worker->queue_g, w) == true) {
WORKERI_DEBUG ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
@@ -364,7 +369,7 @@ worker_spawn(worker_sync_t block, void (*func)(void *data), void *data)
static inline void
worker_spawn_block(worker_sync_t block, void (^func)(void *data), void *data)
{
const worker_order_t w = { block, data, NULL, func };
const worker_order_ct w = { block, data, NULL, func };
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
&& worker_queue_push (block->worker->queue_g, w) == true) {
WORKERI_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
@@ -383,7 +388,7 @@ worker_spawn_block(worker_sync_t block, void (^func)(void *data), void *data)
static inline void
worker_spawn_function(worker_sync_t block, std::function<void(void *data)> func, void *data)
{
const worker_order_t w = { block, data, NULL, func };
const worker_order_ct w = { block, data, NULL, func };
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
&& worker_queue_push (block->worker->queue_g, w) == true) {
WORKERI_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
@@ -425,7 +430,7 @@ worker_sync(worker_sync_t block)
static inline void
worker_flush(worker_t g)
{
worker_order_t w;
worker_order_ct w;
while (worker_queue_pop_blocking (&w, g->queue_g, false) == true) {
workeri_exec(&w);
worker_queue_pop_release(g->queue_g);
@@ -445,81 +450,84 @@ worker_count(worker_t g)
'block' shall be the initialised synchronised block for all threads.
'input' is the list of input variables of the 'core' block within "( )"
'output' is the list of output variables of the 'core' block within "( )"
Output variables are only available after a synchronisation block. */
Output variables are only available after a synchronisation block.
TODO: Support oplist for input & outputs parameters
*/
#if M_USE_WORKER_CLANG_BLOCK
#define WORKER_SPAWN(_block, _input, _core, _output) \
WORKER_DEF_DATA(_input, _output) \
WORKER_DEF_SUBBLOCK(_input, _output, _core) \
#define WORKER_SPAWN(_block, _input, _core, _output) \
WORKER_DEF_DATA(_input, _output) \
WORKER_DEF_SUBBLOCK(_input, _output, _core) \
worker_spawn_block ((_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
#elif M_USE_WORKER_CPP_FUNCTION
// TODO: Explicit pass all arguments by reference.
#define WORKER_SPAWN(_block, _input, _core, _output) \
#define WORKER_SPAWN(_block, _input, _core, _output) \
worker_spawn_function ((_block), [&](void *param) {(void)param ; _core } , NULL)
#else
#define WORKER_SPAWN(_block, _input, _core, _output) \
WORKER_DEF_DATA(_input, _output) \
WORKER_DEF_SUBFUNC(_input, _output, _core) \
#define WORKER_SPAWN(_block, _input, _core, _output) \
WORKER_DEF_DATA(_input, _output) \
WORKER_DEF_SUBFUNC(_input, _output, _core) \
worker_spawn ((_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
#endif
#define WORKER_SPAWN_STRUCT_NAME M_C(worker_data_s_, __LINE__)
#define WORKER_SPAWN_DATA_NAME M_C(worker_data_, __LINE__)
#define WORKER_SPAWN_SUBFUNC_NAME M_C(worker_subfunc_, __LINE__)
#define WORKER_DEF_DATA(_input, _output) \
struct WORKER_SPAWN_STRUCT_NAME { \
WORKER_DEF_DATA_INPUT _input \
M_IF_EMPTY _output ( , WORKER_DEF_DATA_OUTPUT _output) \
} WORKER_SPAWN_DATA_NAME = { \
WORKER_INIT_DATA_INPUT _input \
M_IF_EMPTY _output (, WORKER_INIT_DATA_OUTPUT _output) \
#define WORKER_DEF_DATA(_input, _output) \
struct WORKER_SPAWN_STRUCT_NAME { \
WORKER_DEF_DATA_INPUT _input \
M_IF_EMPTY _output ( , WORKER_DEF_DATA_OUTPUT _output) \
} WORKER_SPAWN_DATA_NAME = { \
WORKER_INIT_DATA_INPUT _input \
M_IF_EMPTY _output (, WORKER_INIT_DATA_OUTPUT _output) \
};
#define WORKER_DEF_SINGLE_INPUT(var) __typeof__(var) var;
#define WORKER_DEF_DATA_INPUT(...) \
#define WORKER_DEF_DATA_INPUT(...) \
M_MAP(WORKER_DEF_SINGLE_INPUT, __VA_ARGS__)
#define WORKER_DEF_SINGLE_OUTPUT(var) \
#define WORKER_DEF_SINGLE_OUTPUT(var) \
__typeof__(var) *M_C(var, _ptr);
#define WORKER_DEF_DATA_OUTPUT(...) \
#define WORKER_DEF_DATA_OUTPUT(...) \
M_MAP(WORKER_DEF_SINGLE_OUTPUT, __VA_ARGS__)
#define WORKER_INIT_SINGLE_INPUT(var) \
#define WORKER_INIT_SINGLE_INPUT(var) \
.var = var,
#define WORKER_INIT_DATA_INPUT(...) \
#define WORKER_INIT_DATA_INPUT(...) \
M_MAP(WORKER_INIT_SINGLE_INPUT, __VA_ARGS__)
#define WORKER_INIT_SINGLE_OUTPUT(var) \
#define WORKER_INIT_SINGLE_OUTPUT(var) \
.M_C(var, _ptr) = &var,
#define WORKER_INIT_DATA_OUTPUT(...) \
#define WORKER_INIT_DATA_OUTPUT(...) \
M_MAP(WORKER_INIT_SINGLE_OUTPUT, __VA_ARGS__)
#define WORKER_DEF_SUBFUNC(_input, _output, _core) \
__extension__ auto void WORKER_SPAWN_SUBFUNC_NAME(void *) ; \
__extension__ void WORKER_SPAWN_SUBFUNC_NAME(void *_data) \
{ \
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
WORKER_INIT_LOCAL_INPUT _input \
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
do { _core } while (0); \
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
#define WORKER_DEF_SUBFUNC(_input, _output, _core) \
__extension__ auto void WORKER_SPAWN_SUBFUNC_NAME(void *) ; \
__extension__ void WORKER_SPAWN_SUBFUNC_NAME(void *_data) \
{ \
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
WORKER_INIT_LOCAL_INPUT _input \
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
do { _core } while (0); \
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
};
#define WORKER_DEF_SUBBLOCK(_input, _output, _core) \
void (^WORKER_SPAWN_SUBFUNC_NAME) (void *) = ^ void (void * _data) \
{ \
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
WORKER_INIT_LOCAL_INPUT _input \
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
do { _core } while (0); \
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
#define WORKER_DEF_SUBBLOCK(_input, _output, _core) \
void (^WORKER_SPAWN_SUBFUNC_NAME) (void *) = ^ void (void * _data) \
{ \
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
WORKER_INIT_LOCAL_INPUT _input \
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
do { _core } while (0); \
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
};
#define WORKER_INIT_SINGLE_LOCAL_INPUT(var) \
#define WORKER_INIT_SINGLE_LOCAL_INPUT(var) \
__typeof__(var) var = _s_data->var;
#define WORKER_INIT_LOCAL_INPUT(...) \
#define WORKER_INIT_LOCAL_INPUT(...) \
M_MAP(WORKER_INIT_SINGLE_LOCAL_INPUT, __VA_ARGS__)
#define WORKER_INIT_SINGLE_LOCAL_OUTPUT(var) \
#define WORKER_INIT_SINGLE_LOCAL_OUTPUT(var) \
__typeof__(var) var;
#define WORKER_INIT_LOCAL_OUTPUT(...) \
#define WORKER_INIT_LOCAL_OUTPUT(...) \
M_MAP(WORKER_INIT_SINGLE_LOCAL_OUTPUT, __VA_ARGS__)
#define WORKER_PROPAGATE_SINGLE_OUTPUT(var) \
#define WORKER_PROPAGATE_SINGLE_OUTPUT(var) \
*(_s_data->M_C(var, _ptr)) = var;
#define WORKER_PROPAGATE_LOCAL_OUTPUT(...) \
#define WORKER_PROPAGATE_LOCAL_OUTPUT(...) \
M_MAP(WORKER_PROPAGATE_SINGLE_OUTPUT, __VA_ARGS__)
M_END_PROTECTED_CODE
#else /* M_USE_WORKER */
+45 -21
View File
@@ -1,3 +1,25 @@
REM Copyright (c) 2017-2021, Patrick Pelissier
REM All rights reserved.
REM
REM Redistribution and use in source and binary forms, with or without
REM modification, are permitted provided that the following conditions are met:
REM + Redistributions of source code must retain the above copyright
REM notice, this list of conditions and the following disclaimer.
REM + Redistributions in binary form must reproduce the above copyright
REM notice, this list of conditions and the following disclaimer in the
REM documentation and/or other materials provided with the distribution.
REM
REM THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
REM EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
REM WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
REM DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
REM DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
REM (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
REM LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
REM ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
REM (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
REM SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REM Execute the test suite for Microsoft Visual Studio
REM
REM Load Micosoft Visual Studio environement file.
@@ -8,46 +30,48 @@ IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxi
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
)
REM Add clang-cl in the PATH. It is the default install of clang for MSVC:
REM %VCINSTALLDIR%\Tools\Llvm\bin;%VCINSTALLDIR%\Tools\Llvm\x64\bin
REM Adding x64 version
REM See https://docs.microsoft.com/de-de/cpp/build/clang-support-msbuild?view=vs-2019
SET PATH=%PATH%;%VCINSTALLDIR%\Tools\Llvm\x64\bin
REM Remove previous results
DEL *.log *.dat
REM List the expected failure (compiler internal error)
set "expectedFailure=test-msnapshot.c"
REM Select compiler to use (either cl or clang-cl)
set "compiler=%1"
echo "Compiler full version:"
cl /Bv
echo " "
echo "Disabled tests passed due to wrong errors C4002 C4003 preventing build"
exit /B 0
echo "Compiler full version (%compiler%):"
%compiler% /Bv
%compiler% -v
REM Perform for each test
for %%f in (test-*.c) do (
echo =================================================
echo Testing %%f
REM Copy the test file as a C++ file as CL.EXE only support C++ file
copy %%f test.cpp
if ERRORLEVEL 1 EXIT /B 1
del test.exe
copy %%f test.cpp || EXIT /B 1
REM Compile the test suite
REM /experimental:preprocessor is mandatory to have a compliant preprocessor
REM /Zc:preprocessor is mandatory to have a compliant preprocessor
REM /Zc:__cplusplus is needed to report the real value of __cplusplus, so that M*LIB uses the C++ atomic, and not its emulation.
echo Compiling %%f
cl.exe /I.. /O2 /std:c++14 /Zc:__cplusplus /experimental:preprocessor test.cpp > %%f.log 2>&1
if ERRORLEVEL 1 (
REM Enable warnings and basic optimization
REM Inform M*LIB to use Annex K by defining __STDC_WANT_LIB_EXT1__
echo Compiling %%f with %compiler%
%compiler% /I.. /O2 /W3 /std:c++14 /Zc:__cplusplus /Zc:preprocessor /D__STDC_WANT_LIB_EXT1__ test.cpp > %%f.log 2>&1 || (
echo *** BUILD ERROR for %%f *** >> %%f.log
type %%f.log
if /i "%%f" NEQ "%expectedFailure%" EXIT /B 1
EXIT /B 1
)
REM Execute it
echo Running %%f
test.exe >> %%f.log 2>&1
if ERRORLEVEL 1 (
test.exe >> %%f.log 2>&1 && echo Test OK for %%f >> %%f.log || (
echo *** RUNTIME ERROR for %%f *** >> %%f.log
type %%f.log
if /i "%%f" NEQ "%expectedFailure%" EXIT /B 1
) ELSE (
echo Test OK for %%f >> %%f.log
EXIT /B 1
)
type %%f.log
)
echo "All tests passed (except %expectedFailure%)"
echo "All tests passed"
exit /B 0
+62 -42
View File
@@ -1,7 +1,29 @@
# 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
WCFLAGS_GCC=-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 -ftrapv
WCFLAGS_CLANG=-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 -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -ftrapv
WCFLAGS_CPP=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wstrict-overflow=5 -Winline -Wundef -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wno-unused-function -ftrapv
WCFLAGS_GCC=-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 -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wunused-function -ftrapv -Wsign-conversion -Wdate-time -Wconversion -Wformat=2 -Winit-self -Wjump-misses-init -Wstack-protector -Wtrampolines -Wwrite-strings -Wformat-security -Wno-float-conversion -O
WCFLAGS_CLANG=-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 -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wunused-function -ftrapv -Wsign-conversion -O
WCFLAGS_CPP=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wstrict-overflow=5 -Winline -Wundef -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wunused-function -ftrapv -Wsign-conversion
XCFLAGS=
CFLAGS=$(WCFLAGS_GCC) $(XCFLAGS)
CPPFLAGS=-I..
@@ -20,9 +42,9 @@ all:
#####################################################################################################
.POSIX:
.PHONY: valgrind scan-build sanitize check clean *.log coverage synthesis
.PHONY: scan-build sanitize check clean *.log coverage synthesis
.SUFFIXES:
.SUFFIXES: .c .exe .log .depend .valgrind .gcov
.SUFFIXES: .c .exe .log .depend .gcov
.SECONDARY:
.c.exe:
@@ -34,9 +56,6 @@ all:
.exe.log:
$(LOG_COMPILER) ./$<
.exe.valgrind:
valgrind ./$<
.c.gcov:
awk '/START_COVERAGE/ { printit=1} (printit == 0) { print }' $< > $<.first.c
awk ' printit { print } /END_COVERAGE/ { printit=1}' $< > $<.end.c
@@ -63,13 +82,17 @@ depend:
# Clean
#####################################################################################################
exe: depend
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.exe/g'` CC="$(CC)" CFLAGS="$(CFLAGS)"
@echo All executable generated
check: depend
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'` `ls fail-*.c|$(SED) 's/\.c/\.log/g'`
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'` `ls fail-*.c|$(SED) 's/\.c/\.log/g'` CC="$(CC)" CFLAGS="$(CFLAGS)"
@echo All tests passed
clean:
$(RM) *.exe *.s *~ *.o *.log a*.dat
$(RM) *.valgrind *.gcda *.gcno *.gcov all.info test.tar *.synt clang_output_* *.c.c *.end.c *.first.c *.middle.c
$(RM) *.gcda *.gcno *.gcov all.info test.tar *.synt clang_output_* *.c.c *.end.c *.first.c *.middle.c
$(RMDIR) coverage coverage-dir mlib-report
distclean: clean
@@ -85,13 +108,13 @@ FAIL_BASE=
FAIL_SEQ=
fail-generic.log:
for i in `seq 1 $(FAIL_SEQ)` ; do \
if $(CC) $(CFLAGS) $(CPPFLAGS) -g -c $(FAIL_BASE).c -o tmp.o -DTEST=$$i 2> $(FAIL_BASE)-$$i.log ; then echo $(FAIL_BASE) -- TEST $$i : ERROR; false; else echo $(FAIL_BASE) -- TEST $$i : OK ; fi \
if $(CC) $(CFLAGS) $(CPPFLAGS) -g -c $(FAIL_BASE).c -o tmp.o -DTEST=$$i 2> $(FAIL_BASE)-$$i.log ; then echo "$(FAIL_BASE) -- TEST $$i : ERROR (compilation succeeded)" ; false ; elif grep -q "M_LIB_" $(FAIL_BASE)-$$i.log ; then echo "$(FAIL_BASE) -- TEST $$i : OK" ; else echo "$(FAIL_BASE) -- TEST $$i : WARNING (Not a M*LIB detected error)" ; fi \
done
fail-no-oplist.log:
@$(MAKE) fail-generic.log FAIL_BASE=fail-no-oplist FAIL_SEQ=44
fail-chain-oplist.log:
@$(MAKE) fail-generic.log FAIL_BASE=fail-chain-oplist FAIL_SEQ=23
@$(MAKE) fail-generic.log FAIL_BASE=fail-chain-oplist FAIL_SEQ=24
fail-incompatible.log:
@$(MAKE) fail-generic.log FAIL_BASE=fail-incompatible FAIL_SEQ=24
@@ -122,7 +145,6 @@ gene-string:
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -march=native -DNDEBUG -S tgen-mstring.c && less tgen-mstring.s
#####################################################################################################
# Coverage
#####################################################################################################
@@ -131,39 +153,40 @@ coverage:
$(MAKE) synthesis
SYNTHESIS_DATA= M-ALGO test-malgo.c.c test-malgo.synt \
M-ARRAY test-marray.c.c test-marray.synt \
M-BITSET ../m-bitset.h test-mbitset.synt \
M-BBPTREE test-mbptree.c test-mbptree.synt \
M-BUFFER test-mbuffer.c.c test-mbuffer.synt \
M-ARRAY test-marray.c.c test-marray.synt \
M-BITSET ../m-bitset.h test-mbitset.synt \
M-BBPTREE test-mbptree.c test-mbptree.synt \
M-BUFFER test-mbuffer.c.c test-mbuffer.synt \
M-CONCURRENT test-mconcurrent.c.c test-mconcurrent.synt \
M-CORE test-mcore.c.c test-mcore.synt \
M-DEQUE test-mdeque.c.c test-mdeque.synt \
M-DICT test-mdict.c.c test-mdict.synt \
M-FUNCOBJ test-mfuncobj.c.c test-mfuncobj.synt \
M-GENINT ../m-genint.h test-mgenint.synt \
M-I-LIST test-milist.c.c test-milist.synt \
M-LIST test-mlist.c.c test-mlist.synt \
M-MEMPOOL test-mmempool.c.c test-mmempool.synt \
M-MUTEX ../m-mutex.h test-mmutex.synt \
M-CORE test-mcore.c.c test-mcore.synt \
M-DEQUE test-mdeque.c.c test-mdeque.synt \
M-DICT test-mdict.c.c test-mdict.synt \
M-FUNCOBJ test-mfuncobj.c.c test-mfuncobj.synt \
M-GENINT ../m-genint.h test-mgenint.synt \
M-I-LIST test-milist.c.c test-milist.synt \
M-I-SHARED test-mishared.c.c test-mishared.synt \
M-LIST test-mlist.c.c test-mlist.synt \
M-MEMPOOL test-mmempool.c.c test-mmempool.synt \
M-MUTEX ../m-mutex.h test-mmutex.synt \
M-PRIOQUEUE test-mprioqueue.c.c test-mprioqueue.synt \
M-RBTREE test-mrbtree.c.c test-mrbtree.synt \
M-RBTREE test-mrbtree.c.c test-mrbtree.synt \
M-SERIAL-BIN ../m-serial-bin.h test-mserial-bin.synt \
M-SERIAL-JSON ../m-serial-json.h test-mserial-json.synt \
M-SHARED test-mshared.c.c test-mshared.synt \
M-SNAPSHOT test-msnapshot.c.c test-msnapshot.synt \
M-STRING ../m-string.h test-mstring.synt \
M-TUPLE test-mtuple.c.c test-mtuple.synt \
M-VARIANT test-mvariant.c.c test-mvariant.synt \
M-SHARED test-mshared.c.c test-mshared.synt \
M-SNAPSHOT test-msnapshot.c.c test-msnapshot.synt \
M-STRING ../m-string.h test-mstring.synt \
M-TUPLE test-mtuple.c.c test-mtuple.synt \
M-VARIANT test-mvariant.c.c test-mvariant.synt \
M-WORKER ../m-worker.h test-mworker.synt
synthesis:
@printf "+-------------------------------+-------------------------------+\n"
@for i in $(SYNTHESIS_DATA) ; do \
if test "$$j" = "" ; then j=$$i ; continue ; fi; \
if test "$$k" = "" ; then k=$$i ; continue ; fi; \
@for i in $(SYNTHESIS_DATA) ; do \
if test "$$j" = "" ; then j=$$i ; continue ; fi; \
if test "$$k" = "" ; then k=$$i ; continue ; fi; \
printf "|\t%16.16s\t|\t%16.16s\t|\n" "$$j" "`grep -v Creating $$i|grep $$k -F -A1 |tail -1|cut -f2 -d':'`"; \
j=""; \
k=""; \
j=""; \
k=""; \
done
@printf "+-------------------------------+-------------------------------+\n"
@@ -172,15 +195,12 @@ synthesis:
# Code analyzer tools
#####################################################################################################
valgrind:
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.valgrind/g'`
scan-build: clean
$(RM) -rf ./mlib-report
scan-build -o ./mlib-report $(MAKE) check XCFLAGS="-std=c99"
scan-build -o ./mlib-report $(MAKE) exe XCFLAGS="-std=c99"
sanitize:
$(MAKE) clean check XCFLAGS="-fsanitize=address,undefined"
$(MAKE) clean check XCFLAGS="-fsanitize=address,undefined,leak"
$(MAKE) clean check XCFLAGS="-fsanitize=thread -pie -fPIE"
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
+10 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -221,6 +221,15 @@ int f(void) {
return r;
}
#elif TEST == 24
#include "m-tuple.h"
#include "m-string.h"
TUPLE_DEF2(aggregate, (x, int), (z, string_t))
#define M_OPL_aggregate_t() TUPLE_OPLIST(aggregate, int, string_t)
TUPLE_DEF2(struct2, (a, aggregate_t))
#else
# warning TEST variable is out of range.
#endif
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
+4 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -40,8 +40,10 @@ void f(int x, int y) {
#elif TEST == 2
#define OP (SWAP(0))
void f(int x, int y) {
M_CALL_SET(M_VALID_OPLIST(DEFAULT_OPLIST), x, y);
M_CALL_SWAP(OP, x, y);
}
#elif TEST == 3
+48 -14
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -48,6 +48,8 @@ DICT_DEF2(dict_obj, string_t, STRING_OPLIST, testobj_t, TESTOBJ_OPLIST)
LIST_DUAL_PUSH_DEF(dlist_int, int)
DICT_DEF2(dict_int, string_t, int)
#define M_OPL_dict_int_t() DICT_OPLIST(dict_int, STRING_OPLIST, M_DEFAULT_OPLIST)
ARRAY_DEF(array_uint, unsigned int)
#define M_OPL_array_uint_t() ARRAY_OPLIST(array_uint)
#include "coverage.h"
START_COVERAGE
@@ -153,7 +155,7 @@ static void test_list(void)
assert(g_count == 101);
assert(list_int_size(tmp) == 101);
for(int i = 0; i < 100; i++) {
assert(*list_int_get(tmp, i) == i * i);
assert(*list_int_get(tmp, (size_t) i) == i * i);
}
assert(*list_int_get(tmp, 100) == 17 * 17);
}
@@ -215,6 +217,37 @@ static void test_list(void)
assert (list_int_end_p (it1));
list_int_clear(l);
M_LET( (l1, 1, 3, 5), (l2, 1, 2, 4), (l3, 1, 2, 3, 4, 5), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
algo_list_sort_union(l1, l2);
assert(list_int_equal_p (l1, l3));
}
M_LET( (l1, 1, 30, 31), (l2, 2, 4, 31, 32), (l3, 1, 2, 4, 30, 31, 32), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
algo_list_sort_union(l1, l2);
assert(list_int_equal_p (l1, l3));
}
M_LET( (l1, 4, 28, 29, 30, 34), (l2, 1, 3, 31, 32, 33), (l3, 1, 3, 4, 28, 29, 30, 31, 32, 33, 34), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
algo_list_sort_union(l1, l2);
assert(list_int_equal_p (l1, l3));
}
M_LET( (l1, 1, 4, 28, 29, 31, 34), (l2, 1, 3, 31, 32, 33), (l3, 1, 31), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
algo_list_sort_intersect(l1, l2);
assert(list_int_equal_p (l1, l3));
}
M_LET( (l1, 4, 28, 29, 31, 34), (l2, 1, 3, 31, 32, 33), (l3, 31), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
algo_list_sort_intersect(l1, l2);
assert(list_int_equal_p (l1, l3));
}
M_LET( (l1, 1, 4, 28, 29, 31, 34), (l2, 3, 32, 33), l3, LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
algo_list_sort_intersect(l1, l2);
assert(list_int_equal_p (l1, l3));
}
}
static void test_array(void)
@@ -282,8 +315,8 @@ static void test_array(void)
assert(g_count == 101);
assert(array_int_size(tmp) == 101);
for(int i = 0; i < 100; i++) {
assert(*array_int_get(l, i) == i);
assert(*array_int_get(tmp, i) == i * i);
assert(*array_int_get(l, (size_t) i) == i);
assert(*array_int_get(tmp, (size_t) i) == i * i);
}
assert(*array_int_get(l, 100) == 17);
assert(*array_int_get(tmp, 100) == 17 * 17);
@@ -293,8 +326,8 @@ static void test_array(void)
ALGO_TRANSFORM(tmp, array_int_t, l, array_int_t, FT);
assert(array_int_size(tmp) == 101);
for(int i = 0; i < 100; i++) {
assert(*array_int_get(l, i) == i);
assert(*array_int_get(tmp, i) == i + 1);
assert(*array_int_get(l, (size_t) i) == i);
assert(*array_int_get(tmp, (size_t) i) == i + 1);
}
array_int_clean(tmp);
@@ -302,8 +335,8 @@ static void test_array(void)
ALGO_TRANSFORM(tmp, array_int_t, l, array_int_t, FT2, 17);
assert(array_int_size(tmp) == 101);
for(int i = 0; i < 100; i++) {
assert(*array_int_get(l, i) == i);
assert(*array_int_get(tmp, i) == i + 17);
assert(*array_int_get(l, (size_t) i) == i);
assert(*array_int_get(tmp, (size_t) i) == i + 17);
}
}
@@ -510,7 +543,10 @@ static void test_extract(void)
assert (dst == 127);
unsigned long long dst_l;
ALGO_REDUCE( (dst_l, M_OPEXTEND(M_STANDARD_OPLIST, TYPE(unsigned long long))), a, array_int_t, sum);
// To avoid warnings about sign conversion between int and unsigned long long
#define my_set(a, b) do { (a) = (unsigned int) (b); } while (0)
#define my_sum(a, b) do { (a) += (unsigned int) (b); } while (0)
ALGO_REDUCE( (dst_l, M_OPEXTEND(M_STANDARD_OPLIST, SET(my_set), TYPE(unsigned long long))), a, array_int_t, my_sum);
assert (dst_l == 100*99/2-10*11/2);
array_int_clean(a);
@@ -559,11 +595,11 @@ static void test_insert(void)
static void test_string_utf8(void)
{
M_LET( (s, "H€llo René Chaînôr¬"), string_t)
M_LET( (ref, 72, 8364, 108, 108, 111, 32, 82, 101, 110, 233, 32, 67, 104, 97, 238, 110, 244, 114, 172), a, array_int_t) {
M_LET( (ref, 72, 8364, 108, 108, 111, 32, 82, 101, 110, 233, 32, 67, 104, 97, 238, 110, 244, 114, 172), a, array_uint_t) {
// Convert the string into an array of unicode.
ALGO_EXTRACT(a, array_int_t, s, string_t);
ALGO_EXTRACT(a, array_uint_t, s, string_t);
// Compare the converted string into the reference array
assert(array_int_equal_p(a, ref));
assert(array_uint_equal_p(a, ref));
}
}
@@ -636,8 +672,6 @@ FUNC_OBJ_INS_DEF(fol_cmp, algo_list_fo_cmp_obj,
M_LET( (obj, 1), fol_cmp_t)
algo_list_fo_sort_fo(tab, fol_cmp_as_interface(obj));
M_LET ( (ref, -1, 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9), LIST_OPLIST(list_int)) {
// NOTE: For a list, the order is revered by default
list_int_reverse(ref);
assert( list_int_equal_p(tab, ref));
}
}
+30 -13
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -33,6 +33,13 @@ END_COVERAGE
// Array with the minimum number of methods.
ARRAY_DEF(array_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear)))
ARRAY_DEF(array_min2_z, testobj_t, (INIT(testobj_init), CLEAR(testobj_clear)))
ARRAY_DEF(array_min3_z, testobj_t, (CLEAR(testobj_clear)))
ARRAY_DEF(array_ulong, uint64_t)
ARRAY_DEF_AS(array_double, ArrayDouble, ArrayDoubleIt, double)
#define M_OPL_ArrayDouble() ARRAY_OPLIST(array_double, M_DEFAULT_OPLIST)
static void test_uint(void)
{
@@ -183,7 +190,7 @@ static void test_uint(void)
assert (x == 1478963);
assert (s == *array_uint_back(v));
s = array_uint_size (v);
s = (unsigned int) array_uint_size (v);
bool b = array_uint_erase (v, 12459);
assert (b == false);
assert (s == array_uint_size (v));
@@ -205,12 +212,12 @@ static void test_mpz(void)
testobj_init (z);
// Test empty
FILE *f = fopen ("a-marray.dat", "wt");
FILE *f = m_core_fopen ("a-marray.dat", "wt");
if (!f) abort();
array_mpz_out_str(f, array1);
fclose (f);
f = fopen ("a-marray.dat", "rt");
f = m_core_fopen ("a-marray.dat", "rt");
if (!f) abort();
bool b = array_mpz_in_str (array2, f);
assert (b == true);
@@ -219,16 +226,16 @@ static void test_mpz(void)
// Test non empty
for(int n = 0; n < 1000; n++) {
testobj_set_ui (z, n);
testobj_set_ui (z, (unsigned int) n);
array_mpz_push_back (array1, z);
}
f = fopen ("a-marray.dat", "wt");
f = m_core_fopen ("a-marray.dat", "wt");
if (!f) abort();
array_mpz_out_str(f, array1);
fclose (f);
f = fopen ("a-marray.dat", "rt");
f = m_core_fopen ("a-marray.dat", "rt");
if (!f) abort();
b = array_mpz_in_str (array2, f);
assert (b == true);
@@ -286,7 +293,7 @@ static void test_d(void)
array_uint_move(a1, a2);
assert (array_uint_empty_p (a1));
for(int i = 0; i < 10; i++)
array_uint_push_back (a1, i);
array_uint_push_back (a1, (unsigned int) i);
array_uint_set_at (a1, 0, 17);
assert (*array_uint_get (a1, 0) == 17);
assert (*array_uint_back(a1) == 9);
@@ -295,10 +302,10 @@ static void test_d(void)
*p = 10;
assert (*array_uint_back(a1) == 10);
for(int i = 0; i < 10; i++)
array_uint_push_at (a1, 9, i);
array_uint_push_at (a1, 9, (unsigned int) i);
assert (*array_uint_back(a1) == 10);
for(int i = 9; i < 19; i++)
assert (*array_uint_get (a1, i) == 18U-i);
assert (*array_uint_get (a1, (size_t) i) == 18U -(unsigned int) i);
*array_uint_get_at(a1, 100) = 100;
assert (*array_uint_back(a1) == 100);
@@ -310,7 +317,7 @@ static void test_d(void)
array_uint_insert_v (a1, 10, 200);
assert (array_uint_size(a1) == 300);
for(int i = 10; i < 210; i++) {
assert (*array_uint_get (a1, i) == 0);
assert (*array_uint_get (a1, (size_t)i) == 0);
}
array_uint_it_t it;
array_uint_it(it, a1);
@@ -329,8 +336,6 @@ static void test_d(void)
assert (*array_uint_ref(it2) == 0);
array_uint_insert(a1, it2, 17);
assert (array_uint_size(a1) == 300);
assert (*array_uint_ref(it2) == 0);
array_uint_next(it2);
assert (*array_uint_ref(it2) == 17);
array_uint_init_set (a2, a1);
@@ -348,10 +353,22 @@ static void test_d(void)
array_uint_clear(a2);
}
static void test_double(void)
{
M_LET( (tab, 0.0, 1.0, 2.0, 3.0), ArrayDouble) {
double ref = 0.0;
for M_EACH(i, tab, ArrayDouble) {
assert (*i == ref);
ref += 1.0;
}
}
}
int main(void)
{
test_uint();
test_mpz();
test_d();
test_double();
exit(0);
}
+22 -17
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -33,10 +33,10 @@ static void test1(void)
assert(bitset_empty_p(set) == true);
for(int i = 0; i < 100; i ++) {
bitset_push_back(set, i%2);
assert (bitset_back(set) == (i%2));
assert (bitset_back(set) == M_ASSIGN_CAST(bool, i%2));
}
for(int i = 0; i < 100; i ++) {
assert (bitset_get(set, i) == (i%2));
assert (bitset_get(set, (size_t) i) == M_ASSIGN_CAST(bool, i%2));
}
assert(bitset_size(set) == 100);
assert(bitset_empty_p(set) == false);
@@ -56,7 +56,7 @@ static void test1(void)
assert(bitset_size(set2) == 50);
assert(bitset_empty_p(set2) == false);
for(int i = 0; i < 50; i ++) {
assert (bitset_get(set2, i) == (i%2));
assert (bitset_get(set2, (size_t) i) == M_ASSIGN_CAST(bool, i%2));
}
bitset_reserve(set2, 100);
assert(bitset_capacity(set2) >= 100); // rounded
@@ -64,10 +64,10 @@ static void test1(void)
assert(bitset_capacity(set2) >= 50 && bitset_capacity(set2) < 100); // rounded
bitset_resize(set2, 100);
for(int i = 0; i < 50; i ++) {
assert (bitset_get(set2, i) == (i%2));
assert (bitset_get(set2, (size_t) i) == M_ASSIGN_CAST(bool, i%2));
}
for(int i = 50; i < 100; i ++) {
assert (bitset_get(set2, i) == false);
assert (bitset_get(set2, (size_t) i) == false);
}
bitset_resize(set2, 50);
@@ -75,16 +75,16 @@ static void test1(void)
bitset_push_at(set2, 0, 1);
assert (bitset_get(set2, 0) == 1);
for(int i = 1; i < 51; i ++) {
assert (bitset_get(set2, i) == ((i-1)%2));
assert (bitset_get(set2, (size_t) i) == M_ASSIGN_CAST(bool, (i-1)%2));
}
// Push from not aligned bit
bitset_push_at(set2, 9, 1);
for(int i = 1; i < 9; i ++) {
assert (bitset_get(set2, i) == ((i-1)%2));
assert (bitset_get(set2, (size_t) i) == M_ASSIGN_CAST(bool, (i-1)%2));
}
assert (bitset_get(set2, 9) == 1);
for(int i = 10; i < 52; i ++) {
assert (bitset_get(set2, i) == ((i)%2));
assert (bitset_get(set2, (size_t) i) == M_ASSIGN_CAST(bool, i%2));
}
bool b;
@@ -94,7 +94,7 @@ static void test1(void)
assert(bitset_size(set2) == 50);
for(int i = 0; i < 200; i++)
bitset_push_back(set, (i%2));
bitset_push_back(set, M_ASSIGN_CAST(bool, i%2));
bitset_pop_at(&b, set, 0);
assert (b == false);
assert (bitset_size(set) == 199);
@@ -123,11 +123,11 @@ static void test1(void)
bitset_clean(set);
for(int i = 0; i < 200; i++)
bitset_push_back(set, (i*17547854547UL)&1) ;
bitset_push_back(set, ((size_t) i*17547854547UL)&1) ;
bitset_it_t it;
int n = 0;
for(bitset_it(it, set); ! bitset_end_p(it); bitset_next(it)) {
bool v = (n*17547854547UL)&1;
bool v = ((size_t) n*17547854547UL)&1;
bool c = *bitset_cref(it);
assert (v == c);
n++;
@@ -135,7 +135,7 @@ static void test1(void)
n = 0;
for M_EACH (item, set, BITSET_OPLIST) {
bool v = (n*17547854547UL)&1;
bool v = ((size_t) n*17547854547UL)&1;
bool c = *item;
assert (v == c);
n++;
@@ -202,7 +202,12 @@ static void test1(void)
assert (bitset_end_p(it));
assert (bitset_hash(set) != 0);
bitset_clean(set);
bitset_it(it, set);
assert(bitset_end_p(it));
assert(bitset_last_p(it));
bitset_clear(set);
bitset_clear(set2);
}
@@ -229,14 +234,14 @@ static void test_str(void)
bitset_init(set2);
for(int i = 0; i < 200; i++)
bitset_push_back(set1, (i*17547854547UL >> 4)&1) ;
bitset_push_back(set1, ((size_t) i*17547854547UL >> 4)&1) ;
FILE *f = fopen ("a-mbitset.dat", "wt");
FILE *f = m_core_fopen ("a-mbitset.dat", "wt");
if (!f) abort();
bitset_out_str(f, set1);
fclose (f);
f = fopen ("a-mbitset.dat", "rt");
f = m_core_fopen ("a-mbitset.dat", "rt");
if (!f) abort();
bool b = bitset_in_str (set2, f);
assert (b == true);
+72 -41
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -40,7 +40,16 @@ BPTREE_DEF(btree_myset, 15, testobj_t, TESTOBJ_CMP_OPLIST)
BPTREE_MULTI_DEF2(multimap, 3, int, M_DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
BPTREE_MULTI_DEF(multiset, 6, int, M_DEFAULT_OPLIST)
BPTREE_DEF2_AS(MapDouble, MapDouble, MapDoubleIt, MapDoubleItRef, 4, double, double)
#define M_OPL_MapDouble() BPTREE_OPLIST2(MapDouble, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
BPTREE_DEF_AS(SetDouble, SetDouble, SetDoubleIt, 7, double)
#define M_OPL_SetDouble() BPTREE_OPLIST(SetDouble, M_DEFAULT_OPLIST)
BPTREE_MULTI_DEF2_AS(MultiMapDouble, MultiMapDouble, MultiMapDoubleIt, MultiMapDoubleItRef, 8, double, double)
#define M_OPL_MultiMapDouble() BPTREE_OPLIST2(MultiMapDouble, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
BPTREE_MULTI_DEF_AS(MultiSetDouble, MultiSetDouble, MultiSetDoubleIt, 9, double)
#define M_OPL_MultiSetDouble() BPTREE_OPLIST(MultiSetDouble, M_DEFAULT_OPLIST)
static void test1(void)
{
btree_t b;
@@ -355,7 +364,7 @@ static void test5(void)
btree_it_t it, it2;
int i = 0;
for(btree_it(it, b), btree_it_set(it2, it); !btree_end_p(it); btree_next(it)) {
const btree_type_t *item = btree_cref(it);
const btree_itref_t *item = btree_cref(it);
assert (*item->key_ptr == i);
assert (*item->value_ptr == 1000*i);
i++;
@@ -368,7 +377,7 @@ static void test5(void)
i = 500;
for(btree_it_from(it, b, 500); !btree_it_until_p(it, 600); btree_next(it)) {
const btree_type_t *item = btree_cref(it);
const btree_itref_t *item = btree_cref(it);
assert (*item->key_ptr == i);
assert (*item->value_ptr == 1000*i);
i++;
@@ -378,7 +387,7 @@ static void test5(void)
btree_erase (b, 500);
i = 501;
for(btree_it_from(it, b, 500); !btree_it_until_p(it, 600); btree_next(it)) {
const btree_type_t *item = btree_cref(it);
const btree_itref_t *item = btree_cref(it);
assert (*item->key_ptr == i);
assert (*item->value_ptr == 1000*i);
i++;
@@ -405,12 +414,12 @@ static void test_io(void)
assert(*endp == 0);
assert (btree_my_equal_p (tree1, tree2));
FILE *f = fopen ("a-mbptree.dat", "wt");
FILE *f = m_core_fopen ("a-mbptree.dat", "wt");
if (!f) abort();
btree_my_out_str(f, tree1);
fclose (f);
f = fopen ("a-mbptree.dat", "rt");
f = m_core_fopen ("a-mbptree.dat", "rt");
if (!f) abort();
b = btree_my_in_str (tree2, f);
assert (b == true);
@@ -431,12 +440,12 @@ static void test_io(void)
assert(*endp == 0);
assert (btree_my_equal_p (tree1, tree2));
f = fopen ("a-mbptree.dat", "wt");
f = m_core_fopen ("a-mbptree.dat", "wt");
if (!f) abort();
btree_my_out_str(f, tree1);
fclose (f);
f = fopen ("a-mbptree.dat", "rt");
f = m_core_fopen ("a-mbptree.dat", "rt");
if (!f) abort();
b = btree_my_in_str (tree2, f);
assert (b == true);
@@ -458,12 +467,12 @@ static void test_io_set(void)
assert(*endp == 0);
assert (btree_myset_equal_p (tree1, tree2));
FILE *f = fopen ("a-mbptree.dat", "wt");
FILE *f = m_core_fopen ("a-mbptree.dat", "wt");
if (!f) abort();
btree_myset_out_str(f, tree1);
fclose (f);
f = fopen ("a-mbptree.dat", "rt");
f = m_core_fopen ("a-mbptree.dat", "rt");
if (!f) abort();
b = btree_myset_in_str (tree2, f);
assert (b == true);
@@ -485,12 +494,12 @@ static void test_io_set(void)
assert(*endp == 0);
assert (btree_myset_equal_p (tree1, tree2));
f = fopen ("a-mbptree.dat", "wt");
f = m_core_fopen ("a-mbptree.dat", "wt");
if (!f) abort();
btree_myset_out_str(f, tree1);
fclose (f);
f = fopen ("a-mbptree.dat", "rt");
f = m_core_fopen ("a-mbptree.dat", "rt");
if (!f) abort();
b = btree_myset_in_str (tree2, f);
assert (b == true);
@@ -499,32 +508,6 @@ static void test_io_set(void)
}
}
#if 0
// Dump code for debug
static void multimap_dump_node(multimap_node_t n)
{
while (n) {
int num = n->num < 0 ? -n->num : n->num;
printf ("[");
for(int i = 0; i < num; i++)
printf ("%d, ", n->key[i]);
printf ("] ");
n = n->next;
}
printf("\n");
}
static void
multimap_dump(multimap_t b)
{
multimap_node_t n = b->root;
while (n->num > 0) {
multimap_dump_node(n);
n = n->kind.node[0];
}
multimap_dump_node(n);
}
#endif
static void
test_multimap(void)
{
@@ -543,7 +526,7 @@ test_multimap(void)
for(multimap_it_from(it, b, k);
multimap_it_while_p(it, k);
multimap_next(it)) {
const multimap_type_t *ref = multimap_cref(it);
const multimap_itref_t *ref = multimap_cref(it);
assert(*ref->key_ptr == k);
assert(*ref->value_ptr == j);
j--;
@@ -579,7 +562,7 @@ test_multiset(void)
for(multiset_it_from(it, b, k);
multiset_it_while_p(it, k);
multiset_next(it)) {
const multiset_type_t *ref = multiset_cref(it);
const multiset_itref_t *ref = multiset_cref(it);
assert(*ref == k);
j++;
}
@@ -596,6 +579,53 @@ test_multiset(void)
multiset_clear(b);
}
static void test_double(void)
{
M_LET( (tree, (1.0, 2.0), (3.0, 4.0)), MapDouble) {
double *r = MapDouble_get(tree, 1.0);
assert( r != NULL);
assert( *r == 2.0);
r = MapDouble_get(tree, 3.0);
assert( r != NULL);
assert( *r == 4.0);
r = MapDouble_get(tree, 4.0);
assert( r == NULL);
}
M_LET( (tree, 1.0, 3.0), SetDouble) {
double *r = SetDouble_get(tree, 1.0);
assert( r != NULL);
assert( *r == 1.0);
r = SetDouble_get(tree, 3.0);
assert( r != NULL);
assert( *r == 3.0);
r = SetDouble_get(tree, 4.0);
assert( r == NULL);
}
M_LET( (tree, (1.0, 2.0), (3.0, 4.0)), MultiMapDouble) {
double *r = MultiMapDouble_get(tree, 1.0);
assert( r != NULL);
assert( *r == 2.0);
r = MultiMapDouble_get(tree, 3.0);
assert( r != NULL);
assert( *r == 4.0);
r = MultiMapDouble_get(tree, 4.0);
assert( r == NULL);
}
M_LET( (tree, 1.0, 3.0), MultiSetDouble) {
double *r = MultiSetDouble_get(tree, 1.0);
assert( r != NULL);
assert( *r == 1.0);
r = MultiSetDouble_get(tree, 3.0);
assert( r != NULL);
assert( *r == 3.0);
r = MultiSetDouble_get(tree, 4.0);
assert( r == NULL);
}
}
int main(void)
{
test1();
@@ -608,5 +638,6 @@ int main(void)
test_io_set();
test_multimap();
test_multiset();
test_double();
exit(0);
}
+106 -11
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -45,6 +45,14 @@ BUFFER_DEF(buffer_mpz, testobj_t, 32, BUFFER_QUEUE, TESTOBJ_OPLIST)
QUEUE_MPMC_DEF(queue_z, testobj_t, BUFFER_QUEUE, TESTOBJ_OPLIST)
QUEUE_SPSC_DEF(squeue_a, testobj_t, BUFFER_QUEUE, TESTOBJ_OPLIST)
// Define other buffers
BUFFER_DEF_AS(BufferDouble1, BufferDouble1, double, 4, BUFFER_QUEUE)
QUEUE_MPMC_DEF_AS(BufferDouble2, BufferDouble2, double, BUFFER_QUEUE)
QUEUE_SPSC_DEF_AS(BufferDouble3, BufferDouble3, double, BUFFER_QUEUE)
#define M_OPL_BufferDouble1() BUFFER_OPLIST(BufferDouble1, M_DEFAULT_OPLIST)
#define M_OPL_BufferDouble2() BUFFER_OPLIST(BufferDouble2, M_DEFAULT_OPLIST)
#define M_OPL_BufferDouble3() BUFFER_OPLIST(BufferDouble3, M_DEFAULT_OPLIST)
buffer_uint_t g_buff;
buffer_uint_t g_buffB;
@@ -157,7 +165,7 @@ static void test_stack(void)
buffer_floats_init(buff, 100);
assert (buffer_floats_capacity(buff) == 100);
for(unsigned int i = 0; i < 100; i++) {
float f = i;
float f = (float) i;
buffer_floats_push(buff, f);
assert (buffer_floats_empty_p(buff) == false);
}
@@ -165,7 +173,7 @@ static void test_stack(void)
for(unsigned int i = 0; i < 100; i++) {
float j;
buffer_floats_pop(&j, buff);
assert(j == 99-i);
assert(j == (float) (99-i) );
assert (buffer_floats_full_p(buff) == false);
}
assert (buffer_floats_empty_p(buff) == true);
@@ -179,7 +187,7 @@ static void test_stack2(void)
char c;
buffer_char_init(buff, 10);
for(int i = 0; i < 10; i++) {
c = i;
c = (char) i;
b = buffer_char_push(buff, c);
assert (b == true);
assert (buffer_char_empty_p(buff) == false);
@@ -234,19 +242,40 @@ static void test_no_thread(void)
/* Test intrusive shared pointer + buffer */
#include "m-i-shared.h"
// Tiny test structure
typedef struct test_s {
ISHARED_PTR_INTERFACE(ishared_itest, struct test_s);
char buffer[52];
char bigbuffer[1000000];
} test_t;
static void test_init(test_t *p) { memset(p->buffer, 0x00, 52); }
static void test_clear(test_t *p) { memset(p->buffer, 0xFF, 52); }
ISHARED_PTR_DEF(ishared_itest, test_t,
(INIT(test_init M_IPTR), CLEAR(test_clear M_IPTR), DEL(free)))
typedef struct test2_s {
ISHARED_PTR_INTERFACE(ishared_itest2, struct test_s);
char buffer[52];
} test2_t;
static inline void ishared_itest2_init_data(test2_t *d)
{
memset(d->buffer, 0, sizeof (d->buffer));
}
ISHARED_PTR_DEF(ishared_itest2, test2_t, (INIT(API_2(ishared_itest2_init_data)), CLEAR(M_NOTHING_DEFAULT)))
typedef struct test3_s {
ISHARED_PTR_INTERFACE(ishared_itest3, struct test_s);
char buffer[52];
} test3_t;
ISHARED_PTR_DEF(ishared_itest3, test3_t, (CLEAR(M_NOTHING_DEFAULT)))
typedef struct test4_s {
ISHARED_PTR_INTERFACE(ishared_itest4, struct test_s);
char buffer[52];
} test4_t;
ISHARED_PTR_DEF(ishared_itest4, test4_t, (INIT(0), DEL(0), INIT(M_MEMSET_DEFAULT), CLEAR(M_NOTHING_DEFAULT)))
static test_t *test_new(void)
{
test_t *p = M_ASSIGN_CAST(test_t*, malloc (sizeof (test_t)));
@@ -290,8 +319,9 @@ static void test_prod(void *arg)
assert (arg == NULL);
for(unsigned int i = 0; i < 10;i++) {
test_t *p = test_new();
for(int j = 0; j < 52; j++)
p->buffer[j] = (j * j * 17) + j * 42 + 1;
for(int j = 0; j < 52; j++) {
p->buffer[j] = (char) ((j * j * 17) + j * 42 + 1);
}
buffer_itest_push(comm1, p);
buffer_itest_push(comm2, p);
ishared_itest_clear(p);
@@ -361,7 +391,7 @@ static void prod2(void *arg)
size_t n = *p_n;
size_t r = n;
for(unsigned int i = 0; i < n;i++) {
while (!queue_uint_push(g_buff2, r ));
while (!queue_uint_push(g_buff2, (unsigned int) r ));
r = r * 31421U + 6927U;
}
}
@@ -388,7 +418,7 @@ static void test_queue(size_t n, int cpu_count, unsigned long long ref)
for(int i = 0; i < conso_count; i++) {
m_thread_create (idx_c[i], conso2, &n);
}
size_t n2 = conso_count;
size_t n2 = (size_t) conso_count;
m_thread_create(idx_final, final2, &n2);
// Wait for jobs to be done.
@@ -489,7 +519,65 @@ static void test_spsc(void)
/********************************************************************************************/
int main(void)
static void test_double1(void)
{
bool b;
M_LET(buffer, BufferDouble1) {
b = BufferDouble1_push(buffer, 0.0);
assert(b);
b= BufferDouble1_push(buffer, 1.0);
assert(b);
double d;
b = BufferDouble1_pop(&d, buffer);
assert(b);
assert(d == 0.0);
b = BufferDouble1_pop(&d, buffer);
assert(b);
assert(d == 1.0);
}
}
static void test_double2(void)
{
bool b;
BufferDouble2 buffer;
BufferDouble2_init(buffer, 2);
b = BufferDouble2_push(buffer, 0.0);
assert(b);
b= BufferDouble2_push(buffer, 1.0);
assert(b);
double d;
b = BufferDouble2_pop(&d, buffer);
assert(b);
assert(d == 0.0);
b = BufferDouble2_pop(&d, buffer);
assert(b);
assert(d == 1.0);
BufferDouble2_clear(buffer);
}
static void test_double3(void)
{
bool b;
BufferDouble3 buffer;
BufferDouble3_init(buffer, 2);
b = BufferDouble3_push(buffer, 0.0);
assert(b);
b= BufferDouble3_push(buffer, 1.0);
assert(b);
double d;
b = BufferDouble3_pop(&d, buffer);
assert(b);
assert(d == 0.0);
b = BufferDouble3_pop(&d, buffer);
assert(b);
assert(d == 1.0);
BufferDouble3_clear(buffer);
}
/********************************************************************************************/
static void test_uint(void)
{
unsigned int x, y;
buffer_uint_t v;
@@ -511,7 +599,11 @@ int main(void)
assert (y == 10);
buffer_uint_clear(v);
}
int main(void)
{
test_uint();
test_global();
test_stack();
test_stack2();
@@ -519,5 +611,8 @@ int main(void)
test_global_ishared();
test_queue(1000000, 2, 2148371710223136ULL);
test_spsc();
test_double1();
test_double2();
test_double3();
exit(0);
}
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Test for Concurrent memory pool allocator
*
* Copyright (c) 2017-2020, 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:
+16 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -97,6 +97,9 @@ CONCURRENT_RP_DEF(rparray1, array1_t, ARRAY_OPLIST(array1))
CONCURRENT_RP_DEF(rpdict1, dict1_t, DICT_OPLIST(dict1))
CONCURRENT_DEF_AS(ConcurrentDouble, ConcurrentDouble, double)
CONCURRENT_RP_DEF_AS(ConcurrentRpDouble, ConcurrentRpDouble, double)
/* OA dict needs more operators than the default ones to work */
static inline bool int_oor_equal_p(int s, unsigned char n)
{
@@ -210,11 +213,23 @@ static void test_rp_basic(void)
rpdict1_clear(dict);
}
static void test_double(void)
{
ConcurrentDouble d;
ConcurrentDouble_init(d);
ConcurrentDouble_clear(d);
ConcurrentRpDouble r;
ConcurrentRpDouble_init(r);
ConcurrentRpDouble_clear(r);
}
int main(void)
{
test_basic();
test_rp_basic();
test_thread();
test_rp_thread();
test_double();
exit(0);
}
+166 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -149,6 +149,32 @@ static void test_empty(void)
assert (M_EMPTY_P(()) == false);
assert (M_EMPTY_P("123") == false);
assert (M_EMPTY_P(,1,2,3) == false);
assert (M_EMPTY_P(+2) == false);
assert (M_EMPTY_P(-2) == false);
assert (M_EMPTY_P( () ) == false);
#define F0() int
#define F1() (void)
#define F2(x) x
#define F3()
#define F4() 1,2
assert (M_EMPTY_P(F0) == false);
#ifndef M_COMMA_P_WORKAROUND
// Disable tests on platform with a non working preprocessor
assert (M_EMPTY_P(F1) == false);
assert (M_EMPTY_P(F2) == false);
assert (M_EMPTY_P(F3) == false);
#endif
assert (M_EMPTY_P(F4) == false);
#define G0 int
#define G1 (void)
#define G2 x
#define G3
#define G4 1,2
assert (M_EMPTY_P(G0) == false);
assert (M_EMPTY_P(G1) == false);
assert (M_EMPTY_P(G2) == false);
assert (M_EMPTY_P(G3) == true);
assert (M_EMPTY_P(G4) == false);
}
#define f(n) (n)*(n) +
@@ -192,6 +218,49 @@ static void test_let(void)
assert(0);
}
assert(b);
int c = 0;
M_LET_IF( assert(c++ == 0), (assert(c++ == 1), true), assert(c++ == 3)) {
assert(c++ == 2);
}
M_LET_IF( assert(c++ == 4), (assert(c++ == 5), false), assert(0)) {
assert(0);
}
assert(c++ == 6);
M_LET_IF(int *p = (int*) malloc(sizeof(int)), p!=0, free(p)) {
assert(p != NULL);
*p = 4;
}
M_LET_IF( assert(c++ == 7), (assert(c++ == 8), true), assert(c++ == 10), assert(0) ) {
assert(c++ == 9);
}
M_LET_IF( assert(c++ == 11), (assert(c++ == 12), false), assert(0), assert(c++ == 13) ) {
assert(0);
}
assert(c++ == 14);
M_LET_IF( assert(c++ == 15), (assert(c++ == 16), true), assert(c++ == 18) ) {
assert(c++ == 17);
break;
assert(0);
}
assert(c++ == 19);
c = 7;
int *p = (int*)malloc(sizeof(int));
assert(p != NULL);
M_DEFER ( (assert(c++ == 8), free(p)) ) {
*p = 4;
assert(c++ == 7);
}
assert(c++ == 9);
M_DEFER ( assert(c++ == 11) ) {
assert(c++ == 10);
break;
assert(0);
}
assert(c++ == 12);
}
static void test_va(void)
@@ -231,6 +300,12 @@ static void test_test(void)
assert(!M_PARENTHESIS_P(()x));
}
static void test_list(void)
{
assert(M_KEEP_ARGS(1, 1, 0, 0, 0, 0));
assert(M_SKIP_ARGS(4, 0, 0, 0, 0, 1));
assert(M_MID_ARGS(2, 1, 0, 0, 1, 0));
}
static void test_oplist(void)
{
@@ -329,6 +404,35 @@ static void test_reduce(void)
== M_REDUCE(M_ID, add, M_SEQ(1, 10)));
}
static void test_as_type(void)
{
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
int i = 42;
float f = 2.5;
void *p = (void*) &i;
struct as_type { int n; } n = { 17 };
assert (M_AS_TYPE(int, i) == 42);
assert (M_AS_TYPE(float, i) == 0.0);
assert (M_AS_TYPE(void *, i) == 0);
assert (M_AS_TYPE(struct as_type, i).n == 0 );
assert (M_AS_TYPE(int, f) == 0);
assert (M_AS_TYPE(float, f) == 2.5);
assert (M_AS_TYPE(void *, f) == 0);
assert (M_AS_TYPE(struct as_type, f).n == 0 );
assert (M_AS_TYPE(int, p) == 0);
assert (M_AS_TYPE(float, p) == 0.0);
assert (M_AS_TYPE(void *, p) == &i);
assert (M_AS_TYPE(struct as_type, p).n == 0 );
assert (M_AS_TYPE(int, n) == 0);
assert (M_AS_TYPE(float, n) == 0.0);
assert (M_AS_TYPE(void *, n) == 0);
assert (M_AS_TYPE(struct as_type, n).n == 17 );
#endif
}
static void test_parse_standard_c_type(void)
{
@@ -459,6 +563,62 @@ static void test_move_default(void)
assert(x2.c == 0);
}
static void test_builtin(void)
{
assert(m_core_clz32(0) == 32);
for(unsigned i = 0; i < 31; i++) {
assert(m_core_clz32((uint32_t) (1UL<<i)) == 31U - i);
assert(m_core_clz32((uint32_t) ((1UL<<i) | 1)) == 31U - i);
}
assert(m_core_clz64(0) == 64);
for(unsigned i = 0; i < 63; i++) {
assert(m_core_clz64((uint64_t) (1ULL<<i)) == 63U - i);
assert(m_core_clz64((uint64_t) ((1ULL<<i) | 1)) == 63U - i);
}
assert ( m_core_roundpow2(0) == 0);
for(unsigned i = 0; i < 62; i++) {
assert ( m_core_roundpow2(1ULL<<i) == 1ULL<<i);
assert ( m_core_roundpow2((1ULL<<i)+1) == 1ULL<<(i+1) );
}
for(unsigned i = 0; i < 3000; i++) {
assert( m_core_rotl32a(i, 1) == i * 2);
assert( m_core_rotl32a(i, 2) == i * 4);
assert( m_core_rotl32a((uint32_t) ((1UL<<31) + i), 1) == i * 2 + 1);
assert( m_core_rotl32a((uint32_t) ((1UL<<31) + i), 2) == i * 4 + 2);
}
for(unsigned i = 0; i < 3000; i++) {
assert( m_core_rotl64a(i, 1) == i * 2);
assert( m_core_rotl64a(i, 2) == i * 4);
assert( m_core_rotl64a((1ULL<<63) + i, 1) == i * 2 + 1);
assert( m_core_rotl64a((1ULL<<63) + i, 2) == i * 4 + 2);
}
}
const char str1[] = "A";
const char str2[] = "AB";
const char str3[] = "Hello";
static void test_str_hash(void)
{
assert (M_CALL_HASH(M_CSTR_OPLIST, str1) != 0);
assert (M_CALL_HASH(M_CSTR_OPLIST, str2) != 0);
assert (M_CALL_HASH(M_CSTR_OPLIST, str3) != 0);
}
static void test_M_CSTR(void)
{
assert ( strcmp(M_CSTR("Len=%d", 17), "Len=17") == 0);
assert ( strcmp(M_CSTR("Hello %s %c", "World", '!'), "Hello World !") == 0);
// Reduce allocation to test truncation
#undef M_USE_CSTR_ALLOC
#define M_USE_CSTR_ALLOC 8
assert ( strcmp(M_CSTR("Hello %s %c", "World", '!'), "Hello W") == 0);
}
int main(void)
{
test_cat();
@@ -468,6 +628,7 @@ int main(void)
test_invert();
test_min();
test_empty();
test_list();
test_map();
test_let();
test_va();
@@ -476,7 +637,11 @@ int main(void)
test_oplist();
test_cast();
test_reduce();
test_as_type();
test_parse_standard_c_type();
test_move_default();
test_builtin();
test_str_hash();
test_M_CSTR();
exit(0);
}
+73 -14
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -36,8 +36,17 @@ DEQUE_DEF(deque_mpz, testobj_t, TESTOBJ_OPLIST)
// Deque with the minimum number of methods.
DEQUE_DEF(deque_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear)))
// Dequeue of an enumerate
typedef enum {
SUCCESS = 0, NULL_PARAM, INVALID_PARAM
} ReturnCode_t;
DEQUE_DEF(deque_retcode, ReturnCode_t, M_ENUM_OPLIST(ReturnCode_t, SUCCESS))
#define OPL DEQUE_OPLIST(deque)
DEQUE_DEF_AS(DequeDouble, DequeDouble, DequeDoubleIt, double)
#define M_OPL_DequeDouble() DEQUE_OPLIST(DequeDouble, M_DEFAULT_OPLIST)
static void test_ti1(int n)
{
deque_t d;
@@ -52,7 +61,7 @@ static void test_ti1(int n)
assert(*deque_front(d) == i);
}
assert (!deque_empty_p(d));
assert (deque_size(d) == (size_t)2*n);
assert (deque_size(d) == (size_t)(2*n));
int s = 0;
for(int i =0; i < 2*n ;i++) {
int z;
@@ -102,7 +111,7 @@ static void test1(void)
}
assert (deque_size(d) == 99*2);
for(int i = 0; i < 99*2; i++)
assert (*deque_get(d, i) == (i < 99) ? i - 99 : i - 98);
assert (*deque_get(d, (size_t) i) == (i < 99) ? i - 99 : i - 98);
for(int i = 0; i < 98; i++) {
deque_pop_back(NULL, d);
assert (*deque_back(d) == i - 98);
@@ -127,15 +136,15 @@ static void test1(void)
static void test_it(void)
{
M_LET(d, OPL) {
for(size_t i = 0; i < 1997; i ++) {
for(int i = 0; i < 1997; i ++) {
deque_push_back(d, 1997+i);
deque_push_front(d, 1996-i);
deque_it_t it;
deque_it_last (it, d);
assert (deque_last_p(it));
assert (*deque_cref (it) == (int)(1997+i));
assert (*deque_cref (it) == (1997+i));
deque_it(it, d);
assert (*deque_cref (it) == (int)(1996-i));
assert (*deque_cref (it) == (1996-i));
}
int s = 0;
for M_EACH(it, d, OPL) {
@@ -188,7 +197,7 @@ static void test_set(void)
{
M_LET(e, d, OPL) {
assert (deque_equal_p(d, e));
for(size_t i = 0; i < 1997; i ++)
for(int i = 0; i < 1997; i ++)
deque_push_back(d, i);
assert (!deque_equal_p(d, e));
deque_set(e, d);
@@ -222,9 +231,9 @@ static void test_set(void)
deque_push_back(d, 10000);
deque_push_front(d, -10000);
assert (deque_size (d) == 1999);
for(size_t i = 0; i < 1999; i ++)
for(int i = 0; i < 1999; i ++)
deque_pop_back(NULL, d);
for(size_t i = 0; i < 3001; i ++)
for(int i = 0; i < 3001; i ++)
deque_push_back(d, i);
deque_init (e);
deque_move (e, d);
@@ -276,12 +285,12 @@ static void test_io(void)
M_LET(z, TESTOBJ_OPLIST)
M_LET(str, STRING_OPLIST) {
// Test empty
FILE *f = fopen ("a-marray.dat", "wt");
FILE *f = m_core_fopen ("a-mdeque.dat", "wt");
if (!f) abort();
deque_mpz_out_str(f, d1);
fclose (f);
f = fopen ("a-marray.dat", "rt");
f = m_core_fopen ("a-mdeque.dat", "rt");
if (!f) abort();
bool b = deque_mpz_in_str (d2, f);
assert (b == true);
@@ -290,16 +299,16 @@ static void test_io(void)
// Test non empty
for(int n = 0; n < 1000; n++) {
testobj_set_ui (z, n);
testobj_set_ui (z, (unsigned int) n);
deque_mpz_push_back (d1, z);
}
f = fopen ("a-marray.dat", "wt");
f = m_core_fopen ("a-mdeque.dat", "wt");
if (!f) abort();
deque_mpz_out_str(f, d1);
fclose (f);
f = fopen ("a-marray.dat", "rt");
f = m_core_fopen ("a-mdeque.dat", "rt");
if (!f) abort();
b = deque_mpz_in_str (d2, f);
assert (b == true);
@@ -340,6 +349,54 @@ static void test_io(void)
}
}
static void test_io_enum(void)
{
deque_retcode_t d1, d2;
string_t s;
string_init(s);
deque_retcode_init(d1);
deque_retcode_init(d2);
ReturnCode_t *ret = deque_retcode_push_back_new(d1);
assert( *ret == SUCCESS);
deque_retcode_push_front(d1, INVALID_PARAM);
FILE *f = m_core_fopen ("a-mdeque.dat", "wt");
if (!f) abort();
deque_retcode_out_str(f, d1);
fclose (f);
f = m_core_fopen ("a-mdeque.dat", "rt");
if (!f) abort();
bool b = deque_retcode_in_str (d2, f);
assert (b == true);
assert (deque_retcode_equal_p (d1, d2));
fclose(f);
deque_retcode_get_str(s, d1, false);
assert (string_equal_str_p(s, "[2,0]"));
b = deque_retcode_parse_str(d2, string_get_cstr(s), NULL);
assert(b == true);
assert (deque_retcode_equal_p (d1, d2));
string_clear(s);
deque_retcode_clear(d1);
deque_retcode_clear(d2);
}
static void test_double(void)
{
M_LET( (tab, 0.0, 1.0, 2.0, 3.0), DequeDouble) {
double ref = 0.0;
for M_EACH(i, tab, DequeDouble) {
assert (*i == ref);
ref += 1.0;
}
}
}
int main(void)
{
test1();
@@ -350,7 +407,9 @@ int main(void)
test_it();
test_set();
test_io();
test_io_enum();
test_z();
test_advance();
test_double();
exit(0);
}
+35 -26
View File
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -47,6 +48,14 @@ DICT_OA_DEF2(dict_oa_str, symbol_t, BOUNDED_STRING_OPLIST(symbol), int, M_DEFAUL
DICT_OA_DEF2(dict_oa_bstr, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
DICT_OASET_DEF(dict_oa_setstr, string_t, STRING_OPLIST)
DICT_DEF2_AS(dictas_int, DictInt, DictIntIt, DictIntItRef, int, M_DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
DICT_STOREHASH_DEF2_AS(dictas_str2, DictSInt, DictSIntIt, DictSIntItRef, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
DICT_SET_DEF_AS(dictas_setstr, DictStr, DictStrIt, string_t, STRING_OPLIST)
DICT_OA_DEF2_AS(dictas_oa_bstr, DictOAStr, DictOAStrIt, DictOAStrItRef, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
DICT_OASET_DEF_AS(dictas_oa_setstr, DictOASStr, DictOASStrIt, string_t, STRING_OPLIST)
/* Helper structure */
ARRAY_DEF(array_string, string_t, STRING_OPLIST)
array_string_t v_str;
@@ -58,10 +67,10 @@ static void init_data(int data_size)
string_init (s);
array_string_init(v_str);
for (int i = 0; i < data_size; ++i) {
int j = (unsigned)(data_size * ((double)x / UINT_MAX) / 4) * 271828183u;
unsigned int j = (unsigned int)(data_size * ((double)x / UINT_MAX) / 4) * 271828183u;
string_printf(s, "%x", j);
array_string_push_back (v_str, s);
x = 1664525L * x + 1013904223L;
x = (uint32_t) (1664525L * x + 1013904223L);
}
string_clear(s);
}
@@ -79,7 +88,7 @@ static void test_data(void)
dict_str_init (dict);
assert(dict_str_empty_p(dict));
for (int i = 0; i < data_size; ++i) {
dict_str_set_at(dict, *array_string_cget(v_str, i), *array_string_cget(v_str, (i+1) % data_size));
dict_str_set_at(dict, *array_string_cget(v_str, (size_t) i), *array_string_cget(v_str, (size_t) ((i+1) % data_size)));
assert(!dict_str_empty_p(dict));
}
assert(dict_str_size(dict) == 1227176);
@@ -118,11 +127,11 @@ static void check_io(void)
assert (*sp == 0);
assert (dict_str_equal_p(dict, dict2));
FILE *f = fopen ("a-mdict.dat", "wt");
FILE *f = m_core_fopen ("a-mdict.dat", "wt");
if (!f) abort();
dict_str_out_str(f, dict);
fclose (f);
f = fopen ("a-mdict.dat", "rt");
f = m_core_fopen ("a-mdict.dat", "rt");
if (!f) abort();
b = dict_str_in_str(dict2, f);
assert (b == true);
@@ -157,14 +166,14 @@ static void test_init(void)
{
M_LET(str1, str2, STRING_OPLIST)
M_LET(d1, d2, DICT_OPLIST(dict_str, STRING_OPLIST, STRING_OPLIST)){
for(size_t i = 0; i < 100; i++) {
for(int i = 0; i < 100; i++) {
string_printf(str1, "%d", 2*i);
string_printf(str2, "%d", 2*i+1);
dict_str_set_at (d1, str1, str2);
}
assert (dict_str_size (d1) == 100);
for(size_t i = 0; i < 100; i++) {
for(int i = 0; i < 100; i++) {
string_printf(str1, "%d", 2*i);
string_printf(str2, "%d", 2*i+1);
string_t *p = dict_str_get (d1, str1);
@@ -191,7 +200,7 @@ static void test_init(void)
assert (b);
assert (!dict_str_equal_p (d2, d1));
for(size_t i = 1; i < 100; i++) {
for(int i = 1; i < 100; i++) {
string_printf(str1, "%d", 2*i);
b = dict_str_erase (d1, str1);
assert (b);
@@ -205,7 +214,7 @@ static void test_init(void)
dict_str_init_move (d3, d1);
assert (dict_str_size (d3) == 100);
for(size_t i = 0; i < 100; i++) {
for(int i = 0; i < 100; i++) {
string_printf(str1, "%d", 2*i);
string_printf(str2, "%d", 2*i+1);
assert (string_equal_p (*dict_str_get (d3, str1), str2));
@@ -218,12 +227,12 @@ static void test_init(void)
assert (dict_str_size (d2) == 0);
assert (dict_str_size (d1) == 100);
for(size_t i = 100; i < 200; i++) {
for(int i = 100; i < 200; i++) {
string_printf(str1, "%d", 2*i);
string_printf(*dict_str_get_at (d1, str1), "%d", 2*i+1);
}
assert (dict_str_size (d1) == 200);
for(size_t i = 100; i < 200; i++) {
for(int i = 100; i < 200; i++) {
string_printf(str1, "%d", 2*i);
string_printf(str2, "%d", 2*i+1);
string_t *p = dict_str_get (d1, str1);
@@ -269,7 +278,7 @@ static void test1(void)
string_init(key);
string_init(ref);
FILE *f = fopen("dict.txt", "rt");
FILE *f = m_core_fopen("dict.txt", "rt");
if (!f) abort();
dict_str_set_at(dict, STRING_CTE("LICENCE"), STRING_CTE("BSD3"));
assert(string_equal_p(*dict_str_cget(dict, STRING_CTE("LICENCE")), STRING_CTE("BSD3")));
@@ -285,7 +294,7 @@ static void test1(void)
fclose(f);
assert(dict_str_size(dict) == 19);
f = fopen("dict.txt", "rt");
f = m_core_fopen("dict.txt", "rt");
if (!f) abort();
while (!feof(f) && !ferror(f)) {
string_fgets(key, f, STRING_READ_PURE_LINE);
@@ -332,28 +341,28 @@ static void test_oa(void)
dict_oa_int_t d;
dict_oa_int_init(d);
for(size_t i = 0 ; i < 150; i+= 3)
for(int i = 0 ; i < 150; i+= 3)
dict_oa_int_set_at(d, i, i*i);
assert(dict_oa_int_size(d) == 50);
for(size_t i = 0 ; i < 150; i++) {
for(int i = 0 ; i < 150; i++) {
int *p = dict_oa_int_get(d, i);
if ((i % 3) == 0) {
assert (p != NULL);
assert (*p == M_ASSIGN_CAST(int, i*i));
assert (*p == i*i);
} else {
assert (p == NULL);
}
}
assert(dict_oa_int_size(d) == 50);
for(size_t i = 1 ; i < 150; i+= 3)
for(int i = 1 ; i < 150; i+= 3)
*dict_oa_int_get_at(d, i) = i*i;
assert(dict_oa_int_size(d) == 100);
for(size_t i = 0 ; i < 150; i++) {
for(int i = 0 ; i < 150; i++) {
int *p = dict_oa_int_get(d, i);
if ((i % 3) != 2) {
assert (p != NULL);
assert (*p == M_ASSIGN_CAST(int, i*i));
assert (*p == i*i);
} else {
assert (p == NULL);
}
@@ -366,7 +375,7 @@ static void test_oa(void)
static void test_init_oa(void)
{
M_LET(d1, d2, DICT_OPLIST(dict_oa_int, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)){
for(size_t i = 0; i < 100; i++) {
for(int i = 0; i < 100; i++) {
dict_oa_int_set_at (d1, 2*i, 2*i+1);
}
assert (dict_oa_int_size (d1) == 100);
@@ -396,7 +405,7 @@ static void test_init_oa(void)
assert (b);
assert (!dict_oa_int_equal_p (d2, d1));
for(size_t i = 1; i < 100; i++) {
for(int i = 1; i < 100; i++) {
b = dict_oa_int_erase (d1, 2*i);
assert (b);
}
@@ -409,7 +418,7 @@ static void test_init_oa(void)
dict_oa_int_init_move (d3, d1);
assert (dict_oa_int_size (d3) == 100);
for(size_t i = 0; i < 100; i++) {
for(int i = 0; i < 100; i++) {
assert (*dict_oa_int_get (d3, 2*i) == 2*(int)i+1);
}
dict_oa_int_init_set (d1, d3);
@@ -426,7 +435,7 @@ static void test_init_oa(void)
static void test_it_oa(void)
{
M_LET(d1, DICT_OPLIST(dict_oa_int, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)){
for(size_t i = 0; i < 100; i++) {
for(int i = 0; i < 100; i++) {
dict_oa_int_set_at (d1, 2*i, 2*i+1);
}
assert (dict_oa_int_size (d1) == 100);
@@ -434,7 +443,7 @@ static void test_it_oa(void)
dict_oa_int_it_t it;
size_t s = 0;
for(dict_oa_int_it(it, d1); !dict_oa_int_end_p(it); dict_oa_int_next(it)) {
dict_oa_int_pair_t *pair = dict_oa_int_ref(it);
dict_oa_int_itref_t *pair = dict_oa_int_ref(it);
assert (pair->key >= 0 && pair->key < 200);
assert (pair->value == pair->key + 1);
s++;
@@ -460,7 +469,7 @@ static void test_it_oa(void)
s = 0;
for(dict_oa_int_it_last(it, d1); !dict_oa_int_end_p(it); dict_oa_int_previous(it)) {
dict_oa_int_pair_t *pair = dict_oa_int_ref(it);
dict_oa_int_itref_t *pair = dict_oa_int_ref(it);
assert (pair->key >= 0 && pair->key < 200);
assert (pair->value == pair->key + 1);
s++;
+21 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -69,6 +69,17 @@ END_COVERAGE
#define M_OPL_instance22_t() FUNC_OBJ_INS_OPLIST(instance22, M_DEFAULT_OPLIST)
FUNC_OBJ_ITF_DEF_AS(Interface, Interface, double, double)
FUNC_OBJ_INS_DEF_AS(Instance, Instance,
Interface,
(a), {
return a * self->a + self->b;
},
(a, double),
(b, double) )
#define M_OPL_Instance() FUNC_OBJ_INS_OPLIST(Instance, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
static void test_instance11(void)
{
instance11_t cmp;
@@ -117,11 +128,20 @@ static void test_instance22(void)
}
}
static void test_double(void)
{
M_LET( (func, 2.0, 3.0), Instance) {
double d = Interface_call(Instance_as_interface(func), 4.0);
assert (d == 2.0 * 4.0 + 3.0);
}
}
int main(void)
{
test_instance11();
test_instance12();
test_instance21();
test_instance22();
test_double();
return 0;
}
+6 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -33,7 +33,7 @@ static void test(size_t n)
genint_t s;
size_t i;
genint_init(s, n);
genint_init(s, (unsigned int) n);
for(int k = 0; k < 3; k++) {
for(size_t j = 0; j< n ; j++) {
i = genint_pop(s);
@@ -44,7 +44,7 @@ static void test(size_t n)
assert (genint_pop(s) == GENINT_ERROR);
for(size_t j = 0; j< n ; j++) {
genint_push(s, (j+k) % n );
genint_push(s, (unsigned int) ((j + (size_t) k) % n ));
}
}
@@ -84,7 +84,7 @@ static void test2(size_t n)
{
m_thread_t idx[4];
genint_init(global, n);
genint_init(global, (unsigned int) n);
for(int i = 0; i < MAX_N; i++)
atomic_init(&tab_g[i], false);
@@ -105,7 +105,7 @@ static void conso2(void *p)
size_t n = *(size_t*)p;
for(int i = 0; i < 1000000; i++) {
unsigned int j = genint_pop(global);
assert (j != -1U);
assert (j != GENINT_ERROR);
assert (j < n);
genint_push(global, j);
}
@@ -116,7 +116,7 @@ static void test3(size_t n)
m_thread_t idx[MAX_N];
assert (n <= MAX_N);
genint_init(global, n);
genint_init(global, (unsigned int) n);
for(size_t i = 0; i < n; i++) {
m_thread_create (idx[i], conso2, (void*)&n);
}
+27 -1
View File
@@ -1,7 +1,7 @@
/*
* MLIB - TEST module
*
* Copyright (c) 2017-2020, 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:
@@ -40,6 +40,14 @@ END_COVERAGE
ILIST_DEF(ilist_free, test_t, (DEL(free)))
typedef struct testd_s {
double n;
ILIST_INTERFACE (ListDouble, struct testd_s);
} TestDouble;
ILIST_DEF_AS(ListDouble, ListDouble, ListDoubleIt, TestDouble, M_OPEXTEND(M_POD_OPLIST, DEL(0)))
#define M_OPL_ListDouble() ILIST_OPLIST(ListDouble, M_POD_OPLIST)
static void test(void)
{
test_t x1, x2, x3;
@@ -239,10 +247,28 @@ static void test_free(void)
ilist_free_clear(list);
}
static void test_double(void)
{
TestDouble base[5];
M_LET( tab, ListDouble) {
for(int i = 0; i < 5; i++) {
base[i].n = (double) i;
ListDouble_init_field(&base[i]);
ListDouble_push_back(tab, &base[i]);
}
double ref = 0.0;
for M_EACH(i, tab, ListDouble) {
assert (i->n == ref);
ref += 1.0;
}
}
}
int main(void)
{
test();
test2();
test_free();
test_double();
exit(0);
}
+146
View File
@@ -0,0 +1,146 @@
/*
* 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.
*/
#include <assert.h>
#include "test-obj.h"
#include "m-i-shared.h"
#include "m-mutex.h"
#include "coverage.h"
typedef struct ishared_s {
ISHARED_PTR_INTERFACE(ishared1, struct ishared_s);
ISHARED_PTR_INTERFACE(ishared2, struct ishared_s);
int data[100];
} ishared_t[1];
static void ishared_init_data(struct ishared_s *x)
{
for(int i = 0 ; i < 100; i++)
x->data[i] = i * i;
}
static void ishared_test(struct ishared_s *x)
{
for(int i = 0 ; i < 100; i++) {
assert (x->data[i] == i*i);
}
}
START_COVERAGE
ISHARED_PTR_DEF(ishared1, struct ishared_s, (INIT(API_2(ishared_init_data))))
ISHARED_PTR_DEF(ishared2, struct ishared_s, (INIT(API_2(ishared_init_data)), NEW(0), DEL(0)) )
END_COVERAGE
/*ISHARED_PTR_DEF_AS(SharedDouble, SharedDouble, double) */
static void test_single(void)
{
ishared1_t p1, p2;
p1 = ishared1_init_new();
ishared_test(p1);
p2 = ishared1_init_set(p1);
ishared_test(p2);
ishared1_clear(p1);
ishared_test(p2);
p1 = ishared1_init(NULL);
ishared1_set(&p1, p2);
ishared1_clean(&p2);
assert(p2 == NULL);
ishared_test(p1);
ishared1_clear(p1);
p1 = ishared1_init_set(p2);
assert(p1 == NULL);
ishared1_clear(p1);
ishared1_clear(p2);
struct ishared_s *x = (struct ishared_s *) malloc(sizeof (struct ishared_s));
assert(x != NULL);
ishared_init_data(x);
p1 = ishared1_init(x);
ishared_test(p1);
ishared1_clear(p1);
}
static struct ishared_s g_var = {
ISHARED_PTR_STATIC_INIT(ishared1, struct ishared_s),
ISHARED_PTR_STATIC_INIT(ishared2, struct ishared_s),
{ 0 }
};
static void test_static(void)
{
ishared2_t p1, p2;
p1 = ishared2_init_once(NULL);
assert(p1 == NULL);
p1 = ishared2_init_once(&g_var);
ishared_test(p1);
p2 = ishared2_init_once(&g_var);
ishared_test(p2);
ishared2_clear(p1);
ishared_test(p2);
ishared2_clear(p2);
}
#define MAX_THREAD 256
#define MAX_VAR 5
#define VAL(x) { ISHARED_PTR_STATIC_INIT(ishared1, struct ishared_s), ISHARED_PTR_STATIC_INIT(ishared2, struct ishared_s), { 0 } }
static struct ishared_s g_tab[MAX_VAR] = {
M_MAP_C(VAL, M_SEQ(1, MAX_VAR))
};
static void func(void *arg)
{
int id = (int)(intptr_t) arg;
int v = id % MAX_VAR;
ishared2_t p = ishared2_init_once(&g_tab[v]);
for(int i = 0; i < 100; i++) {
ishared_test(p);
}
ishared2_clear(p);
}
static void test_shared(void)
{
m_thread_t id[MAX_THREAD];
for(int i = 0; i < MAX_THREAD; i++) {
m_thread_create(id[i], func, (void*) (intptr_t) i);
}
for(int i = 0; i < MAX_THREAD; i++) {
m_thread_join(id[i]);
}
}
int main(void)
{
test_single();
test_static();
test_shared();
exit(0);
}
+33 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -40,6 +40,12 @@ LIST_DEF(list_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), C
LIST_DUAL_PUSH_DEF(list2_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear)))
LIST_DEF_AS(list_double, ListDouble, ListDoubleIt, double)
#define M_OPL_ListDouble() LIST_OPLIST(list_double, M_DEFAULT_OPLIST)
LIST_DUAL_PUSH_DEF_AS(list_doubleDP, ListDoubleDP, ListDoubleDPIt, double)
#define M_OPL_ListDoubleDP() LIST_OPLIST(list_doubleDP, M_DEFAULT_OPLIST)
static void test_uint(void)
{
list_uint_t v;
@@ -251,14 +257,14 @@ static void test_mpz(void)
}
assert (testobj_get_ui(s) == 1000*999/2);
FILE *f = fopen ("a-mlist.dat", "wt");
FILE *f = m_core_fopen ("a-mlist.dat", "wt");
if (!f) abort();
list_mpz_out_str(f, v);
fclose (f);
list_mpz_t list2;
list_mpz_init(list2);
f = fopen ("a-mlist.dat", "rt");
f = m_core_fopen ("a-mlist.dat", "rt");
bool b = list_mpz_in_str (list2, f);
assert (b == true);
fclose(f);
@@ -603,13 +609,13 @@ static void test_out_default_oplist(void)
{
M_LET(str, string_t)
M_LET(list, l2, list_int_t) {
FILE *f = fopen ("a-mlist.dat", "wt");
FILE *f = m_core_fopen ("a-mlist.dat", "wt");
if (!f) abort();
list_int_push_back(list, 2);
list_int_push_back(list, 3);
list_int_out_str(f, list);
fclose(f);
f = fopen("a-mlist.dat", "rt");
f = m_core_fopen("a-mlist.dat", "rt");
if (!f) abort();
char buffer[1024];
assert (fgets(buffer, 1024, f) == buffer);
@@ -617,7 +623,7 @@ static void test_out_default_oplist(void)
fclose(f);
list_int_get_str(str, list, false);
assert (string_equal_str_p(str, "[3,2]"));
f = fopen("a-mlist.dat", "rt");
f = m_core_fopen("a-mlist.dat", "rt");
if (!f) abort();
assert (list_int_in_str(l2, f) == true);
assert (list_int_equal_p(l2, list));
@@ -626,7 +632,7 @@ static void test_out_default_oplist(void)
M_LET(str, string_t)
M_LET( (list, 1, 2, 3, 4, 5), list_int_t) {
list_int_get_str(str, list, false);
assert (string_equal_str_p(str, "[5,4,3,2,1]"));
assert (string_equal_str_p(str, "[1,2,3,4,5]"));
}
}
#else
@@ -635,6 +641,25 @@ static void test_out_default_oplist(void)
}
#endif
static void test_double(void)
{
M_LET( (tab, 0.0, 1.0, 2.0, 3.0), ListDouble) {
double ref = 0.0;
for M_EACH(i, tab, ListDouble) {
assert (*i == ref);
ref += 1.0;
}
}
M_LET( (tab, 0.0, 1.0, 2.0, 3.0), ListDoubleDP) {
double ref = 0.0;
for M_EACH(i, tab, ListDoubleDP) {
assert (*i == ref);
ref += 1.0;
}
}
}
int main(void)
{
test_uint();
@@ -642,6 +667,7 @@ int main(void)
test_dual_push1();
test_dual_it1();
test_out_default_oplist();
test_double();
exit(0);
}
+38 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -31,6 +31,8 @@ START_COVERAGE
MEMPOOL_DEF(mempool_uint, unsigned int)
END_COVERAGE
MEMPOOL_DEF_AS(MempoolDouble, MempoolDouble, unsigned int)
static void test(void)
{
mempool_uint_t m;
@@ -65,8 +67,43 @@ static void test(void)
mempool_uint_clear(m);
}
static void test_double(void)
{
MempoolDouble m;
MempoolDouble_init(m);
unsigned int *tab[100000];
for(unsigned int i = 0; i < 100000; i++) {
tab[i] = MempoolDouble_alloc(m);
*tab[i] = i;
}
for(unsigned int i = 0; i < 100000; i++) {
assert (*tab[i] == i);
}
for(unsigned int i = 0; i < 100000; i+=2) {
MempoolDouble_free(m, tab[i]);
tab[i] = NULL;
}
for(unsigned int i = 1; i < 100000; i+=2) {
assert (*tab[i] == i);
}
for(unsigned int i = 0; i < 100000; i+=2) {
tab[i] = MempoolDouble_alloc(m);
*tab[i] = i;
}
for(unsigned int i = 0; i < 100000; i++) {
assert (*tab[i] == i);
}
for(unsigned int i = 0; i < 100000; i++) {
MempoolDouble_free(m, tab[i]);
tab[i] = NULL;
}
MempoolDouble_clear(m);
}
int main(void)
{
test();
test_double();
exit(0);
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
+234 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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,7 +29,16 @@
START_COVERAGE
PRIOQUEUE_DEF(int_pqueue, int)
END_COVERAGE
PRIOQUEUE_DEF(mpz_pqueue, testobj_t, TESTOBJ_CMP_OPLIST)
static inline bool testobj_equal2_p(const testobj_t z1, const testobj_t z2)
{
return z1->a == z2->a;
}
PRIOQUEUE_DEF(obj_pqueue, testobj_t, M_OPEXTEND(TESTOBJ_CMP_OPLIST, EQUAL(testobj_equal2_p) ))
PRIOQUEUE_DEF_AS(PrioDouble, PrioDouble, PrioDoubleIt, double)
#define M_OPL_PrioDouble() PRIOQUEUE_OPLIST(PrioDouble, M_DEFAULT_OPLIST)
static void test1(void)
{
@@ -61,6 +70,7 @@ static void test1(void)
assert (x == 60);
assert (int_pqueue_empty_p(p));
assert (int_pqueue_size(p) == 0);
int_pqueue_push(p, 10);
int_pqueue_push(p, 30);
int_pqueue_pop(&x, p);
@@ -71,8 +81,29 @@ static void test1(void)
int_pqueue_push(p, 17);
bool b = int_pqueue_erase(p, 17);
assert(b);
assert (int_pqueue_size(p) == 1);
b = int_pqueue_erase(p, 1742);
assert(!b);
b = int_pqueue_erase(p, 30);
assert(b);
assert (int_pqueue_size(p) == 0);
int_pqueue_push(p, 30);
int_pqueue_push(p, 40);
int_pqueue_push(p, 10);
int_pqueue_push(p, 50);
int_pqueue_push(p, 20);
assert (int_pqueue_size(p) == 5);
int_pqueue_erase(p, 30);
int_pqueue_push(p, 30);
assert (*int_pqueue_front(p) == 10);
int_pqueue_update(p, 40, 15);
assert (*int_pqueue_front(p) == 10);
int_pqueue_update(p, 20, 5);
assert (*int_pqueue_front(p) == 5);
int_pqueue_update(p, 5, 25);
assert (*int_pqueue_front(p) == 10);
int_pqueue_clear(p);
}
@@ -98,12 +129,213 @@ static void test2(void)
assert (x == i);
}
assert (int_pqueue_size(p) == 0);
for(int i = -100; i < 100; i++) {
int_pqueue_push(p, i);
}
assert (int_pqueue_size(p) == 200);
for(int i = -100; i < 100; i++) {
bool b = int_pqueue_erase(p, i);
assert (b);
}
assert (int_pqueue_size(p) == 0);
int_pqueue_clear(p);
}
static void test_update(void)
{
obj_pqueue_t p;
obj_pqueue_init(p);
const testobj_t *front;
M_LET( x, y, z, TESTOBJ_OPLIST) {
testobj_set_ui(x, 7);
testobj_set_id(x, 1);
obj_pqueue_push(p, x);
testobj_set_ui(x, 30);
testobj_set_id(x, 2);
obj_pqueue_push(p, x);
testobj_set_ui(x, 40);
testobj_set_id(x, 3);
obj_pqueue_push(p, x);
testobj_set_ui(x, 10);
testobj_set_id(x, 4);
obj_pqueue_push(p, x);
testobj_set_ui(x, 20);
testobj_set_id(x, 5);
obj_pqueue_push(p, x);
testobj_set_ui(x, 3);
testobj_set_id(x, 6);
obj_pqueue_push(p, x);
testobj_set_ui(x, 35);
testobj_set_id(x, 7);
obj_pqueue_push(p, x);
front = obj_pqueue_front(p);
assert ( (*front)->a == 6);
testobj_set_ui(y, 8);
testobj_set_id(y, 5);
obj_pqueue_update(p, y, y);
front = obj_pqueue_front(p);
assert ( (*front)->a == 6);
testobj_set_ui(y, 1);
testobj_set_id(y, 5);
obj_pqueue_update(p, y, y);
front = obj_pqueue_front(p);
assert ( (*front)->a == 5);
testobj_set_ui(y, 4);
testobj_set_id(y, 5);
obj_pqueue_update(p, y, y);
front = obj_pqueue_front(p);
assert ( (*front)->a == 6);
testobj_set_ui(y, 4);
testobj_set_id(y, 6);
obj_pqueue_erase(p, y);
front = obj_pqueue_front(p);
assert ( (*front)->a == 5);
testobj_set_ui(y, 100);
testobj_set_id(y, 5);
obj_pqueue_update(p, y, y);
front = obj_pqueue_front(p);
assert ( (*front)->a == 1);
testobj_set_ui(y, 4);
testobj_set_id(y, 2);
obj_pqueue_erase(p, y);
front = obj_pqueue_front(p);
assert ( (*front)->a == 1);
testobj_set_ui(y, 4);
testobj_set_id(y, 3);
obj_pqueue_erase(p, y);
front = obj_pqueue_front(p);
assert ( (*front)->a == 1);
testobj_set_ui(y, 4);
testobj_set_id(y, 4);
obj_pqueue_erase(p, y);
front = obj_pqueue_front(p);
assert ( (*front)->a == 1);
testobj_set_ui(y, 4);
testobj_set_id(y, 1);
obj_pqueue_erase(p, y);
front = obj_pqueue_front(p);
assert ( (*front)->a == 7);
testobj_set_ui(y, 4);
testobj_set_id(y, 7);
obj_pqueue_erase(p, y);
front = obj_pqueue_front(p);
assert ( (*front)->a == 5);
}
obj_pqueue_clear(p);
}
static void test_it(void)
{
int_pqueue_t p, q;
int_pqueue_init(p);
for(int i = -10; i < 10; i++) {
int_pqueue_push(p, i*i);
}
assert(int_pqueue_size(p) == 20);
int_pqueue_init_set(q, p);
assert(int_pqueue_equal_p(p, q));
assert(int_pqueue_size(q) == 20);
int_pqueue_push(q, 43);
assert(int_pqueue_size(p) == 20);
assert(int_pqueue_size(q) == 21);
int_pqueue_swap(p, q);
assert(int_pqueue_size(p) == 21);
assert(int_pqueue_size(q) == 20);
int_pqueue_swap(p, q);
assert(int_pqueue_size(p) == 20);
assert(int_pqueue_size(q) == 21);
int_pqueue_clean(q);
assert(!int_pqueue_equal_p(p, q));
assert(int_pqueue_empty_p(q));
assert(!int_pqueue_empty_p(p));
int_pqueue_set(q, p);
assert(int_pqueue_equal_p(p, q));
assert(int_pqueue_size(q) == 20);
int_pqueue_move(q, p);
assert(int_pqueue_size(q) == 20);
int_pqueue_init_move(p, q);
assert(int_pqueue_size(p) == 20);
int_pqueue_it_t it, it2;
int i = 0;
const int tab[] = {0 , 1 , 1 , 16 , 4 , 4 , 9 , 25 , 49 , 64 , 9 , 81 , 25 , 36 , 16 , 100 , 36 , 49 , 64 , 81};
assert (int_pqueue_size(p) == sizeof(tab)/sizeof(tab[0]) );
for(int_pqueue_it(it, p) ;
!int_pqueue_end_p(it) ;
int_pqueue_next(it) ) {
assert(tab[i] == *int_pqueue_cref(it) );
i++;
}
int_pqueue_it_end(it, p);
assert(int_pqueue_end_p(it)) ;
int_pqueue_it_last(it, p);
assert(!int_pqueue_end_p(it)) ;
int_pqueue_next(it);
assert(int_pqueue_end_p(it)) ;
int_pqueue_previous(it);
int_pqueue_it_set(it2, it);
assert(int_pqueue_last_p(it2));
assert(int_pqueue_it_equal_p(it, it2));
int_pqueue_previous(it2);
assert(!int_pqueue_it_equal_p(it, it2));
int_pqueue_clear(p);
}
static void test_double(void)
{
M_LET( (tab, 0.0, 1.0, 2.0, 3.0), PrioDouble) {
double ref = 0.0;
// NOTE: The binary heap is sorted in the same natural order that the sorted array
for M_EACH(i, tab, PrioDouble) {
assert (*i == ref);
ref += 1.0;
}
}
}
int main(void)
{
test1();
test2();
test_update();
test_double();
test_it();
exit(0);
}
+26 -11
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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,14 +27,14 @@
static bool uint_in_str(unsigned int *u, FILE *f)
{
int n = fscanf(f, "%u", u);
int n = m_core_fscanf(f, "%u", u);
return n == 1;
}
static bool uint_parse_str(unsigned int *u, const char str[], const char **endptr)
{
char *end;
*u = strtol(str, &end, 0);
*u = (unsigned int) strtol(str, &end, 0);
if (endptr) { *endptr = (const char*) end; }
return (uintptr_t) end != (uintptr_t) str;
}
@@ -60,6 +60,9 @@ RBTREE_DEF(rbtree_mpz, testobj_t, TESTOBJ_OPLIST)
#define UINT_OPLIST RBTREE_OPLIST(rbtree_uint)
#define FLOAT_OP RBTREE_OPLIST(rbtree_float)
RBTREE_DEF_AS(TreeDouble, TreeDouble, TreeDoubleIt, double, M_DEFAULT_OPLIST)
#define M_OPL_TreeDouble() RBTREE_OPLIST(TreeDouble, M_DEFAULT_OPLIST)
static void test_uint(void)
{
rbtree_uint_t tree, tree2, tree3;
@@ -83,6 +86,7 @@ static void test_uint(void)
}
assert (k == 5);
rbtree_uint_it_t it, it2;
rbtree_uint_it(it2, tree);
for (rbtree_uint_it_last(it, tree) ; !rbtree_uint_end_p(it) ; rbtree_uint_previous(it)) {
k--;
rbtree_uint_it_set(it2, it);
@@ -176,8 +180,8 @@ static void test_uint_permut(void)
for(unsigned int i = 0; i < num; i++)
tab[i] = i;
for(unsigned int i = 0; i < 2 * num; i++) {
int j = rand() % num;
int k = rand() % num;
unsigned int j = (unsigned int) rand() % num;
unsigned int k = (unsigned int) rand() % num;
M_SWAP(unsigned int, tab[j], tab[k]);
}
for(unsigned int i = 0; i < num; i++)
@@ -195,7 +199,7 @@ static void test_uint_permut(void)
static void test_float(void)
{
M_LET(tree, FLOAT_OP) {
for(float f = -17.42; f < 17.42; f+=0.01)
for(float f = -17.42f; f < 17.42f; f+=0.01f)
rbtree_float_push (tree, f);
bool p = false;
float g;
@@ -214,12 +218,12 @@ static void test_io(void)
M_LET(str, STRING_OPLIST)
M_LET(tree1, tree2, UINT_OPLIST) {
// Empty one
FILE *f = fopen ("a-mrbtree.dat", "wt");
FILE *f = m_core_fopen ("a-mrbtree.dat", "wt");
if (!f) abort();
rbtree_uint_out_str(f, tree1);
fclose (f);
f = fopen ("a-mrbtree.dat", "rt");
f = m_core_fopen ("a-mrbtree.dat", "rt");
if (!f) abort();
bool b = rbtree_uint_in_str (tree2, f);
assert (b == true);
@@ -238,12 +242,12 @@ static void test_io(void)
for(unsigned int i = 0 ; i < 10; i++)
rbtree_uint_push(tree1, i);
f = fopen ("a-mrbtree.dat", "wt");
f = m_core_fopen ("a-mrbtree.dat", "wt");
if (!f) abort();
rbtree_uint_out_str(f, tree1);
fclose (f);
f = fopen ("a-mrbtree.dat", "rt");
f = m_core_fopen ("a-mrbtree.dat", "rt");
if (!f) abort();
b = rbtree_uint_in_str (tree2, f);
assert (b == true);
@@ -256,8 +260,18 @@ static void test_io(void)
assert(b);
assert(*sp == 0);
assert(rbtree_uint_equal_p(tree1, tree2));
}
}
static void test_double(void)
{
M_LET( (tree, 0.0, 1.0, 2.0), TreeDouble) {
double ref = 0.0;
for M_EACH(i, tree, TreeDouble) {
assert (*i == ref);
ref += 1.0;
}
}
}
int main(void)
@@ -266,5 +280,6 @@ int main(void)
test_uint_permut();
test_float();
test_io();
test_double();
exit(0);
}
+15 -17
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -62,27 +62,25 @@ TUPLE_DEF2(my2,
static void test_out_empty(void)
{
m_serial_read_t in;
m_serial_write_t out;
m_serial_return_code_t ret;
my2_t el1, el2;
my2_init(el1);
my2_init(el2);
FILE *f = fopen ("a-mbin.dat", "wt");
FILE *f = m_core_fopen ("a-mbin.dat", "wt");
if (!f) abort();
m_serial_bin_write_init(out, f);
ret = my2_out_serial(out, el1);
assert (ret == M_SERIAL_OK_DONE);
m_serial_bin_write_clear(out);
M_LET( (serial, f), m_serial_bin_write_t) {
ret = my2_out_serial(serial, el1);
assert (ret == M_SERIAL_OK_DONE);
}
fclose(f);
f = fopen ("a-mbin.dat", "rt");
f = m_core_fopen ("a-mbin.dat", "rt");
if (!f) abort();
m_serial_bin_read_init(in, f);
ret = my2_in_serial(el2, in);
assert (ret == M_SERIAL_OK_DONE);
m_serial_bin_read_clear(in);
M_LET( (serial, f), m_serial_bin_read_t) {
ret = my2_in_serial(el2, serial);
assert (ret == M_SERIAL_OK_DONE);
}
fclose(f);
assert (my2_equal_p (el1, el2));
@@ -104,7 +102,7 @@ static void test_out_fill(void)
el2->activated = true;
el2->data->vala = 145788;
el2->data->valb = -0.1;
el2->data->valb = -0.1f;
el2->data->valc = false;
string_set_str(el2->data->vald, "This is a string test.");
a2_push_back(el2->data->vale, 1);
@@ -118,7 +116,7 @@ static void test_out_fill(void)
d2_set_at(el2->data->valh, STRING_CTE("Paul"), 1);
d2_set_at(el2->data->valh, STRING_CTE("Smith"), 2);
f = fopen ("a-mbin.dat", "wt");
f = m_core_fopen ("a-mbin.dat", "wt");
if (!f) abort();
m_serial_bin_write_init(out, f);
ret = my2_out_serial(out, el2);
@@ -126,7 +124,7 @@ static void test_out_fill(void)
m_serial_bin_write_clear(out);
fclose(f);
f = fopen ("a-mbin.dat", "rt");
f = m_core_fopen ("a-mbin.dat", "rt");
if (!f) abort();
m_serial_bin_read_init(in, f);
ret = my2_in_serial(el1, in);
@@ -142,7 +140,7 @@ static void test_out_fill(void)
int main(void)
{
//test_out_empty();
test_out_empty();
test_out_fill();
exit(0);
}
+29 -19
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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:
@@ -43,7 +43,12 @@ VARIANT_DEF2(v2,
(is_int, int),
(is_bool, bool) )
#define M_OPL_v2_t() VARIANT_OPLIST(v2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
typedef enum {
SUCCESS = 0, NULL_PARAM, INVALID_PARAM
} my_return_code_t;
#define M_OPL_my_return_code_t() M_ENUM_OPLIST(my_return_code_t, SUCCESS)
TUPLE_DEF2(my,
(vala, int),
(valb, float),
@@ -52,9 +57,10 @@ TUPLE_DEF2(my,
(vale, a2_t),
(valf, v2_t),
(valg, l2_t),
(valh, d2_t)
(valh, d2_t),
(vali, my_return_code_t)
)
#define M_OPL_my_t() TUPLE_OPLIST(my, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST, STRING_OPLIST, M_OPL_a2_t(), M_OPL_v2_t(), M_OPL_l2_t(), M_OPL_d2_t() )
#define M_OPL_my_t() TUPLE_OPLIST(my, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST, STRING_OPLIST, M_OPL_a2_t(), M_OPL_v2_t(), M_OPL_l2_t(), M_OPL_d2_t(), M_OPL_my_return_code_t() )
TUPLE_DEF2(my2,
(activated, bool),
@@ -69,7 +75,7 @@ static void test_out_empty(void)
my2_init(el1);
my2_init(el2);
FILE *f = fopen ("a-mjson.dat", "wt");
FILE *f = m_core_fopen ("a-mjson.dat", "wt");
if (!f) abort();
m_serial_json_write_init(out, f);
ret = my2_out_serial(out, el1);
@@ -77,15 +83,15 @@ static void test_out_empty(void)
m_serial_json_write_clear(out);
fclose(f);
f = fopen ("a-mjson.dat", "rt");
f = m_core_fopen ("a-mjson.dat", "rt");
if (!f) abort();
static const char expected[] = "{ \"activated\":false,\"data\":{ \"vala\":0,\"valb\":0.000000,\"valc\":false,\"vald\":\"\",\"vale\":[],\"valf\":{},\"valg\":[],\"valh\":{}}";
static const char expected[] = "{ \"activated\":false,\"data\":{ \"vala\":0,\"valb\":0.000000,\"valc\":false,\"vald\":\"\",\"vale\":[],\"valf\":{},\"valg\":[],\"valh\":{},\"vali\":0}";
char get[sizeof expected];
fgets (get, sizeof expected , f);
assert (strcmp(get, expected) == 0);
char *unused = fgets (get, sizeof expected , f);
assert (unused != NULL && strcmp(get, expected) == 0);
fclose(f);
f = fopen ("a-mjson.dat", "rt");
f = m_core_fopen ("a-mjson.dat", "rt");
if (!f) abort();
m_serial_json_read_init(in, f);
ret = my2_in_serial(el2, in);
@@ -108,7 +114,7 @@ static void test_out_fill(void)
my2_init(el1);
my2_init(el2);
FILE *f = fopen("a-mjson.dat", "wt");
FILE *f = m_core_fopen("a-mjson.dat", "wt");
if (!f) abort();
fprintf(f,
"{\n"
@@ -121,10 +127,11 @@ static void test_out_fill(void)
"\"valf\": { \"is_bool\": true },\n"
" \"vala\":1742,\n"
" \"vald\": \"This is a test\",\n"
"\"vali\": 3,"
" \"valc\": true } }\n");
fclose(f);
f = fopen ("a-mjson.dat", "rt");
f = m_core_fopen ("a-mjson.dat", "rt");
if (!f) abort();
m_serial_json_read_init(in, f);
ret = my2_in_serial(el2, in);
@@ -132,7 +139,7 @@ static void test_out_fill(void)
m_serial_json_read_clear(in);
fclose(f);
f = fopen ("a-mjson.dat", "wt");
f = m_core_fopen ("a-mjson.dat", "wt");
if (!f) abort();
m_serial_json_write_init(out, f);
ret = my2_out_serial(out, el2);
@@ -140,16 +147,19 @@ static void test_out_fill(void)
m_serial_json_write_clear(out);
fclose(f);
f = fopen ("a-mjson.dat", "rt");
f = m_core_fopen ("a-mjson.dat", "rt");
if (!f) abort();
static const char expected[] = "{ \"activated\":false,\"data\":{ \"vala\":1742,\"valb\":-2.300000,\"valc\":true,\"vald\":\"This is a test\",\"vale\":[1,2,3],\"valf\":{\"is_bool\":true},\"valg\":[1,2,3,4,5,6],\"valh\":{\"steeve\":-4,\"jane\":3}}}";
static const char expected2[] = "{ \"activated\":false,\"data\":{ \"vala\":1742,\"valb\":-2.300000,\"valc\":true,\"vald\":\"This is a test\",\"vale\":[1,2,3],\"valf\":{\"is_bool\":true},\"valg\":[1,2,3,4,5,6],\"valh\":{\"jane\":3,\"steeve\":-4}}}";
static const char expected[] = "{ \"activated\":false,\"data\":{ \"vala\":1742,\"valb\":-2.300000,\"valc\":true,\"vald\":\"This is a test\",\"vale\":[1,2,3],\"valf\":{\"is_bool\":true},\"valg\":[1,2,3,4,5,6],\"valh\":{\"steeve\":-4,\"jane\":3},\"vali\":3}}";
static const char expected2[] = "{ \"activated\":false,\"data\":{ \"vala\":1742,\"valb\":-2.300000,\"valc\":true,\"vald\":\"This is a test\",\"vale\":[1,2,3],\"valf\":{\"is_bool\":true},\"valg\":[1,2,3,4,5,6],\"valh\":{\"jane\":3,\"steeve\":-4},\"vali\":3}}";
char get[sizeof expected];
fgets (get, sizeof expected , f);
assert (strcmp(get, expected) == 0 || strcmp(get, expected2) == 0);
char *unused2 = fgets (get, sizeof expected , f);
assert(unused2 != NULL);
// Workaround string literal of length 4350 exceeds maximum length 4095
if (!(strcmp(get, expected) == 0 || strcmp(get, expected2) == 0))
assert (0);
fclose(f);
f = fopen ("a-mjson.dat", "rt");
f = m_core_fopen ("a-mjson.dat", "rt");
if (!f) abort();
m_serial_json_read_init(in, f);
ret = my2_in_serial(el1, in);
+50 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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,9 +30,14 @@ START_COVERAGE
SHARED_PTR_DEF(shared_int, int)
SHARED_RESOURCE_DEF(shared_ressource, testobj_t, TESTOBJ_OPLIST)
END_COVERAGE
SHARED_PTR_DEF(shared_mpz, testobj_t, TESTOBJ_OPLIST)
SHARED_PTR_RELAXED_DEF(shared_relaxed_int, int)
SHARED_PTR_DEF_AS(SharedDouble, SharedDouble, double)
SHARED_PTR_RELAXED_DEF_AS(SharedDouble2, SharedDouble2, double, M_DEFAULT_OPLIST)
SHARED_RESOURCE_DEF_AS(SharedRessource, SharedRessource, SharedRessourceIt, double)
static int f(const shared_int_t p)
{
return *shared_int_cref(p);
@@ -139,13 +144,13 @@ static void test_ressource(int n)
shared_ressource_it_t copy[MAX_RESSOURCE];
shared_ressource_it_t onemore;
shared_ressource_init (ressource, n);
shared_ressource_init (ressource, (size_t) n);
for(int i = 0; i < n ; i++) {
shared_ressource_it (it[i], ressource);
assert (!shared_ressource_end_p(it[i]));
testobj_t *z = shared_ressource_ref(it[i]);
assert (z != NULL);
testobj_set_ui(*z, i);
testobj_set_ui(*z, (unsigned int) i);
}
shared_ressource_it (onemore, ressource);
assert (shared_ressource_end_p(onemore));
@@ -154,7 +159,7 @@ static void test_ressource(int n)
assert (!shared_ressource_end_p(copy[i]));
const testobj_t *z = shared_ressource_cref(copy[i]);
assert (z != NULL);
assert (testobj_cmp_ui(*z, i) == 0);
assert (testobj_cmp_ui(*z, (unsigned int) i) == 0);
}
shared_ressource_it (onemore, ressource);
assert (shared_ressource_end_p(onemore));
@@ -177,12 +182,52 @@ static void test_ressource(int n)
shared_ressource_clear(ressource);
}
static void test_double(void){
SharedDouble p;
SharedDouble_init_new(p);
assert(*SharedDouble_ref(p) == 0.0);
*SharedDouble_ref(p) = 5678.0;
SharedDouble q;
SharedDouble_init_set(q, p);
assert(*SharedDouble_ref(q) == 5678.0);
SharedDouble_clear(p);
SharedDouble_clear(q);
}
static void test_double2(void){
SharedDouble2 p;
SharedDouble2_init_new(p);
assert(*SharedDouble2_ref(p) == 0.0);
*SharedDouble2_ref(p) = 5678.0;
SharedDouble2 q;
SharedDouble2_init_set(q, p);
assert(*SharedDouble2_ref(q) == 5678.0);
SharedDouble2_clear(p);
SharedDouble2_clear(q);
}
static void test_double_res(void){
SharedRessource r;
SharedRessource_init(r, 4);
SharedRessourceIt i;
SharedRessource_it(i, r);
assert(*SharedRessource_ref(i) == 0);
*SharedRessource_ref(i) = 3456.0;
SharedRessource_end(i, r);
SharedRessource_it(i, r);
assert(*SharedRessource_ref(i) == 3456.0);
SharedRessource_clear(r);
}
int main(void)
{
test1();
test2();
for(int i = 1; i < MAX_RESSOURCE; i++)
for(int i = 1; i < MAX_RESSOURCE; i++) {
test_ressource(i);
}
test_double();
test_double2();
test_double_res();
exit(0);
}
+72 -11
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020, 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,9 +37,9 @@ typedef struct {
void *v;
} data_t;
static void data_crc(data_t *p) { p->p = -p->n; p->c = ~p->n; }
static void data_crc(data_t *p) { p->p = 0-p->n; p->c = ~p->n; }
static void data_init(data_t *p) { p->n = 0; p->spare1 = 0; p->spare2 = 0; data_crc(p); p->v = calloc(1, 1); assert(p->v); }
static void data_valid_p(const data_t *p) { assert (p->n == -p->p && p->n == ~p->c); }
static void data_valid_p(const data_t *p) { assert (p->n == (0-p->p) && p->n == ~p->c); }
static void data_clear(data_t *p) { free(p->v); }
static void data_set(data_t *p, data_t o) { p->n = o.n; data_crc(p); }
static void data_init_set(data_t *p, data_t o) { data_init(p); data_set(p, o); }
@@ -53,8 +53,12 @@ SNAPSHOT_SPSC_DEF(snapshot_mpz, testobj_t, TESTOBJ_OPLIST)
SNAPSHOT_SPMC_DEF(snapshot_mrsw_data, data_t, DATA_OPLIST)
SNAPSHOT_MPMC_DEF(snapshot_mrmw_data, data_t, DATA_OPLIST)
END_COVERAGE
SNAPSHOT_SPSC_DEF(snapshot_data, data_t, DATA_OPLIST )
SNAPSHOT_SPSC_DEF_AS(SnapshotDouble, SnapshotDouble, double)
SNAPSHOT_SPMC_DEF_AS(SnapshotDoubleSPMC, SnapshotDoubleSPMC, double)
SNAPSHOT_MPMC_DEF_AS(SnapshotDoubleMPMC, SnapshotDoubleMPMC, double)
static void test_uint(void)
{
@@ -150,7 +154,7 @@ static void test_global(void)
static void test_mrsw_int1(void)
{
snapshot_mrsw_int_t idx;
snapshot_mrsw_int_ct idx;
snapshot_mrsw_int_init(idx, 1);
assert (snapshot_mrsw_int_get_write_idx(idx) == 1);
@@ -180,7 +184,7 @@ static void test_mrsw_int1(void)
static void test_mrsw_int2(void)
{
snapshot_mrsw_int_t idx;
snapshot_mrsw_int_ct idx;
snapshot_mrsw_int_init(idx, 2);
assert (snapshot_mrsw_int_get_write_idx(idx) == 1);
@@ -215,13 +219,20 @@ snapshot_mrsw_data_t global_mrsw;
static void conso2(void *arg)
{
assert (arg == NULL);
unsigned int idx = (unsigned) (uintptr_t) arg;
while (true) {
const data_t *p = snapshot_mrsw_data_read_start(global_mrsw);
assert (p != NULL);
unsigned int n = p->n;
data_valid_p(p);
if (p->n == 0)
return;
break;
if (idx > 0) {
// Simulate slow readers if idx > 0
m_thread_sleep(idx * 10);
data_valid_p(p);
assert (n == p->n);
}
snapshot_mrsw_data_read_end(global_mrsw, p);
}
}
@@ -230,12 +241,21 @@ static void prod2(void *arg)
{
assert (arg == NULL);
data_t *p = snapshot_mrsw_data_get_write_buffer(global_mrsw);
for(unsigned int i = 1; i < 200000;i++) {
for(unsigned int i = 1; i < 190000;i++) {
assert (p != NULL);
p->n = i * i;
data_crc(p);
p = snapshot_mrsw_data_write(global_mrsw);
}
for(unsigned int i = 190000; i < 200000;i++) {
assert (p != NULL);
p->n = i * i;
data_crc(p);
// Simulate slow writes
m_thread_sleep(1);
m_thread_yield();
p = snapshot_mrsw_data_write(global_mrsw);
}
p->n = 0;
data_crc(p);
p = snapshot_mrsw_data_write(global_mrsw);
@@ -250,7 +270,7 @@ static void test_mrsw_global(int reader)
m_thread_t idx_w;
m_thread_t idx[MAX_READER];
snapshot_mrsw_data_init(global_mrsw, reader);
snapshot_mrsw_data_init(global_mrsw, (size_t) reader);
data_t *p = snapshot_mrsw_data_write(global_mrsw);
assert (p != NULL);
p->n = 42;
@@ -259,7 +279,7 @@ static void test_mrsw_global(int reader)
assert (p != NULL);
for(int i = 0 ; i < reader; i++)
m_thread_create (idx[i], conso2, NULL);
m_thread_create (idx[i], conso2, (void*) (uintptr_t) i);
m_thread_create (idx_w, prod2, NULL);
m_thread_join(idx_w);
@@ -305,7 +325,7 @@ static void test_mrmw_global(int reader, int writer)
m_thread_t idx_w[MAX_WRITER];
m_thread_t idx[MAX_READER];
snapshot_mrmw_data_init(global_mrmw, reader, writer);
snapshot_mrmw_data_init(global_mrmw, (size_t) reader, (size_t) writer);
data_t *p = snapshot_mrmw_data_write_start(global_mrmw);
assert (p != NULL);
p->n = 42;
@@ -325,6 +345,44 @@ static void test_mrmw_global(int reader, int writer)
snapshot_mrmw_data_clear(global_mrmw);
}
static void test_double(void)
{
SnapshotDouble s;
SnapshotDouble_init(s);
double *p = SnapshotDouble_get_write_buffer(s);
*p = 42.0;
p = SnapshotDouble_write(s);
const double *q = SnapshotDouble_read(s);
assert (*q == 42.0);
SnapshotDouble_clear(s);
}
static void test_doubleSPMC(void)
{
SnapshotDoubleSPMC s;
SnapshotDoubleSPMC_init(s, 1);
double *p = SnapshotDoubleSPMC_get_write_buffer(s);
*p = 42.0;
p = SnapshotDoubleSPMC_write(s);
const double *q = SnapshotDoubleSPMC_read_start(s);
assert (*q == 42.0);
SnapshotDoubleSPMC_read_end(s, q);
SnapshotDoubleSPMC_clear(s);
}
static void test_doubleMPMC(void)
{
SnapshotDoubleMPMC s;
SnapshotDoubleMPMC_init(s, 1, 1);
double *p = SnapshotDoubleMPMC_write_start(s);
*p = 42.0;
SnapshotDoubleMPMC_write_end(s, p);
const double *q = SnapshotDoubleMPMC_read_start(s);
assert (*q == 42.0);
SnapshotDoubleMPMC_read_end(s, q);
SnapshotDoubleMPMC_clear(s);
}
int main(void)
{
test_uint();
@@ -337,6 +395,9 @@ int main(void)
test_mrsw_global(MAX_READER);
test_mrmw_global(1, 1);
test_mrmw_global(MAX_READER/4, MAX_WRITER/4);
test_double();
test_doubleSPMC();
test_doubleMPMC();
exit(0);
}
Loaded 100 of 111 files, more files were not shown because too many files have changed in this diff. Show more