589 Commits
Author SHA1 Message Date
Patrick Pelissier b596e81e88 Regenerate depend 2018-12-14 21:48:21 +01:00
Patrick Pelissier b7bbe15547 Fix missing header in install 2018-12-14 21:46:38 +01:00
Patrick Pelissier cb5f8c20c8 Update analysis 2018-12-11 23:23:09 +01:00
Patrick Pelissier 61a1e15103 Update analysis 2018-12-11 23:19:33 +01:00
Patrick Pelissier 2416c2e466 Fix bug of overflow of 'alloc-num' if alloc < num (case where the service is called with a big number to insert 2018-12-05 17:52:02 +01:00
Patrick Pelissier b898ce3c56 update analysis 2018-11-29 23:24:11 +01:00
Patrick Pelissier 061e83b9e1 Add basic test for CONCURRENT_RP_DEF 2018-11-29 22:18:44 +01:00
Patrick Pelissier 0a8f727908 Remove CONCURRENT_RP2_DEF (Insuficient performance) 2018-11-27 07:47:06 +01:00
Patrick Pelissier ba584ab096 Use M_THREAD_ATTR 2018-11-26 23:26:42 +01:00
Patrick Pelissier 1fb1fa2e0a Add M_THREAD_ATTR 2018-11-26 23:26:08 +01:00
Patrick Pelissier 8cf780a60f Update comment 2018-11-25 22:43:37 +01:00
Patrick Pelissier ae171115bc Export method _size in concurrent if operator GET_SIZE defined. 2018-11-25 18:03:25 +01:00
Patrick Pelissier a8620c3aff Export method _size for operator GET_SIZE 2018-11-25 18:00:47 +01:00
Patrick Pelissier c154cdf46c Add operator GET_SIZE 2018-11-25 17:52:24 +01:00
Patrick Pelissier 77c59e2b85 Fix const issue. 2018-11-25 17:49:36 +01:00
Patrick Pelissier f07656757f Add another candidate for concurrent with parallel reader. 2018-11-25 11:44:28 +01:00
Patrick Pelissier a1c22fb679 Add first alpha version of Concurrent Container with support concurrent reading. 2018-11-24 19:31:31 +01:00
Patrick Pelissier 3640041c47 Port internal functions of concurrent to use the local lock interface. 2018-11-24 12:20:37 +01:00
Patrick Pelissier d3934dccb9 Add missing const in prototypes. 2018-11-24 11:46:28 +01:00
Patrick Pelissier 10cf2f2270 Prepare concurent for using different lock strategy 2018-11-24 11:37:09 +01:00
Patrick Pelissier c180b2b96d Update analysisd 2018-11-22 07:49:15 +01:00
Patrick Pelissier 5d5c2380ed Update release notes due to valgrind being unable to launch the test suite and scan-build producing too many false positives. 2018-11-16 22:54:04 +01:00
Patrick Pelissier a8b5c3ff4e Improve assertions 2018-11-10 17:54:13 +01:00
Patrick Pelissier 16587aeb93 Update doc 2018-11-08 20:55:28 +01:00
Patrick Pelissier 629a3a3dc1 Update depend 2018-11-08 20:54:42 +01:00
Patrick Pelissier ea46379d24 Update long term issue. 2018-11-07 19:54:07 +01:00
Patrick Pelissier ee0c77edc8 Replace SET+CLEAR by MOVE. 2018-11-04 20:28:56 +01:00
Patrick Pelissier c0610b2d60 Update doc 2018-11-04 20:15:15 +01:00
Patrick Pelissier 13ab545246 Update example for concurrent 2018-11-03 19:05:57 +01:00
Patrick Pelissier d85d6bcb13 Update doc 2018-11-01 17:21:11 +01:00
Patrick Pelissier 138662d6a0 Update checkall 2018-11-01 16:29:55 +01:00
Patrick Pelissier e45437e19f Add missing const 2018-11-01 16:11:42 +01:00
Patrick Pelissier 725846e155 Add missing type 2018-11-01 16:11:27 +01:00
Patrick Pelissier 74aa514903 Add missing const 2018-11-01 16:11:12 +01:00
Patrick Pelissier 7f7230be90 Fix doc 2018-10-31 17:38:04 +01:00
Patrick Pelissier d4a6e8c47a Add doc for m-concurrent 2018-10-31 17:37:17 +01:00
Patrick Pelissier 9c19ed4471 Add more encapsulation tests. 2018-10-31 11:33:58 +01:00
Patrick Pelissier 357c37c69d Add missing const qualifier 2018-10-31 11:33:41 +01:00
Patrick Pelissier 7c2d9c8643 Add missing const 2018-10-31 11:31:48 +01:00
Patrick Pelissier 69d699b80e Add contract 2018-10-31 11:26:00 +01:00
Patrick Pelissier 40832dd727 Add assertions 2018-10-31 08:24:06 +01:00
Patrick Pelissier 31c3baa42b Update comment 2018-10-30 20:10:15 +01:00
Patrick Pelissier 0ed03224c2 Update test 2018-10-30 20:04:01 +01:00
Patrick Pelissier f8d82ae74a Fix oplist definition. 2018-10-30 20:00:50 +01:00
Patrick Pelissier 16234bde82 Add const 2018-10-30 17:23:59 +01:00
Patrick Pelissier 31a5d7ee3b Add oplist 2018-10-30 10:56:02 +01:00
Patrick Pelissier f908c7e04d Update 2018-10-30 10:27:29 +01:00
Patrick Pelissier eb20f66bd9 Update 2018-10-30 10:25:22 +01:00
Patrick Pelissier 3b3e853cf8 Add first test cases 2018-10-29 23:07:34 +01:00
Patrick Pelissier 998ae05a5b Update dict_set to be like a B+TREE (API breakage). _ref returns pointer to the data 2018-10-29 22:59:31 +01:00
Patrick Pelissier 155d01b8c3 Fix blocking=false for _pop & _get 2018-10-29 18:10:07 +01:00
Patrick Pelissier 1a4cce7efd Add concurrent benchmark 2018-10-29 17:17:14 +01:00
Patrick Pelissier 3a0dd2ffe7 Fix errors 2018-10-29 17:15:20 +01:00
Patrick Pelissier 68b705b16a Proper export of additional methods for DICT_SET 2018-10-29 17:02:58 +01:00
Patrick Pelissier fe245e76cf Fix DICT_SET_DEF macro 2018-10-29 16:51:33 +01:00
Patrick Pelissier 618e37b07c Remove pop operator as there is no method for it. 2018-10-29 16:51:17 +01:00
Patrick Pelissier 3dde8d45c1 Add _empty_p & _pop_move_blocking 2018-10-29 13:26:16 +01:00
Patrick Pelissier 4691f95b73 Add blocking methods for concurrent container. 2018-10-29 11:18:20 +01:00
Patrick Pelissier 02d4bf0e09 Export method _empty_p for operator TEST_EMPTY for all containers. 2018-10-29 11:06:54 +01:00
Patrick Pelissier 5ecf4f37c0 Change deprecated functions. 2018-10-29 11:06:29 +01:00
Patrick Pelissier 15f6484dd2 Fix comment 2018-10-29 11:02:55 +01:00
Patrick Pelissier 2ead3905e5 Rename m-protect to m-concurrent 2018-10-28 22:17:33 +01:00
Patrick Pelissier 99d883253c Add TEST_EMPTY operator 2018-10-28 22:13:48 +01:00
Patrick Pelissier ed4d4f9f23 Fix formatting 2018-10-28 17:53:41 +01:00
Patrick Pelissier d76f9565b2 Add new primitives. 2018-10-28 17:53:16 +01:00
Patrick Pelissier 1c637f1182 Proper export of KEY_OPLIST & VALUE_OPLIST 2018-10-28 11:17:05 +01:00
Patrick Pelissier 4dbe5de79c Fix in progress 2018-10-28 11:16:46 +01:00
Patrick Pelissier afcb88d04c Add PROTECT module that automaticaly add a lock on container access. 2018-10-28 10:41:10 +01:00
Patrick Pelissier 1ea1deef94 Update doc with last changes. 2018-10-28 10:40:18 +01:00
Patrick Pelissier 08d2af22db Add KEY_OPLIST & VALUE_OPLIST operators 2018-10-28 10:38:41 +01:00
Patrick Pelissier 70179bb1d7 Add VALUE_TYPE operator 2018-10-28 10:33:25 +01:00
Patrick Pelissier 83226c5ce8 Add KEY_TYPE operator 2018-10-28 10:03:47 +01:00
Patrick Pelissier 3d6b737c46 Export *KEY operators in OPLIST for array, dict, B+tree 2018-10-27 23:37:06 +02:00
Patrick Pelissier fff511101c Add _erase for array 2018-10-27 23:30:38 +02:00
Patrick Pelissier 6672becdd5 Add _erase for array 2018-10-27 23:30:21 +02:00
Patrick Pelissier bd315c7e43 Add method ERASE_KEY 2018-10-27 23:04:56 +02:00
Patrick Pelissier fbfe28c087 Port the test suite to use _erase instead of _remove. 2018-10-27 22:59:33 +02:00
Patrick Pelissier adbafc0b02 Fix usage of pop_at after later change. 2018-10-27 22:59:19 +02:00
Patrick Pelissier 4e6dad939a API Compatibility change: rename _remove for DICT & B+TREE into _erase for API uniformization. 2018-10-27 22:56:00 +02:00
Patrick Pelissier 12bf9c0f59 ERASE method returns bool (like dictionnary) 2018-10-27 22:43:06 +02:00
Patrick Pelissier f7f7d7bc38 Add asertion 2018-10-27 22:34:53 +02:00
Patrick Pelissier c169c05bba Clarify name of old methods SET_KEY, GET_KEY, GET_SET_KEY 2018-10-27 22:34:34 +02:00
Patrick Pelissier 19d48740cd Modify prototype of buffer _init_set & _set to allow const argument for src. Not proud of the solution. 2018-10-27 16:13:02 +02:00
Patrick Pelissier 7a067a4b90 Add M_PTR_OPLIST 2018-10-27 11:13:09 +02:00
Patrick Pelissier 13f3dab23a Update with more examples. 2018-10-27 11:12:55 +02:00
Patrick Pelissier fd9d308b28 Allow tuple initilization in M_LET 2018-10-27 09:28:17 +02:00
Patrick Pelissier 1047d842d0 Add OPLIST for buffer & an example. Still a WIP for the constness of the BUFFER source. 2018-10-26 23:30:04 +02:00
Patrick Pelissier 77385e53f7 Add _init1 for buffer (internal use) 2018-10-26 22:23:44 +02:00
Patrick Pelissier f7b3de2750 Add test cases for _init_set & _set for buffers 2018-10-26 22:05:14 +02:00
Patrick Pelissier a65e6de66b Add more cases. 2018-10-26 21:44:25 +02:00
Patrick Pelissier 41cf523dfc Adding _set & _init_set for buffer (to test) 2018-10-26 21:21:29 +02:00
Patrick Pelissier 3774f8fd11 Fix M_POD_OPLIST in C11 mode 2018-10-26 20:18:32 +02:00
Patrick Pelissier b9e26b1c2c Add test with musl-gcc to test C11 library thread.h 2018-10-26 20:09:32 +02:00
Patrick Pelissier 609175713b Fix C11 backend. 2018-10-26 19:40:51 +02:00
Patrick Pelissier d56b794177 Fix bug in _get method of deque container. 2018-10-21 22:41:29 +02:00
Patrick Pelissier 608a929fcb Added another test case for _get method for DEQUE container. 2018-10-21 22:40:56 +02:00
Patrick Pelissier 4bf045e3d6 Make INIT conditional for DEQUE containers. 2018-10-21 22:31:22 +02:00
Patrick Pelissier 6b5434d64f Fix regression:
even if there is no INIT method for the base type,
the container still defines a INIT method.
2018-10-21 22:27:52 +02:00
Patrick Pelissier abb5480890 Port DEQUE to CALL infrastructure. 2018-10-20 19:02:48 +02:00
Patrick Pelissier 95069b0d4c Update doc 2018-10-20 16:59:56 +02:00
Patrick Pelissier 8f15b50b5f Update documentation of arrays. 2018-10-20 16:57:55 +02:00
Patrick Pelissier c7a1505f9b Update doc 2018-10-10 21:54:34 +02:00
Patrick Pelissier ff098c91f4 Add _capacity for deque 2018-10-07 09:05:09 +02:00
Patrick Pelissier fb40a4f904 Update state 2018-10-03 22:03:08 +02:00
Patrick Pelissier c87696f5c1 Add _hash, _equal_p, _out_str, _in_str, _get_str, _parse_str
for intrusive list.
2018-10-03 22:01:40 +02:00
Patrick Pelissier 4f3dad4bea Add _reverse for I-LIST 2018-10-01 21:22:19 +02:00
Patrick Pelissier 46c2e33096 Remove WIP 2018-09-29 10:23:31 +02:00
Patrick Pelissier 66ee266b90 Move depend.png in doc folder. 2018-09-29 10:22:03 +02:00
Patrick Pelissier 14883b1e26 Update image 2018-09-29 10:10:30 +02:00
Patrick Pelissier 33f74988b1 Update doc 2018-09-29 10:09:18 +02:00
Patrick Pelissier 78b157ff7f Update documentation. 2018-09-29 10:05:40 +02:00
Patrick Pelissier 546b756932 Port TUPLE & VARIANT to API transformation infrastructure. 2018-09-25 21:38:31 +02:00
Patrick Pelissier 5b74d54c64 Remove unused macro. 2018-09-25 20:10:44 +02:00
Patrick Pelissier fc608b21ee Update comment 2018-09-25 20:02:58 +02:00
Patrick Pelissier 2b6a266b93 Optimize _pop_back for dual push list. 2018-09-22 11:58:22 +02:00
Patrick Pelissier 7cb5092010 Update document on dual_push list 2018-09-22 11:58:05 +02:00
Patrick Pelissier a1c3681002 Optimization of _init_set for list. 2018-09-22 11:37:23 +02:00
Patrick Pelissier 91f35aa3bb Update documentation of LIST. 2018-09-22 11:36:38 +02:00
Patrick Pelissier 49a6715dfe Merge branch 'master' of https://github.com/P-p-H-d/mlib 2018-09-19 22:22:57 +02:00
Patrick Pelissier b799725bef Update comment. 2018-09-19 22:22:48 +02:00
Patrick Pelissier 1ada22462f Update comment. 2018-09-19 22:20:11 +02:00
Patrick Pelissier b0ec9680a1 Merge branch 'master' of https://github.com/P-p-H-d/mlib 2018-09-19 07:58:38 +02:00
Patrick Pelissier 7a8a6b1bb1 Rewrite in order to be easier to read. 2018-09-19 07:57:59 +02:00
Patrick Pelissier 1380a91bf1 Update comments. 2018-09-17 22:20:39 +02:00
Patrick Pelissier 83208f74ec Add one more test. 2018-09-17 22:20:26 +02:00
Patrick Pelissier 5f571418d0 Clarify documentation 2018-09-16 00:01:41 +02:00
Patrick Pelissier a7d8ff208f Fix. 2018-09-15 19:42:54 +02:00
Patrick Pelissier 1046f3e220 Add more structure in example. 2018-09-15 19:38:18 +02:00
Patrick Pelissier 6406f97f56 Clarify documentation about oplist usage. 2018-09-15 18:28:43 +02:00
Patrick Pelissier e0c456490a Fix definition of oplist for containers:
if no argument is given, it shall behave as if it was defined with
a standard C type.
2018-09-15 17:59:50 +02:00
Patrick Pelissier 6a1b2a3964 Add new example. 2018-09-15 15:46:22 +02:00
Patrick Pelissier 3452b72add Fix regression of M*LIB:
oplist of tuple/variant wasn't able to detect the default INIT creation
as no valid OPLIST was passed in the absence of OPLIST.
Give the explicit default OPLIST in this case.
2018-09-15 15:30:03 +02:00
Patrick Pelissier 2e3b312fab Fix issue of recursive usage of M_GLOBAL_OPLIST_OR_DEF
Update the way to use the macro to avoid being limited by the
preprocessor limitation.
2018-09-14 20:57:55 +02:00
Patrick Pelissier 8f67ca339b Rename internal macros. 2018-09-13 22:59:38 +02:00
Patrick Pelissier 1679b7b5cf Mark ALGO_INIT_VA & ALGO_LET_INIT_VA as obsolete:
the M_LET macro supports their feature in a more generic way.
2018-09-10 22:57:52 +02:00
Patrick Pelissier 757049543d Port to M_CALL infrastructure the M-ALGO 2018-09-10 22:50:26 +02:00
Patrick Pelissier 38b098b547 Port to M_CALL for M-STRING 2018-09-10 21:59:29 +02:00
Patrick Pelissier 60478e3f61 Port to M_CALL for M-SNAPSHOT 2018-09-10 21:55:18 +02:00
Patrick Pelissier 6325f01122 Port to M_CALL M-SHARED 2018-09-10 21:39:38 +02:00
Patrick Pelissier 74c12e6ea2 Port to M_CALL for R/B TREE. 2018-09-10 21:34:18 +02:00
Patrick Pelissier fd3453bb2a Port to M_CALL infrastructure M-I-SHARED 2018-09-10 07:55:47 +02:00
Patrick Pelissier 2ff7631c9c Port to M_CALL infrastructure. 2018-09-10 07:53:07 +02:00
Patrick Pelissier 7a6b0ab641 Port dict to new M_CALL infrastructure to support API transformation. 2018-09-09 14:04:49 +02:00
Patrick Pelissier 8fd0003548 Update 2018-09-08 22:51:46 +02:00
Patrick Pelissier bb8de993b6 Start porting to M_CALL infrastructure, enabling support for
API transformation.
2018-09-08 22:49:12 +02:00
Patrick Pelissier 7c83d733cd Fix grammar 2018-09-08 20:34:12 +02:00
Patrick Pelissier 6f49a1905c Minor fix 2018-09-08 20:32:49 +02:00
Patrick Pelissier d0378aadeb Update doc 2018-09-08 20:25:38 +02:00
Patrick Pelissier 4834318742 Update doc about missing parse_str methods. 2018-09-08 09:56:25 +02:00
Patrick Pelissier 1838a490ba Update doc 2018-09-08 09:47:47 +02:00
Patrick Pelissier de3cbe45b4 Make INIT method optional. 2018-09-08 09:47:36 +02:00
Patrick Pelissier a34cb6c89d Simplification 2018-09-08 09:34:01 +02:00
Patrick Pelissier 9c0724ddb9 Simplification. 2018-09-08 09:10:37 +02:00
Patrick Pelissier ce948bd9ce Make INIT optional for TUPLE. 2018-09-08 09:02:54 +02:00
Patrick Pelissier 5eb5d2420e Make INIT method optional for oplists. 2018-09-08 08:57:02 +02:00
Patrick Pelissier 7510e36f6b Update doc 2018-09-08 08:56:53 +02:00
Patrick Pelissier 8bfdf2bd5f Add M_IF_METHOD2_BOTH 2018-09-08 08:48:09 +02:00
Patrick Pelissier 2174c28aa2 Make INIT operator optionnal for ARRAY & LIST. 2018-09-08 08:21:13 +02:00
Patrick Pelissier 7a55667a5d Remove lib (link broken) 2018-09-04 22:15:44 +02:00
Patrick Pelissier 79d0452427 Instead of fixed string, enable using printf like formatting for initialization of a string. 2018-09-02 11:05:27 +02:00
Patrick Pelissier ad5c141a7c Enable support to initialize a string_t with a const char[] within M_LET. 2018-09-02 11:00:14 +02:00
Patrick Pelissier d4cd327ea3 Add API transform call for all operators. 2018-09-02 10:40:09 +02:00
Patrick Pelissier 27b29d5ffe Clean up & fix DICT_SET_OPLIST 2018-09-01 21:40:17 +02:00
Patrick Pelissier b52222cad9 Add operator INIT_WITH for oplist with PUSH. 2018-09-01 21:22:18 +02:00
Patrick Pelissier 822c27399c Add M_INIT_VAI to initialize a container with a VA.
(pretty much like it was done for ALGO).
Use if for array & list so that you can init them in M_LET
by giving it a VA.
2018-09-01 21:12:02 +02:00
Patrick Pelissier 0e717389c1 Add API transform support for the method in an oplist. 2018-09-01 20:42:51 +02:00
Patrick Pelissier 2197c4ce81 Add more cases to test. 2018-09-01 09:50:28 +02:00
Patrick Pelissier b894d64063 Add support for INIT_WITH in M_LET in C99 mode. 2018-09-01 09:47:32 +02:00
Patrick Pelissier d95a11365a * New method INIT_WITH
* Prepare variable number of arguments for M_LET with INIT_WITH
2018-09-01 09:39:09 +02:00
Patrick Pelissier dbcade3087 Add support for given an argument for the initialization of a variable in M_LET
if the variable is within parenthesis:
 M_LET((a,b), string_t)
 ==> It will init a & set it to b.

For the moment, we can only init with value of the same type (through init_set)
2018-08-31 00:02:03 +02:00
Patrick Pelissier 7ac54c0eb8 Update doc 2018-08-29 22:17:52 +02:00
Patrick Pelissier 91c74b863d Update comments 2018-08-26 09:26:44 +02:00
Patrick Pelissier 8c0b6f1e9d Fix spellings. 2018-08-25 21:35:37 +02:00
Patrick Pelissier 539f388e66 Update doc (fix spelling). 2018-08-25 09:00:19 +02:00
Patrick Pelissier b03c312b4e Update doc 2018-08-25 08:32:51 +02:00
Patrick Pelissier 71db5f9a79 Support for break to break the execution of M_LET 2018-08-25 00:11:20 +02:00
Patrick Pelissier e33e77595f Simplify the logic for parsing bool. 2018-08-24 21:03:25 +02:00
Patrick Pelissier d4016b310d Add support for conditionnal support for stdio.h
(needed for special environnement where no stdio is supported).
2018-08-24 20:59:54 +02:00
Patrick Pelissier a41177a110 Add support for bool in default type support.
Needs to rewritefully how to dispatch the default type for IN_STR method
Add also proper non-support for const char* & char * for IN_STR & PARSE_STR
(We cannot do it reliabelty, so the function says it always fail).
2018-08-24 20:45:26 +02:00
Patrick Pelissier f8600296f0 Add missing const for dict's equal_p 2018-08-24 19:18:29 +02:00
Patrick Pelissier e1147fb33d Add support for IN_STR for default C types. 2018-08-23 19:58:02 +02:00
Patrick Pelissier ec0d020669 Fix documentation about right prototype of in_str. 2018-08-23 19:38:19 +02:00
Patrick Pelissier e8eab86546 Fix issue in warning about discarding const attribute. 2018-08-22 00:21:23 +02:00
Patrick Pelissier c9ebedb01f Rename _get_ methods for tuple & variants into _get_at_ methods.
Add _cget_at_ methods too.
2018-08-21 23:58:03 +02:00
Patrick Pelissier af5742ce2d Change the value used to generate the enumerate of a variant:
the previous values didn't prevent to have a name collision
with other methods defined for the variant.
2018-08-21 22:53:07 +02:00
Patrick Pelissier 8f85c71654 Rename some internal macros to a better name. 2018-08-21 22:15:11 +02:00
Patrick Pelissier 70753c1082 Add method parse_str for the oplist of default C type. 2018-08-21 20:04:11 +02:00
Patrick Pelissier 2ab2b9efd6 Add primitive to parse standard C types (except const char*) 2018-08-21 19:53:55 +02:00
Patrick Pelissier dbb34b75fd Add method for the operator OUT_STR for the default type. 2018-08-21 19:26:18 +02:00
Patrick Pelissier 7447492c76 Fix issue with deque in case of successive _clean:
the CLEAR method was called more than once for an object.
2018-08-20 23:13:55 +02:00
Patrick Pelissier 492e4c33db Adding more assertions to check the good call of the test object. 2018-08-20 23:11:13 +02:00
Patrick Pelissier cbb08bdcfc Amend previous commit. 2018-08-19 20:28:46 +02:00
Patrick Pelissier 0de829741a Add synonimous for pointers. 2018-08-19 20:27:45 +02:00
Patrick Pelissier 0fa7aed1c4 Add missing synonim 2018-08-19 20:07:58 +02:00
Patrick Pelissier 3b0e940284 Add missing _ptr & _srcptr alias. 2018-08-19 17:58:23 +02:00
Patrick Pelissier 48a970ceb9 Avoid using '__' within words.
It seems to be a reserved naming of C++.
2018-08-19 11:31:09 +02:00
Patrick Pelissier c7b533f21e Cleanup terminology 2018-08-19 10:54:48 +02:00
Patrick Pelissier 839d4da191 Update doc 2018-08-19 10:36:30 +02:00
Patrick Pelissier b76ddfe93c Update doc 2018-08-19 10:07:04 +02:00
Patrick Pelissier 4ba0156ad8 Backport solution from tuple to variant. 2018-08-19 08:45:10 +02:00
Patrick Pelissier 6ef9936e24 Fix issue of recusrive definition of TUPLE using GLOBAL oplist:
There was a recursive call of M_REDUCE2 that fails to expand properly on its second invocation
Rewrite fully how global oplists are implemented:
it performs a first pass to expand the oplists, and the a separate pass to define the functions.
This enables to separate the pass, and use M_REDUCE2 in both.
2018-08-19 08:28:17 +02:00
Patrick Pelissier e835dbc7c6 Update Makefile for also testing clang++ 2018-08-19 08:27:51 +02:00
Patrick Pelissier 5c8429a7bb Reformating 2018-08-16 07:29:22 +02:00
Patrick Pelissier 824011657a Improve once again mapping of the buffer structure to avoid
false sharing.
2018-08-15 10:33:20 +02:00
Patrick Pelissier 8e2031bf5a Add comments. 2018-08-15 10:30:17 +02:00
Patrick Pelissier 8bb5f5475e Avoid putting the push mutex & the pop mutex inside the same cache line.
Avoid false sharing for multi-threading scenario and should increase performance.
2018-08-15 10:21:23 +02:00
Patrick Pelissier eb4f249a54 Add missing CLEAN method in export OPLIST. 2018-08-14 23:09:12 +02:00
Patrick Pelissier 3aa3b87709 Add missing CLEAN method in export OPLIST. 2018-08-14 23:08:33 +02:00
Patrick Pelissier 0046157862 Fix issue for SWAP method not exported correctly for tuple. 2018-08-14 08:00:16 +02:00
Patrick Pelissier acbf1efad6 Fix issue: CLEAN method was not properly exported by tuple. 2018-08-14 07:58:37 +02:00
Patrick Pelissier 5d1eb45d5c Export CLEAN method. 2018-08-14 07:49:31 +02:00
Patrick Pelissier c52c41c885 Export CLEAN method for tuple if it is defined. 2018-08-13 20:14:37 +02:00
Patrick Pelissier 822f9aacf6 Add CLEAN method for tuple. 2018-08-13 20:05:32 +02:00
Patrick Pelissier 7d5608ca0e Export CLEAN method for string. 2018-08-13 20:03:06 +02:00
Patrick Pelissier 937bbef818 Add method _erase & _update_further for priority queue. 2018-08-12 21:35:09 +02:00
Patrick Pelissier c506443ed0 Add comment about ALGO_EXTRACT 2018-08-08 22:54:56 +02:00
Patrick Pelissier 5f42f26587 Fix warning about shadowed variables 2018-08-08 22:49:49 +02:00
Patrick Pelissier f84e96d790 Reexport IT_INSERT for array.
Even it is slow, it may be useful.
2018-08-08 22:49:25 +02:00
Patrick Pelissier ede57a20be Add ALGO ALGO_INSERT that allows inserting a container into another one. 2018-08-08 22:44:17 +02:00
Patrick Pelissier df8306c721 Export IT_INSERT method 2018-08-08 22:43:44 +02:00
Patrick Pelissier 1bb144e256 VARIANT: Oplist is now optional for their definition. 2018-08-07 23:18:37 +02:00
Patrick Pelissier 7d83603646 TUPLE: Oplist is now optional for tuple definition. 2018-08-06 23:20:02 +02:00
Patrick Pelissier 7e4d51bab0 Add support for global oplist for deque 2018-08-05 22:33:13 +02:00
Patrick Pelissier 4ef1b079cb Can omit optlist in B+TREE definition 2018-08-05 11:08:18 +02:00
Patrick Pelissier e95d13adb1 Add support for multiple M_LET on the same line
without warning about shadow variables.
2018-08-04 08:34:35 +02:00
Patrick Pelissier 92d7009804 Fis issue if given type is a T * = TYPE:
token pasting created const T *, which is not the same as
const TYPE = T * const
2018-08-03 20:35:37 +02:00
Patrick Pelissier 354327e40b Fix issue for string_strim if string was empty and not allocated. 2018-08-03 20:23:24 +02:00
Patrick Pelissier 34d56c54c8 Test strim with an empty string.
(Shall do nothing).
2018-08-03 20:22:32 +02:00
Patrick Pelissier 143a5fdf4f Fix issue if given type is a T * = TYPE:
token pasting created const T *, which is not the same as
const TYPE = T * const
2018-08-03 20:20:57 +02:00
Patrick Pelissier 030510613c Add more assertions. 2018-08-03 19:57:38 +02:00
Patrick Pelissier 984b8e7da0 Fix const cast issue for 'void *' pointer. 2018-08-03 18:55:01 +02:00
Patrick Pelissier aba1ac1646 Fix issue in 64 bits with overwriting enabled for buffer. 2018-08-02 23:31:48 +02:00
Patrick Pelissier 6b93d7644a Proper constant definition for unicode error. 2018-08-02 23:31:17 +02:00
Patrick Pelissier 68c737dcef Clean up interface if (internal) genint:
it returns at most an 2048, so an unsigned int is more enought
(and internally it was already used!).
So transform the interface to take as input unsigned int.

Fix maximum size supported by the genint package.

Add proper constant used for error, and use it in the code.
2018-08-02 23:19:05 +02:00
Patrick Pelissier b8f8ffe0a2 Perform same optimization than previous commit for
M_GLOBAL_OPLIST_OR_DEF
2018-08-02 22:48:28 +02:00
Patrick Pelissier 02e8681f76 M_GLOBAL_OPLIST:
More robust implementation that delays the evaluation of the concatenation
2018-08-02 20:02:15 +02:00
Patrick Pelissier 603fb9db62 Replace some size displayed with '%lu' as unsigned long
with proper '%zu' as size_t.
2018-08-02 19:34:10 +02:00
Patrick Pelissier b01459d1ef Add out_str for CSTR_OPLIST 2018-08-01 23:36:04 +02:00
Patrick Pelissier 667f1f5951 Update documentation. 2018-08-01 23:28:01 +02:00
Patrick Pelissier 660c5a2db4 Add M_GET_STRING to transform a standard numerical C type into a string_t
(with a method compatible with the operator GET_STR).
2018-08-01 23:26:58 +02:00
Patrick Pelissier 8a4d013354 Fix issues (normal contract where used for I/O whereas they could be used
with OA Dict)
2018-08-01 22:55:54 +02:00
Patrick Pelissier faedca81d1 Add M_CORE_VERSION_* macros. 2018-08-01 22:28:50 +02:00
Patrick Pelissier 166d408f5e Add support for out_str for the default C types if C11 is enabled. 2018-08-01 20:12:24 +02:00
Patrick Pelissier 017f25d9d5 M_PRINT_ARG & M_FPRINT_ARG don't put a final semicolon at the end
of their expansion anymore (cleaner and no longer needed with the
new available tools).
2018-08-01 19:59:57 +02:00
Patrick Pelissier 6a70eba83f Document some missing methods for priority queues. 2018-08-01 19:35:54 +02:00
Patrick Pelissier ef13ab6938 Add rapidstring 2018-08-01 00:31:58 +02:00
Patrick Pelissier 75cb61fd36 Fix issue of deque's _init_move. 2018-07-31 23:11:43 +02:00
Patrick Pelissier 9c31f8aa92 Complete test to show failure of _init_move for deque. 2018-07-31 23:11:26 +02:00
Patrick Pelissier 27a08da430 Add node contract check. 2018-07-31 08:19:45 +02:00
Patrick Pelissier fdada9661f Update comment. 2018-07-30 22:45:24 +02:00
Patrick Pelissier f1a52439bb Add more tests. 2018-07-30 22:42:33 +02:00
Patrick Pelissier d13849c173 Update formatting. 2018-07-30 22:42:09 +02:00
Patrick Pelissier d8a0e73899 Update comment. 2018-07-30 22:24:03 +02:00
Patrick Pelissier b6a3387f8a User are able to customize the number of elements of a mempool globaly. 2018-07-30 22:02:46 +02:00
Patrick Pelissier 04dd708941 Delayed the inclusion of the common headers, so that the backend may properly
set up additional parameters for the headers.
2018-07-29 19:40:37 +02:00
Patrick Pelissier 39ffe1c95a Fix issue for 32 bits build due to previous modification of limb size to 64 bits. 2018-07-29 19:40:08 +02:00
Patrick Pelissier 7b5ae3c15b Update API so that the worker_t parameter is given on creating the sync bloc.
(API breakage), more RAII like.
2018-07-28 19:09:07 +02:00
Patrick Pelissier 7678625071 Review:
* add comments
* change error code from assertion to proper memory failure
* add new assertions
2018-07-28 13:48:30 +02:00
Patrick Pelissier dbe8817d95 Add bitset_clz 2018-07-27 06:19:54 +02:00
Patrick Pelissier 09e117cd57 Update comments.
Update _new_node: it shall never return NULL.
2018-07-24 00:34:35 +02:00
Patrick Pelissier 4b8779d8d3 Update formula for increasing the size. 2018-07-24 00:24:50 +02:00
Patrick Pelissier 79158dabbc Rename _map into _for_each. 2018-07-22 21:32:46 +02:00
Patrick Pelissier f962bc8da5 Avoid overflow in case of huge computations.
Add more comments.
2018-07-22 21:32:19 +02:00
Patrick Pelissier 28e8dde06d Make target uninstall PHONY 2018-07-21 12:12:50 +02:00
Patrick Pelissier 6c3d41a124 Add target uninstall 2018-07-21 12:12:19 +02:00
Patrick Pelissier 9c2967f8df Cleanup install target with proper use of COMMAND VARIABLES. 2018-07-19 22:55:56 +02:00
Patrick Pelissier 99311364e7 Regenerate the dependency graph. 2018-07-18 22:35:25 +02:00
Patrick Pelissier 16e86b8291 Don't regenerate depend.png everytime but only if the headers have been updated.
Optimize the generation of the PNG.
2018-07-18 22:34:52 +02:00
Patrick Pelissier 5741af8fd3 Add 'dist' target in the Makefile. 2018-07-18 22:31:53 +02:00
Patrick Pelissier 6bdd47a557 Don't remove depend with a make clean
otherwise you'll get a regeneration of the dependency file for each clean command
which is useless.
make distclean shall be used to remove the dependency file.
2018-07-18 22:28:19 +02:00
Patrick Pelissier 750ba93c14 Add note. 2018-07-18 21:43:27 +02:00
Patrick Pelissier 18be930507 Fix bug in case of error returned by vsnprintf:
the buffer may have been corrupted in case of error.
Clean it before returning.
2018-07-18 21:41:52 +02:00
Patrick Pelissier be26176828 Add one more test case. 2018-07-18 21:41:14 +02:00
Patrick Pelissier 540e01f1fe Fix prototype of the callback to InitOnceExecuteOnce: Missing CALLBACK.
(Some version of the compilers for windows produced warnings)
2018-07-18 21:21:35 +02:00
Patrick Pelissier 7cfb6b16e4 Update cross compilation information. 2018-07-18 01:01:13 +02:00
Patrick Pelissier d5a8b9648f Simplify 2018-07-18 01:01:04 +02:00
Patrick Pelissier 1657d7af7d Support of LOG_COMPILER for cross-compilation test. 2018-07-18 00:28:35 +02:00
Patrick Pelissier 318f1a2818 Update/Add comments. 2018-07-17 23:03:45 +02:00
Patrick Pelissier 8b0b115709 Update comment. 2018-07-17 23:03:33 +02:00
Patrick Pelissier 7d2494b7f9 Fix bug of SPMC / MPMC snapshots: not all items in buffers
were properly cleared.
2018-07-17 21:10:14 +02:00
Patrick Pelissier 3b642ffeb3 Update after internal review. 2018-07-17 21:00:55 +02:00
Patrick Pelissier 815bf5f0e0 Include proper header and do not depend on other headers to include it. 2018-07-16 21:45:28 +02:00
Patrick Pelissier 4af48724ce Update after internal review. 2018-07-16 21:43:17 +02:00
Patrick Pelissier 001272820c Update example to latests API. 2018-07-15 23:11:00 +02:00
Patrick Pelissier 4aca0664ef Add methods _find_again, _find_again_if, _mismatch_again and _mismatch_again_if 2018-07-15 23:06:22 +02:00
Patrick Pelissier 6721a86768 Add method _mismatch and _mismatch_if 2018-07-15 22:34:29 +02:00
Patrick Pelissier 5025b3690d Add test. 2018-07-15 22:26:59 +02:00
Patrick Pelissier 42b37a718f Add test. 2018-07-15 22:26:21 +02:00
Patrick Pelissier fcdfd836ec Add method _count_if 2018-07-15 11:05:58 +02:00
Patrick Pelissier b2f005239b API breakage:
rename _constains into _contain_p
to be more uniform with other predicate functions,
and to use infinitive form for the method.
2018-07-15 10:54:38 +02:00
Patrick Pelissier bc3fa890bd Add method _find_if. 2018-07-15 10:48:22 +02:00
Patrick Pelissier 95dbbf6e75 Simplification of the example. 2018-07-15 02:53:35 +02:00
Patrick Pelissier 22f2ae7341 Add methods _all_of_p, _any_of_p and _none_of_p. 2018-07-14 18:21:46 +02:00
Patrick Pelissier 96202aa78f Do not use reserved identifiers of the C standard (See 7.1.3 Reserved identifiers) 2018-07-14 14:35:14 +02:00
Patrick Pelissier cef8a13cc2 Add a new test. 2018-07-14 14:18:25 +02:00
Patrick Pelissier 54271231a0 Update doc. 2018-07-14 14:13:18 +02:00
Patrick Pelissier d1bb651596 Update doc. 2018-07-14 14:03:17 +02:00
Patrick Pelissier 10b7f65437 Update DEV. 2018-07-13 10:54:41 +02:00
Patrick Pelissier 3a70324d43 Fix spelling. 2018-07-13 10:42:26 +02:00
Patrick Pelissier 21b72cd174 Update 2018-07-13 10:40:45 +02:00
Patrick Pelissier ce8656f1b2 Update 2018-07-13 10:40:40 +02:00
Patrick Pelissier 9277dc967b Update 2018-07-11 00:04:45 +02:00
Patrick Pelissier 67b1e65d97 Update comment 2018-07-08 00:33:18 +02:00
Patrick Pelissier 79fe9da2da Update 2018-07-05 12:21:02 +02:00
Patrick Pelissier 3164e2698d Improve comments. 2018-07-05 12:12:16 +02:00
Patrick Pelissier ffae33e6f7 Update 2018-07-05 12:12:09 +02:00
Patrick Pelissier 8dafe3b7a6 Add macro M_GET_AT. 2018-07-04 17:39:03 +02:00
Patrick Pelissier e23616169b Improve comments. 2018-07-04 17:38:48 +02:00
Patrick Pelissier 9d7fc942f7 Rename DICT_SET_DEF2 into DICT_SET_DEF 2018-07-03 15:50:14 +02:00
Patrick Pelissier 982d8cf19d DICT_*_DEF* doesn't require anymore oplists for defining the function:
it can get them from global oplists or default oplits.
2018-07-03 15:44:40 +02:00
Patrick Pelissier aae460623d Replace _set_at by _push 2018-07-03 15:07:36 +02:00
Patrick Pelissier df14e5bcb6 Update 2018-07-03 10:42:51 +02:00
Patrick Pelissier 15d5a83c16 Update doc 2018-07-03 10:42:11 +02:00
Patrick Pelissier 4b0f7543ee Rename _set_at to _push method for SET dictionnary.
Add proper _splice method for SET dictionnary.
2018-07-03 10:40:26 +02:00
Patrick Pelissier 362c64aa9c Fix URL to show preview. 2018-07-03 10:11:40 +02:00
Patrick Pelissier 56c497cf2c Add ref card. 2018-07-03 10:08:16 +02:00
Patrick Pelissier e0dc2da80a Add synthesis of the API. 2018-07-03 09:35:35 +02:00
Patrick Pelissier 41362f12ea Add comment about _hash for dict. 2018-07-01 22:54:19 +02:00
Patrick Pelissier 3765c0b0fb Add _equal_p method for OA dictionary. 2018-07-01 22:44:56 +02:00
Patrick Pelissier d1f2b62f66 Replace _set_at2 by _get_at for array.
(Break API)
2018-07-01 22:35:05 +02:00
Patrick Pelissier 26b8c1d0a2 Add method _move & _init_move. 2018-07-01 17:16:36 +02:00
Patrick Pelissier aa195f9f6f Add methods _cget. 2018-07-01 17:16:25 +02:00
Patrick Pelissier cd1d59264e Fix build issue with C++ 2018-06-29 22:50:41 +02:00
Patrick Pelissier 923e009fd3 Fix issue for new method _get_at for OA dict. 2018-06-29 22:32:10 +02:00
Patrick Pelissier 70a4fd99f4 iFix buiild issue with mutex based atomics. 2018-06-29 21:43:33 +02:00
Patrick Pelissier feb4011f57 Add new example. 2018-06-29 19:41:55 +02:00
Patrick Pelissier bf2a04ff66 Add method _get_at:
_get or create an entry.
2018-06-29 19:41:34 +02:00
Patrick Pelissier e16d352e71 Fix prototype (forgot const) 2018-06-29 19:41:20 +02:00
Patrick Pelissier 817724ce39 Fix issue for get_word:
the separators need to be skipped first.
2018-06-29 19:40:35 +02:00
Patrick Pelissier 0fda117ffe Add push/pop_front/back_move methods. 2018-06-27 20:10:42 +02:00
Patrick Pelissier e5be1e1f05 Add a name to the structure. 2018-06-27 20:10:28 +02:00
Patrick Pelissier 7d7af8cf59 Add a name to the structure. 2018-06-27 20:10:12 +02:00
Patrick Pelissier cbc09f83d4 Disable MOVE & INIT_MOVE for such containers (TBC). 2018-06-27 20:09:45 +02:00
Patrick Pelissier 31913ae80e Add bench for DualPushList. 2018-06-27 20:09:24 +02:00
Patrick Pelissier 522632bea6 Remove deprecated macro SNAPSHOT_DEF.
Shall use SNAPSHOT_SPSC_DEF
2018-06-27 20:04:18 +02:00
Patrick Pelissier 397f75a4db Add missing method _front for bitset. 2018-06-27 07:33:23 +02:00
Patrick Pelissier 0bf84a321b Add missing methods _capacity for MPMC queue & SPSC queue. 2018-06-27 07:28:34 +02:00
Patrick Pelissier 5915208dee API breakage:
Rename _pop method into _pop_at method
as the provided function is a _pop_at method, not a _pop method.
Remove _pop from the oplist as it doesn't follow _pop convention.
2018-06-27 07:17:33 +02:00
Patrick Pelissier 2167931e3f Remove _pop method from OPLIST as it doesn't follow _pop
convention.
2018-06-27 07:17:09 +02:00
Patrick Pelissier 2d18171914 Rename _pop method into _pop_at methods
as the provided function follow the prototype of a _pop_at method
rather than a _pop method.
2018-06-27 07:13:10 +02:00
Patrick Pelissier 28f6a7d399 Add missing _empty_p methods for dictionnaries. 2018-06-27 07:10:18 +02:00
Patrick Pelissier 8e042435e5 Update comment and use of a different hash function. 2018-06-23 13:26:46 +02:00
Patrick Pelissier cddf8712e4 Update comment. 2018-06-23 13:12:28 +02:00
Patrick Pelissier 88fd96e022 Add a more complete example of use. 2018-06-23 13:10:33 +02:00
Patrick Pelissier 17e715f408 Remove _last as it is a duplicate with _back! 2018-06-23 11:07:06 +02:00
Patrick Pelissier c821d9ea65 Add methods _front & _last for arrays. 2018-06-23 11:05:29 +02:00
Patrick Pelissier 5cb8a9ddd0 Document priority queue API. 2018-06-20 23:25:41 +02:00
Patrick Pelissier f0131b2c39 Fix prototype of _front:
missing const.
2018-06-20 23:25:25 +02:00
Patrick Pelissier bc3c68a3cb Move a section. 2018-06-14 22:34:42 +02:00
Patrick Pelissier b81d387778 Simplify the code by factoring similar branches. 2018-06-11 23:08:56 +02:00
Patrick Pelissier 0afbe72672 Fix spelling. 2018-06-11 21:09:20 +02:00
Patrick Pelissier 5fc63485f3 Update 2018-06-07 21:56:09 +02:00
Patrick Pelissier 1bc84c98f8 Update 2018-06-07 21:51:19 +02:00
Patrick Pelissier 737af45c85 Adding the long term ISSUES in configuration. 2018-06-07 21:47:23 +02:00
Patrick Pelissier e08fbc7d86 Move all core macros to support up to 52 arguments. 2018-06-06 23:33:23 +02:00
Patrick Pelissier 91090d20de Remove non defined operators from the oplist. 2018-06-06 00:00:08 +02:00
Patrick Pelissier 05a22e20b8 Add documentation on B+TREE. 2018-06-05 23:58:49 +02:00
Patrick Pelissier 7c43f343a3 Update 2018-06-05 00:39:07 +02:00
Patrick Pelissier 029e6aa251 Remove reference to libraries without working sites. 2018-06-04 23:11:18 +02:00
Patrick Pelissier 2f26d4ffd3 Add more tests / improve coverage. 2018-06-02 21:26:54 +02:00
Patrick Pelissier d306bae035 Generate cleaner coverage. 2018-06-02 21:26:32 +02:00
Patrick Pelissier 34dc8b32cb Fix broken _swap 2018-06-02 21:26:20 +02:00
Patrick Pelissier fe38244d7c Micro optimisation. 2018-06-02 19:31:07 +02:00
Patrick Pelissier 25e8c9f637 Update comments. 2018-06-02 19:23:46 +02:00
Patrick Pelissier 337b568b5e Update comments. 2018-06-02 19:21:59 +02:00
Patrick Pelissier e696192ef7 Update comments.
Cosmetic change.
2018-05-31 23:09:11 +02:00
Patrick Pelissier 928fc077b8 Remove a warning. 2018-05-30 23:17:37 +02:00
Patrick Pelissier 2a448b932c Update doc 2018-05-30 23:17:30 +02:00
Patrick Pelissier d40d23a50e Add test for _splice_at for Intrusive list. 2018-05-30 20:21:37 +02:00
Patrick Pelissier c4548c4355 Fix splice_at which was broken. 2018-05-30 20:21:27 +02:00
Patrick Pelissier 50fdea813b Update doc 2018-05-30 19:26:13 +02:00
Patrick Pelissier 0ff163e541 Fix issue for intrusive list and _splice_back. 2018-05-29 23:00:25 +02:00
Patrick Pelissier 38cd8847a2 Adding a generic merge sort if container has both _splice_back & _splice_at
methods
2018-05-28 23:51:41 +02:00
Patrick Pelissier e62ae9fb94 Fix the iterators calculation of _splice_at.
NOTE: iterator seems broken for _splice_back. To check
2018-05-28 23:51:10 +02:00
Patrick Pelissier 187b6cf072 Update to new specification. 2018-05-28 23:46:30 +02:00
Patrick Pelissier a3fad5966a Update test to reflect the new specifications. 2018-05-28 23:46:10 +02:00
Patrick Pelissier 74350f3638 Reuse a local variable instead of reading once again from memory. 2018-05-28 23:45:40 +02:00
Patrick Pelissier ee2c7caac2 Update _splice_at with new specification.
Fix issue of _splice_at (iterator not properly set).
Export _split_at methods in oplist.
2018-05-28 23:44:15 +02:00
Patrick Pelissier c915a6912e Update specification of _splice_at.
It is more interressing to have the iterator of the target list
to advance too. It allows copying items from list to list in the same order.
2018-05-28 23:43:05 +02:00
Patrick Pelissier d5cd232441 Add method SPLICE_AT as a generic method. 2018-05-28 23:42:46 +02:00
Patrick Pelissier c4c14b0fc6 Add _splice_at 2018-05-28 22:08:55 +02:00
Patrick Pelissier e5f5563249 Add method _splice_at for dual_push_list 2018-05-28 21:58:45 +02:00
Patrick Pelissier 2a6893efb4 Add method _splice_at for singly list. 2018-05-28 21:22:14 +02:00
Patrick Pelissier 9fd920945a Remove condition that the list shall be different for splice_back.
No need.
2018-05-28 20:59:27 +02:00
Patrick Pelissier a116daa7a1 Splice_back may work if old & new are the same list. 2018-05-28 20:58:51 +02:00
Patrick Pelissier 0b8759380b Fix name of called method to avoid infinite recursion... 2018-05-27 11:17:11 +02:00
Patrick Pelissier 00c5e3544f Export _splice_back methods.
Add _push_move & _pop_move methods for dual push list.
2018-05-27 11:16:16 +02:00
Patrick Pelissier 53a79e3170 Export splice_back method for list 2018-05-27 11:06:35 +02:00
Patrick Pelissier 5810bf9acd Add method SPLICE_BACK. 2018-05-27 11:05:00 +02:00
Patrick Pelissier 7815feddba Proper expand algorithms for intrusive list. 2018-05-24 22:58:16 +02:00
Patrick Pelissier f529a5eea8 Use of a trick to make the function compatible with other
definition of the _it method (use of const for the container).
2018-05-24 22:57:27 +02:00
Patrick Pelissier 40e9550b29 Generate algo for intrusive list. 2018-05-23 21:10:58 +02:00
Patrick Pelissier 64d0202f95 ALGO macros accept now a type instead of an oplist
if a global oplist has been registered for the type.

Add macro ALGO_LET_INIT_VA which declares, initializes, sets and clears
a container.
2018-05-22 20:39:51 +02:00
Patrick Pelissier da9483aa3a Add reference to C standard about CONST_CAST. 2018-05-22 19:38:38 +02:00
Patrick Pelissier 0221e555fe Fix bug in deque: _clean doesn't call CLEAR on all created objects. 2018-05-22 05:46:37 +02:00
Patrick Pelissier 494ee2c099 Add proper check of allocation for testing object. 2018-05-22 05:46:04 +02:00
Patrick Pelissier dc92ad9c02 Fix compatbility issue with C++ which doesn't support
compound literal...
2018-05-21 23:00:48 +02:00
Patrick Pelissier 8a4a019973 Fix build issue with C++ 2018-05-21 07:23:19 +02:00
Patrick Pelissier a1a49ebf4b Update comment 2018-05-20 22:38:00 +02:00
Patrick Pelissier 45263a6261 Fix parenthesis 2018-05-20 18:07:58 +02:00
Patrick Pelissier 7ccede36b1 Test with deque too. 2018-05-19 12:52:40 +02:00
Patrick Pelissier 482e1631fa Remove warning in case of some kind of type
(Famous problem of C not allowing to cast
a T (*)[N] into a const T (*)[N].
2018-05-19 12:51:31 +02:00
Patrick Pelissier d0fe7f3e25 Add method _push_move & _pop_move.
Add assertion on _pop_back to check that the container is not empty.
2018-05-19 11:21:57 +02:00
Patrick Pelissier 86083e3a92 Add methods push_move & pop_move.
Rewrite _pop_back to be a little bit faster for complex structure as it used
DO_MOVE instead of plain _set.
2018-05-19 11:21:18 +02:00
Patrick Pelissier 281f567d97 Add proper usage of const. 2018-05-19 11:10:09 +02:00
Patrick Pelissier 7f887720cc Add methods PUSH_MOVE & POP_MOVE. 2018-05-19 11:09:36 +02:00
Patrick Pelissier 717268add9 Simplify the macro usage. 2018-05-19 11:09:20 +02:00
Patrick Pelissier 2f7e3b1596 Update documentation. 2018-05-19 11:08:54 +02:00
Patrick Pelissier 1a3cd2f626 Add experimental support for cmp function with user define order. 2018-05-16 22:36:26 +02:00
Patrick Pelissier 2fbea43a5c Add M_MAP3 macro. 2018-05-16 20:00:41 +02:00
Patrick Pelissier 70788e932e Update doc 2018-05-16 19:47:06 +02:00
Patrick Pelissier 949d12052e Update 2018-05-16 07:52:37 +02:00
Patrick Pelissier 2af35673bb Update comments about TODO. 2018-05-15 21:02:34 +02:00
Patrick Pelissier 4a64ca58ac Update tested systems. 2018-05-15 20:41:15 +02:00
Patrick Pelissier 815c594fa6 Add new libraries 2018-05-15 20:41:06 +02:00
Patrick Pelissier fc4dba4569 Add DSC versions of the _sort function to reverve the sort (DSC=descending). 2018-05-14 23:08:46 +02:00
Patrick Pelissier 1d8df98339 Rename undocumented methods _union & _intersect to _sort_union & _sort_intersect
as they depend on the sort order.
2018-05-14 22:58:52 +02:00
Patrick Pelissier 745aabcfd5 Factorisation of all calls to GET_CMP within the sort functions
to a single function.
2018-05-14 22:55:17 +02:00
Patrick Pelissier be100790f1 Uniformize the comparaisons to always be in the same order. 2018-05-14 22:51:07 +02:00
Patrick Pelissier afc5e82906 Externalize _sort generation from the main macro. 2018-05-14 22:49:11 +02:00
Patrick Pelissier 2951d4b7fa Document new methods. 2018-05-14 22:30:08 +02:00
Patrick Pelissier dcd300211f Add methods _cmp_field for tuples. 2018-05-14 22:29:58 +02:00
Patrick Pelissier f796d27bb4 Update 2018-05-13 09:55:08 +02:00
Patrick Pelissier 47a2553356 Add new test on B*TREE as set. 2018-05-11 22:41:56 +02:00
Patrick Pelissier 67bf199254 Fix comparison of object.
memcmp compares object as little endian, which is not what we want.
2018-05-11 22:41:22 +02:00
Patrick Pelissier 4b1ed25ef3 Rewrite inner loop. should be a little bit faster. 2018-05-11 22:41:00 +02:00
Patrick Pelissier a5ac43e5f3 Fix issue with oplist of set. 2018-05-11 17:57:33 +02:00
Patrick Pelissier 0557527bfe Update format of serialisation for B+TREE:
as the tree is ordered, a '[]' has to be used.
2018-05-11 17:32:32 +02:00
Patrick Pelissier dc1445e0d6 Remove TODO comment. 2018-05-10 23:12:38 +02:00
Patrick Pelissier 431401bc96 Improve example. 2018-05-10 01:59:05 +02:00
Patrick Pelissier fded6c404a Add new libraries. 2018-05-10 01:34:20 +02:00
Patrick Pelissier 680a850618 Add test of _in_str, _out_str, _get_str and _parse_str 2018-05-09 21:48:42 +02:00
Patrick Pelissier 7d08a7ba1a Fix issue in _parse_str 2018-05-09 21:48:32 +02:00
Patrick Pelissier e9f603fa30 Rename internal calls to my_mpz* to testobj* 2018-05-08 10:40:29 +02:00
Patrick Pelissier 1a064e033b Rename mympz.h --> test-obj.h
as it is used only for testing purpose.
2018-05-08 10:29:51 +02:00
Patrick Pelissier ebcfcf9bfa Add I/O test for B+TREE 2018-05-07 23:08:47 +02:00
Patrick Pelissier cf063b75ff Update oplist to reflect all methods. 2018-05-07 23:08:12 +02:00
Patrick Pelissier 951a9d7989 Fix issue in parse. 2018-05-07 23:08:01 +02:00
Patrick Pelissier 37191a53c3 Fix unclear variable. 2018-05-04 00:14:52 +02:00
Patrick Pelissier 42d420db6a Add generation for string. 2018-05-03 22:12:32 +02:00
Patrick Pelissier 122cf63a3f Preshift the state by 8, to avoid a shift within the decoder.
Rewrite the size_u to avoid a branch.
2018-05-03 22:11:43 +02:00
Patrick Pelissier fafce60f9e Add method _parse_str
NOTE: _in_str, _out_str, _get_str & _parse_str remain to be tested.
2018-05-03 18:06:11 +02:00
Patrick Pelissier e855f27c8c Add method _parse_str for RBTREE.
NOTE: A refactorisation seems needed as all the in_str / parse_str
share a lot of the same algorithms. Maybe move them into algo?
2018-05-03 17:59:34 +02:00
Patrick Pelissier f01a593ff7 Update 2018-05-03 17:59:21 +02:00
Patrick Pelissier 6af34b1c16 Update doc to add _parse_str method 2018-05-03 17:51:36 +02:00
Patrick Pelissier 188b329eae Add method _parse_str for dict. 2018-05-03 17:43:40 +02:00
Patrick Pelissier 7b0f71cc99 Add method _parse_str for deque
(missing tests for in, out, get_str & parse_str).
2018-05-03 17:34:17 +02:00
Patrick Pelissier 73f8baf464 Add method _parse_str for array. 2018-05-03 17:29:10 +02:00
Patrick Pelissier 3a09efde91 Skip spaces in serialisation. 2018-05-03 17:22:50 +02:00
Patrick Pelissier 4efa8c1ef9 Add function _parse_str for list. 2018-05-03 17:14:10 +02:00
Patrick Pelissier 9f178208f2 Fix bug in new function. 2018-05-03 17:13:47 +02:00
Patrick Pelissier 0f2113ee12 Fix 2018-05-03 17:03:09 +02:00
Patrick Pelissier 139e003b0b Add method _parse_str for variant. 2018-05-03 17:01:03 +02:00
Patrick Pelissier 1bf80cf315 Add function _parse_str 2018-05-03 13:37:19 +02:00
Patrick Pelissier bcf182f515 Add _parse_str method 2018-05-03 13:30:39 +02:00
Patrick Pelissier c34fb94e77 Proper export of the method PARSE_STR 2018-05-03 13:19:36 +02:00
Patrick Pelissier 64080fadd3 Update comments. 2018-05-03 13:07:52 +02:00
Patrick Pelissier 1009cd6ed4 Export _parse_str function. 2018-05-03 13:05:45 +02:00
Patrick Pelissier 839c1af124 Export _parse_str function. 2018-05-03 13:04:04 +02:00
Patrick Pelissier 6b24842704 Add _parse_str interface.
Rewrite _set_str to use the _parse_str
2018-05-03 12:59:58 +02:00
Patrick Pelissier 2ad8ae3451 Rewrite parse_str interface to be more like strol 2018-05-03 12:59:10 +02:00
Patrick Pelissier b1597f6f61 Rewrite comments. 2018-05-02 23:57:24 +02:00
Patrick Pelissier 47a49263ae Add function _parse_str for string. 2018-05-02 19:36:51 +02:00
Patrick Pelissier 9fed336c9e Add proper const to prototype. 2018-05-01 12:44:43 +02:00
Patrick Pelissier ac5b689950 Add method _set2 for tuple. 2018-04-30 20:00:26 +02:00
Patrick Pelissier 3d43bb260a Update 2018-04-30 13:32:24 +02:00
Patrick Pelissier 2eaeb26d4c Make Serialization input of array / dict more flexible
by supporting space characters within the input.
2018-04-30 11:02:42 +02:00
Patrick Pelissier 34d0f8ec81 Add missing function for variant:
variant_init_element
variant_init_set_element
2018-04-30 10:24:37 +02:00
Patrick Pelissier ddc1c7e98f Update to display checksum correctly. 2018-04-30 08:24:31 +02:00
Patrick Pelissier e41475f672 Rewrite 2018-04-29 11:52:19 +02:00
Patrick Pelissier e954622925 Rewrite 2018-04-29 11:48:02 +02:00
Patrick Pelissier fae899e52e Add benchmark udb2. 2018-04-29 10:45:03 +02:00
Patrick Pelissier 7b11f5afbc Add benchmark UDB 2018-04-28 19:44:52 +02:00
Patrick Pelissier 40c0bf79b1 Update 2018-04-28 19:09:30 +02:00
Patrick Pelissier df2df593b6 Replace complex convertion from int to string into a simple call to to_string 2018-04-27 21:54:57 +02:00
Patrick Pelissier 1dc59d610d Use of new function m_thread_yield 2018-04-27 21:54:34 +02:00
Patrick Pelissier 8fc8decd09 Add m_thread_yield & m_thread_sleep.
Rewrite the windows package (it wasn't fully working before) and use functions
available since WINDOWS VISTA (increasing minimum supported version).
2018-04-27 20:12:44 +02:00
Patrick Pelissier 08f44845ce Fix issue for SPSC queue:
computing the number of elements in the queue is not reliable enough
as we can get more than than the size of the queue.
2018-04-26 22:41:11 +02:00
Patrick Pelissier 4fbffc4788 Use plain 'unsigned int' instead of 'unsigned long long'
for index of SPSC queues. There is no issue as we don't compare
the index, but only substract them.
2018-04-26 22:38:43 +02:00
Patrick Pelissier 8cf4050d3d Remove uneeded alignment constraint for SPSC queue. 2018-04-26 22:26:30 +02:00
Patrick Pelissier 31c18fc56d Bench SPSC queues too. 2018-04-26 22:05:54 +02:00
Patrick Pelissier 005207cfd6 Remove a warning in release mode. 2018-04-26 22:05:36 +02:00
Patrick Pelissier c8d668ad96 Merge branch 'master' of https://github.com/P-p-H-d/mlib 2018-04-25 22:04:42 +02:00
Patrick Pelissier a39c4ba9a4 Rewrite the code by adding an additional cast to avoid new warning with GCC8. 2018-04-25 22:03:52 +02:00
Patrick Pelissier f4deea05bf Update doc. 2018-04-24 22:42:19 +02:00
Patrick Pelissier 1c18133603 Close the handle of the thread in case of joining thread. 2018-04-22 19:30:24 +02:00
Patrick Pelissier 15566b4b65 Add bench of library SDS for string 2018-04-21 18:53:38 +02:00
Patrick Pelissier 737185752c Merge branch 'master' of https://github.com/P-p-H-d/mlib 2018-04-21 12:46:26 +02:00
Patrick Pelissier a12e3534c6 Rewrite I/O functions so that they handle properly
non printable characters.
2018-04-21 10:26:05 +02:00
Patrick Pelissier 51575b341b Use of static library for liblfds. 2018-04-20 22:24:20 +02:00
Patrick Pelissier 06b330ec51 Update doc 2018-04-20 21:44:59 +02:00
Patrick Pelissier e0a6bce5b0 Add SDS 2018-04-20 21:43:19 +02:00
Patrick Pelissier da07a5b613 string_strim allows optionnal second argument which list the characters to strim. 2018-04-20 20:46:44 +02:00
Patrick Pelissier fbbca37b55 Ignore a*.dat file too. 2018-04-20 19:51:56 +02:00
Patrick Pelissier 7fa1c2264e Fix issue for C++ layer (memory order constants have to be put in the current namespace too). 2018-04-20 19:34:22 +02:00
Patrick Pelissier dcfbe53713 Fix conformity bug in _splice. 2018-04-20 19:30:45 +02:00
Patrick Pelissier 8b2993c979 Add more assertions to help scan-build with false positive. 2018-04-20 19:30:15 +02:00
Patrick Pelissier 131da660c8 Fix bug in _clean. 2018-04-20 19:30:01 +02:00
Patrick Pelissier f3de34a62b Optimization for MPMC queues:
* use of atomic_explicit functions to give the memory order we want,
* reduce the size of the index to unsigned int: even if there is an
overflow, it doesn't matter as we don't compare the index with < or >
but with ==.
2018-04-19 22:15:37 +02:00
Patrick Pelissier 928d6bafcb Fix issue if there is no working stdatomic / atomic header:
definition of atomic_compare_exchange_strong_explicit was wrong.
Same for atomic_compare_exchange_weak_explicit
2018-04-19 22:14:16 +02:00
Patrick Pelissier 704fb0cbd9 Add a cast to avoid a warning with some compilers
(I am not sure the warning was justified).
2018-04-19 22:13:53 +02:00
Patrick Pelissier 3be27aefa3 Fix the format for size_t 2018-04-19 22:13:27 +02:00
Patrick Pelissier 8be81ac09e Update the list of tested systems. 2018-04-19 22:13:05 +02:00
Patrick Pelissier e2fc9c3699 Update 2018-04-19 20:21:54 +02:00
Patrick Pelissier 472eaff6f0 Add gene queue 2018-04-19 20:20:18 +02:00
Patrick Pelissier 805b016aee Reformat test and reduce pressure on thread creation for some tests
(Some systems didn't handle so much thread creation).
2018-04-17 23:01:05 +02:00
Patrick Pelissier 624a13ba1a Update version with added parallelism for long computation. 2018-04-17 00:00:56 +02:00
Patrick Pelissier 9692bf3991 Start list of API breakage. 2018-04-17 00:00:29 +02:00
Patrick Pelissier 3f5406f1d4 API breakage:
worker_sync takes an extra parameter (worker_t) to perform a
wait-on-event instead of a busy waiting, reducing consummer ressources.

worker_init takes an int instead of an unsigned int for the number of workers.
It allows additional extra value -1 to initialize the number of workers to
twice the number of CPU, allowing to overload the CPU with loads and keep
them fully working in some scenario.
2018-04-16 23:57:28 +02:00
Patrick Pelissier b684a62f8b Add more local information about the origin of a failure. 2018-04-16 22:05:17 +02:00
Patrick Pelissier 6bb94db22f Add function dict_splice 2018-04-15 21:02:14 +02:00
Patrick Pelissier d70a971d2e Add note 2018-04-15 20:59:04 +02:00
Patrick Pelissier b05b515f3d Reformat 2018-04-15 20:58:52 +02:00
Patrick Pelissier 12b15e0037 Add function array_splice just like function list_splice
as it can be done faster at low level.
2018-04-15 11:41:32 +02:00
Patrick Pelissier 2c9169308b Add code generation for OA dict 2018-04-15 10:53:55 +02:00
Patrick Pelissier 74a3d50c88 Minor optimization for _clean
No need to fill in the complete array with invalid param
as the array will be reduced.
2018-04-15 10:53:15 +02:00
Patrick Pelissier 6b8bb33221 Convert unsigned long to size_t in function prototypes for 32 bits systems. 2018-04-15 01:10:49 +02:00
Patrick Pelissier 175fb46508 Fix issue for 32 bits system 2018-04-15 00:48:31 +02:00
Patrick Pelissier 2f65400641 Add target checkall to lanch the test suite wih multiple compilers / options. 2018-04-15 00:40:48 +02:00
Patrick Pelissier b5f4f2fc4b Finish splitting m_core_clz into m_core_clz32 & m_core_clz64 2018-04-15 00:10:38 +02:00
Patrick Pélissier 8c34f44dae Finish fixing for 32 bits / clz 2018-04-14 23:14:21 +02:00
Patrick Pélissier d97f46133b Fix issue for 32 bits systems
mpz_core_clz wasn't reproductible for 32 bits system.
2018-04-14 23:08:53 +02:00
Patrick Pélissier a94a5feb84 Fix issue with 32 bits systems (size_t != unsigned long) 2018-04-14 20:52:29 +02:00
Patrick Pelissier ead5d7511a Use of proper oplist with the CMP method. 2018-04-14 08:33:37 +02:00
Patrick Pelissier 1cd7446013 Add more instantiation of the containter 2018-04-14 08:27:26 +02:00
Patrick Pelissier 40747a463b Remove dependecies from GMP header, allowing to run the test suite without GMP 2018-04-14 08:16:31 +02:00
Patrick Pelissier 8e20118ab6 Reformat 2018-04-14 08:12:58 +02:00
Patrick Pelissier 19f330e670 Rename also MYMPZ2_OPLIST into MY_MPZ_CMP_OPLIST 2018-04-14 08:12:27 +02:00
Patrick Pelissier 20d549b5e1 Rename MYMPZ_OPLIST into MY_MPZ_OPLIST 2018-04-14 08:11:14 +02:00
Patrick Pelissier e09fa89781 Little bit rewrite to help the compiler optimizes the loop a bit more:
as the variables are not longer on the stack, it uses more registers
and more instructions in the critical loop than before. By
copying the data into stack local variable, the compiler is once again
able to optimize the loop properly.
2018-04-14 08:07:01 +02:00
Patrick Pelissier 70b1421114 Update after review 2018-04-13 20:56:48 +02:00
Patrick Pelissier b80a30785a Fix 2018-04-13 20:28:57 +02:00
Patrick Pelissier c3245ac301 Full refactorisation and proper use of M*LIB.
Should be as fast as before.
2018-04-13 20:28:01 +02:00
Patrick Pelissier 085d5b411c Add oplist for B*TREE 2018-04-13 20:16:23 +02:00
Patrick Pelissier 8c26d6d0b5 Update 2018-04-12 23:39:19 +02:00
Patrick Pelissier 76f5085e84 Merge branch 'master' of https://github.com/P-p-H-d/mlib 2018-04-11 22:42:46 +02:00
Patrick Pelissier 80d78e3270 Add bounded string cte macro 2018-04-11 22:42:22 +02:00
Patrick Pelissier 654521b74c Add some tests of _equal_p 2018-04-10 23:25:04 +02:00
Patrick Pelissier 353d2d4cc9 Fix issue in copy of B*TREE:
the _next field wasn't properly set for the deepest nodes.
2018-04-10 23:23:36 +02:00
Patrick Pelissier b38d84419a Add methods hash, eqal_p, out_str, in_str & get_str
Format of serialisation needs to be properly uniformised between:
dictionnary,
red-black tree,
set,
b+tree with key,value,
b+tree with only key.
2018-04-09 18:42:34 +02:00
Patrick Pelissier 0d085771e4 Add tests for new methods 2018-04-09 18:07:03 +02:00
Patrick Pelissier f3b2b6b41e Add methods _swap, _move & _init_move 2018-04-09 18:06:48 +02:00
Patrick Pelissier fb35ad7ab3 Update due no new LIBSRT API. 2018-04-08 21:43:25 +02:00
Patrick Pelissier cf6e721994 Fix wrong usage of CollectionC by the benchmark. 2018-04-08 21:32:57 +02:00
Patrick Pelissier 9faea5ff15 Rewrite bench code so that it computes what is expected. 2018-04-08 21:10:29 +02:00
Patrick Pelissier fe18009bc0 Rewrite the loop so that the result is the same for dict and dict_oa. 2018-04-08 21:07:20 +02:00
Patrick Pelissier 10f900ea3e Rewrite code to avoid warning if optimisations are turned on. 2018-04-08 20:27:37 +02:00
Patrick Pelissier 63874694f8 Rewrite the code to avoid some silly warnings on some implementation. 2018-04-08 20:01:04 +02:00
Patrick Pelissier 9b9e246e66 More tests 2018-04-08 11:16:31 +02:00
Patrick Pelissier e6a6eb9be5 Fix issue in it_from for B+TREE 2018-04-08 11:13:48 +02:00
Patrick Pelissier 050bb5dbfa Add tests for it_from & it_to_p for B+TREE 2018-04-08 11:13:22 +02:00
Patrick Pelissier b005ec1845 Fix function max for B+TREE 2018-04-08 10:48:02 +02:00
Patrick Pelissier f158a94e0a Add tests for min & max 2018-04-08 10:47:52 +02:00
Patrick Pelissier a166620a6d Add method _from, _to_p, _min & _max for B+TREE 2018-04-08 10:39:27 +02:00
Patrick Pelissier 47fb467878 Add basic it test for B+tree 2018-04-08 07:24:56 +02:00
Patrick Pelissier 67af80c772 Fix issue in it_end for B+TREE 2018-04-08 07:22:34 +02:00
Patrick Pelissier 1f44155127 Add one more corner case 2018-04-07 12:11:50 +02:00
Patrick Pelissier 87a3ac4a76 Add test for methods _init_set & _set for B+tree 2018-04-07 12:10:50 +02:00
Patrick Pelissier 73354a04d5 Add method _init_set & _set for B+tree 2018-04-07 12:10:19 +02:00
Patrick Pelissier cb3038e73c Add more checks 2018-04-07 11:51:38 +02:00
Patrick Pelissier b6ec31fe11 Add more test. 2018-04-07 11:50:18 +02:00
Patrick Pelissier c7059a60ee Add more tests 2018-04-07 11:44:16 +02:00
Patrick Pelissier af49aaf8b1 Add more tests. 2018-04-07 11:42:12 +02:00
Patrick Pelissier 4149b8388b Improve quality of coverage report by not expanding contract function. 2018-04-07 11:41:43 +02:00
Patrick Pelissier df0d723714 Compute coverage for B+TREE 2018-04-07 11:28:50 +02:00
Patrick Pelissier 44209ed93e Add more tests 2018-04-07 11:19:58 +02:00
Patrick Pelissier 930a3c8637 More tests. 2018-04-07 11:14:31 +02:00
Patrick Pelissier d2f5698397 iMake oplist optional for BPTREE_DEF 2018-04-07 11:10:13 +02:00
Patrick Pelissier 42d9fc3284 Update doc 2018-04-07 00:43:51 +02:00
Patrick Pelissier 91db494898 Add basic iterator for B+tree
I can't match the exact interface of a dictionary of the key and the value are in separate place in the structure
(so I can't return a pair of (key,value)). Instead I return a pair of pointer (key_ptr, value_ptr).
I don't see any other way which doesn't evolve copy of the key/value.
For the RBtree interface, no such problem occurs.
2018-04-05 22:44:36 +02:00
Patrick Pelissier 75217d4914 Rewrite / cleanup 2018-04-04 22:57:47 +02:00
Patrick Pelissier ceaf004719 Remove wrong comment 2018-04-04 22:55:19 +02:00
Patrick Pelissier 27b7380433 B+TREE: Add _size operator 2018-04-04 22:54:39 +02:00
Patrick Pelissier 7ca254ade9 B+TREE: Add _pop function. 2018-04-04 22:39:46 +02:00
Patrick Pelissier c91864c2a7 B+TREE: _remove returns a boolean indicating if the item
removed was present or not
2018-04-04 22:35:47 +02:00
Patrick Pelissier 4925297a35 Update doc 2018-04-04 20:27:44 +02:00
Patrick Pelissier d7ece50ed0 Replace "Dict" by "DictOA" since KLIB uses an OpenAddressing dictionnary. 2018-04-03 20:13:18 +02:00
Patrick Pelissier 3ef4a9f413 Fix issue with the way of benching the BTREE of KLIB.
Forgot to initialize the key in the search pass.
2018-04-03 20:10:11 +02:00
Patrick Pelissier 9768b5b37a Add bench of B+TREE 2018-04-03 20:07:21 +02:00
Patrick Pelissier e4cd999bd0 Test expansion of new container. 2018-04-03 20:01:24 +02:00
Patrick Pelissier 8e335535cc Add new container without a value. 2018-04-03 20:01:04 +02:00
Patrick Pelissier 2f53d98806 Fix issue with kind_s being redefined if the macro is used again.
Fix issue of not using proper method for type.
Render usage of value optional so that we can create B+TREE with only keys.
2018-04-03 18:29:28 +02:00
Patrick Pelissier 5d99331358 Add expansion of a user type. 2018-04-03 18:29:16 +02:00
Patrick Pelissier 316022cde4 Add oplist with CMP operator 2018-04-03 18:28:51 +02:00
Patrick Pelissier 8d1abca8de Add link to the comparison between STL & M*LIB 2018-04-03 12:47:44 +02:00
Patrick Pelissier 1b2e73eaa2 Prepare doc 2018-04-03 12:43:30 +02:00
Patrick Pelissier 6127371920 Add B+TREE container.
Fix #4
2018-04-03 12:40:29 +02:00
Patrick Pelissier 7936dbbf8c Minor fix 2018-03-31 16:31:47 +02:00
Patrick Pelissier 8aa45309a2 Update doc 2018-03-31 12:10:50 +02:00
96 changed files with 11799 additions and 2699 deletions

No files matched your search

+1
View File
@@ -36,3 +36,4 @@ depend
# Others
other/
a*.dat
+48 -8
View File
@@ -1,8 +1,26 @@
PREFIX=/usr/local
# Environnement variable. To customize if needed.
RM=rm -f
MKDIR=mkdir -p
INSTALL=install
INSTALL_PROGRAM=${INSTALL}
INSTALL_DATA=${INSTALL} -m 644
.PHONY: all test check doc clean distclean depend depend.png install
# Installation directory
PREFIX=/usr/local
# Package name & version.
PACKAGE=m*lib-$(VERSION)
VERSION=0.2.1
# Define the contain of the distribution tarball
# TODO: Get theses lists from GIT itself.
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-concurrent.h m-core.h m-deque.h m-dict.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-shared.h m-snapshot.h m-string.h m-tuple.h m-variant.h m-worker.h
DOC1=LICENSE README.md
DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/DEV.md doc/ISSUES.org doc/depend.png doc/oplist.png
EXAMPLE=example/ex-array01.c example/ex-array04.c example/ex-dict02.c example/ex-grep01.c example/ex-multi01.c example/ex-rbtree01.c example/ex-array02.c example/ex-buffer01.c example/ex-dict03.c example/ex-list01.c example/ex-multi02.c example/Makefile example/ex-array03.c example/ex-dict01.c example/ex-dict04.c example/ex-mph.c example/ex-multi03.c
TEST=tests/coverage.h tests/test-malgo.c tests/test-mbptree.c tests/test-mdeque.c tests/test-milist.c tests/test-mmutex.c tests/test-mshared.c tests/test-mtuple.c tests/test-obj.h tests/tgen-mdict.c tests/tgen-openmp.c tests/wip-mregister.c tests/dict.txt tests/test-marray.c tests/test-mbuffer.c tests/test-mdict.c tests/test-mlist.c tests/test-mprioqueue.c tests/test-msnapshot.c tests/test-mvariant.c tests/tgen-bitset.c tests/tgen-mlist.c tests/tgen-queue.c tests/Makefile tests/test-mbitset.c tests/test-mcore.c tests/test-mgenint.c tests/test-mmempool.c tests/test-mrbtree.c tests/test-mstring.c tests/test-mworker.c tests/tgen-marray.c tests/tgen-mstring.c tests/tgen-shared.c
.PHONY: all test check doc clean distclean depend install uninstall dist
all:
@echo "Nothing to be done."
@@ -13,25 +31,47 @@ check:
cd tests && $(MAKE) check
cd example && $(MAKE) all
doc: README.md
html: doc
doc: README.md doc/depend.png
markdown < README.md > README.html
clean:
cd tests && $(MAKE) clean
cd example && $(MAKE) clean
cd bench && $(MAKE) clean
$(RM) -f README.html depend.dot
$(RM) README.html depend.dot
$(RM) -r 'm*lib-$(VERSION)'
$(RM) 'm*lib-$(VERSION).tar.bz2'
distclean:
distclean: clean
cd tests && $(MAKE) distclean
depend:
cd tests && $(MAKE) depend
depend.png:
doc/depend.png: $(HEADER)
(echo "digraph g { " ; for i in *.h ; do list=$$(grep "include \"" $$i |cut -f2 -d\") ; for j in $$list ; do echo "\"$$i\" -> \"$$j\" ;" ; done ; done ; echo "}" )> depend.dot
dot -Tpng depend.dot -o depend.png
dot -Tpng depend.dot -o doc/depend.png
optipng -o7 doc/depend.png
dist: $(HEADER) $(DOC1) $(DOC2) $(EXAMPLE) $(TEST) Makefile clean
$(MKDIR) '$(PACKAGE)'
$(MKDIR) '$(PACKAGE)/doc'
$(MKDIR) '$(PACKAGE)/tests'
$(MKDIR) '$(PACKAGE)/example'
cp $(HEADER) $(DOC1) Makefile '$(PACKAGE)'
cp $(EXAMPLE) '$(PACKAGE)/example'
cp $(TEST) '$(PACKAGE)/tests'
cp $(DOC2) '$(PACKAGE)/doc'
cd '$(PACKAGE)/tests' && $(MAKE) depend
tar jcf '$(PACKAGE).tar.bz2' '$(PACKAGE)'
distcheck: dist
cd '$(PACKAGE)' && make check
install:
$(MKDIR) $(DESTDIR)$(PREFIX)/include
cp m-*.h $(DESTDIR)$(PREFIX)/include
$(INSTALL_DATA) $(HEADER) $(DESTDIR)$(PREFIX)/include
uninstall:
for i in $(HEADER) ; do $(RM) $(DESTDIR)$(PREFIX)/include/$$i ; done
+1572 -462
View File
File diff suppressed because it is too large. Load diff
+17 -2
View File
@@ -34,8 +34,10 @@ plain: bench-plain
bench-mlib:
$(CC) $(CFLAGS) $(CPPFLAGS) -pthread bench-mlib.c -o bench-mlib.exe
@./bench-mlib.exe 10
@./bench-mlib.exe 11
@./bench-mlib.exe 20
@./bench-mlib.exe 30
@./bench-mlib.exe 31
@./bench-mlib.exe 40
@./bench-mlib.exe 41
@./bench-mlib.exe 42
@@ -46,8 +48,10 @@ bench-mlib:
bench-mlib-mempool:
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c -DUSE_MEMPOOL -pthread -o bench-mlib-mempool.exe
@./bench-mlib-mempool.exe 10
@./bench-mlib-mempool.exe 11
@./bench-mlib-mempool.exe 20
@./bench-mlib-mempool.exe 30
@./bench-mlib-mempool.exe 31
@./bench-mlib-mempool.exe 40
@./bench-mlib-mempool.exe 41
@./bench-mlib-mempool.exe 42
@@ -59,6 +63,10 @@ bench-mlib-thread:
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c -DMULTI_THREAD_MEASURE -pthread -o bench-mlib-thread.exe
@./bench-mlib-thread.exe 60
@./bench-mlib-thread.exe 61
@./bench-mlib-thread.exe 62
@./bench-mlib-thread.exe 63
@./bench-mlib-thread.exe 64
@./bench-mlib-thread.exe 65
bench-stl:
$(CXX) $(CFLAGS) $(CPPFLAGS) bench-stl.cpp -o bench-stl.exe
@@ -232,7 +240,7 @@ bench-libsrt0:
bench-liblfds:
@if test -n "$${LIBLFDS}" ; then $(MAKE) bench-liblfds0 ; else echo "Nothing to be done for LIBLFDS." ; fi
bench-liblfds0:
$(CC) $(CFLAGS) $(CPPFLAGS) -I "$${LIBLFDS}/inc" -Wno-unknown-pragmas bench-liblfds.c -o bench-liblfds.exe $${LIBLFDS}/bin/liblfds711.so -lpthread
$(CC) $(CFLAGS) $(CPPFLAGS) -I "$${LIBLFDS}/inc" -Wno-unknown-pragmas bench-liblfds.c -o bench-liblfds.exe $${LIBLFDS}/bin/liblfds711.a -lpthread
@LD_LIBRARY_PATH="$${LIBLFDS}/bin:$${LD_LIBRARY_PATH}" ./bench-liblfds.exe 60
@@ -295,7 +303,14 @@ bench-string:
@if test -n "$${BSTRLIB}" ; then $(MAKE) bench-string-with BENCH_DEF="-DBENCH_CAN_USE_BSTRLIB -I ${BSTRLIB} $${BSTRLIB}/obj/bstrlib.o $${BSTRLIB}/obj/bstraux.o $${BSTRLIB}/obj/bstrwrap.o" ; else $(MAKE) bench-string-with ; fi
bench-string-with:
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-exe BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/src $${LIBSRT}/libsrt.a" ; else $(MAKE) bench-string-exe BENCH_DEF="$(BENCH_DEF)"; fi
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-with2 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/src $${LIBSRT}/libsrt.a" ; else $(MAKE) bench-string-with2 BENCH_DEF="$(BENCH_DEF)"; fi
#NOTE: Need to build by hand sds.o since it is not build by default and sds.c is not compatible with C++
bench-string-with2:
@if test -n "$${SDS}" ; then $(MAKE) bench-string-with3 BENCH_DEF="$(BENCH_DEF) -fpermissive -DBENCH_CAN_USE_SDS -I$${SDS}/ $${SDS}/sds.o" ; else $(MAKE) bench-string-with3 BENCH_DEF="$(BENCH_DEF)"; fi
bench-string-with3:
@if test -n "$${RAPIDSTRING}" ; then $(MAKE) bench-string-exe BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_RAPIDSTRING -I$${RAPIDSTRING}/ " ; else $(MAKE) bench-string-exe BENCH_DEF="$(BENCH_DEF)"; fi
bench-string-exe:
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${BSTRLIB}" -DBENCH_CAN_USE_STL -DBENCH_CAN_USE_MSTARLIB bench-string.cpp -o bench-string.exe $(BENCH_DEF)
+14 -6
View File
@@ -93,7 +93,7 @@ static void test_rbtree(size_t n)
stat = treetable_new(compare, &tree);
if (stat != CC_OK) abort();
for (size_t i = 0; i < n; i++) {
void *key = (void*)(uintptr_t) i;
void *key = (void*)(uintptr_t) rand_get();
stat = treetable_add(tree, key, key);
if (stat != CC_OK) abort();
}
@@ -122,11 +122,11 @@ static int equal_func(const void *key1, const void *key2)
{
const unsigned long pa = (uintptr_t) key1;
const unsigned long pb = (uintptr_t) key2;
return pa == pb;
return (pa < pb) ? -1 : pa > pb;
}
static void
test_dict(unsigned long n)
test_dict(size_t n)
{
HashTable *dict;
enum cc_stat stat;
@@ -138,8 +138,8 @@ test_dict(unsigned long n)
if (stat != CC_OK) abort();
for (size_t i = 0; i < n; i++) {
void *key = (void*)(uintptr_t) rand_get();
void *value = (void*)(uintptr_t) rand_get();
void *key = (void*)(uintptr_t) rand_get();
stat = hashtable_add(dict, key, value );
if (stat != CC_OK) abort();
}
@@ -164,7 +164,7 @@ static int char_equal (const void* a, const void * b)
{
const char_array_t *pa = (const char_array_t *)a;
const char_array_t *pb = (const char_array_t *)b;
return strcmp(*pa,*pb)==0;
return strcmp(*pa,*pb);
}
static size_t char_hash(const void *a, int l, uint32_t seed)
@@ -178,7 +178,7 @@ static size_t char_hash(const void *a, int l, uint32_t seed)
}
static void
test_dict_big(unsigned long n)
test_dict_big(size_t n)
{
HashTable *dict;
enum cc_stat stat;
@@ -189,9 +189,14 @@ test_dict_big(unsigned long n)
stat = hashtable_new_conf(&htc, &dict);
if (stat != CC_OK) abort();
char_array_t **tab = malloc (sizeof(char_array_t *)*2*n);
if (!tab) abort();
size_t cpt = 0;
for (size_t i = 0; i < n; i++) {
char_array_t *key = malloc (sizeof (char_array_t));
char_array_t *value = malloc (sizeof (char_array_t));
tab[cpt++] = key;
tab[cpt++] = value;
sprintf(*key, "%u", rand_get());
sprintf(*value, "%u", rand_get());
stat = hashtable_add(dict, key, value );
@@ -209,6 +214,9 @@ test_dict_big(unsigned long n)
}
g_result = s;
hashtable_destroy(dict);
if (cpt != 2*n) abort();
for(size_t i = 0; i < 2*n;i++)
free(tab[i]);
}
/********************************************************************************************/
+3 -3
View File
@@ -25,7 +25,7 @@ using namespace std;
/********************************************************************************************/
static void
test_dict2(unsigned long n)
test_dict2(size_t n)
{
dense_hash_map<unsigned long, unsigned long> dict;
dict.set_empty_key(-1);
@@ -75,7 +75,7 @@ namespace std {
}
static void
test_dict_big(unsigned long n)
test_dict_big(size_t n)
{
dense_hash_map<char_array_s, char_array_s> dict;
struct char_array_s empty, del;
@@ -104,7 +104,7 @@ test_dict_big(unsigned long n)
/********************************************************************************************/
static void
test_dict_str(unsigned long n)
test_dict_str(size_t n)
{
dense_hash_map<string, string> dict;
string empty, del;
+3 -3
View File
@@ -26,7 +26,7 @@ using namespace std;
/********************************************************************************************/
static void
test_dict2(unsigned long n)
test_dict2(size_t n)
{
flat_hash_map<unsigned long, unsigned long> dict;
for (size_t i = 0; i < n; i++) {
@@ -62,7 +62,7 @@ namespace std {
}
static void
test_dict_big(unsigned long n)
test_dict_big(size_t n)
{
flat_hash_map<char_array_s, char_array_s> dict;
@@ -86,7 +86,7 @@ test_dict_big(unsigned long n)
/********************************************************************************************/
static void
test_dict_str(unsigned long n)
test_dict_str(size_t n)
{
flat_hash_map<string, string> dict;
+2 -2
View File
@@ -97,7 +97,7 @@ static gboolean equal_func(gconstpointer a, gconstpointer b)
}
static void
test_dict(unsigned long n)
test_dict(size_t n)
{
GHashTable *dict = g_hash_table_new_full(hash_func, equal_func, free, free);
for (size_t i = 0; i < n; i++) {
@@ -140,7 +140,7 @@ static guint char_hash(gconstpointer a)
}
static void
test_dict_big(unsigned long n)
test_dict_big(size_t n)
{
GHashTable *dict = g_hash_table_new_full(char_hash, char_equal, free, free);
for (size_t i = 0; i < n; i++) {
+3 -3
View File
@@ -25,7 +25,7 @@ using namespace std;
/********************************************************************************************/
static void
test_dict2(unsigned long n)
test_dict2(size_t n)
{
tsl::hopscotch_map<unsigned long, unsigned long> dict;
@@ -63,7 +63,7 @@ namespace std {
}
static void
test_dict_big(unsigned long n)
test_dict_big(size_t n)
{
hopscotch_map<char_array_s, char_array_s> dict;
@@ -87,7 +87,7 @@ test_dict_big(unsigned long n)
/********************************************************************************************/
static void
test_dict_str(unsigned long n)
test_dict_str(size_t n)
{
hopscotch_map<string, string> dict;
+4 -4
View File
@@ -82,7 +82,7 @@ static void test_rbtree(size_t n)
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
unsigned long j = 0;
unsigned long j = rand_get();
if (kb_getp(kTree, tree, &j) != 0)
s+= j;
}
@@ -98,7 +98,7 @@ static void test_rbtree(size_t n)
KHASH_INIT(iun, unsigned long, unsigned long, 1, hash_func, hash_eq)
static void
test_dict(unsigned long n)
test_dict(size_t n)
{
khash_t(iun) *dict = kh_init(iun);
@@ -137,7 +137,7 @@ static inline size_t char_hash(const char_array_t a) {
KHASH_INIT(iub, char_array_t, char_array_t, 1, char_hash, char_equal_p)
static void
test_dict_big(unsigned long n)
test_dict_big(size_t n)
{
khash_t(iub) *dict = kh_init(iub);
@@ -195,7 +195,7 @@ int main(int argc, const char *argv[])
if (n == 30)
test_function("B-tree time", 1000000, test_rbtree);
if (n == 40)
test_function("Dict time", 1000000, test_dict);
test_function("DictOA time", 1000000, test_dict);
if (n == 41)
test_function("DictB time", 1000000, test_dict_big);
if (n == 50)
+2 -2
View File
@@ -64,7 +64,7 @@ struct map_element
};
static void
test_dict(unsigned long n)
test_dict(size_t n)
{
map dict;
map_construct(&dict, sizeof(map_element), (map_element[]) {{.key = -1}}, set_func);
@@ -115,7 +115,7 @@ struct big_map_element
};
static void
test_dict_big(unsigned long n)
test_dict_big(size_t n)
{
map dict;
big_map_element empty;
+282 -45
View File
@@ -7,12 +7,15 @@
#include "m-array.h"
#include "m-list.h"
#include "m-rbtree.h"
#include "m-bptree.h"
#include "m-dict.h"
#include "m-algo.h"
#include "m-mempool.h"
#include "m-string.h"
#include "m-buffer.h"
#include "m-mutex.h"
#include "m-deque.h"
#include "m-concurrent.h"
#include "common.h"
@@ -68,6 +71,37 @@ static void test_list (size_t n)
/********************************************************************************************/
// Two benched mode: with or without mempool
#ifdef USE_MEMPOOL
LIST_DUAL_PUSH_DEF(dlist_uint, unsigned int, (MEMPOOL( dlist_mpool), MEMPOOL_LINKAGE(static)))
#else
LIST_DUAL_PUSH_DEF(dlist_uint, unsigned int)
#endif
static void test_dlist (size_t n)
{
#ifdef USE_MEMPOOL
dlist_uint_mempool_init(dlist_mpool);
#endif
M_LET(a1, a2, LIST_OPLIST(dlist_uint)) {
for(size_t i = 0; i < n; i++) {
dlist_uint_push_back(a1, rand_get() );
dlist_uint_push_back(a2, rand_get() );
}
unsigned int s = 0;
dlist_uint_it_t it1, it2;
for(dlist_uint_it(it1, a1), dlist_uint_it(it2,a2); !dlist_uint_end_p(it1); dlist_uint_next(it1), dlist_uint_next(it2)) {
s += *dlist_uint_cref(it1) * *dlist_uint_cref(it2);
}
g_result = s;
}
#ifdef USE_MEMPOOL
dlist_uint_mempool_clear(dlist_mpool);
#endif
}
/********************************************************************************************/
#ifdef USE_MEMPOOL
RBTREE_DEF(rbtree_ulong, unsigned long, (MEMPOOL( rbtree_mpool), MEMPOOL_LINKAGE(static)))
#else
@@ -99,6 +133,27 @@ static void test_rbtree(size_t n)
/********************************************************************************************/
BPTREE_DEF(bptree_ulong, 21, unsigned long, M_DEFAULT_OPLIST)
static void test_bptree(size_t n)
{
M_LET(tree, BPTREE_OPLIST(bptree_ulong)) {
for (size_t i = 0; i < n; i++) {
bptree_ulong_push(tree, rand_get());
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
unsigned long *p = bptree_ulong_get(tree, rand_get());
if (p)
s += *p;
}
g_result = s;
}
}
/********************************************************************************************/
#ifdef USE_MEMPOOL
DICT_DEF2(dict_ulong, unsigned long, M_OPEXTEND(M_DEFAULT_OPLIST, MEMPOOL(dict_mpool), MEMPOOL_LINKAGE(static)), unsigned long, M_DEFAULT_OPLIST)
#else
@@ -106,15 +161,16 @@ DICT_DEF2(dict_ulong, unsigned long, M_DEFAULT_OPLIST, unsigned long, M_DEFAULT_
#endif
static void
test_dict(unsigned long n)
test_dict(size_t n)
{
#ifdef USE_MEMPOOL
dict_ulong_list_pair_mempool_init(dict_mpool);
#endif
M_LET(dict, DICT_OPLIST(dict_ulong)) {
for (size_t i = 0; i < n; i++) {
unsigned long value = rand_get();
unsigned long key = rand_get();
dict_ulong_set_at(dict, key, rand_get() );
dict_ulong_set_at(dict, key, value);
}
rand_init();
unsigned int s = 0;
@@ -147,7 +203,7 @@ DICT_OA_DEF2(dict_oa_ulong,
unsigned long, M_DEFAULT_OPLIST)
static void
test_dict_oa(unsigned long n)
test_dict_oa(size_t n)
{
M_LET(dict, DICT_OPLIST(dict_oa_ulong)) {
for (size_t i = 0; i < n; i++) {
@@ -167,23 +223,20 @@ test_dict_oa(unsigned long n)
/********************************************************************************************/
typedef char char_array_t[256];
static void char_init (char_array_t a) { a[0] = 0; }
static void char_set (char_array_t a, const char_array_t b) { strcpy(a, b); }
static bool char_equal_p (const char_array_t a, const char_array_t b) { return strcmp(a,b)==0; }
static size_t char_hash(const char_array_t a) { return m_core_hash (a, strlen(a)); }
// NOTE: Can't use the name OPLIST as a macro!
#define CHAR_OPLIST (INIT(char_init), INIT_SET(char_set), SET(char_set), CLEAR(char_init), HASH(char_hash), EQUAL(char_equal_p))
#define M_OPL_char_array_t() (INIT(char_init), INIT_SET(char_set), SET(char_set), CLEAR(char_init), HASH(char_hash), EQUAL(char_equal_p))
#ifdef USE_MEMPOOL
DICT_STOREHASH_DEF2(dict_char, char_array_t, M_OPEXTEND(CHAR_OPLIST,MEMPOOL(dict_mpool2), MEMPOOL_LINKAGE(static)), char_array_t, CHAR_OPLIST)
DICT_STOREHASH_DEF2(dict_char, char_array_t, M_OPEXTEND(M_OPL_char_array_t(),MEMPOOL(dict_mpool2), MEMPOOL_LINKAGE(static)), char_array_t, M_OPL_char_array_t())
#else
DICT_STOREHASH_DEF2(dict_char, char_array_t, CHAR_OPLIST, char_array_t, CHAR_OPLIST)
DICT_STOREHASH_DEF2(dict_char, char_array_t, M_OPL_char_array_t(), char_array_t, M_OPL_char_array_t())
#endif
static void
test_dict_big(unsigned long n)
test_dict_big(size_t n)
{
#ifdef USE_MEMPOOL
dict_char_list_pair_mempool_init(dict_mpool2);
@@ -220,7 +273,7 @@ DICT_DEF2(dict_str, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
#endif
static void
test_dict_str(unsigned long n)
test_dict_str(size_t n)
{
#ifdef USE_MEMPOOL
dict_str_list_pair_mempool_init(dict_mpool3);
@@ -276,73 +329,76 @@ static void test_stable_sort(size_t n)
/********************************************************************************************/
#define SIZE_LIMIT (UINT_MAX/2)
BUFFER_DEF(buffer_uint, unsigned int, 0, BUFFER_QUEUE|BUFFER_BLOCKING)
buffer_uint_t g_buff;
buffer_uint_t g_buff_lock;
BUFFER_DEF(buffer_ull, unsigned long long, 0, BUFFER_QUEUE|BUFFER_BLOCKING)
buffer_ull_t g_final;
buffer_ull_t g_final_lock;
static void final(void *arg)
static void final_lock(void *arg)
{
size_t *p_n = arg;
size_t n = *p_n;
unsigned long long j, s = 0;
for(int i = 0; i < n;i++) {
buffer_ull_pop(&j, g_final);
buffer_ull_pop(&j, g_final_lock);
s += j;
}
g_result = s;
}
static void conso(void *arg)
static void conso_lock(void *arg)
{
unsigned int j;
size_t *p_n = arg;
size_t n = *p_n;
unsigned long long s = 0;
for(int i = 0; i < n;i++) {
buffer_uint_pop(&j, g_buff);
buffer_uint_pop(&j, g_buff_lock);
s += j;
}
buffer_ull_push(g_final, s);
buffer_ull_push(g_final_lock, s);
}
static void prod(void *arg)
static void prod_lock(void *arg)
{
size_t *p_n = arg;
size_t n = *p_n;
size_t r = n;
for(unsigned int i = 0; i < n;i++) {
buffer_uint_push(g_buff, r );
buffer_uint_push(g_buff_lock, r );
r = r * 31421U + 6927U;
}
}
static void test_buffer(size_t n)
{
const int cpu_count = get_cpu_count();
const int cpu_count = n > SIZE_LIMIT ? 2 : 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;
}
n = n > SIZE_LIMIT ? n - SIZE_LIMIT : n;
// Init
buffer_uint_init(g_buff, 64*cpu_count);
buffer_ull_init (g_final, 64*cpu_count);
buffer_uint_init(g_buff_lock, 64*cpu_count);
buffer_ull_init (g_final_lock, 64*cpu_count);
// 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);
m_thread_create (idx_p[i], prod_lock, &n);
}
for(int i = 0; i < conso_count; i++) {
m_thread_create (idx_c[i], conso, &n);
m_thread_create (idx_c[i], conso_lock, &n);
}
size_t n2 = conso_count;
m_thread_create(idx_final, final, &n2);
m_thread_create(idx_final, final_lock, &n2);
// Wait for jobs to be done.
for(int i = 0; i < prod_count; i++) {
@@ -354,79 +410,80 @@ static void test_buffer(size_t n)
m_thread_join(idx_final);
// Clear & quit
buffer_ull_clear(g_final);
buffer_uint_clear(g_buff);
buffer_ull_clear(g_final_lock);
buffer_uint_clear(g_buff_lock);
}
/********************************************************************************************/
QUEUE_MPMC_DEF(queue_uint, unsigned int, BUFFER_QUEUE)
queue_uint_t g_buff2;
queue_uint_t g_buff_mpmc;
QUEUE_MPMC_DEF(queue_ull, unsigned long long, BUFFER_QUEUE)
queue_ull_t g_final2;
queue_ull_t g_final_mpmc;
static void final2(void *arg)
static void final_mpmc(void *arg)
{
size_t *p_n = arg;
size_t n = *p_n;
unsigned long long j, s = 0;
for(int i = 0; i < n;i++) {
while (!queue_ull_pop(&j, g_final2));
while (!queue_ull_pop(&j, g_final_mpmc)) m_thread_yield();
s += j;
}
g_result = s;
}
static void conso2(void *arg)
static void conso_mpmc(void *arg)
{
unsigned int j;
size_t *p_n = arg;
size_t n = *p_n;
unsigned long long s = 0;
for(int i = 0; i < n;i++) {
while (!queue_uint_pop(&j, g_buff2));
while (!queue_uint_pop(&j, g_buff_mpmc));
s += j;
}
while (!queue_ull_push(g_final2, s));
while (!queue_ull_push(g_final_mpmc, s));
}
static void prod2(void *arg)
static void prod_mpmc(void *arg)
{
size_t *p_n = 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_buff_mpmc, r ));
r = r * 31421U + 6927U;
}
}
static void test_queue(size_t n)
{
const int cpu_count = get_cpu_count();
const int cpu_count = n > SIZE_LIMIT ? 2 : 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 Queue performance.\n");
return;
}
n = n > SIZE_LIMIT ? n - SIZE_LIMIT : n;
// Init
queue_uint_init(g_buff2, 64*cpu_count);
queue_ull_init (g_final2, 64*cpu_count);
queue_uint_init(g_buff_mpmc, 64*cpu_count);
queue_ull_init (g_final_mpmc, 64*cpu_count);
// 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], prod2, &n);
m_thread_create (idx_p[i], prod_mpmc, &n);
}
for(int i = 0; i < conso_count; i++) {
m_thread_create (idx_c[i], conso2, &n);
m_thread_create (idx_c[i], conso_mpmc, &n);
}
size_t n2 = conso_count;
m_thread_create(idx_final, final2, &n2);
m_thread_create(idx_final, final_mpmc, &n2);
// Wait for jobs to be done.
for(int i = 0; i < prod_count; i++) {
@@ -438,8 +495,176 @@ static void test_queue(size_t n)
m_thread_join(idx_final);
// Clear & quit
queue_ull_clear(g_final2);
queue_uint_clear(g_buff2);
queue_ull_clear(g_final_mpmc);
queue_uint_clear(g_buff_mpmc);
}
/********************************************************************************************/
QUEUE_SPSC_DEF(queue_single_uint, unsigned int, BUFFER_QUEUE)
queue_single_uint_t g_buff_spsc;
QUEUE_SPSC_DEF(queue_single_ull, unsigned long long, BUFFER_QUEUE)
queue_single_ull_t g_final_spsc;
static void final_spsc(void *arg)
{
size_t *p_n = arg;
size_t n = *p_n;
unsigned long long j, s = 0;
for(int i = 0; i < n;i++) {
while (!queue_single_ull_pop(&j, g_final_spsc)) m_thread_yield();
s += j;
}
g_result = s;
}
static void conso_spsc(void *arg)
{
unsigned int j;
size_t *p_n = arg;
size_t n = *p_n;
unsigned long long s = 0;
for(int i = 0; i < n;i++) {
while (!queue_single_uint_pop(&j, g_buff_spsc));
s += j;
}
while (!queue_single_ull_push(g_final_spsc, s));
}
static void prod_spsc(void *arg)
{
size_t *p_n = arg;
size_t n = *p_n;
size_t r = n;
for(unsigned int i = 0; i < n;i++) {
while (!queue_single_uint_push(g_buff_spsc, r ));
r = r * 31421U + 6927U;
}
}
static void test_queue_single(size_t n)
{
const int cpu_count = 2;
const int prod_count = cpu_count/2;
const int conso_count = cpu_count - prod_count;
// Init
queue_single_uint_init(g_buff_spsc, 64*cpu_count);
queue_single_ull_init (g_final_spsc, 64*cpu_count);
// 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_spsc, &n);
}
for(int i = 0; i < conso_count; i++) {
m_thread_create (idx_c[i], conso_spsc, &n);
}
size_t n2 = conso_count;
m_thread_create(idx_final, final_spsc, &n2);
// Wait for jobs to be done.
for(int i = 0; i < prod_count; i++) {
m_thread_join(idx_p[i]);
}
for(int i = 0; i < conso_count; i++) {
m_thread_join(idx_c[i]);
}
m_thread_join(idx_final);
// Clear & quit
queue_single_ull_clear(g_final_spsc);
queue_single_uint_clear(g_buff_spsc);
}
/********************************************************************************************/
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)
CONCURRENT_DEF(cdeque_ull, deque_ull_t, M_OPEXTEND(DEQUE_OPLIST(deque_ull, M_DEFAULT_OPLIST), PUSH(deque_ull_push_front)))
cdeque_uint_t g_buff_conc;
cdeque_ull_t g_final_conc;
static void final_conc(void *arg)
{
size_t *p_n = arg;
size_t n = *p_n;
unsigned long long j, s = 0;
for(int i = 0; i < n;i++) {
cdeque_ull_pop_blocking(&j, g_final_conc, true);
s += j;
}
g_result = s;
}
static void conso_conc(void *arg)
{
unsigned int j;
size_t *p_n = arg;
size_t n = *p_n;
unsigned long long s = 0;
for(int i = 0; i < n;i++) {
cdeque_uint_pop_blocking(&j, g_buff_conc, true);
s += j;
}
cdeque_ull_push(g_final_conc, s);
}
static void prod_conc(void *arg)
{
size_t *p_n = arg;
size_t n = *p_n;
size_t r = n;
for(unsigned int i = 0; i < n;i++) {
cdeque_uint_push(g_buff_conc, r );
r = r * 31421U + 6927U;
}
}
static void test_queue_concurrent(size_t n)
{
const int cpu_count = n > SIZE_LIMIT ? 2 : 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 CONCURRENT performance.\n");
return;
}
n = n > SIZE_LIMIT ? n - SIZE_LIMIT : n;
// Init
cdeque_uint_init(g_buff_conc);
cdeque_ull_init (g_final_conc);
// 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_conc, &n);
}
for(int i = 0; i < conso_count; i++) {
m_thread_create (idx_c[i], conso_conc, &n);
}
size_t n2 = conso_count;
m_thread_create(idx_final, final_conc, &n2);
// Wait for jobs to be done.
for(int i = 0; i < prod_count; i++) {
m_thread_join(idx_p[i]);
}
for(int i = 0; i < conso_count; i++) {
m_thread_join(idx_c[i]);
}
m_thread_join(idx_final);
// Clear & quit
cdeque_ull_clear(g_final_conc);
cdeque_uint_clear(g_buff_conc);
}
/********************************************************************************************/
@@ -482,10 +707,14 @@ int main(int argc, const char *argv[])
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 10)
test_function("List time",10000000, test_list);
if (n == 11)
test_function("DPList time",10000000, test_dlist);
if (n == 20)
test_function("Array time", 100000000, test_array);
if (n == 30)
test_function("Rbtree time", 1000000, test_rbtree);
if (n == 31)
test_function("B+tree time", 1000000, test_bptree);
if (n == 40)
test_function("Dict time", 1000000, test_dict);
if (n == 42)
@@ -502,6 +731,14 @@ int main(int argc, const char *argv[])
test_function("Buffer time", 1000000, test_buffer);
if (n == 61)
test_function("Queue MPMC time", 1000000, test_queue);
if (n == 62)
test_function("Buffer time (P2)", SIZE_LIMIT+1000000, test_buffer);
if (n == 63)
test_function("Queue MPMC time (P2)", SIZE_LIMIT+1000000, test_queue);
if (n == 64)
test_function("Queue SPSC time", 1000000, test_queue_single);
if (n == 65)
test_function("Queue CONCURRENT time", 1000000, test_queue_concurrent);
if (n == 70) {
n = (argc > 2) ? atoi(argv[2]) : 100000000;
test_hash_prepare(n);
+2 -2
View File
@@ -26,7 +26,7 @@ static inline size_t fookeyfunct(const foo_t *r)
NEDTRIE_GENERATE(static, foo_tree_s, foo_s, link, fookeyfunct, NEDTRIE_NOBBLEZEROS(foo_tree_s))
static void
test_dict(unsigned long n)
test_dict(size_t n)
{
foo_tree_t footree;
NEDTRIE_INIT(&footree);
@@ -58,7 +58,7 @@ test_dict(unsigned long n)
}
static void
test_dict_noalloc(unsigned long n)
test_dict_noalloc(size_t n)
{
foo_tree_t footree;
NEDTRIE_INIT(&footree);
+3 -3
View File
@@ -72,7 +72,7 @@ static void test_rbtree(size_t n)
/********************************************************************************************/
static void
test_dict1(unsigned long n)
test_dict1(size_t n)
{
QMap<unsigned long, unsigned long> dict;
@@ -92,7 +92,7 @@ test_dict1(unsigned long n)
/********************************************************************************************/
static void
test_dict2(unsigned long n)
test_dict2(size_t n)
{
QHash<unsigned long, unsigned long> dict;
@@ -126,7 +126,7 @@ uint qHash(const char_array_s &k)
};
static void
test_dict_big(unsigned long n)
test_dict_big(size_t n)
{
QHash<char_array_s, char_array_s> dict;
+3 -3
View File
@@ -25,7 +25,7 @@ using namespace std;
/********************************************************************************************/
static void
test_dict2(unsigned long n)
test_dict2(size_t n)
{
sparse_hash_map<unsigned long, unsigned long> dict;
@@ -63,7 +63,7 @@ namespace std {
}
static void
test_dict_big(unsigned long n)
test_dict_big(size_t n)
{
sparse_hash_map<char_array_s, char_array_s> dict;
@@ -87,7 +87,7 @@ test_dict_big(unsigned long n)
/********************************************************************************************/
static void
test_dict_str(unsigned long n)
test_dict_str(size_t n)
{
sparse_hash_map<string, string> dict;
+11 -11
View File
@@ -73,7 +73,7 @@ static void test_rbtree(size_t n)
/********************************************************************************************/
static void
test_dict1(unsigned long n)
test_dict1(size_t n)
{
map<unsigned long, unsigned long> dict;
@@ -93,7 +93,7 @@ test_dict1(unsigned long n)
/********************************************************************************************/
static void
test_dict2(unsigned long n)
test_dict2(size_t n)
{
unordered_map<unsigned long, unsigned long> dict;
@@ -131,7 +131,7 @@ namespace std {
}
static void
test_dict_big(unsigned long n)
test_dict_big(size_t n)
{
unordered_map<char_array_s, char_array_s> dict;
@@ -155,19 +155,19 @@ test_dict_big(unsigned long n)
/********************************************************************************************/
static void
test_dict_str(unsigned long n)
test_dict_str(size_t n)
{
unordered_map<string, string> dict;
for (size_t i = 0; i < n; i++) {
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
string s1 = to_string(rand_get());
string s2 = to_string(rand_get());
dict[s1] = s2;
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
string s1 = to_string (rand_get());
unordered_map<string, string>::iterator it = dict.find(s1);
if (it != dict.end())
s ++;
@@ -176,19 +176,19 @@ test_dict_str(unsigned long n)
}
static void
test_dict_str2(unsigned long n)
test_dict_str2(size_t n)
{
map<string, string> dict;
for (size_t i = 0; i < n; i++) {
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
string s1 = to_string(rand_get());
string s2 = to_string(rand_get());
dict[s1] = s2;
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
string s1 = to_string(rand_get());
map<string, string>::iterator it = dict.find(s1);
if (it != dict.end())
s ++;
+269 -49
View File
@@ -35,7 +35,15 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Update of integrating M*LIB done by Patrick Pelissier */
/* Update of integrating M*LIB, LIBSRT & SDS done by Patrick Pelissier */
/*
* Benchmark based on the features tested by benchmark seen here:
* http://www.utilitycode.com/str/performance.aspx
*
* The idea is to measure the performance empty constructors, char *
* constructors, assignment, concatenation and scanning.
*/
#include <stdio.h>
#include <time.h>
@@ -56,53 +64,52 @@
#include "sstring.h"
#endif
/*
* Benchmark based on the features tested by benchmark seen here:
* http://www.utilitycode.com/str/performance.aspx
*
* The idea is to measure the performance empty constructors, char *
* constructors, assignment, concatenation and scanning. But rather than
* comparing MFC's CString to Str Library, we are going to compare STL to
* CBString.
*
* The results are interesting. CBString basically beats std::string quite
* severely, except for the empty constructor.
*/
#ifdef BENCH_CAN_USE_SDS
extern "C" {
#include "sds.h"
};
#endif
#if defined (BENCH_CAN_USE_STL)
#include <string>
#endif
#if defined (BENCH_CAN_USE_RAPIDSTRING)
#define NDEBUG
#include "rapidstring.h"
#endif
#define TEST_SECONDS (5)
int timeTest (double &res, int (*testfn) (int count), int count) {
clock_t t0, t1;
int p = 0;
double x, c = 0;
t0 = clock ();
do {
p += testfn (count);
t1 = clock ();
c += count;
if (t1 == t0) {
if (count < (INT_MAX / 2)) count += count;
continue;
}
if (t1 - t0 >= TEST_SECONDS*CLOCKS_PER_SEC) break;
x = (TEST_SECONDS*CLOCKS_PER_SEC - (t1 - t0)) * c / (t1 - t0);
if (x > INT_MAX) x = INT_MAX;
count = (int) x;
if (count < 1000) count = 1000;
} while (1);
res = c * CLOCKS_PER_SEC / (t1 - t0);
return p;
clock_t t0, t1;
int p = 0;
double x, c = 0;
t0 = clock ();
do {
p += testfn (count);
t1 = clock ();
c += count;
if (t1 == t0) {
if (count < (INT_MAX / 2)) count += count;
continue;
}
if (t1 - t0 >= TEST_SECONDS*CLOCKS_PER_SEC) break;
x = (TEST_SECONDS*CLOCKS_PER_SEC - (t1 - t0)) * c / (t1 - t0);
if (x > INT_MAX) x = INT_MAX;
count = (int) x;
if (count < 1000) count = 1000;
} while (1);
res = c * CLOCKS_PER_SEC / (t1 - t0);
return p;
}
#define TESTSTRING1 ("<sometag name=\"John Doe\" position=\"Executive VP Marketing\"/>")
@@ -280,7 +287,7 @@ int testCBS_replace (int count) {
int testSRT_emptyCtor (int count) {
int i, c = 0;
for (c=i=0; i < count; i++) {
ss_t *b = ss_alloc(0);
srt_string *b = ss_alloc(0);
c += ss_size(b) ^i;
ss_free(&b);
}
@@ -290,7 +297,7 @@ int testSRT_emptyCtor (int count) {
int testSRT_nonemptyCtor (int count) {
int i, c = 0;
for (c=i=0; i < count; i++) {
ss_t *b = ss_dup_c(TESTSTRING1);
srt_string *b = ss_dup_c(TESTSTRING1);
c += ss_size(b) ^i;
ss_free(&b);
}
@@ -299,7 +306,7 @@ int testSRT_nonemptyCtor (int count) {
int testSRT_cstrAssignment (int count) {
int i, c = 0;
ss_t *b = ss_alloc(0);
srt_string *b = ss_alloc(0);
for (c=i=0; i < count; i++) {
ss_cpy_cn(&b, TESTSTRING1, strlen(TESTSTRING1));
c += ss_size(b) ^i;
@@ -310,7 +317,7 @@ int testSRT_cstrAssignment (int count) {
int testSRT_extraction (int count) {
int i, c = 0;
ss_t *b = ss_dup_c(TESTSTRING1);
srt_string *b = ss_dup_c(TESTSTRING1);
for (c=i=0; i < count; i++) {
c += ss_at(b,(i & 7));
c += ss_at(b,(i & 7) ^ 8);
@@ -322,7 +329,7 @@ int testSRT_extraction (int count) {
int testSRT_scan (int count) {
int i, c = 0;
ss_t *b = ss_dup_c("Dot. 123. Some more data.");
srt_string *b = ss_dup_c("Dot. 123. Some more data.");
for (c=i=0; i < count; i++) {
c += ss_findc (b, 0, '.');
c += ss_find_cn (b, 0, "123", strlen("123"));
@@ -336,8 +343,8 @@ int testSRT_scan (int count) {
int testSRT_concat (int count) {
int i, j, c = 0;
ss_t *a = ss_dup_c(TESTSTRING1);
ss_t *accum = ss_alloc(0);
srt_string *a = ss_dup_c(TESTSTRING1);
srt_string *accum = ss_alloc(0);
for (j=0; j < count; j++) {
ss_cpy_c(&accum, "");
@@ -455,6 +462,168 @@ int testMLIB_replace (int count) {
}
#endif
#ifdef BENCH_CAN_USE_SDS
int testSDS_emptyCtor (int count) {
int i, c = 0;
for (c=i=0; i < count; i++) {
sds b;
b = sdsempty();
c += sdslen(b) ^ i;
sdsfree(b);
}
return c;
}
int testSDS_nonemptyCtor (int count) {
int i, c = 0;
for (c=i=0; i < count; i++) {
sds b;
b = sdsnew(TESTSTRING1);
c += sdslen(b) ^i;
sdsfree(b);
}
return c;
}
int testSDS_cstrAssignment (int count) {
int i, c = 0;
sds b;
b = sdsempty();
for (c=i=0; i < count; i++) {
b = sdscpy(b, TESTSTRING1);
c += sdslen(b) ^i;
}
sdsfree(b);
return c;
}
int testSDS_extraction (int count) {
int i, c = 0;
sds b;
b = sdsnew(TESTSTRING1);
for (c=i=0; i < count; i++) {
c += b[(i & 7)];
c += b[(i & 7) ^ 8];
c += b[(i & 7) ^ 4] ^i;
}
sdsfree(b);
return c;
}
int testSDS_scan (int count) {
int i, c = 0;
sds b;
b = sdsnew("Dot. 123. Some more data.");
for (c=i=0; i < count; i++) {
c += (intptr_t) strchr(b, '.');
c += (intptr_t) strstr (b, "123");
c += (intptr_t) strpbrk (b, "sm") ^i;
}
sdsfree(b);
return c;
}
int testSDS_concat (int count) {
int i, j, c = 0;
sds a, accum;
a = sdsnew(TESTSTRING1);
accum = sdsempty();
for (j=0; j < count; j++) {
accum = sdscpy(accum, "");
for (i=0; i < 250; i++) {
accum = sdscat(accum, a);
accum = sdscat(accum, "!!");
c += sdslen(accum) ^i;
}
}
sdsfree(a);
sdsfree(accum);
return c;
}
// Not found
//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);
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);
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);
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;
}
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, "!!");
c += rs_len(&accum) ^i;
}
}
rs_free(&a);
rs_free(&accum);
return c;
}
#endif
#define NTESTS 7
struct flags {
int runtest[NTESTS];
@@ -583,7 +752,58 @@ int benchTest (const struct flags * runflags) {
printf ("M*LIB string replace: %20.1f per second\n", cps);
}
#endif
return c;
#ifdef BENCH_CAN_USE_SDS
if (runflags->runtest[0]) {
c += timeTest (cps, testSDS_emptyCtor, 100000);
printf ("SDS string empty constructor: %20.1f per second\n", cps);
}
if (runflags->runtest[1]) {
c += timeTest (cps, testSDS_nonemptyCtor, 100000);
printf ("SDS string non-empty constructor: %20.1f per second\n", cps);
}
if (runflags->runtest[2]) {
c += timeTest (cps, testSDS_cstrAssignment, 100000);
printf ("SDS string char * assignment: %20.1f per second\n", cps);
}
if (runflags->runtest[3]) {
c += timeTest (cps, testSDS_extraction, 100000);
printf ("SDS string char extraction: %20.1f per second\n", cps);
}
if (runflags->runtest[4]) {
c += timeTest (cps, testSDS_scan, 100000);
printf ("SDS string scan: %20.1f per second\n", cps);
}
if (runflags->runtest[5]) {
c += timeTest (cps, testSDS_concat, 10);
printf ("SDS string concatenation: %20.1f per second\n", cps * 250);
}
#endif
#ifdef BENCH_CAN_USE_RAPIDSTRING
if (runflags->runtest[0]) {
c += timeTest (cps, testRAPIDSTRING_emptyCtor, 100000);
printf ("RAPIDSTRING empty constructor: %20.1f per second\n", cps);
}
if (runflags->runtest[1]) {
c += timeTest (cps, testRAPIDSTRING_nonemptyCtor, 100000);
printf ("RAPIDSTRING non-empty constructor: %20.1f per second\n", cps);
}
if (runflags->runtest[2]) {
c += timeTest (cps, testRAPIDSTRING_cstrAssignment, 100000);
printf ("RAPIDSTRING char * assignment: %20.1f per second\n", cps);
}
if (runflags->runtest[3]) {
c += timeTest (cps, testRAPIDSTRING_extraction, 100000);
printf ("RAPIDSTRING char extraction: %20.1f per second\n", cps);
}
if (runflags->runtest[5]) {
c += timeTest (cps, testRAPIDSTRING_concat, 10);
printf ("RAPIDSTRING concatenation: %20.1f per second\n", cps * 250);
}
#endif
return c;
}
int main (int argc, char * argv[]) {
+2 -2
View File
@@ -124,7 +124,7 @@ static int equal_func(const void* arg, const void *obj_p)
}
static void
test_dict(unsigned long n)
test_dict(size_t n)
{
tommy_hashlin dict;
tommy_hashlin_init(&dict);
@@ -174,7 +174,7 @@ static size_t char_hash(const char *s)
}
static void
test_dict_big(unsigned long n)
test_dict_big(size_t n)
{
tommy_hashlin dict;
tommy_hashlin_init(&dict);
+2 -2
View File
@@ -85,7 +85,7 @@ struct hash_i_node_s {
};
static void
test_dict(unsigned long n)
test_dict(size_t n)
{
struct hash_i_node_s *dict = NULL;
@@ -131,7 +131,7 @@ struct hash_b_node_s {
};
static void
test_dict_big(unsigned long n)
test_dict_big(size_t n)
{
struct hash_b_node_s *dict = NULL;
+3
View File
@@ -63,6 +63,9 @@ cputime (void)
#endif
unsigned long g_result;
#if defined(MULTI_THREAD_MEASURE)
M_THREAD_ATTR
#endif
unsigned int randValue = 0;
static void rand_init(void)
+180 -206
View File
@@ -3,50 +3,51 @@
//
// Original version Contributed by Jeremy Zerfas
// M*LIB port contributed by Patrick Pélissier
// gcc -O2 -march=native nucleotide.c -I../.. -std=c11 -lpthread -DNDEBUG
#define NDEBUG
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <assert.h>
#include "m-worker.h"
#include "m-dict.h"
#include "m-bptree.h"
// This controls the maximum length for each set of oligonucleotide frequencies
// and each oligonucleotide count output by this program.
#define MAXIMUM_OUTPUT_LENGTH 4096
// Define Open Addressing dictionnary. Need to define how to handle out of bound data.
static inline bool oor_equal_p(uint64_t k, unsigned char n)
// Number of outputs to display
#define MAXMUM_NUMBER_OUTPUT 7
/* Define the needed containers */
/* Define Open Addressing dictionary of uint64_t --> uint32_t. Need to define how to handle out of bound data. */
static inline bool my_oor_equal_p(uint64_t k, unsigned char n)
{
return k == ~(uint64_t) n;
}
static inline void oor_set(uint64_t *k, unsigned char n)
static inline void my_oor_set(uint64_t *k, unsigned char n)
{
*k = ~(uint64_t)n;
}
// Custom hash function.
static inline size_t my_hash(uint64_t key)
{
return ((key) ^ (key)>>7);
}
// Define a dictionnary of uint64_t --> uint32_t
static inline void update_val(uint32_t *p, uint32_t v) { *p += v;}
DICT_OA_DEF2(dict_oligonucleotide,
uint64_t, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
uint32_t, M_DEFAULT_OPLIST)
// Define oplist of dictionary
#define OLIGONUCLEOTIDE_OPLIST DICT_OPLIST(dict_oligonucleotide, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(oor_hash), OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)), M_DEFAULT_OPLIST)
uint64_t, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(my_oor_equal_p), OOR_SET(my_oor_set M_IPTR)),
uint32_t, M_OPEXTEND(M_DEFAULT_OPLIST, UPDATE(update_val M_IPTR)))
#define M_OPL_dict_oligonucleotide_t() DICT_OPLIST(dict_oligonucleotide, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(my_oor_equal_p), OOR_SET(my_oor_set M_IPTR)), M_DEFAULT_OPLIST)
typedef struct {
uint64_t key;
uint32_t value;
} element;
// Define a B*TREE-21 of uint32_t --> uint64_t and register its oplist
#define TREE_CMP(a,b) ((a) > (b) ? -1 : (a) < (b)) /* reverse natural order */
BPTREE_DEF2(tree_dict_oligonucleotide, 21, uint32_t, M_OPEXTEND(M_DEFAULT_OPLIST, CMP(TREE_CMP)), uint64_t, M_DEFAULT_OPLIST)
#define M_OPL_tree_dict_oligonucleotide_t() BPTREE_OPLIST2(tree_dict_oligonucleotide, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
/* Define the data to analyse (a plain array) */
ARRAY_DEF(polynucleotide, unsigned char)
// Macro to convert a nucleotide character to a code. Note that upper and lower
// case ASCII letters only differ in the fifth bit from the right and we only
@@ -55,143 +56,167 @@ typedef struct {
// characters other than 'A', 'C', 'G', and 'T' aren't used.
#define CODE_FOR_NUCLEOTIDE(nucleotide) (" \0 \1\3 \2"[nucleotide & 0x7])
// And one more macro to convert the codes back to nucleotide characters.
#define NUCLEOTIDE_FOR_CODE(code) ("ACGT"[code & 0x3])
static worker_t worker;
// Function to use when sorting elements with qsort() later. Elements with
// larger values will come first and in cases of identical values then elements
// with smaller keys will come first.
static int element_Compare(const void *a, const void *b)
// Read from the given stream the data and fill in the array with the converted one.
static void polynucleotide_init_stream(polynucleotide_t p, FILE *stream)
{
const element * const left_Element = a;
const element * const right_Element = b;
// Sort based on element values.
if(left_Element->value < right_Element->value) return 1;
if(left_Element->value > right_Element->value) return -1;
// If we got here then both items have the same value so then sort based on
// key.
return left_Element->key > right_Element->key ? 1 : -1;
char buffer[MAXIMUM_OUTPUT_LENGTH], c;
polynucleotide_init(p);
polynucleotide_reserve(p, MAXIMUM_OUTPUT_LENGTH);
// Find the start of the third polynucleotide.
while(fgets(buffer, sizeof(buffer), stream) && memcmp(">THREE", buffer, 6));
// Start reading and encoding the third polynucleotide.
while(fgets(buffer, sizeof(buffer), stream) && buffer[0]!='>'){
for(size_t i = 0; (c = buffer[i]) !='\0'; i++) {
if (c != '\n') {
polynucleotide_push_back(p, CODE_FOR_NUCLEOTIDE(c));
}
}
}
}
// Generate frequencies for all oligonucleotides in polynucleotide that are of
// desired_Length_For_Oligonucleotides and then save it to output.
static void
generate_Frequencies_For_Desired_Length_Oligonucleotides(const char polynucleotide[],
const int polynucleotide_Length,
const int desired_Length_For_Oligonucleotides,
char * const output)
{
assert (2*desired_Length_For_Oligonucleotides <= 64);
dict_oligonucleotide_t hash_Table;
dict_oligonucleotide_init(hash_Table);
uint64_t key=0;
const uint64_t mask=(1ULL<<(2*desired_Length_For_Oligonucleotides))-1;
// This is the function which does 95% of the work.
/* NOTE: paralelisation is not done by cutting the input set in two.
This is not efficient as the size of the output table will be the same
as for the whole table. */
static void init_hash(dict_oligonucleotide_t hash_Table, const size_t size, const unsigned char tab[size], const size_t desiredLength, const size_t offset, const size_t skip)
{
uint64_t key = 0;
const uint64_t mask = (1ULL<<(2*desiredLength))-1;
assert (2*desiredLength < 64 && desiredLength < size);
assert ((1 == skip || 4 == skip) && offset < size);
// For the first several nucleotides we only need to append them to key in
// preparation for the insertion of complete oligonucleotides to hash_Table.
for(int i=0; i<desired_Length_For_Oligonucleotides-1; i++)
key=(key<<2 & mask) | polynucleotide[i];
// preparation for the insertion of complete oligonucleotides to hash.
for(size_t i = 0; i < desiredLength - 1 + offset; i++)
key = (key<<2) | tab[i];
key &= mask;
dict_oligonucleotide_t hash;
dict_oligonucleotide_init(hash);
// Add all the complete oligonucleotides of
// desired_Length_For_Oligonucleotides to hash_Table and update the count
// for each oligonucleotide.
for(int i=desired_Length_For_Oligonucleotides-1
; i<polynucleotide_Length; i++){
key=(key<<2 & mask) | polynucleotide[i];
uint32_t *p = dict_oligonucleotide_get(hash_Table, key);
if (p != NULL)
(*p) ++;
else {
dict_oligonucleotide_set_at(hash_Table, key, 1);
// desiredLength to hash, updating their count
if (skip == 1) {
for(size_t i = desiredLength-1+offset ; i < size; i++) {
key = (key<<2) | tab[i+0];
key &= mask;
uint32_t *p = dict_oligonucleotide_get(hash, key);
if (p != NULL) {
(*p) ++;
} else {
dict_oligonucleotide_set_at(hash, key, 1);
}
}
} else { // skip = 4
for(size_t i = desiredLength-1+offset ; i < size; i+=4) {
for (size_t j = 0; j < 4; j++)
key = (key<<2) | tab[i+j];
key &= mask;
uint32_t *p = dict_oligonucleotide_get(hash, key);
if (p != NULL) {
(*p) ++;
} else {
dict_oligonucleotide_set_at(hash, key, 1);
}
}
}
// Create an array of elements from hash_Table.
int elements_Array_Size=dict_oligonucleotide_size(hash_Table), i=0;
element * elements_Array=malloc(elements_Array_Size*sizeof(element));
if (!elements_Array) abort();
for M_EACH(item, hash_Table, OLIGONUCLEOTIDE_OPLIST) {
elements_Array[i++]=((element){item->key, item->value});
}
// Clear the hash table
dict_oligonucleotide_clear(hash_Table);
// Sort elements_Array.
qsort(elements_Array, elements_Array_Size, sizeof(element), element_Compare);
// Print the frequencies for each oligonucleotide.
for(int output_Position=0, i=0; i<elements_Array_Size; i++) {
// Convert the key for the oligonucleotide to a string.
char oligonucleotide[desired_Length_For_Oligonucleotides+1];
for(int j=desired_Length_For_Oligonucleotides-1; j>-1; j--){
oligonucleotide[j]=NUCLEOTIDE_FOR_CODE(elements_Array[i].key);
elements_Array[i].key>>=2;
}
oligonucleotide[desired_Length_For_Oligonucleotides]='\0';
// Output the frequency for oligonucleotide to output.
output_Position+=snprintf(output+output_Position
, MAXIMUM_OUTPUT_LENGTH-output_Position, "%s %.3f\n", oligonucleotide
, 100.0f*elements_Array[i].value
/(polynucleotide_Length-desired_Length_For_Oligonucleotides+1));
}
free(elements_Array);
dict_oligonucleotide_init_move(hash_Table, hash);
}
static void compute_hash(dict_oligonucleotide_t hash_Table, const polynucleotide_t p, const size_t desiredLength)
{
size_t size = polynucleotide_size(p);
unsigned char *tab = polynucleotide_get(p, 0);
if (desiredLength < 8) {
init_hash(hash_Table, size, tab, desiredLength, 0, 1);
return;
}
worker_sync_t block; // Define a synchronization block
worker_start(block, worker);
dict_oligonucleotide_t hash_Table3, *p_hash_Table3 = &hash_Table3;
dict_oligonucleotide_t hash_Table2, *p_hash_Table2 = &hash_Table2;
dict_oligonucleotide_t hash_Table1, *p_hash_Table1 = &hash_Table1;
WORKER_SPAWN(block, (p_hash_Table1, size, tab, desiredLength), {
init_hash(*p_hash_Table1, size, tab, desiredLength, 3, 4);
}, (/*no output*/));
WORKER_SPAWN(block, (p_hash_Table2, size, tab, desiredLength), {
init_hash(*p_hash_Table2, size, tab, desiredLength, 2, 4);
}, (/*no output*/));
WORKER_SPAWN(block, (p_hash_Table3, size, tab, desiredLength), {
init_hash(*p_hash_Table3, size, tab, desiredLength, 1, 4);
}, (/*no output*/));
init_hash(hash_Table, size, tab, desiredLength, 0, 4);
worker_sync(block);
// Merge all hashtables
dict_oligonucleotide_splice(hash_Table, hash_Table1);
dict_oligonucleotide_splice(hash_Table, hash_Table2);
dict_oligonucleotide_splice(hash_Table, hash_Table3);
// Clear extra hashtables
dict_oligonucleotide_clear(hash_Table3);
dict_oligonucleotide_clear(hash_Table2);
dict_oligonucleotide_clear(hash_Table1);
}
// Generate frequencies for all oligonucleotides in polynucleotide that are of
// desiredLength and then save it to output.
static void compute_freq(const polynucleotide_t p, const size_t desiredLength, char output[])
{
dict_oligonucleotide_t hash_Table;
compute_hash(hash_Table, p, desiredLength);
// Order key is the count frequency (inverse value & key)
tree_dict_oligonucleotide_t tree;
tree_dict_oligonucleotide_init(tree);
for M_EACH(item, hash_Table, dict_oligonucleotide_t) {
tree_dict_oligonucleotide_set_at (tree, item->value, item->key);
}
// Create Output
char oligonucleotide[64];
const double invSum = 100.0 / (double) (polynucleotide_size(p) - desiredLength + 1);
int output_Position = 0;
for M_EACH(item, tree, tree_dict_oligonucleotide_t) {
// Convert the key for the oligonucleotide to a string.
uint64_t freq = *item->value_ptr;
uint32_t count = *item->key_ptr;
for(size_t j = desiredLength-1; j < desiredLength; j--){
oligonucleotide[j]=NUCLEOTIDE_FOR_CODE(freq);
freq>>=2;
}
oligonucleotide[desiredLength]='\0';
// Output the frequency for oligonucleotide to output.
output_Position+=snprintf(output+output_Position, MAXIMUM_OUTPUT_LENGTH-output_Position,
"%s %.3f\n", oligonucleotide, invSum * count);
}
dict_oligonucleotide_clear(hash_Table);
tree_dict_oligonucleotide_clear(tree);
}
// Generate a count for the number of times oligonucleotide appears in
// polynucleotide and then save it to output.
static void
generate_Count_For_Oligonucleotide(const char * const polynucleotide,
const int polynucleotide_Length,
const char * const oligonucleotide,
char * const output)
static void compute_count(polynucleotide_t p, const char oligonucleotide[], char output[])
{
const int oligonucleotide_Length=strlen(oligonucleotide);
assert (2*oligonucleotide_Length <= 64);
const size_t oligonucleotide_Length = strlen(oligonucleotide);
dict_oligonucleotide_t hash_Table;
dict_oligonucleotide_init(hash_Table);
uint64_t key = 0;
const uint64_t mask=(1ULL<<(2*oligonucleotide_Length))-1;
// For the first several nucleotides we only need to append them to key in
// preparation for the insertion of complete oligonucleotides to hash_Table.
for(int i=0; i<oligonucleotide_Length-1; i++)
key=(key<<2 & mask) | polynucleotide[i];
// Add all the complete oligonucleotides of oligonucleotide_Length to
// hash_Table and update the count for each oligonucleotide.
for(int i=oligonucleotide_Length-1; i<polynucleotide_Length; i++){
key=(key<<2 & mask) | polynucleotide[i];
uint32_t *p = dict_oligonucleotide_get(hash_Table, key);
if (p != NULL)
(*p) ++;
else {
dict_oligonucleotide_set_at(hash_Table, key, 1);
}
}
compute_hash(hash_Table, p, oligonucleotide_Length);
// Generate the key for oligonucleotide.
key=0;
for(int i=0; i<oligonucleotide_Length; i++)
key=(key<<2) | CODE_FOR_NUCLEOTIDE(oligonucleotide[i]);
uint64_t key=0;
for(size_t i=0; i<oligonucleotide_Length; i++)
key = (key<<2) | CODE_FOR_NUCLEOTIDE(oligonucleotide[i]);
// Output the count for oligonucleotide to output.
uint32_t *p = dict_oligonucleotide_get(hash_Table, key);
uintmax_t count= p== NULL ? 0 : *p;
uint32_t *val = dict_oligonucleotide_get(hash_Table, key);
uintmax_t count= val== NULL ? 0 : *val;
snprintf(output, MAXIMUM_OUTPUT_LENGTH, "%ju\t%s", count, oligonucleotide);
dict_oligonucleotide_clear(hash_Table);
@@ -199,94 +224,43 @@ generate_Count_For_Oligonucleotide(const char * const polynucleotide,
int main()
{
char buffer[MAXIMUM_OUTPUT_LENGTH];
worker_t worker;
// Initialize the different worker threads by auto-detecting the number of cores of the system
worker_init(worker, 0, 1, NULL);
worker_init(worker, -1, 0, NULL);
// Read the input
polynucleotide_t p, *ptr = &p;
polynucleotide_init_stream(p, stdin);
// Find the start of the third polynucleotide.
while(fgets(buffer, sizeof(buffer), stdin) && memcmp(">THREE", buffer
, sizeof(">THREE")-1));
// Start with 1 MB of storage for reading in the polynucleotide and grow
// geometrically.
int polynucleotide_Capacity=1048576;
int polynucleotide_Length=0;
char * polynucleotide=malloc(polynucleotide_Capacity);
if (!polynucleotide) abort();
// Start reading and encoding the third polynucleotide.
while(fgets(buffer, sizeof(buffer), stdin) && buffer[0]!='>'){
for(int i=0; buffer[i]!='\0'; i++)
if(buffer[i]!='\n')
polynucleotide[polynucleotide_Length++]
=CODE_FOR_NUCLEOTIDE(buffer[i]);
// Make sure we still have enough memory allocated for any potential
// nucleotides in the next line.
if(polynucleotide_Capacity-polynucleotide_Length<sizeof(buffer)) {
polynucleotide=realloc(polynucleotide, polynucleotide_Capacity*=2);
if (!polynucleotide) abort();
}
}
char output_Buffer[7][MAXIMUM_OUTPUT_LENGTH];
char (*output)[MAXIMUM_OUTPUT_LENGTH] = output_Buffer;
// Prepare outputs
char outputBuffer[MAXMUM_NUMBER_OUTPUT][MAXIMUM_OUTPUT_LENGTH];
char (*output)[MAXIMUM_OUTPUT_LENGTH] = outputBuffer;
// Do the following functions in parallel.
// Define a synchronization block
worker_sync_t block;
worker_start(block);
worker_sync_t block; // Define a synchronization block
worker_start(block, worker);
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
generate_Count_For_Oligonucleotide(polynucleotide,
polynucleotide_Length,
"GGTATTTTAATTTATAGT", output[6]);
WORKER_SPAWN(block, (ptr, output), {
compute_count(*ptr, "GGTATTTTAATTTATAGT", output[6]);
}, (/*no output*/));
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
generate_Count_For_Oligonucleotide(polynucleotide,
polynucleotide_Length,
"GGTATTTTAATT", output[5]);
WORKER_SPAWN(block, (ptr, output), {
compute_count(*ptr, "GGTATTTTAATT", output[5]);
}, (/*no output*/));
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
generate_Count_For_Oligonucleotide(polynucleotide,
polynucleotide_Length,
"GGTATT", output[4]);
WORKER_SPAWN(block, (ptr, output), {
compute_count(*ptr, "GGTATT", output[4]);
}, (/*no output*/));
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
generate_Count_For_Oligonucleotide(polynucleotide,
polynucleotide_Length,
"GGTA", output[3]);
WORKER_SPAWN(block, (ptr, output), {
compute_count(*ptr, "GGTA", output[3]);
}, (/*no output*/));
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
generate_Count_For_Oligonucleotide(polynucleotide,
polynucleotide_Length,
"GGT", output[2]);
}, (/*no output*/));
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
generate_Frequencies_For_Desired_Length_Oligonucleotides(polynucleotide,
polynucleotide_Length,
2,
output[1]);
}, (/*no output*/));
generate_Frequencies_For_Desired_Length_Oligonucleotides(polynucleotide,
polynucleotide_Length,
1,
output[0]);
compute_count(*ptr, "GGT", output[2]);
compute_freq(*ptr, 2, output[1]);
compute_freq(p, 1, output[0]);
worker_sync(block);
// Output the results to stdout.
for(int i=0; i<7; i++)
printf("%s\n", output_Buffer[i]);
for(int i=0; i<MAXMUM_NUMBER_OUTPUT; i++)
printf("%s\n", outputBuffer[i]);
free(polynucleotide);
polynucleotide_clear(p);
worker_clear(worker);
return 0;
+53
View File
@@ -0,0 +1,53 @@
CC= gcc
CXX= g++
CFLAGS= -g -Wall -O2 -fomit-frame-pointer -march=native -lm -include stddef.h
CXXFLAGS= $(CFLAGS)
LDFLAGS=
OBJS=
LIBS= -lm
all: run
benchmarks:
git clone https://github.com/attractivechaos/benchmarks.git
build: benchmarks
mkdir -p benchmarks/udb/mlib
cp test-mlib.c benchmarks/udb/mlib/test.c
cp Makefile-mlib benchmarks/udb/mlib/Makefile
mkdir -p benchmarks/udb/mlib-oa
cp test-mlib-oa.c benchmarks/udb/mlib-oa/test.c
cp Makefile-mlib benchmarks/udb/mlib-oa/Makefile
touch build
all-recur: build
cd benchmarks/udb; \
wdir=`pwd`; \
list_c=`find . -name 'test.c'`; \
list_cc=`find . -name 'test.cc'`; \
for t in $$list_c $$list_cc ; do \
subdir=`dirname $$t`; \
cd $$subdir; \
$(MAKE) CC="$(CC)" CXX="$(CXX)" DFLAGS="$(DFLAGS)" CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" || exit 1; \
cd $$wdir; \
done;
run: all-recur
@cd benchmarks/udb; \
echo ; echo "LIBRARY | INT TIME | STR TIME" ; \
for i in `find . -name 'test'` ; do \
printf "%s|" `dirname $$i|sed -e 's+./++g'`; \
$$i -is | awk ' \
/\[int data\] # element/ { nbInt= $$5 } \
/\[int data\] CPU time/ {timeInt= $$5 } \
/\[str data\] # element/ { nbStr= $$5 } \
/\[str data\] CPU time/ {timeStr= $$5 } \
END { \
if (nbInt != 624444) timeInt="BRK" ; \
if (nbStr != 624444) timeStr="BRK" ; \
print timeInt,"|" ,timeStr \
}' ; \
done
clean:
rm -rf benchmarks build
+22
View File
@@ -0,0 +1,22 @@
CC= gcc
CFLAGS= -g -Wall -O2 -march=native
OBJS= ../benchmark/benchmark.o ../runit/runlib.o test.o
DFLAGS=
INCLUDES= -I../benchmark -I../runit -I../../../../..
LIBS=
.SUFFIXES:.c .o
.c.o:
$(CC) -std=gnu11 -DNDEBUG -c $(INCLUDES) $(CFLAGS) $(DFLAGS) $< -o $@
all:test
test:$(OBJS)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
cleanlocal:
rm -f *.o a.out *~ test
clean:cleanlocal
+78
View File
@@ -0,0 +1,78 @@
#ifndef NDEBUG
#define NDEBUG
#endif
#undef NDEBUG
#include <string.h>
#include "benchmark.h"
#include "m-dict.h"
#include "m-mempool.h"
static inline bool oor_equal_p(int k, unsigned char n)
{
return k == (int)-n - 1;
}
static inline void oor_set(int *k, unsigned char n)
{
*k = (int)-n - 1;
}
DICT_OA_DEF2(dict_int,
int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
int, M_DEFAULT_OPLIST)
static const char *const oor[2] = { "EMPTY", "DELETED" };
static inline bool str_oor_equal_p(const char *k, unsigned char n)
{
return k == oor[n];
}
static inline void str_oor_set(const char * *k, unsigned char n)
{
*k = oor[n];
}
DICT_OA_DEF2(dict_str, const char *,
M_OPEXTEND (M_CSTR_OPLIST, OOR_EQUAL(str_oor_equal_p), OOR_SET(str_oor_set M_IPTR)),
int, M_DEFAULT_OPLIST)
int test_int(int N, const unsigned *data)
{
int ret;
M_LET(h, DICT_OPLIST(dict_int)) {
for (int i = 0; i < N; ++i) {
if (dict_int_get (h, data[i]) == NULL) {
dict_int_set_at (h, data[i], i);
} else {
dict_int_remove(h, data[i]);
}
}
ret = (int)dict_int_size(h);
}
return ret;
}
int test_str(int N, char * const *data)
{
int ret;
M_LET(h, DICT_OPLIST(dict_str)) {
for (int i = 0; i < N; ++i) {
if (dict_str_get (h, data[i]) == NULL) {
dict_str_set_at (h, data[i], i);
} else {
dict_str_remove(h, data[i]);
}
}
ret = (int)dict_str_size(h);
}
return ret;
}
int main(int argc, char *argv[])
{
return udb_benchmark(argc, argv, test_int, test_str);
}
+53
View File
@@ -0,0 +1,53 @@
#include <string.h>
#include "benchmark.h"
#include "m-dict.h"
#include "m-mempool.h"
DICT_DEF2(dict_int,
int, M_OPEXTEND(M_DEFAULT_OPLIST, MEMPOOL(mpool_int), MEMPOOL_LINKAGE(static)),
int, M_DEFAULT_OPLIST)
DICT_DEF2(dict_str,
const char *, M_OPEXTEND (M_CSTR_OPLIST, MEMPOOL(mpool_str), MEMPOOL_LINKAGE(static)),
int, M_DEFAULT_OPLIST)
int test_int(int N, const unsigned *data)
{
int ret;
dict_int_list_pair_mempool_init(mpool_int);
M_LET(h, DICT_OPLIST(dict_int)) {
for (int i = 0; i < N; ++i) {
if (dict_int_get (h, data[i]) == NULL) {
dict_int_set_at (h, data[i], i);
} else {
dict_int_remove(h, data[i]);
}
}
ret = (int)dict_int_size(h);
}
dict_int_list_pair_mempool_clear(mpool_int);
return ret;
}
int test_str(int N, char * const *data)
{
int ret;
dict_str_list_pair_mempool_init(mpool_str);
M_LET(h, DICT_OPLIST(dict_str)) {
for (int i = 0; i < N; ++i) {
if (dict_str_get (h, data[i]) == NULL) {
dict_str_set_at (h, data[i], i);
} else {
dict_str_remove(h, data[i]);
}
}
ret = (int)dict_str_size(h);
}
dict_str_list_pair_mempool_clear(mpool_str);
return ret;
}
int main(int argc, char *argv[])
{
return udb_benchmark(argc, argv, test_int, test_str);
}
+33
View File
@@ -0,0 +1,33 @@
CC= gcc
CXX= g++
CFLAGS= -g -Wall -O2 -fomit-frame-pointer -march=native -lm -include stddef.h
CXXFLAGS= $(CFLAGS)
LDFLAGS=
OBJS=
LIBS=
all: run
udb2:
git clone https://github.com/attractivechaos/udb2.git
build: udb2
mkdir -p udb2/mlib
cp test-mlib.c udb2/mlib/test.c
cp Makefile-mlib udb2/mlib/Makefile
touch build
all-recur: build
cd udb2/stb && make CC="gcc -lm"
cd udb2 && for dir in `ls | egrep -v '^(Makefile|common.c|_)'`; do cd $$dir && make && cd -; done
run: all-recur
@cd udb2; \
echo ; echo RUNNING BENCH ; echo ; \
for i in `find . -name 'run-test'` ; do \
echo ; echo `dirname $$i|sed -e 's+./++g'`; \
$$i ; \
done
clean:
rm -rf udb2 build *~
+8
View File
@@ -0,0 +1,8 @@
all:run-test
run-test:test.c ../common.c
$(CC) -std=gnu99 -O2 -Wall -I../../../.. $< -o $@
clean:
rm -f run-test* *~
rm -rf mlib
+31
View File
@@ -0,0 +1,31 @@
#include "../common.c"
#include "m-dict.h"
static inline bool oor_equal_p(unsigned int k, unsigned char n)
{
return k == (unsigned int)n;
}
static inline void oor_set(unsigned int *k, unsigned char n)
{
*k = (unsigned int)n;
}
DICT_OA_DEF2(dict_oa_uint,
unsigned int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
unsigned int, M_DEFAULT_OPLIST)
void test_int(uint32_t n, uint32_t x0)
{
uint32_t i, x, z = 0;
dict_oa_uint_t h;
dict_oa_uint_init(h);
for (i = 0, x = x0; i < n; ++i) {
x = hash32(x);
unsigned int key = get_key(n, x);
unsigned int *ptr = dict_oa_uint_get(h, key);
if (ptr) { (*ptr)++; z+= *ptr; }
else { dict_oa_uint_set_at(h, key, 1); z+=1; }
}
fprintf(stderr, "# unique keys: %d; checksum: %u\n", (int) dict_oa_uint_size(h), z);
dict_oa_uint_clear(h);
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

+37
View File
@@ -0,0 +1,37 @@
API incompatibility
-------------------
V0.1.*: * First formal version of API
V0.2.*: * worker_start takes a 'worker_t' as an additional parameter
(This enables to perform a wait-on-event instead of a busy waiting).
* worker_spawn doesn't take into a 'worker_t' anymore.
* worker_init takes an int as numWorker instead of an unsigned int.
* RBTREE pop method has been renamed into _pop_at (as it takes a key parameter).
* SNAPSHOT_DEF has been removed. use SNAPSHOT_SPSC_DEF
* array's _set_at2 has been replaced by array's _get_at.
The interface is similar to dict _get_at, making the API cleaner and more generic.
_set_at2(a,i,x) ==> set(*_get_at(a,i),x)
* DICT_SET:
- Rename method _set_at as _push
Since there is no key, it is a push method, not a _set_at method.
- Rename DICT_SET_DEF2 as DICT_SET_DEF
since it only requires one argument.
- The method _ref returns a pointer to the data,
instead of a pointer to a single tuple like other DICT_SET interface.
- The format of the output to character string as changed.
* ALGO:
- Rename _contains as _contain_p
since it is a predicate '_p' and it shall be in infinitive form.
- Rename _map as _for_each (Standard name).
* M_PRINT_ARG & M_FPRINT_ARG don't put a final semicolon at the end
of their expansion anymore (cleaner and no longer needed with the
new available tools).
* For the TUPLE and the VARIANT
change name of _get_ ## field into _get_at_ ## fields
Since there is a name collision with other methods
if a field is named 'str'.
* Rename method _remove into _erase for dictionary & B+TREE (adding a compatibility layer) for API uniformization.
The provided _remove doesn't use an iterator but a 'key', incompatible with the one of array or list.
But is like the one provided by the priority queue.
+84
View File
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><!--This file was converted to xhtml by LibreOffice - see http://cgit.freedesktop.org/libreoffice/core/tree/filter/source/xslt for the code.--><head profile="http://dublincore.org/documents/dcmi-terms/"><meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8"/><title xml:lang="en-US">- no title specified</title><meta name="DCTERMS.title" content="" xml:lang="en-US"/><meta name="DCTERMS.language" content="en-US" scheme="DCTERMS.RFC4646"/><meta name="DCTERMS.source" content="http://xml.openoffice.org/odf2xhtml"/><meta name="DCTERMS.issued" content="2018-07-01T11:06:00.978729880" scheme="DCTERMS.W3CDTF"/><meta name="DCTERMS.provenance" content="" xml:lang="en-US"/><meta name="DCTERMS.subject" content="," xml:lang="en-US"/><link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" hreflang="en"/><link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" hreflang="en"/><link rel="schema.DCTYPE" href="http://purl.org/dc/dcmitype/" hreflang="en"/><link rel="schema.DCAM" href="http://purl.org/dc/dcam/" hreflang="en"/><style type="text/css">
@page { }
table { border-collapse:collapse; border-spacing:0; empty-cells:show }
td, th { vertical-align:top; font-size:10pt;}
h1, h2, h3, h4, h5, h6 { clear:both }
ol, ul { margin:0; padding:0;}
li { list-style: none; margin:0; padding:0;}
<!-- "li span.odfLiEnd" - IE 7 issue-->
li span. { clear: both; line-height:0; width:0; height:0; margin:0; padding:0; }
span.footnodeNumber { padding-right:1em; }
span.annotation_style_by_filter { font-size:95%; font-family:Arial; background-color:#fff000; margin:0; border:0; padding:0; }
* { margin:0;}
.ta1 { writing-mode:lr-tb; }
.Default { font-family:Liberation Sans; }
.ce100 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce101 { font-family:Liberation Sans; border-bottom-style:none; background-color:#ffff00; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce102 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#ffff00; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce103 { font-family:Liberation Sans; border-bottom-style:none; background-color:#ffff00; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; }
.ce104 { font-family:Liberation Sans; background-color:#e6e6e6; font-size:11pt; text-decoration:underline; font-weight:bold; }
.ce57 { font-family:Liberation Sans; background-color:transparent; font-size:11pt; text-decoration:none ! important; font-weight:bold; }
.ce58 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:transparent; border-left-style:none; border-right-style:none; border-top-style:none; font-size:11pt; text-decoration:none ! important; font-weight:bold; }
.ce59 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; font-size:11pt; text-decoration:underline; font-weight:bold; }
.ce60 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-style:none; font-size:11pt; text-decoration:none ! important; font-weight:bold; }
.ce61 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#e6e6e6; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-style:none; font-size:11pt; text-decoration:none ! important; font-weight:bold; }
.ce62 { font-family:Liberation Sans; background-color:#e6e6e6; font-size:11pt; text-decoration:none ! important; font-weight:bold; }
.ce63 { font-family:Liberation Sans; background-color:#e6e6e6; border-width:0,0621cm; border-style:solid; border-color:#000000; text-align:center ! important; margin-left:0cm; font-size:11pt; font-weight:bold; }
.ce64 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; font-weight:bold; }
.ce65 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; font-weight:bold; }
.ce66 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#e6e6e6; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; font-weight:bold; }
.ce67 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6ff; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; font-weight:bold; }
.ce68 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#e6e6ff; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; font-weight:bold; }
.ce69 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6ff; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; font-weight:bold; }
.ce70 { font-family:Liberation Sans; background-color:#e6e6e6; font-weight:bold; }
.ce71 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; font-size:11pt; text-decoration:underline; font-weight:bold; }
.ce72 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#e6e6e6; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; font-weight:bold; }
.ce73 { font-family:Liberation Sans; border-bottom-style:none; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; }
.ce74 { font-family:Liberation Sans; border-bottom-style:none; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce75 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce76 { font-family:Liberation Sans; border-bottom-style:none; background-color:transparent; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce77 { font-family:Liberation Sans; text-align:center ! important; margin-left:0cm; }
.ce78 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-style:none; border-right-style:none; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; font-size:11pt; text-decoration:underline; font-weight:bold; }
.ce79 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#e6e6e6; border-left-style:none; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; font-weight:bold; }
.ce80 { font-family:Liberation Sans; border-bottom-style:none; border-left-style:none; border-right-style:none; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; }
.ce81 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; border-left-style:none; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce82 { font-family:Liberation Sans; background-color:transparent; text-align:center ! important; margin-left:0cm; }
.ce83 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:transparent; border-left-style:none; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce84 { font-family:Liberation Sans; background-color:#ffff00; text-align:center ! important; margin-left:0cm; }
.ce85 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#ffff00; border-left-style:none; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce86 { font-family:Liberation Sans; border-bottom-style:none; background-color:#ffff00; border-left-style:none; border-right-style:none; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; }
.ce87 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; font-size:11pt; text-decoration:underline; font-weight:bold; }
.ce88 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#e6e6e6; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; font-weight:bold; }
.ce89 { font-family:Liberation Sans; border-bottom-style:none; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; }
.ce90 { font-family:Liberation Sans; border-bottom-style:none; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce91 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce92 { font-family:Liberation Sans; border-bottom-style:none; background-color:#ffff00; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce93 { font-family:Liberation Sans; border-bottom-style:none; background-color:#ffff00; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce94 { font-family:Liberation Sans; border-bottom-style:none; background-color:transparent; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce95 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:transparent; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.ce96 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; font-size:11pt; text-decoration:none ! important; font-weight:bold; }
.ce97 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#e6e6e6; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; font-weight:bold; }
.ce98 { font-family:Liberation Sans; border-bottom-style:none; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; }
.ce99 { font-family:Liberation Sans; border-bottom-style:none; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
.co1 { width:3.399cm; }
.co10 { width:1.304cm; }
.co11 { width:1.942cm; }
.co12 { width:1.815cm; }
.co13 { width:1.348cm; }
.co14 { width:1.432cm; }
.co15 { width:2.258cm; }
.co2 { width:6.281cm; }
.co3 { width:1.475cm; }
.co4 { width:1.277cm; }
.co5 { width:1.602cm; }
.co6 { width:1.39cm; }
.co7 { width:1.686cm; }
.co8 { width:1.644cm; }
.co9 { width:2.452cm; }
.ro1 { height:0.487cm; }
.ro2 { height:0.885cm; }
.ro3 { height:0.452cm; }
<!-- ODF styles with no properties representable as CSS -->
{ }
</style></head><body dir="ltr" style="writing-mode:lr-tb; "><table border="0" cellspacing="0" cellpadding="0" class="ta1"><colgroup><col width="149"/><col width="274"/><col width="64"/><col width="56"/><col width="70"/><col width="61"/><col width="74"/><col width="72"/><col width="107"/><col width="57"/><col width="107"/><col width="107"/><col width="74"/><col width="85"/><col width="79"/><col width="79"/><col width="59"/><col width="61"/><col width="63"/><col width="99"/></colgroup><tr class="ro1"><td style="text-align:left;width:3.399cm; " class="ce57"> </td><td style="text-align:left;width:6.281cm; " class="ce57"> </td><td colspan="6" style="text-align:left;width:1.475cm; " class="ce71"><p>Sequence Containers</p></td><td colspan="4" style="text-align:left;width:2.452cm; " class="ce71"><p>Associative Containers</p></td><td style="text-align:left;width:1.686cm; " class="ce96"> </td><td colspan="6" style="text-align:left;width:1.942cm; " class="ce71"><p>Synchronization Containers</p></td><td style="text-align:left;width:2.258cm; " class="ce104"> </td></tr><tr class="ro2"><td style="text-align:left;width:3.399cm; " class="ce58"> </td><td style="text-align:left;width:6.281cm; " class="ce63"><p>Method</p></td><td style="text-align:left;width:1.475cm; " class="ce72"><p>ARRAY</p></td><td style="text-align:left;width:1.277cm; " class="ce79"><p>LIST</p></td><td style="text-align:left;width:1.602cm; " class="ce79"><p>DUALP</p><p>LIST</p></td><td style="text-align:left;width:1.39cm; " class="ce79"><p>I-LIST</p></td><td style="text-align:left;width:1.686cm; " class="ce79"><p>DEQUE</p></td><td style="text-align:left;width:1.644cm; " class="ce88"><p>BITSET</p></td><td style="text-align:left;width:2.452cm; " class="ce72"><p>B+TREE</p><p>DICT/SET</p></td><td style="text-align:left;width:1.304cm; " class="ce79"><p>R/B</p><p>TREE</p></td><td style="text-align:left;width:2.452cm; " class="ce79"><p>[S]HASH</p><p>DICT / SET</p></td><td style="text-align:left;width:2.452cm; " class="ce88"><p>OA DICT</p></td><td style="text-align:left;width:1.686cm; " class="ce97"><p>PRIO </p><p>QUEUE</p></td><td style="text-align:left;width:1.942cm; " class="ce72"><p>BUFFER</p></td><td style="text-align:left;width:1.815cm; " class="ce79"><p>QUEUE </p><p>MPMC</p></td><td style="text-align:left;width:1.815cm; " class="ce79"><p>QUEUE </p><p>SPSC</p></td><td style="text-align:left;width:1.348cm; " class="ce79"><p>SNAP</p><p>SPSC</p></td><td style="text-align:left;width:1.39cm; " class="ce79"><p>SNAP</p><p>SPMC</p></td><td style="text-align:left;width:1.432cm; " class="ce88"><p>SNAP </p><p>MPMC</p></td><td style="text-align:left;width:2.258cm; " class="ce70"> </td></tr><tr class="ro1"><td style="text-align:left;width:3.399cm; " class="ce59"><p>CONSTRUCTOR</p></td><td style="text-align:left;width:6.281cm; " class="ce64"><p>_init</p></td><td style="text-align:left;width:1.475cm; " class="ce73"><p>X</p></td><td style="text-align:left;width:1.277cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.602cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.39cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.686cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.644cm; " class="ce89"><p>X</p></td><td style="text-align:left;width:2.452cm; " class="ce73"><p>X</p></td><td style="text-align:left;width:1.304cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:2.452cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:2.452cm; " class="ce89"><p>X</p></td><td style="text-align:left;width:1.686cm; " class="ce98"><p>X</p></td><td style="text-align:left;width:1.942cm; " class="ce73"><p>X</p></td><td style="text-align:left;width:1.815cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.815cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.348cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.39cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.432cm; " class="ce89"><p>X</p></td><td style="text-align:left;width:2.258cm; " class="Default"> </td></tr><tr class="ro1"><td style="text-align:left;width:3.399cm; " class="ce60"> </td><td style="text-align:left;width:6.281cm; " class="ce65"><p>_set</p></td><td style="text-align:left;width:1.475cm; " class="ce74"><p>X</p></td><td style="text-align:left;width:1.277cm; " class="ce77"><p>X</p></td><td style="text-align:left;width:1.602cm; " class="ce77"><p>X</p></td><td style="text-align:left;width:1.39cm; " class="ce77"> </td><td style="text-align:left;width:1.686cm; " class="ce77"><p>X</p></td><td style="text-align:left;width:1.644cm; " class="ce90"><p>X</p></td><td style="text-align:left;width:2.452cm; " class="ce74"><p>X</p></td><td style="text-align:left;width:1.304cm; " class="ce77"><p>X</p></td><td style="text-align:left;width:2.452cm; " class="ce77"><p>X</p></td><td style="text-align:left;width:2.452cm; " class="ce90"><p>X</p></td><td style="text-align:left;width:1.686cmLine truncated
BIN
View File
Binary file not shown.
+46 -22
View File
@@ -2,39 +2,63 @@ How to make a release?
======================
1) Check that all test pass on all primary systems.
Run 'make check' on all primary systems.
Run 'make check' or 'make checkall' on all primary systems.
No error shall be reported.
2) Check that no memory leak is reported by valgrind:
Run 'make valgrind' in tests folder on a system.
NOTE: valgrind seems completly lost in all the tests which spawn a lot of threads.
3) Check that no undefined behavior, nor data race, ... is reported by sanitizer:
2) Check that no undefined behavior, nor data race, ... is reported by sanitizer:
Run 'make sanitize' in tests folder on a system.
This needs at least GCC 7
4) Check that no new warning is reported by static analyser:
Run 'make scan-build' in tests folder on a system.
This needs at least clang 4.
Currently there is a false positive detected in m-shared:
"Argument to free() is offset by 8 bytes from the start of memory allocated by malloc()"
scan-build is not able to properly track that this case cannot open.
5) Check that coverage is reasonnable.
3) Check that coverage is reasonable.
Run 'make coverage' and analyze result.
6) Publish the release
4) Publish the release
In case of problem, open a problem report.
List of primary systems
List of tested systems
=======================
* gcc 4.9 on linux/x86-64
* gcc 7 on linux/x86-64
* clang 3.5 on linux/x86-64
* clang 4 on linux/x86-64
* g++ 7 on linux/x86-64
* gcc 4.9, 7 & 8 on linux/x86-64
* clang 3.5, 4 & 6 on linux/x86-64
* g++ 7 & 8 on linux/x86-64
* tcc on linux/x86-64
* gcc 6 on windows/x86-64
* gcc 7 on windows/x86-64
* gcc 4.9 on linux/powerpc
* gcc 6 on linux/armv7l
* clang 3.8 on linux/armv7l
Cross compilation
=================
There is no need to cross compile the library as it is a header only library.
However if you want to run the test with a cross-compiler, do like the following
command. It performs a cross-compilation of the test suite from linux to windows
and run the test suite with wine:
make CC="i586-mingw32msvc-gcc -std=c99 -DWINVER=0x600 -D_WIN32_WINNT=0x600" LOG_COMPILER=wine check
Handling issues
===============
Issues are opened in the bug tracker of the project (typically https://github.com/P-p-H-d/mlib/issues )
If the issue cannot be closed and taken into account in less than (typically) one month,
or before a release,
it shall be moved into the long term issues included in the repository:
https://github.com/P-p-H-d/mlib/blob/master/doc/ISSUES.org
This is a file in ORG mode: the issues are created with the proper tags.
The original issue in the tracker can then be closed with the issuer agreement.
This will have the following gains:
- no hard dependencies on any bug tracking infrastructure (can be migrated easily).
- a release will automatically contain all its open problem reports.
Once one issue of ISSUES.org is taken into account,
its state shall be changed to DONE (the issue shall not be removed).
+408
View File
@@ -0,0 +1,408 @@
*Long term issues*
------------------
* TODO #21: Generic Binary serialization :ENHANCEMENT:
Based on issue #26 of https://github.com/P-p-H-d/mlib/issues/26
Some kind of "binary serialization" on the model of get_str/parse_str
could be possible. It would be a great feature from the application
point-of-view: binary representation is more bandwidth-efficient if
used on network communications.
It will be good to have import/export methods to the
XML/JSON/MSGPACK/PROTOBUF/BINARY format.
However, adding all of them on by one in the M*LIB containers
doesn't seem satisfactory.
Instead, adding a generic interface for the serialization of data
that may be customized by the user to perform the import/export of
objects in whatever format they want into what they want (FILE/memory/...).
To simplify it, this interface could only support one kind of import/export
per compilation unit.
Problem:
the interface is either too high level (limiting too much what we can do)
or too low level (exporting too many internal things of the library).
* TODO #20: Bucket priority queue :ENHANCEMENT:
Add a new kind of priority queue.
See https://en.wikipedia.org/wiki/Bucket_queue
Check if it will be better as intrusive or non-intrusive container.
To test if a bucket is empty or not, a bitfield can be used to check if
the bit associated to the bucket is set or not. To get the highest bucket
non empty, we can perform a CLZ of the bitset, which shall be much faster than
performing a linear search of the buckets (algorithm complexity is the same,
except that we can scan 64 entries at a time).
Check if we can use BITSET, or introduce fixed size BITSET or use ad-hock
implementation.
* TODO #19: Intrusive Red Black Tree :ENHANCEMENT:
Add intrusive red black tree.
* TODO #18: Missing methods :ENHANCEMENT:
Some containers don't have all the methods they should.
See the cells in yellow here:
http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Container.html
* TODO #17: Ressource handler :ENHANCEMENT:
A ressouce handler which shall associated a unique handle to a ressource.
The handle shall be unique for the ressource and shall not be reused.
It is typically a 64 bits integers always incremented (even if the program
creates one billion ressources per second, the counter won't overflow
until 585 years).
The ressource handler shall make an association between a HANDLE 64 bits and:
- how much real owners claim to own the ressource
(the ressource is only owned by the ressource handler, however
it acts as a delegate of the real owner),
- how much users keep a pointer to the ressource.
- pointer to the resource itself.
This may be a better alternative than shared_ptr & weak_ptr:
- reduce fragmentation,
- no cycle dependencies,
- shared_ref & weak_ref becomes only HANDLE,
- all ressources can be freed in one pass.
Needs lock free dictionnary or at least concurrent dictionnary.
How to handle multiple resource ?
* variant: works fine. Memory usage can be (much) higher than needed if there is a lot of dissimilarity between the size of the objects.
* embedded the type in the ressource handler: more work, API more complex. Memory usage seems better.
* TODO #16: Lock Free List :ENHANCEMENT:
Implement a lock free list. Most of the difficulty is the memory reclamation part.
Typically this lock free list shall be compatible with RCU method.
A node can be in the following state:
- FREE: Can be used for allocation.
- IN_USE: The node is currently used in the list.
- TO_BE_RECLAIMED: The node is semantically removed, but some others may still be used it.
So separate lists shall be used for the memory handler.
It shall also be compatible with NUMA and avoid putting all nodes in the same lists if possible:
otherwise the head will become a hot spot and slow down everything.
The ABA problem shall also be taken into account. Normaly with the provided state of the nodes,
it should not be a problem.
backoff should also be considered when using CAS.
Concurrent insertion / insertion and insertion / deletion and deletion / deletion shall be taken into account.
** First step: lock free node pool :
*** API based on Lock-Free Queue List
-- node_t is { node_t *next; uint ticket; data_t }
-- freelist_t : basic internal lockfree list used to construct more user friendly list (FIFO queue to avoid putting constraints on free & alloc at the same times + it is needed for reclaim part).
do not ensure consistensy of data.
is { _Atomic(node*) head, tail; }
Atomic Queue List : See algorithm by Michael & Scott on Lock Free Queue List (aka MSList)
+ freelist_push (&list, &node)
+ freelist_pop(&list) return node
+ freelist_pop_if(&list, ticket) return node Needs minor adaptation on _pop.
-- lf_memory_core_t : basic type responsible for the centralization of the list allocation.
+ init(lf_mc_t &, int max_thread, size_t alloc_size)
+ clear(lf_mc_t &)
+ lc_mc_t is {
atomic_uint ticket;
atomic_uint reg_thread; // ==> genint instead
atomic_uint tab_ticket[MAX_THREAD];
freelist_t free[MAX_THREAD];
freelist_t to_be_reclaimed[MAX_THREAD];
}
-- lf_memory_thread_t: specialization for the current thread
* lf_mt_t is { int thd_idx; lf_mc_t *global;}
* init(lf_mt_t &, &lf_mc_t g) is { thd_idx := atomic_add(&g.reg_tread, 1); .global := g; }
* clear is ??
* awake () is preparing the thread to handle operations on the list { .global.tab_ticket[.thd_idx] := atomic_add(&global.ticket, 1)+1; }
* sleep () is sleeping the thread so that it doesn't handle operations on the list and perform memory reclamation if needed {
.global.tab_ticket[.thd_idx] := UINT_MAX;
min_ticket := min(global.tab_ticket);
scan the list to_be_reclaimed while node.cpt < min_ticket,
pop the node from to_be_reclaimed and push it to the list free
lf_memory_thread_t shall be in awake state to do anything on the list.
*** Bench
Basic malloc / free: 9.6s
LF Node : 10.6s
Even if LF Node ensures a correct life cycle of the node for the read, the performance is passable.
Too much CAS:
51.40 6.13 6.13 51146587 0.00 0.00 lf_freelist_push
20.10 8.53 2.40 28143911 0.00 0.00 lf_freelist_pop
15.65 10.40 1.87 253579 0.01 0.02 lf_mempool_sleep
*** Mixed API
To overcome this limitation performs a mixed approache:
- having a simple (non atomic) list of nodes to alloc quickly the nodes.
- embedded within an atomic list of list of nodes for GC.
Thread data will be:
- FreeList is a non atomic singly linked list.
- ToBeReclaimedList is the same
- FreeListList is an atomic queue list of non atomic singly list.
- CanBeReclaimedListList is an atomic queue list of non atomic singly list
**** alloc() returns node:
- Pop from FreeList a node.
- If failure, atomic pop from FreeListList a list of list of free nodes. If success, update FreeList with the new list and pop a node from it.
- If failure, try an atomic from the FreeListList of other threads. If success, update FreeList with the new list and pop a node from it.
- If failure, malloc a new pool of FreeListList (TBD: all nodes in one pass? Needs a separate list to handle final free of nodes).
*** free(node)
- Push node in ToBeReclaimedList
*** GarbageCollector called on sleep:
- Compute min_ticket for all threads
- Atomic push of ToBeReclaimedList in CanBeReclaimedListList
- for each thread starting from mine:
-- Atomic pop from CanBeReclaimedListList[] if max ticket of pool of nodes < min_ticket and atomic push in FreeListList
max ticket of pool is the ticket of the top node of the list.
==> Should be much faster since there is much less CAS operations performed and GC is perfomed per block.
** Second step: lf_list_t is a stack based list based on RCU:
_read: classic non atomic operations.
_push(list, data, lf_mt_t) is {
allocate new node from lf_mt_t.global.free, or malloc if nothing.
copy data into node
head := atomic_load(&list.head)
do
node->next := head
while !CAS(&list.head, &head, node)
# ABA problem shall not happen since node cannot be reused immediately
_pop(list, data, lf_mt_t) is {
head := atomic_load(&list.head)
do {
if head == NULL return NULL
} while !CAS(&list.head, &head, head.next)
copy head.data into data
head.cpt := atomic_read(&global.ticket)
push node in global.to_be_reclaimed
}
_erase() TODO
_update() TODO
** Example / Way to use:
- init global memory handler.
- for each thread,
-- init thread memory handler XX,
-- ...
-- XX.awake()
-- ...
-- do as many stuff on any list as we want (this is hot spot).
-- ...
-- XX.sleep() # Memory can be reclaimed
-- XX.awake()
* TODO #15: Constructor / Destructor Prologue / Epilogue for Stack Exception Handling :ENHANCEMENT:
Constructor (and destructor) need to use user-defined prologue / epilogue.
This is in order to register the constructed object into a proper Stack Exception Handling so that exceptions throwing may work reliably.
Proposal:
- M_CONSTRUCTOR_PROLOGUE(object, oplist);
- M_CONSTRUCTOR_EPILOGUE(object, oplist);
- M_DESTRUCTOR_PROLOGUE(object, oplist);
- M_DESTRUCTOR_EPILOGUE(object, oplist);
Object creation will need to add all sub-objects into the stack, then unstack all to push instead the root object (which will recursively remove them).
See also http://freetype.sourceforge.net/david/reliable-c.html#cseh
* TODO #14: Memory allocation enhancement :ENHANCEMENT:
Enhancement of the memory allocation scheme to find way to deal properly with advance allocators:
- non-default alignment requirements for types,
- instance-based allocator (may need instance based variable access),
- expected life of created type (temporary or permanent),
- stack based allocator,
- global variable access for allocator,
- maximum allocation before failure.
Most of theses are already more or less supported. Examples shall be created to show how to deal with this:
- alignement shall be implemented with the attributes of <stdalign.h>
However I sill don't know how to implement "instance-based allocator" which is what is missing.
The problem is how to give to methods context local information store within the container itself.
Update:
API transformation support enables "instance-based allocator" to be made easily.
Needs some formal operator in the oplist to support it fully and an example.
Can be supported using another API extension, some more operators and forcing some names:
* API_N: call like FUNC(obj->extra_data, type)
'obj' is a forced named corresponding to an alias to an object in the function.
Operator needed:
- EXTRA_DATA: Add an extra-data field wihtin the container. Defines the type of data.
* TODO #12: Atomic shared pointer :ENHANCEMENT:
Add an extension to the SHARED_PTR API:
- New type atomic_shared_ptr
- name_init_atomic_set (&atomic_shared_ptr, shared_ptr);
- name_init_set_atomic (shared_ptr, &atomic_shared_ptr);
- name_init_atomic_set_atomic (&atomic_shared_ptr, &atomic_shared_ptr);
- name_atomic_set (&atomic_shared_ptr, shared_ptr);
- name_set_atomic (shared_ptr, &atomic_shared_ptr);
- name_atomic_set_atomic (&atomic_shared_ptr, &atomic_shared_ptr);
- name_atomic_clear
No _ref or direct _init: we need to init first a normal shared_ptr then the atomic (TBC)
** _atomic_set method:
It can be implemented by incrementing the non atomic shared pointer reference, then performs a compare_and_swap to the data of the atomic shared pointer, finally decrement and dec/free the swapped previous data of the atomic .
** _set_atomic method:
It needs to perform the following atomic operation : <read the pointer, deref pointer and increment the pointed value> I don't known how to do it properly.
See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4162.pdf
Proposition for _set_atomic we store temporary NULL to the atomic_ptr struct to request an exclusive access to the data (this looks like a lock and other operations need to handle NULL) :
#+BEGIN_SRC C
void shared_ptr_set_atomic(ptr a, atomic_ptr *ptr)
{
// Get exclusive access to the data
p = atomic_load(ptr);
do {
if (p == NULL) {
// TODO: exponential backoff
p = atomic_load(ptr);
continue;
}
} while (!atomic_compare_exchange_weak(ptr, &p, NULL));
// p has exclusive access to the pointer
p->data->cpt ++;
a->data = p->data;
atomic_exchange (ptr, p);
}
#+END_SRC
This prevents using NULL which obliges atomic shared pointer to point to a created object...
Other alternative solution is to use the bit 0 to mark the pointer as being updated, preventing other from using it (TBC only clear):
#+BEGIN_SRC C
void shared_ptr_set_atomic(ptr a, atomic_ptr *ptr)
{
// Get exclusive access to the data
p = atomic_load(ptr);
do {
if ( (p&1) != 0) {
// TODO: exponential backoff
p = atomic_load(ptr);
continue;
}
} while (!atomic_compare_exchange_weak(ptr, &p, p|1));
// Exclusive access (kind of lock).
p->data->cpt ++;
a->data = p->data;
atomic_set (ptr, p);
}
#+END_SRC
Other implementation seems to have it hard to be lock-free: cf. https://github.com/llvm-mirror/libcxx/commit/5fec82dc0db3623546038e4a86baa44f749e554f
* TODO #5: Concurrent dictionary Container :ENHANCEMENT:
Implement a more efficient dictionary than lock + std dictionary for all operations when dealing with threads.
See https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx
** Multiple locks within the dictionnary
A potential implementation may be to request at initialization time the number of concurrent thread N.
Create a static array of N dictionnary with N mutex. Then to access the data will perform :
- compute hash of object,
- access high bits of hash and select which dictionnary shall have the data,
- lock it,
- perform classic access to the data (check if the compiler can properly optimize the hash computation),
- unlock it.
The property of the hash shall allow a good dispersion of the data across multiple locks, reducing the constraints on the lock. This implementation could be build easily upon the already existent dictionary.
To test.
See also https://github.com/simonhf/sharedhashfile
** Lock Free dictionnary
Evaluate also lock-free dictionary (easier with open addressing).
It needs a complete rewrite of the inner loop through. The hard part is the dynamic resizing of the internal array (see http://preshing.com/20160222/a-resizable-concurrent-map/ for a potential solution and http://www.cs.toronto.edu/~tomhart/papers/tomhart_thesis.pdf for memory reclamation techniques). See also https://www.research.ibm.com/people/m/michael/spaa-2002.pdf
https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.2017.11.22a.pdf persents different techniques used by linux kernel.
It needs before lock-free list: http://www.cse.yorku.ca/~ruppert/papers/lfll.pdf http://www.cse.yorku.ca/~ruppert/Mikhail.pdf
** Context
The best parallel algorithm is still when there is as few synchronization as possible. A concurrent dictionary will fail at this and will result in average performance at best.
The typical best case will be in RCU context (a lot of readers, few writers), so the interface shall be compatible with such structure.
** Linked list
Another solution is to create a huge list of items which is:
- atomically updated,
- in reverse order of the hash (bit 0 is highest bit, Bit 63 is the lowest bit).
Hash table will only give quick access to items to this list. Expanding the table won't change the order of the list (so the items will remain at the same place and always accessible by other threads) but just add sentinel in the sentinel at the right place (there won't be any reallocation of the list). Inserting will need to insert an item at the right place.
Not sure it will really help. To analyse.
Concurrent dictionary is possible now with CONCURRENT_DEF + DICT_DEF.
But it uses a global lock for all dictionary access.
** Open Addressing Indirect Table with a lock free node pool used as transaction pool.
A good way maybe Open Addessing table used only for indirection and a freelist memory reclamation container for handle the entries
(like a transaction).
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

+2 -2
View File
@@ -15,7 +15,7 @@ int main(void) {
char *k = dict_m32_get(h, 10); // No 10 in h, so k == NULL
int is_missing = (k != NULL); // true
assert (is_missing);
dict_m32_remove(h, 5); // h is now empty
dict_m32_erase(h, 5); // h is now empty
dict_m32_it_t it; // iterate over all dictionnary
for (dict_m32_it (it, h) ; !dict_m32_end_p (it); dict_m32_next(it)) {
struct dict_m32_pair_s *item = dict_m32_ref(it);
@@ -33,7 +33,7 @@ int main(void) {
char *k = dict_m32_get(h, 10); // k == NULL
int is_missing = (k != NULL); // true
assert (is_missing);
dict_m32_remove(h, 5); // h is now empty
dict_m32_erase(h, 5); // h is now empty
for M_EACH(item, h, M32_OPLIST) { // traverse each item
item->value = 1; // Set its value to 1
}
+2 -2
View File
@@ -50,11 +50,11 @@ int main(void)
printf("Enter the mapped string to be deleted: ");
string_fgets (str, stdin, STRING_READ_PURE_LINE);
s = atoi(string_get_cstr(str));
dict_map_remove(mp, s);
dict_map_erase(mp, s);
break;
case 3:
printf("Size of Map: %lu\n", (unsigned long) dict_map_size(mp) );
printf("Size of Map: %zu\n", dict_map_size(mp) );
break;
case 4:
+3 -3
View File
@@ -5,14 +5,14 @@
/* program that reads text from standard-input,
and prints the total number of distinct words found in the text.
*/
DICT_SET_DEF2(dict_str, string_t, STRING_OPLIST)
DICT_SET_DEF(dict_str, string_t, STRING_OPLIST)
int main(void)
{
M_LET(word, STRING_OPLIST)
M_LET(wordcount, DICT_SET_OPLIST(dict_str, STRING_OPLIST)) {
while (string_fget_word(word, " \t\n,.!;:?", stdin))
dict_str_set_at(wordcount, word);
printf ("Words: %lu\n", dict_str_size(wordcount));
dict_str_push(wordcount, word);
printf ("Words: %zu\n", dict_str_size(wordcount));
}
}
+32
View File
@@ -0,0 +1,32 @@
#include <stdio.h>
#include "m-string.h"
#include "m-array.h"
#include "m-dict.h"
ARRAY_DEF(array_size, size_t)
#define M_OPL_array_size_t() ARRAY_OPLIST(array_size)
DICT_DEF2(map_pos, string_t, array_size_t)
#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");
}
}
}
}
+246
View File
@@ -0,0 +1,246 @@
#include <stdio.h>
#include <stdint.h>
#include "m-array.h"
#include "m-dict.h"
#include "m-string.h"
#include "m-algo.h"
/* Based on:
* Easy Perfect Minimal Hashing
* By Steve Hanov. Released to the public domain.
* http://stevehanov.ca/blog/index.php?id=119
*
* Based on:
* Edward A. Fox, Lenwood S. Heath, Qi Fan Chen and Amjad M. Daoud,
* "Practical minimal perfect hash functions for large databases", CACM, 35(1):105-121
*
* also a good reference:
* Compress, Hash, and Displace algorithm by Djamal Belazzougui,
* Fabiano C. Botelho, and Martin Dietzfelbinger
*/
/* Define the needed data structure : */
// Define a dictionnary of constant string --> integer
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
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
ARRAY_DEF(array_seed, int32_t)
#define M_OPL_array_seed_t() ARRAY_OPLIST(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)
static inline int array_cstr_cmp(const array_cstr_t a, const array_cstr_t b) {
size_t sa = array_cstr_size(a);
size_t sb = array_cstr_size(b);
return (sa > sb) ? -1 : (sa < sb);
}
#define M_OPL_array_cstr_t() M_OPEXTEND(ARRAY_OPLIST(array_cstr, M_CSTR_OPLIST), CMP(array_cstr_cmp))
// Define an array of array of constant string, and some algo over this container
ARRAY_DEF(array_bucket, array_cstr_t)
#define M_OPL_array_bucket_t() ARRAY_OPLIST(array_bucket, M_OPL_array_cstr_t() )
ALGO_DEF(array_bucket, array_bucket_t)
// Define an array of string to save the input.
ARRAY_DEF(array_string, string_t)
#define M_OPL_array_string_t() ARRAY_OPLIST(array_string, M_OPL_string_t())
/* The algorithm may not converge on all inputs if the hash function
* doesn't randomly distribute the inputs:
* str1 != str2 ==> \exist seed \such_as hash(seed,str1) != hash(seed, str2)
* The first hash function below doesn't provide the needed property for
* inputs with two words 'a' and 'c'
* The second one is more robust but may still have this issue.
*/
static uint32_t hash(int32_t seed, const char str[])
{
#if 0
if (seed == 0) seed = 0x01000193;
while (*str) {
seed = ((seed * 0x01000193) ^ *str);
str++;
}
return seed;
#else
if (seed == 0) seed = 0x811C9DC5;
while (*str) {
seed = (seed ^ *str) * 16777619;
str++;
}
return seed ^ (seed >> 16);
#endif
}
// Step 1: place all key keys into buckets
static void
CreateMinimalPerfectHash1(array_seed_t seed, array_value_t value,
array_bucket_t bucket,
const dict_mph_t dict)
{
size_t size = dict_mph_size (dict);
array_value_resize(value, size);
array_seed_resize(seed, size);
array_bucket_resize(bucket, size);
for M_EACH(item, dict, dict_mph_t) {
size_t i = hash(0, item->key) % size;
array_cstr_push_back (*array_bucket_get (bucket, i), item->key);
}
}
// Step 2: Sort the buckets and process the ones with the most items first.
static void
CreateMinimalPerfectHash2(array_seed_t seed, array_value_t value,
array_bucket_t bucket,
const dict_mph_t dict)
{
size_t size = dict_mph_size (dict);
array_bucket_sort(bucket);
M_LET(slots, array_seed_t) {
for M_EACH(b, bucket, array_bucket_t) {
if (array_cstr_size(*b) <= 1)
break;
size_t d = 1;
/* Repeatedly try different values of d until we find a hash function
that places all items in the bucket into free slots.
This may loop forever on some inputs if the hash function is not good
enought. */
for(bool cont = true; cont ; ) {
cont = false;
array_seed_clean(slots);
for M_EACH(it, *b, array_cstr_t) {
size_t s = hash(d, *it) % size;
if (*array_value_get(value, s) != 0 || array_seed_contain_p(slots, s)){
d++;
cont = true;
break;
}
array_seed_push_back (slots, s);
}
}
// Fill in the seed & value with the computed value
array_seed_set_at(seed, hash(0, *array_cstr_get(*b, 0)) % size, d);
d = 0;
for M_EACH(it, *b, array_cstr_t) {
array_value_set_at(value,
*array_seed_get(slots, d),
*dict_mph_get(dict, *it));
d++;
}
}
}
}
/* Step 3:
* Only buckets with 1 item remain. Process them more quickly by directly
* placing them into a free slot. Use a negative value of d to indicate
* this.
*/
static void
CreateMinimalPerfectHash3(array_seed_t seed, array_value_t value,
array_bucket_t bucket,
const dict_mph_t dict)
{
size_t size = dict_mph_size (dict);
M_LET(freelist, array_seed_t) {
// Get a list of available slot
for(size_t i = 0; i < size; i++)
if (*array_value_get(value, i) == 0)
array_seed_push_back(freelist, i);
for M_EACH(b, bucket, array_bucket_t) {
if (array_cstr_size(*b) != 1)
continue;
int32_t slot;
array_seed_pop_back(&slot, freelist);
/*We subtract one to ensure it's negative even if the zeroeth slot was
used. */
array_seed_set_at (seed, hash(0, *array_cstr_get(*b, 0)) % size,
-slot-1);
array_value_set_at(value, slot, *dict_mph_get(dict, *array_cstr_get(*b, 0)));
}
}
}
static void
CreateMinimalPerfectHash(array_seed_t seed, array_value_t value,
const dict_mph_t dict)
{
M_LET(bucket, array_bucket_t) {
CreateMinimalPerfectHash1(seed, value, bucket, dict);
CreateMinimalPerfectHash2(seed, value, bucket, dict);
CreateMinimalPerfectHash3(seed, value, bucket, dict);
}
}
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();
uint32_t line = 1;
M_LET(str, string_t) {
while (!feof(f) && !ferror(f)) {
string_fgets(str, f, STRING_READ_PURE_LINE);
string_strim(str);
if (!string_empty_p(str)) {
// Not clean as items of 'dict' points are linked to items of 'arr'
// and the containers are not aware of this link.
array_string_push_back (arr, str);
dict_mph_set_at(dict, string_get_cstr(*array_string_back(arr)), line);
line++;
}
}
}
fclose(f);
}
static uint32_t
perfect_hash_lockup(array_seed_t seed, array_value_t value,
const char key[])
{
int32_t s = *array_seed_get(seed, hash(0, key) % array_seed_size(seed));
if (s < 0)
return *array_value_get(value, -s-1);
else
return *array_value_get(value, hash(s, key) % array_value_size(value));
}
static void
test(array_seed_t seed, array_value_t value, dict_mph_t dict)
{
for M_EACH(item, dict, dict_mph_t) {
const char *key = item->key;
uint32_t v = perfect_hash_lockup(seed, value, key);
if (v != item->value) {
fprintf(stderr, "ERROR for %s: %u VS %u\n", key, v, item->value);
}
}
}
int main(int argc, const char *argv[])
{
M_LET(arr, array_string_t) M_LET(dict, dict_mph_t) M_LET(seed, array_seed_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);
}
return 0;
}
+2 -2
View File
@@ -47,8 +47,8 @@ static void program_init(program_t p, string_t text) {
int left;
array_int_pop_back(&left, leftstack);
int right = pc;
array_int_set_at2 (p->bracket_map, left, right);
array_int_set_at2 (p->bracket_map, right, left);
*array_int_get_at (p->bracket_map, left) = right;
*array_int_get_at (p->bracket_map, right) = left;
}
pc++;
+3 -1
View File
@@ -12,7 +12,9 @@ unsigned long long rand_seed;
#include "m-variant.h"
/* This example will show how to create JSON-like files.
This is a JSON **like** syntax, not exactly JSON format */
This is a JSON **like** syntax, not exactly JSON format.
For an example with JSON format, see https://github.com/P-p-H-d/mjsonlib
*/
/* First let's handle the OUT/IN functions of boolean */
static inline void boolean_out_str(FILE *f, bool b)
+90
View File
@@ -0,0 +1,90 @@
#include <stdio.h>
#include "m-tuple.h"
#include "m-array.h"
#include "m-string.h"
#include "m-list.h"
#include "m-buffer.h"
/* This example chains the structure in different ways in
order to show/test the good chaining of the structures */
TUPLE_DEF2(symbol, (type, int), (name, string_t))
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_DEFAULT_OPLIST, STRING_OPLIST)
ARRAY_DEF(symbol_list, symbol_t)
#define M_OPL_symbol_list_t() ARRAY_OPLIST(symbol_list, M_OPL_symbol_t())
TUPLE_DEF2(record, (fields, symbol_list_t))
#define M_OPL_record_t() TUPLE_OPLIST(record, M_OPL_symbol_list_t())
TUPLE_DEF2(my_tuple, (name, string_t), (value, int))
#define M_OPL_my_tuple_t() TUPLE_OPLIST(my_tuple)
ARRAY_DEF(my_list_of_tuple, my_tuple_t)
#define M_OPL_my_list_of_tuple_t() ARRAY_OPLIST(my_list_of_tuple)
TUPLE_DEF2(my_tuple_of_tuple, (name, string_t), (inner_tuple, my_tuple_t))
#define M_OPL_my_tuple_of_tuple_t() TUPLE_OPLIST(my_tuple_of_tuple)
LIST_DEF(list_of_tuple_of_tuple, my_tuple_of_tuple_t)
#define M_OPL_list_of_tuple_of_tuple_t() LIST_OPLIST(list_of_tuple_of_tuple, M_OPL_my_tuple_of_tuple_t() )
TUPLE_DEF2(my_triple_tuple, (name, string_t), (inner_tuple, my_tuple_t), (list, list_of_tuple_of_tuple_t) )
#define M_OPL_my_triple_tuple_t() TUPLE_OPLIST(my_triple_tuple, STRING_OPLIST, M_OPL_my_tuple_t(), M_OPL_list_of_tuple_of_tuple_t())
BUFFER_DEF(trbuff, my_triple_tuple_t, 100, BUFFER_QUEUE)
#define M_OPL_trbuff_t() BUFFER_OPLIST(trbuff, M_OPL_my_triple_tuple_t())
TUPLE_DEF2(my_junction, (active, bool), (buffer, trbuff_t))
#define M_OPL_my_junction_t() TUPLE_OPLIST(my_junction, M_DEFAULT_OPLIST, M_OPL_trbuff_t())
TUPLE_DEF2(mlib_point, (x, int), (y, int))
#define M_OPL_mlib_point_t() \
TUPLE_OPLIST(mlib_point, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
TUPLE_DEF2(mlib_points, (first_ref, mlib_point_ptr, M_PTR_OPLIST),
(second_ref, mlib_point_ptr, M_PTR_OPLIST),
(third, mlib_point_t))
#define M_OPL_mlib_points_t() \
TUPLE_OPLIST(mlib_points, M_PTR_OPLIST, M_PTR_OPLIST, M_OPL_mlib_point_t())
static void let2(void)
{
M_LET((p1, 4, 4), (p2, 5, 5), mlib_point_t) {
M_LET(pair, mlib_points_t) {
pair->first_ref = p1;
pair->second_ref = p2;
pair->third->x = pair->third->y = 6;
assert(pair->first_ref->x == 4);
p1->x = 10;
assert(pair->first_ref->x == 10);
assert(pair->third->x == 6);
}
}
}
static void let(void)
{
M_LET(s, symbol_t)
M_LET(l, symbol_list_t)
M_LET(r,record_t)
M_LET(tup, my_tuple_t)
M_LET(l2, my_list_of_tuple_t)
M_LET(tuptup, my_tuple_of_tuple_t)
M_LET(ltuptup, list_of_tuple_of_tuple_t)
M_LET(tuptuptup, my_triple_tuple_t)
M_LET(junc, my_junction_t)
{
printf("Init ok\n");
}
}
int main(void)
{
let();
let2();
}
+531 -273
View File
File diff suppressed because it is too large. Load diff
+224 -87
View File
@@ -22,33 +22,38 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_ARRAY_H
#define __M_ARRAY_H
#ifndef MSTARLIB_ARRAY_H
#define MSTARLIB_ARRAY_H
#include "m-core.h"
/* Define an array of a given type.
/* Define a dynamic array of the given type and its associated functions.
USAGE: ARRAY_DEF(name, type [, oplist_of_the_type]) */
#define ARRAY_DEF(name, ...) \
ARRAYI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t), M_C(name,_it_t) ), \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name,_it_t) ), \
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t))))
/* Define the oplist of an array of type.
/* Define the oplist of a dynamic array given its name and its oplist.
USAGE: ARRAY_OPLIST(name[, oplist of the type]) */
#define ARRAY_OPLIST(...) \
ARRAYI_OPLIST(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
(__VA_ARGS__ )))
/********************************** INTERNAL ************************************/
// Deferred evaluation for the oplist definition.
#define ARRAYI_OPLIST(arg) ARRAYI_OPLIST2 arg
/* OPLIST definition of a dynamic array */
/* FIXME: Do we want to export some methods as they are slow and
are not fit to be used for building other methods (like _remove)? */
#define ARRAYI_OPLIST2(name, oplist) \
(INIT(M_C(name, _init)) \
(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)) \
@@ -56,6 +61,7 @@
,SWAP(M_C(name, _swap)) \
,TYPE(M_C(name,_t)) \
,SUBTYPE(M_C(name, _type_t)) \
,TEST_EMPTY(M_C(name,_empty_p)) \
,IT_TYPE(M_C(name,_it_t)) \
,IT_FIRST(M_C(name,_it)) \
,IT_LAST(M_C(name,_it_last)) \
@@ -68,13 +74,26 @@
,IT_PREVIOUS(M_C(name,_previous)) \
,IT_REF(M_C(name,_ref)) \
,IT_CREF(M_C(name,_cref)) \
,IT_REMOVE(M_C(name,_remove)) \
,IT_INSERT(M_C(name,_insert)) \
,IT_REMOVE(M_C(name,_remove)) \
,CLEAN(M_C(name,_clean)) \
,KEY_TYPE(size_t) \
,VALUE_TYPE(M_C(name, _type_t)) \
,KEY_OPLIST(M_DEFAULT_OPLIST) \
,VALUE_OPLIST(oplist) \
,SET_KEY(M_C(name, _set_at)) \
,GET_KEY(M_C(name, _get)) \
,M_IF_METHOD(INIT, oplist)(GET_SET_KEY(M_C(name, _get_at)) ,) \
,ERASE_KEY(M_C(name, _erase)) \
,GET_SIZE(M_C(name, _size)) \
,PUSH(M_C(name,_push_back)) \
,POP(M_C(name,_pop_back)) \
,PUSH_MOVE(M_C(name,_push_move)) \
,POP_MOVE(M_C(name,_pop_move)) \
,OPLIST(oplist) \
,M_IF_METHOD(CMP, oplist)(SORT(M_C(name, _special_sort)),) \
,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),) \
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),) \
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),) \
,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),) \
,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),) \
@@ -84,22 +103,26 @@
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
)
/* Define the contract of an array */
#define ARRAYI_CONTRACT(a) do { \
assert (a != NULL); \
assert (a->size <= a->alloc); \
assert (a->size == 0 || a->ptr != NULL); \
} while (0)
// Deferred evaluation.
// Deferred evaluation for the array definition.
#define ARRAYI_DEF(arg) ARRAYI_DEF2 arg
// Internal definition.
#define ARRAYI_DEF2(name, type, oplist, array_t, array_it_t) \
\
typedef struct M_C(name, _s) { \
size_t size, alloc; \
type *ptr; \
size_t size; /* Number of elements in the array */ \
size_t alloc; /* Allocated size for the array */ \
type *ptr; /* Pointer to the array */ \
} array_t[1]; \
typedef struct M_C(name, _s) *M_C(name, _ptr); \
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
\
typedef type M_C(name, _type_t); \
\
@@ -112,8 +135,10 @@
M_C(name, _init)(array_t v) \
{ \
assert (v != NULL); \
v->size = v->alloc = 0; \
v->ptr = NULL; \
/* Initialy, the array is empty with nothing allocated */ \
v->size = 0; \
v->alloc = 0; \
v->ptr = NULL; \
ARRAYI_CONTRACT(v); \
} \
\
@@ -122,7 +147,7 @@
{ \
ARRAYI_CONTRACT(v); \
for(size_t i = 0; i < v->size; i++) \
M_GET_CLEAR oplist(v->ptr[i]); \
M_CALL_CLEAR(oplist, v->ptr[i]); \
v->size = 0; \
ARRAYI_CONTRACT(v); \
} \
@@ -132,7 +157,7 @@
{ \
ARRAYI_CONTRACT(v); \
M_C(name, _clean)(v); \
M_GET_FREE oplist(v->ptr); \
M_CALL_FREE(oplist, v->ptr); \
v->alloc = 0; \
v->ptr = NULL; \
} \
@@ -145,7 +170,7 @@
if (M_UNLIKELY (d == s)) return; \
if (s->size > d->alloc) { \
const size_t alloc = s->size; \
type *ptr = M_GET_REALLOC oplist (type, d->ptr, alloc); \
type *ptr = M_CALL_REALLOC(oplist, type, d->ptr, alloc); \
if (M_UNLIKELY (ptr == NULL)) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return ; \
@@ -155,11 +180,11 @@
} \
size_t i, step1 = M_MIN(s->size, d->size); \
for(i = 0; i < step1; i++) \
M_GET_SET oplist (d->ptr[i], s->ptr[i]); \
M_CALL_SET(oplist, d->ptr[i], s->ptr[i]); \
for( ; i < s->size; i++) \
M_GET_INIT_SET oplist (d->ptr[i], s->ptr[i]); \
M_CALL_INIT_SET(oplist, d->ptr[i], s->ptr[i]); \
for( ; i < d->size; i++) \
M_GET_CLEAR oplist (d->ptr[i]); \
M_CALL_CLEAR(oplist, d->ptr[i]); \
d->size = s->size; \
ARRAYI_CONTRACT(d); \
} \
@@ -180,7 +205,7 @@
d->size = s->size; \
d->alloc = s->alloc; \
d->ptr = s->ptr; \
s->size = s->alloc = 0; \
s->alloc = 0; \
s->ptr = NULL; \
ARRAYI_CONTRACT(d); \
} \
@@ -194,14 +219,14 @@
} \
\
static inline void \
M_C(name, _set_at)(array_t v, size_t i, type x) \
M_C(name, _set_at)(array_t v, size_t i, type const x) \
{ \
ARRAYI_CONTRACT(v); \
assert(v->size > 0 && v->ptr != NULL && i < v->size); \
M_GET_SET oplist(v->ptr[i], x); \
M_CALL_SET(oplist, v->ptr[i], x); \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _back)(array_t v) \
{ \
ARRAYI_CONTRACT(v); \
@@ -215,13 +240,13 @@
ARRAYI_CONTRACT(v); \
if (M_UNLIKELY (v->size >= v->alloc)) { \
assert(v->size == v->alloc); \
size_t alloc = M_GET_INC_ALLOC oplist (v->alloc); \
size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \
if (M_UNLIKELY (alloc <= v->alloc)) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return NULL; \
} \
assert (alloc > v->size); \
type *ptr = M_GET_REALLOC oplist (type, v->ptr, alloc); \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \
if (M_UNLIKELY (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return NULL; \
@@ -242,17 +267,29 @@
type *data = M_C(name, _push_raw)(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_GET_INIT_SET oplist(*data, x); \
M_CALL_INIT_SET(oplist, *data, x); \
} \
\
M_IF_METHOD(INIT, oplist)( \
static inline type * \
M_C(name, _push_new)(array_t v) \
{ \
type *data = M_C(name, _push_raw)(v); \
if (M_UNLIKELY (data == NULL) ) \
return NULL; \
M_GET_INIT oplist(*data); \
M_CALL_INIT(oplist, *data); \
return data; \
} \
, /* No INIT */ ) \
\
static inline void \
M_C(name, _push_move)(array_t v, type *x) \
{ \
assert (x != NULL); \
type *data = M_C(name, _push_raw)(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_DO_INIT_MOVE (oplist, *data, *x); \
} \
\
static inline void \
@@ -262,13 +299,13 @@
assert (key <= v->size); \
if (M_UNLIKELY (v->size >= v->alloc) ) { \
assert(v->size == v->alloc); \
size_t alloc = M_GET_INC_ALLOC oplist (v->alloc); \
size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \
if (M_UNLIKELY (alloc <= v->alloc)) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return ; \
} \
assert (alloc > v->size); \
type *ptr = M_GET_REALLOC oplist (type, v->ptr, alloc); \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \
if (M_UNLIKELY (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return; \
@@ -279,10 +316,11 @@
assert(v->ptr != NULL); \
memmove(&v->ptr[key+1], &v->ptr[key], (v->size-key)*sizeof(type)); \
v->size++; \
M_GET_INIT_SET oplist (v->ptr[key], x); \
M_CALL_INIT_SET(oplist, v->ptr[key], x); \
ARRAYI_CONTRACT(v); \
} \
\
M_IF_METHOD(INIT, oplist)( \
static inline void \
M_C(name, _resize)(array_t v, size_t size) \
{ \
@@ -290,13 +328,13 @@
if (v->size > size) { \
/* Decrease size of array */ \
for(size_t i = size ; i < v->size; i++) \
M_GET_CLEAR oplist(v->ptr[i]); \
M_CALL_CLEAR(oplist, v->ptr[i]); \
v->size = size; \
} else if (v->size < size) { \
/* Increase size of array */ \
if (size > v->alloc) { \
size_t alloc = size ; \
type *ptr = M_GET_REALLOC oplist (type, v->ptr, alloc); \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \
if (M_UNLIKELY (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return; \
@@ -305,11 +343,12 @@
v->alloc = alloc; \
} \
for(size_t i = v->size ; i < size; i++) \
M_GET_INIT oplist(v->ptr[i]); \
M_CALL_INIT(oplist, v->ptr[i]); \
v->size = size; \
} \
ARRAYI_CONTRACT(v); \
} \
, /* No INIT */ ) \
\
static inline void \
M_C(name, _reserve)(array_t v, size_t alloc) \
@@ -320,11 +359,11 @@
alloc = v->size; \
} \
if (M_UNLIKELY (alloc == 0)) { \
M_GET_FREE oplist (v->ptr); \
M_CALL_FREE(oplist, v->ptr); \
v->size = v->alloc = 0; \
v->ptr = NULL; \
} else { \
type *ptr = M_GET_REALLOC oplist (type, v->ptr, alloc); \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \
if (M_UNLIKELY (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return; \
@@ -335,50 +374,67 @@
ARRAYI_CONTRACT(v); \
} \
\
static inline void \
M_C(name, _set_at2)(array_t v, size_t idx, type x) \
M_IF_METHOD(INIT, oplist)( \
static inline type * \
M_C(name, _get_at)(array_t v, size_t idx) \
{ \
ARRAYI_CONTRACT(v); \
const size_t size = idx + 1; \
/* NOTE: set at and resize if needed */ \
/* resize if needed */ \
if (v->size <= size) { \
/* Increase size of array */ \
if (M_UNLIKELY (size > v->alloc) ) { \
size_t alloc = M_GET_INC_ALLOC oplist (size) ; \
size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \
/* In case of overflow of size_t */ \
if (M_UNLIKELY (alloc <= v->alloc)) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return ; \
return NULL; \
} \
type *ptr = M_GET_REALLOC oplist (type, v->ptr, alloc); \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \
if (M_UNLIKELY (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return; \
return NULL; \
} \
v->ptr = ptr; \
v->alloc = alloc; \
} \
for(size_t i = v->size ; i < size; i++) \
M_GET_INIT oplist(v->ptr[i]); \
M_CALL_INIT(oplist, v->ptr[i]); \
v->size = size; \
} \
assert (idx < v->size); \
M_GET_SET oplist(v->ptr[idx], x); \
ARRAYI_CONTRACT(v); \
return &v->ptr[idx]; \
} \
, /* No INIT */) \
\
static inline void \
M_C(name, _pop_back)(type *dest, array_t v) \
{ \
ARRAYI_CONTRACT(v); \
assert (v->size > 0 && v->ptr != NULL); \
v->size--; \
if (dest) \
if (dest) { \
M_DO_MOVE (oplist, *dest, v->ptr[v->size]); \
else \
M_GET_CLEAR oplist (v->ptr[v->size]); \
} else { \
M_CALL_CLEAR(oplist, v->ptr[v->size]); \
} \
ARRAYI_CONTRACT(v); \
} \
\
static inline void \
M_C(name, _pop_move)(type *dest, array_t v) \
{ \
ARRAYI_CONTRACT(v); \
assert (v->size > 0 && v->ptr != NULL); \
assert (dest != NULL); \
v->size--; \
M_DO_INIT_MOVE (oplist, *dest, v->ptr[v->size]); \
ARRAYI_CONTRACT(v); \
} \
\
M_IF_METHOD(INIT, oplist)( \
static inline void \
M_C(name, _pop_until)(array_t v, array_it_t pos) \
{ \
ARRAYI_CONTRACT(v); \
@@ -386,6 +442,7 @@
M_ASSUME (pos->index <= v->size); \
M_C(name, _resize)(v, pos->index); \
} \
, /* No INIT */ ) \
\
static inline bool \
M_C(name, _empty_p)(const array_t v) \
@@ -413,28 +470,47 @@
{ \
ARRAYI_CONTRACT(v); \
assert (v->size > 0 && v->ptr != NULL); \
assert (i < v->size); \
if (dest) \
M_DO_MOVE (oplist, *dest, v->ptr[i]); \
else \
M_GET_CLEAR oplist (v->ptr[i]); \
M_CALL_CLEAR(oplist, v->ptr[i]); \
memmove(&v->ptr[i], &v->ptr[i+1], sizeof(type)*(v->size - i) ); \
v->size--; \
ARRAYI_CONTRACT(v); \
} \
\
static inline bool \
M_C(name, _erase)(array_t a, size_t i) \
{ \
ARRAYI_CONTRACT(a); \
if (i >= a->size) return false; \
M_C(name, _pop_at)(NULL, a, i); \
return true; \
} \
\
M_IF_METHOD(INIT, oplist)( \
static inline void \
M_C(name, _insert_v)(array_t v, size_t i, size_t num) \
{ \
ARRAYI_CONTRACT(v); \
assert(i <= v->size); \
size_t size = v->size + num; \
/* Test for overflow of variable size */ \
if (M_UNLIKELY (size <= v->size)) { \
/* Unlikely case of nothing to do */ \
if (num == 0) return; \
M_MEMORY_FULL(sizeof (type) * v->size); \
return ; \
} \
/* Test if alloc array is sufficient */ \
if (size > v->alloc) { \
size_t alloc = M_GET_INC_ALLOC oplist (size) ; \
if (M_UNLIKELY (alloc <= v->alloc)) { \
size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \
if (M_UNLIKELY (alloc <= v->alloc)) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return ; \
} \
type *ptr = M_GET_REALLOC oplist (type, v->ptr, alloc); \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \
if (M_UNLIKELY (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return; \
@@ -444,10 +520,11 @@
} \
memmove(&v->ptr[i+num], &v->ptr[i], sizeof(type)*(v->size - i) ); \
for(size_t k = i ; k < i+num; k++) \
M_GET_INIT oplist(v->ptr[k]); \
M_CALL_INIT(oplist, v->ptr[k]); \
v->size = size; \
ARRAYI_CONTRACT(v); \
} \
, /* No INIT */) \
\
static inline void \
M_C(name, _remove_v)(array_t v, size_t i, size_t j) \
@@ -455,7 +532,7 @@
ARRAYI_CONTRACT(v); \
assert(i < v->size && j <= v->size && i < j && v->ptr != NULL); \
for(size_t k = i ; k < j; k++) \
M_GET_CLEAR oplist(v->ptr[k]); \
M_CALL_CLEAR(oplist, v->ptr[k]); \
memmove(&v->ptr[i], &v->ptr[j], sizeof(type)*(v->size - j) ); \
v->size -= (j-i); \
ARRAYI_CONTRACT(v); \
@@ -486,14 +563,14 @@
assert(i < v->size && j < v->size && v->ptr != NULL); \
type tmp; \
M_IF_METHOD(INIT_MOVE, oplist) ( \
M_GET_INIT_MOVE oplist (tmp, v->ptr[i]); \
M_GET_INIT_MOVE oplist (v->ptr[i], v->ptr[j]); \
M_GET_INIT_MOVE oplist (v->ptr[j], tmp); \
, \
M_GET_INIT_SET oplist (tmp, v->ptr[i]); \
M_GET_SET oplist(v->ptr[i], v->ptr[j]); \
M_GET_SET oplist(v->ptr[j], tmp); \
M_GET_CLEAR oplist(tmp); \
M_CALL_INIT_MOVE(oplist, tmp, v->ptr[i]); \
M_CALL_INIT_MOVE(oplist, v->ptr[i], v->ptr[j]); \
M_CALL_INIT_MOVE(oplist, v->ptr[j], tmp); \
, \
M_CALL_INIT_SET(oplist, tmp, v->ptr[i]); \
M_CALL_SET(oplist, v->ptr[i], v->ptr[j]); \
M_CALL_SET(oplist, v->ptr[j], tmp); \
M_CALL_CLEAR(oplist, tmp); \
) /* IF INIT_MOVE method */ \
ARRAYI_CONTRACT(v); \
} \
@@ -506,7 +583,7 @@
return &v->ptr[i]; \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cget)(const array_t v, size_t i) \
{ \
ARRAYI_CONTRACT(v); \
@@ -514,6 +591,14 @@
return M_CONST_CAST(type, &v->ptr[i]); \
} \
\
static inline type const * \
M_C(name, _front)(const array_t v) \
{ \
ARRAYI_CONTRACT(v); \
assert (v->size > 0); \
return M_C(name, _cget)(v, 0); \
} \
\
static inline void \
M_C(name, _it)(array_it_t it, const array_t v) \
{ \
@@ -597,7 +682,7 @@
return M_C(name, _get)(it->array, it->index); \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cref)(const array_it_t it) \
{ \
assert(it != NULL); \
@@ -622,7 +707,7 @@
M_IF_METHOD(CMP, oplist) \
( \
static inline void M_C(name, _special_sort)(array_t l, \
int (*func_type) (const type *a, const type *b)) \
int (*func_type) (type const *a, type const *b)) \
{ \
/* Using qsort is more compact but slower than a full templated \
version which can be twice faster */ \
@@ -641,7 +726,7 @@
assert (size > 1); \
/* Let's select the threshold of the pass 1 to be sure \
the final result is in tab.*/ \
if (m_core_clz(size-1) & 1) \
if (m_core_clz64(size-1) & 1) \
th += th; \
\
/* Pass 1: insertion sort (stable) */ \
@@ -650,8 +735,8 @@
M_ASSUME(max >= th); \
for(size_t i = 1; i < max; i++) { \
size_t j = i; \
while (j > 0 && M_GET_CMP oplist (tab[k+j-1], tab[k+j]) > 0) { \
M_GET_SWAP oplist (tab[k+j-1], tab[k+j]); \
while (j > 0 && M_CALL_CMP(oplist, tab[k+j-1], tab[k+j]) > 0) { \
M_CALL_SWAP(oplist, tab[k+j-1], tab[k+j]); \
j = j - 1; \
} \
} \
@@ -672,8 +757,8 @@
assert (0 < n2 && n2 <= size); \
k += n1+n2; \
for (;;) { \
if (M_GET_CMP oplist (*el1, *el2) <= 0) { \
M_GET_SET oplist (*dest, *el1); \
if (M_CALL_CMP(oplist, *el1, *el2) <= 0) { \
M_CALL_SET(oplist, *dest, *el1); \
dest++; \
el1++; \
if (-- n1 == 0) { \
@@ -684,7 +769,7 @@
break; \
} \
} else { \
M_GET_SET oplist (*dest, *el2); \
M_CALL_SET(oplist, *dest, *el2); \
dest++; \
el2++; \
if (-- n2 == 0) { \
@@ -710,13 +795,13 @@
{ \
if (M_UNLIKELY (l->size < 2)) \
return; \
type *temp = M_GET_REALLOC oplist (type, NULL, l->size); \
type *temp = M_CALL_REALLOC(oplist, type, NULL, l->size); \
if (temp == NULL) { \
M_MEMORY_FULL(sizeof (type) * l->size); \
return ; \
} \
M_C(name, _special_stable_sort_noalloc)(l->ptr, l->size, temp); \
M_GET_FREE oplist(temp); \
M_CALL_FREE(oplist, temp); \
} \
,) /* IF SWAP method */ \
\
@@ -724,7 +809,7 @@
\
M_IF_METHOD(GET_STR, oplist)( \
static inline void \
M_C(name, _get_str)(string_t str, array_t array, \
M_C(name, _get_str)(string_t str, array_t const array, \
bool append) \
{ \
STRINGI_CONTRACT(str); \
@@ -734,8 +819,8 @@
for (M_C(name, _it)(it, array) ; \
!M_C(name, _end_p)(it); \
M_C(name, _next)(it)){ \
const type *item = M_C(name, _cref)(it); \
M_GET_GET_STR oplist (str, *item, true); \
type const *item = M_C(name, _cref)(it); \
M_CALL_GET_STR(oplist, str, *item, true); \
if (!M_C(name, _last_p)(it)) \
string_push_back (str, M_GET_SEPARATOR oplist); \
} \
@@ -752,8 +837,8 @@
assert (file != NULL); \
fputc ('[', file); \
for (size_t i = 0; i < array->size; i++) { \
const type *item = M_C(name, _cget)(array, i); \
M_GET_OUT_STR oplist (file, *item); \
type const *item = M_C(name, _cget)(array, i); \
M_CALL_OUT_STR(oplist, file, *item); \
if (i != array->size-1) \
fputc (M_GET_SEPARATOR oplist, file); \
} \
@@ -761,7 +846,38 @@
} \
, /* no OUT_STR */ ) \
\
M_IF_METHOD(IN_STR, oplist)( \
M_IF_METHOD2(PARSE_STR, INIT, oplist)( \
static inline bool \
M_C(name, _parse_str)(array_t array, const char str[], const char**endp) \
{ \
ARRAYI_CONTRACT(array); \
assert (str != NULL); \
M_C(name,_clean)(array); \
bool success = false; \
int c = *str++; \
if (M_UNLIKELY (c != '[')) goto exit; \
c = *str++; \
if (M_UNLIKELY (c == ']')) { success = true; goto exit; } \
if (M_UNLIKELY (c == 0)) goto exit; \
str--; \
type item; \
M_CALL_INIT(oplist, item); \
do { \
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
do { c = *str++; } while (isspace(c)); \
if (b == false || c == 0) { goto exit; } \
M_C(name, _push_back)(array, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_CALL_CLEAR(oplist, item); \
ARRAYI_CONTRACT(array); \
success = (c == ']'); \
exit: \
if (endp) *endp = str; \
return success; \
} \
, /* no PARSE_STR & INIT */ ) \
\
M_IF_METHOD2(IN_STR, INIT, oplist)( \
static inline bool \
M_C(name, _in_str)(array_t array, FILE *file) \
{ \
@@ -775,18 +891,18 @@
if (M_UNLIKELY (c == EOF)) return false; \
ungetc(c, file); \
type item; \
M_GET_INIT oplist (item); \
M_CALL_INIT(oplist, item); \
do { \
bool b = M_GET_IN_STR oplist (item, file); \
c = fgetc(file); \
bool b = M_CALL_IN_STR(oplist, item, file); \
do { c = fgetc(file); } while (isspace(c)); \
if (b == false || c == EOF) { break; } \
M_C(name, _push_back)(array, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_GET_CLEAR oplist (item); \
M_CALL_CLEAR(oplist, item); \
ARRAYI_CONTRACT(array); \
return c == ']'; \
} \
, /* no IN_STR */ ) \
, /* no IN_STR & INIT */ ) \
\
M_IF_METHOD(EQUAL, oplist)( \
static inline bool \
@@ -798,9 +914,9 @@
if (array1->size != array2->size) return false; \
size_t i; \
for(i = 0; i < array1->size; i++) { \
const type *item1 = M_C(name, _cget)(array1, i); \
const type *item2 = M_C(name, _cget)(array2, i); \
bool b = M_GET_EQUAL oplist (*item1, *item2); \
type const *item1 = M_C(name, _cget)(array1, i); \
type const *item2 = M_C(name, _cget)(array2, i); \
bool b = M_CALL_EQUAL(oplist, *item1, *item2); \
if (!b) return false; \
} \
return i == array1->size; \
@@ -814,11 +930,32 @@
ARRAYI_CONTRACT(array); \
M_HASH_DECL(hash); \
for(size_t i = 0 ; i < array->size; i++) { \
size_t hi = M_GET_HASH oplist (array->ptr[i]); \
size_t hi = M_CALL_HASH(oplist, array->ptr[i]); \
M_HASH_UP(hash, hi); \
} \
return M_HASH_FINAL (hash); \
} \
, /* no HASH */ ) \
\
static inline void \
M_C(name, _splice)(array_t a1, array_t a2) \
{ \
ARRAYI_CONTRACT(a1); \
ARRAYI_CONTRACT(a2); \
if (M_LIKELY (a2->size > 0)) { \
size_t newSize = a1->size + a2->size; \
if (newSize > a1->alloc) { \
type *ptr = M_CALL_REALLOC(oplist, type, a1->ptr, newSize); \
if (M_UNLIKELY (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (type) * newSize); \
} \
a1->ptr = ptr; \
a1->alloc = newSize; \
} \
memcpy(&a1->ptr[a1->size], &a2->ptr[0], a2->size * sizeof (type)); \
a2->size = 0; \
a1->size = newSize; \
} \
} \
#endif
+47 -40
View File
@@ -22,8 +22,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_ATOMIC_H
#define __M_ATOMIC_H
#ifndef MSTARLIB_ATOMIC_H
#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
@@ -89,6 +89,13 @@ using std::atomic_flag_test_and_set_explicit;
using std::atomic_flag_clear;
using std::atomic_flag_clear_explicit;
using std::memory_order_relaxed;
using std::memory_order_consume;
using std::memory_order_acquire;
using std::memory_order_release;
using std::memory_order_acq_rel;
using std::memory_order_seq_cst;
#define _Atomic(T) std::atomic< T >
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
@@ -111,20 +118,20 @@ using std::atomic_flag_clear_explicit;
#include "m-mutex.h"
/* The structure is quite large:
__val : value of the atomic type,
__zero : zero value of the atomic type (constant),
__previous: temporary value used within the mutex lock,
__lock : the mutex lock.
_val : value of the atomic type,
_zero : zero value of the atomic type (constant),
_previous: temporary value used within the mutex lock,
_lock : the mutex lock.
*/
#define _Atomic(T) \
struct { \
volatile T __val; \
T __zero; \
T __previous; \
m_mutex_t __lock; \
volatile T _val; \
T _zero; \
T _previous; \
m_mutex_t _lock; \
}
/* Even memory order is defined, only the strongest constraint is used */
/* Even if memory order is defined, only the strongest constraint is used */
typedef enum {
memory_order_relaxed,
memory_order_consume,
@@ -152,7 +159,7 @@ typedef _Atomic(size_t) atomic_size_t;
typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
/* Define the minimum size supported by the architecture
for atomic read or write.
for an atomic read or write.
This can help a lot since it avoids locking for atomic_load and
atomic_store.
*/
@@ -183,16 +190,16 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
lock the atomic value, read it and returns the value.
In order to avoid any compiler extension, we need to transform the
atomic type into 'long long' then convert it back to its value.
This is because __previous can't be read after the lock, and we can't
This is because _previous can't be read after the lock, and we can't
generate temporary variable within a macro.
The trick is computing _val - _zero within the lock, then
returns retvalue + _zero after the lock.
*/
#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)
(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_add(ptr, val) atomic_fetch_op(ptr, val, +=)
#define atomic_fetch_sub(ptr, val) atomic_fetch_op(ptr, val, -=)
@@ -204,38 +211,38 @@ 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 }
#define atomic_init(ptr, val) \
(m_mutex_init((ptr)->__lock), (ptr)->__val = val, (ptr)->__zero = 0)
(m_mutex_init((ptr)->_lock), (ptr)->_val = val, (ptr)->_zero = 0)
#define atomic_load_lock(ptr) \
(m_mutex_lock((ptr)->__lock), \
(ptr)->__previous = (ptr)->__val, \
atomic_fetch_unlock(&(ptr)->__lock, (ptr)->__previous-(ptr)->__zero)+(ptr)->__zero)
(m_mutex_lock((ptr)->_lock), \
(ptr)->_previous = (ptr)->_val, \
atomic_fetch_unlock(&(ptr)->_lock, (ptr)->_previous-(ptr)->_zero)+(ptr)->_zero)
#define atomic_store_lock(ptr, val) \
(m_mutex_lock((ptr)->__lock), \
(ptr)->__val = (val), \
m_mutex_unlock((ptr)->__lock))
(m_mutex_lock((ptr)->_lock), \
(ptr)->_val = (val), \
m_mutex_unlock((ptr)->_lock))
#define atomic_load(ptr) \
( sizeof ((ptr)->__val) <= ATOMICI_MIN_RW_SIZE \
? (ptr)->__val \
( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE \
? (ptr)->_val \
: atomic_load_lock(ptr))
#define atomic_store(ptr, val) do { \
if ( sizeof ((ptr)->__val) <= ATOMICI_MIN_RW_SIZE) { \
(ptr)->__val = (val); \
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); \
long long _offset = (val) - (ptr)->_zero; \
atomic_store_lock(ptr, (ptr)->_zero + _offset); \
} \
} while (0)
#define atomic_compare_exchange_strong(ptr, exp, val) \
(m_mutex_lock((ptr)->__lock), \
atomic_fetch_unlock(&(ptr)->__lock, \
(ptr)->__val == *(exp) \
? ((ptr)->__val = (val), true) \
: (*(exp) = (ptr)->__val, false)))
#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)))
#define atomic_fetch_add_explicit(ptr, val, mem) atomic_fetch_op(ptr, val, +=)
@@ -250,9 +257,9 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
#define atomic_thread_fence(mem) (void) 0
#define atomic_signal_fence(mem) (void) 0
#define atomic_is_lock_free(ptr) false
#define atomic_compare_exchange_strong_explicit(ptr, exp, val, mem) atomic_compare_exchange_strong(ptr, exp, val)
#define atomic_compare_exchange_weak_explicit(ptr, exp, val, mem) atomic_compare_exchange_strong(ptr, exp, val)
#define atomic_compare_exchange_weak(ptr, exp, val) atomic_compare_exchange_strong(ptr, exp, val)
#define atomic_compare_exchange_strong_explicit(ptr, exp, val, mem1, mem2) atomic_compare_exchange_strong(ptr, exp, val)
#define atomic_compare_exchange_weak_explicit(ptr, exp, val, mem1, mem2) atomic_compare_exchange_strong(ptr, exp, val)
#define atomic_compare_exchange_weak(ptr, exp, val) atomic_compare_exchange_strong(ptr, exp, val)
/* TODO: Missing atomic_flag. Problem: it needs to be lock free! */
+77 -24
View File
@@ -22,15 +22,16 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_BITSET_H
#define __M_BITSET_H
#ifndef MSTARLIB_BITSET_H
#define MSTARLIB_BITSET_H
#include <stdint.h>
#include "m-core.h"
/********************************** INTERNAL ************************************/
// Define a limb of a bitset
typedef unsigned long bitset_limb;
typedef uint64_t bitset_limb;
#define BITSET_LIMB_BIT (sizeof(bitset_limb) * CHAR_BIT)
typedef struct bitset_s {
@@ -38,6 +39,8 @@ typedef struct bitset_s {
size_t alloc; // Alloc is the number of allocated limbs
bitset_limb *ptr; // Pointer to the allocated limbs
} bitset_t[1];
typedef struct bitset_s *bitset_ptr;
typedef const struct bitset_s *bitset_srcptr;
typedef struct bitset_it_s {
size_t index; // index to the array of bit
@@ -46,7 +49,7 @@ typedef struct bitset_it_s {
} bitset_it_t[1];
// bitset grow policy
#define BITSETI_INC_ALLOC_SIZE(n) ((n) < 2 ? 4 : (n) * 2)
#define BITSETI_INC_ALLOC_SIZE(n) ((n) < 4 ? 4 : (n) * 2)
// Compute the number of allocated limbs needed to handle 'n' bits.
#define BITSETI_TO_ALLOC(n) (((n) + BITSET_LIMB_BIT - 1) / BITSET_LIMB_BIT)
@@ -70,7 +73,8 @@ bitset_init(bitset_t t)
{
assert (t != NULL);
assert (M_POWEROF2_P(BITSET_LIMB_BIT));
t->size = t->alloc = 0;
t->size = 0;
t->alloc = 0;
t->ptr = NULL;
BITSETI_CONTRACT(t);
}
@@ -148,7 +152,7 @@ bitset_set_at(bitset_t v, size_t i, bool x)
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 size_t mask = (bitset_limb)1<<index;
const bitset_limb mask = ((bitset_limb)1)<<index;
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (-(bitset_limb)x));
BITSETI_CONTRACT (v);
}
@@ -183,6 +187,7 @@ bitset_push_back (bitset_t v, bool x)
return;
}
// Clear allocated memory
// FIXME: Why?
for(size_t a = v->alloc; a < needAlloc; a++)
ptr[a] = 0;
v->ptr = ptr;
@@ -272,6 +277,14 @@ bitset_pop_back(bool *dest, bitset_t v)
BITSETI_CONTRACT (v);
}
static inline bool
bitset_front(bitset_t v)
{
BITSETI_CONTRACT (v);
assert(v->size > 0);
return bitset_get(v, 0);
}
static inline bool
bitset_back(bitset_t v)
{
@@ -407,7 +420,7 @@ 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 size_t mask = (((bitset_limb)1) << index) - 1;
const bitset_limb mask = (((bitset_limb)1) << index) - 1;
if ((set1->ptr[limbSize] & mask) != (set2->ptr[limbSize] & mask))
return false;
}
@@ -523,22 +536,32 @@ bitset_in_str(bitset_t set, FILE *file)
}
static inline bool
bitset_set_str(bitset_t set, const char str[])
bitset_parse_str(bitset_t set, const char str[], const char **endptr)
{
BITSETI_CONTRACT (set);
assert(str != NULL);
bool success = false;
bitset_clean(set);
char c = *str++;
if (c != '[') return false;
if (c != '[') goto exit;
c = *str++;
do {
if (c != '0' && c != '1') return false;
if (c != '0' && c != '1') goto exit;
const bool b = (c == '1');
bitset_push_back (set, b);
c = *str++;
} while (c != ']' && c != 0);
BITSETI_CONTRACT (set);
return c == ']';
success = (c == ']');
exit:
if (endptr) *endptr = str;
return success;
}
static inline bool
bitset_set_str(bitset_t dest, const char str[])
{
return bitset_parse_str(dest, str, NULL);
}
static inline void
@@ -552,7 +575,7 @@ 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) {
size_t mask = (((bitset_limb)1) << m) - 1;
bitset_limb mask = (((bitset_limb)1) << m) - 1;
dest->ptr[n] = (dest->ptr[n] & src->ptr[n]) & mask;
}
dest->size = s;
@@ -570,7 +593,7 @@ 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) {
size_t mask = (((bitset_limb)1) << m) - 1;
bitset_limb mask = (((bitset_limb)1) << m) - 1;
dest->ptr[n] = (dest->ptr[n] | src->ptr[n]) & mask;
}
dest->size = s;
@@ -588,7 +611,7 @@ 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) {
size_t mask = (((bitset_limb)1) << m) - 1;
bitset_limb mask = (((bitset_limb)1) << m) - 1;
dest->ptr[n] = (dest->ptr[n] ^ src->ptr[n]) & mask;
}
dest->size = s;
@@ -605,7 +628,7 @@ bitset_not(bitset_t dest)
for(size_t i = 0 ; i < n; i++)
dest->ptr[i] = ~ (dest->ptr[i]);
if (m) {
size_t mask = (((bitset_limb)1) << m) - 1;
bitset_limb mask = (((bitset_limb)1) << m) - 1;
dest->ptr[n] = (~ dest->ptr[n]) & mask;
}
dest->size = s;
@@ -613,25 +636,51 @@ bitset_not(bitset_t dest)
}
static inline size_t
bitset_hash(const bitset_t dest)
bitset_hash(const bitset_t set)
{
BITSETI_CONTRACT(dest);
size_t s = dest->size;
BITSETI_CONTRACT(set);
size_t s = set->size;
size_t n = s / BITSET_LIMB_BIT;
size_t m = s % BITSET_LIMB_BIT;
M_HASH_DECL(hash);
for(size_t i = 0 ; i < n; i++)
M_HASH_UP(hash, dest->ptr[i]);
M_HASH_UP(hash, set->ptr[i]);
if (m) {
size_t mask = (((bitset_limb)1) << m) - 1;
M_HASH_UP(hash, (dest->ptr[n] & mask));
bitset_limb mask = (((bitset_limb)1) << m) - 1;
M_HASH_UP(hash, (set->ptr[n] & mask));
}
return M_HASH_FINAL (hash);
}
static inline size_t
bitset_clz(const bitset_t set)
{
BITSETI_CONTRACT(set);
size_t s = set->size;
assert (s > 0);
size_t n = (s -1) / BITSET_LIMB_BIT;
size_t m = s % BITSET_LIMB_BIT;
bitset_limb limb = set->ptr[n];
if (m) {
bitset_limb mask = (((bitset_limb)1) << m) - 1;
limb &= mask;
} else {
m = BITSET_LIMB_BIT;
}
s = 0;
while (limb == 0 && n > 0) {
s += m;
limb = set->ptr[--n];
m = BITSET_LIMB_BIT;
}
s += m_core_clz64(limb) - (BITSET_LIMB_BIT - m);
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) \
@@ -639,6 +688,8 @@ bitset_hash(const bitset_t dest)
,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) \
@@ -656,10 +707,12 @@ bitset_hash(const bitset_t dest)
,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 */
#define M_OPL_bitset_t() BITSET_OPLIST
// TODO: set_at2, insert_v, remove_v
@@ -667,9 +720,9 @@ bitset_hash(const bitset_t dest)
#endif
// NOTE: Define this function only if m-string has been included
#ifndef __M_BITSET_STRING_H
#ifdef __M_STRING_H
#define __M_BITSET_STRING_H
#ifndef MSTARLIB_BITSET_STRING_H
#ifdef MSTARLIB_STRING_H
#define MSTARLIB_BITSET_STRING_H
static inline void
bitset_get_str(string_t str, const bitset_t set, bool append)
+1133
View File
File diff suppressed because it is too large. Load diff
+311 -101
View File
@@ -22,8 +22,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_BUFFER_H
#define __M_BUFFER_H
#ifndef MSTARLIB_BUFFER_H
#define MSTARLIB_BUFFER_H
#include "m-core.h"
#include "m-mutex.h"
@@ -54,16 +54,23 @@ typedef enum {
USAGE: BUFFER_DEF(name, type, size_of_buffer_or_0, policy[, oplist]) */
#define BUFFER_DEF(name, type, m_size, ... ) \
BUFFERI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, type, m_size,__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t)), \
((name, type, m_size,__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), M_C(name,_t)), \
(name, type, m_size,__VA_ARGS__, M_C(name,_t))))
/* Define the oplist of a lock based buffer given its name and its oplist.
USAGE: BUFFER_OPLIST(name[, oplist of the type]) */
#define BUFFER_OPLIST(...) \
BUFFERI_OPLIST(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
(__VA_ARGS__ )))
/* Define a lock-free queue for Many Producer Many Consummer
Much faster than queue of BUFFER_DEF in heavy communication scenario
Size of created queue can only a power of 2.
*/
#define QUEUE_MPMC_DEF(name, type, ...) \
QUEUEI_MPMC_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t)), \
((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), M_C(name,_t)), \
(name, type, __VA_ARGS__, M_C(name,_t))))
/* Define a wait-free queue for Single Producer Single Consummer
@@ -72,10 +79,12 @@ typedef enum {
*/
#define QUEUE_SPSC_DEF(name, type, ...) \
QUEUEI_SPSC_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t)), \
((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), M_C(name,_t)), \
(name, type, __VA_ARGS__, M_C(name,_t))))
/********************************** INTERNAL ************************************/
#define BUFFERI_IF_CTE_SIZE(m_size) M_IF(M_BOOL(m_size))
@@ -98,16 +107,26 @@ typedef enum {
#define BUFFERI_DEF2(name, type, m_size, policy, oplist, buffer_t) \
\
typedef struct M_C(name, _s) { \
m_mutex_t mutexPush; \
m_mutex_t mutexPop; \
m_cond_t there_is_data; \
m_cond_t there_is_room_for_data; \
BUFFERI_IF_CTE_SIZE(m_size)( ,size_t size;) \
size_t idx_prod, idx_cons, overwrite; \
m_mutex_t mutexPush; /* MUTEX used for pushing elements */ \
size_t idx_prod; /* Index of the production threads */ \
size_t overwrite; /* Number of overwritten values */ \
m_cond_t there_is_data; /* condition raised when there is data */ \
m_cond_t there_is_room_for_data; /* Cond. raised when there is room */ \
m_mutex_t mutexPop; /* MUTEX used for popping elements */ \
size_t idx_cons; /* Index of the consumption threads */ \
BUFFERI_IF_CTE_SIZE(m_size)( ,size_t size;) /* Size of the buffer */ \
/* number[0] := Number of elements in the buffer */ \
/* number[1] := [OPTION] Number of elements being deferred in the buffer */ \
atomic_ulong number[1 + BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)]; \
/* If fixed size, array of elements, otherwise pointer to element */ \
BUFFERI_IF_CTE_SIZE(m_size)(type data[m_size], type *data); \
} buffer_t[1]; \
\
typedef struct M_C(name, _s) *M_C(name, _ptr); \
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
typedef union { M_C(name, _srcptr) cptr; M_C(name, _ptr) ptr; } M_C(name, _uptr); \
typedef type M_C(name, _type_t); \
\
static inline void \
M_C(name, _init)(buffer_t v, size_t size) \
{ \
@@ -124,7 +143,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
} else \
assert(BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING)); \
BUFFERI_IF_CTE_SIZE(m_size)( , \
v->data = M_GET_REALLOC oplist (type, NULL, BUFFERI_SIZE(m_size)); \
v->data = M_CALL_REALLOC(oplist, type, NULL, BUFFERI_SIZE(m_size)); \
if (v->data == NULL) { \
M_MEMORY_FULL (BUFFERI_SIZE(m_size)*sizeof(type)); \
return; \
@@ -132,33 +151,41 @@ M_C(name, _init)(buffer_t v, size_t size) \
) \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
for(size_t i = 0; i < size; i++) { \
M_GET_INIT oplist(v->data[i]); \
M_CALL_INIT(oplist, v->data[i]); \
} \
} \
BUFFERI_CONTRACT(v,m_size); \
} \
\
BUFFERI_IF_CTE_SIZE(m_size)( \
static inline void \
M_C(name, _int_init)(buffer_t v) \
{ \
M_C(name, _init)(v, m_size); \
} \
, ) \
\
static inline void \
M_C(name, _int_clear_obj)(buffer_t v) \
{ \
BUFFERI_CONTRACT(v,m_size); \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
for(size_t i = 0; i < BUFFERI_SIZE(m_size); i++) { \
M_GET_CLEAR oplist(v->data[i]); \
M_CALL_CLEAR(oplist, v->data[i]); \
} \
} else { \
size_t i = BUFFERI_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \
while (i != v->idx_prod) { \
M_GET_CLEAR oplist(v->data[i]); \
M_CALL_CLEAR(oplist, v->data[i]); \
i++; \
if (!BUFFERI_POLICY_P((policy), BUFFER_STACK) && i >= BUFFERI_SIZE(m_size)) \
i = 0; \
} \
} \
v->idx_prod = v->idx_cons = 0; \
atomic_store (&v->number[0], 0UL); \
atomic_store_explicit (&v->number[0], 0UL, memory_order_relaxed); \
if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
atomic_store(&v->number[1], 0UL); \
atomic_store_explicit(&v->number[1], 0UL, memory_order_relaxed); \
BUFFERI_CONTRACT(v,m_size); \
} \
\
@@ -168,7 +195,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
BUFFERI_CONTRACT(v,m_size); \
M_C(name, _int_clear_obj)(v); \
BUFFERI_IF_CTE_SIZE(m_size)( , \
M_GET_FREE oplist (v->data); \
M_CALL_FREE(oplist, v->data); \
v->data = NULL; \
) \
v->overwrite = 0; \
@@ -192,9 +219,9 @@ M_C(name, _init)(buffer_t v, size_t size) \
if (BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) \
M_C(name, _int_clear_obj)(v); \
v->idx_prod = v->idx_cons = 0; \
atomic_store (&v->number[0], 0UL); \
atomic_store_explicit (&v->number[0], 0UL, memory_order_relaxed); \
if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
atomic_store(&v->number[1], 0UL); \
atomic_store_explicit(&v->number[1], 0UL, memory_order_relaxed); \
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
m_cond_broadcast(v->there_is_room_for_data); \
m_mutex_unlock(v->mutexPop); \
@@ -203,6 +230,120 @@ M_C(name, _init)(buffer_t v, size_t size) \
BUFFERI_CONTRACT(v,m_size); \
} \
\
static inline void \
M_C(name, _init_set)(buffer_t dest, const buffer_t src) \
{ \
/* unconst 'src', so that we can lock it (semantically it is const) */ \
M_C(name, _uptr) vu; \
vu.cptr = src; \
M_C(name, _ptr) v = vu.ptr; \
assert (dest != v); \
BUFFERI_CONTRACT(v,m_size); \
M_C(name, _init)(dest, BUFFERI_SIZE(m_size)); \
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
m_mutex_lock(v->mutexPush); \
m_mutex_lock(v->mutexPop); \
} \
\
BUFFERI_PROTECTED_CONTRACT(v, m_size); \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
for(size_t i = 0; i < BUFFERI_SIZE(m_size); i++) { \
M_CALL_INIT_SET(oplist, dest->data[i], v->data[i]); \
} \
} else { \
size_t i = BUFFERI_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \
while (i != v->idx_prod) { \
M_CALL_INIT_SET(oplist, dest->data[i], v->data[i]); \
i++; \
if (!BUFFERI_POLICY_P((policy), BUFFER_STACK) && i >= BUFFERI_SIZE(m_size)) \
i = 0; \
} \
} \
\
dest->idx_prod = v->idx_prod; \
dest->idx_cons = v->idx_cons; \
atomic_store_explicit (&dest->number[0], atomic_load(&v->number[0]), memory_order_relaxed); \
if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
atomic_store_explicit(&dest->number[1], atomic_load(&v->number[1]), memory_order_relaxed); \
\
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
m_mutex_unlock(v->mutexPop); \
m_mutex_unlock(v->mutexPush); \
} \
BUFFERI_CONTRACT(v,m_size); \
BUFFERI_CONTRACT(dest, m_size); \
} \
\
static inline void \
M_C(name, _set)(buffer_t dest, const buffer_t src) \
{ \
/* unconst 'src', so that we can lock it (semantically it is const) */ \
M_C(name, _uptr) vu; \
vu.cptr = src; \
M_C(name, _ptr) v = vu.ptr; \
BUFFERI_CONTRACT(dest,m_size); \
BUFFERI_CONTRACT(v,m_size); \
\
if (dest == v) return; \
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
/* Case of deadlock: A := B, B:=C, C:=A (all in //) \
Solution: order the lock by increasing memory */ \
if (dest < v) { \
m_mutex_lock(dest->mutexPush); \
m_mutex_lock(dest->mutexPop); \
m_mutex_lock(v->mutexPush); \
m_mutex_lock(v->mutexPop); \
} else { \
m_mutex_lock(v->mutexPush); \
m_mutex_lock(v->mutexPop); \
m_mutex_lock(dest->mutexPush); \
m_mutex_lock(dest->mutexPop); \
} \
} \
\
BUFFERI_PROTECTED_CONTRACT(v, m_size); \
M_C(name, _int_clear_obj)(dest); \
\
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
for(size_t i = 0; i < BUFFERI_SIZE(m_size); i++) { \
M_CALL_INIT_SET(oplist, dest->data[i], v->data[i]); \
} \
} else { \
size_t i = BUFFERI_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \
while (i != v->idx_prod) { \
M_CALL_INIT_SET(oplist, dest->data[i], v->data[i]); \
i++; \
if (!BUFFERI_POLICY_P((policy), BUFFER_STACK) && i >= BUFFERI_SIZE(m_size)) \
i = 0; \
} \
} \
\
dest->idx_prod = v->idx_prod; \
dest->idx_cons = v->idx_cons; \
atomic_store_explicit (&dest->number[0], atomic_load(&v->number[0]), memory_order_relaxed); \
if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
atomic_store_explicit(&dest->number[1], atomic_load(&v->number[1]), memory_order_relaxed); \
\
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
/* It may be false, but it is not wrong! */ \
m_cond_broadcast(v->there_is_room_for_data); \
m_cond_broadcast(v->there_is_data); \
if (dest < v) { \
m_mutex_unlock(v->mutexPop); \
m_mutex_unlock(v->mutexPush); \
m_mutex_unlock(dest->mutexPop); \
m_mutex_unlock(dest->mutexPush); \
} else { \
m_mutex_unlock(dest->mutexPop); \
m_mutex_unlock(dest->mutexPush); \
m_mutex_unlock(v->mutexPop); \
m_mutex_unlock(v->mutexPush); \
} \
} \
BUFFERI_CONTRACT(v,m_size); \
BUFFERI_CONTRACT(dest, m_size); \
} \
\
static inline bool \
M_C(name, _empty_p)(buffer_t v) \
{ \
@@ -212,23 +353,24 @@ M_C(name, _init)(buffer_t v, size_t size) \
deferred pop has reached 0, not the number of items in the \
buffer is 0. */ \
if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
return atomic_load (&v->number[1]) == 0; \
return atomic_load_explicit (&v->number[1], memory_order_relaxed) == 0; \
else \
return atomic_load (&v->number[0]) == 0; \
return atomic_load_explicit (&v->number[0], memory_order_relaxed) == 0; \
} \
\
static inline bool \
M_C(name, _full_p)(buffer_t v) \
{ \
BUFFERI_CONTRACT(v,m_size); \
return atomic_load (&v->number[0]) == BUFFERI_SIZE(m_size); \
return atomic_load_explicit (&v->number[0], memory_order_relaxed) \
== BUFFERI_SIZE(m_size); \
} \
\
static inline size_t \
M_C(name, _size)(buffer_t v) \
{ \
BUFFERI_CONTRACT(v,m_size); \
return atomic_load (&v->number[0]); \
return atomic_load_explicit (&v->number[0], memory_order_relaxed); \
} \
\
static inline bool \
@@ -261,10 +403,10 @@ M_C(name, _init)(buffer_t v, size_t size) \
/* Compute the index of the last push element */ \
idx--; \
if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \
idx = (idx == -1U) ? BUFFERI_SIZE(m_size)-1 : idx; \
idx = idx >= BUFFERI_SIZE(m_size) ? BUFFERI_SIZE(m_size)-1 : idx; \
} \
/* Update data in the buffer */ \
M_GET_SET oplist (v->data[idx], data); \
M_CALL_SET(oplist, v->data[idx], data); \
previousSize = BUFFERI_SIZE(m_size); \
\
} else { \
@@ -272,9 +414,9 @@ M_C(name, _init)(buffer_t v, size_t size) \
/* Add a new item in the buffer */ \
/* PUSH data in the buffer */ \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
M_GET_SET oplist (v->data[idx], data); \
M_CALL_SET(oplist, v->data[idx], data); \
} else { \
M_GET_INIT_SET oplist(v->data[idx], data); \
M_CALL_INIT_SET(oplist, v->data[idx], data); \
} \
\
/* Increment production INDEX of the buffer */ \
@@ -336,7 +478,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \
/* FIFO queue */ \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
M_GET_SET oplist (*data, v->data[v->idx_cons]); \
M_CALL_SET(oplist, *data, v->data[v->idx_cons]); \
} else { \
M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_cons]); \
} \
@@ -345,7 +487,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
/* STACK queue */ \
v->idx_prod --; \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
M_GET_SET oplist (*data, v->data[v->idx_prod]); \
M_CALL_SET(oplist, *data, v->data[v->idx_prod]); \
} else { \
M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_prod]); \
} \
@@ -424,6 +566,26 @@ M_C(name, _init)(buffer_t v, size_t size) \
} \
// Deferred evaluation for the oplist definition.
#define BUFFERI_OPLIST(arg) BUFFERI_OPLIST2 arg
/* OPLIST defininition of a buffer */
#define BUFFERI_OPLIST2(name, oplist) \
(INIT(M_C(name, _int_init)) \
,INIT_SET(M_C(name, _init_set)) \
,SET(M_C(name, _set)) \
,CLEAR(M_C(name, _clear)) \
,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)) \
)
/* Definition of a a QUEUE for Many Produccer / Many Consummer
for high bandwidth scenario:
@@ -443,9 +605,8 @@ M_C(name, _init)(buffer_t v, size_t size) \
# define QUEUEI_MPMC_CONTRACT(v) do { \
assert (v != 0); \
assert (v->Tab != NULL); \
unsigned long long _r = atomic_load(&v->ConsoIdx); \
unsigned long long _w = atomic_load(&v->ProdIdx); \
assert (_r <= _w); \
unsigned int _r = atomic_load(&v->ConsoIdx); \
unsigned int _w = atomic_load(&v->ProdIdx); \
_r = atomic_load(&v->ConsoIdx); \
assert (_r > _w || _w-_r <= v->size); \
assert (M_POWEROF2_P(v->size)); \
@@ -457,17 +618,23 @@ M_C(name, _init)(buffer_t v, size_t size) \
/* The sequence number of an element will be equal to either \
- 2* the index of the production which creates it, \
- 1 + 2* the index of the consumption which consummes it \
In case of overflow, as there is no order comparison but only \
equal comparison, there is no special issue. \
Each element is put in a separate cache line to avoid false \
sharing. \
*/ \
typedef struct M_C(name, _el_s) { \
atomic_ullong seq; /* Can only increase. */ \
atomic_uint seq; /* Can only increase until overflow */ \
type x; \
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(atomic_ullong)+sizeof(type) ? M_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(atomic_ullong)-sizeof(type) : 1]; \
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(atomic_uint)+sizeof(type) ? M_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(atomic_uint)-sizeof(type) : 1]; \
} M_C(name, _el_t); \
\
/* If there is only one producer and one consummer, then they won't \
typically use the same cache line, increasing performance. */ \
typedef struct M_C(name, _s) { \
atomic_ullong ProdIdx; /* Can only increase */ \
atomic_uint ProdIdx; /* Can only increase until overflow */ \
char align1[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
atomic_ullong ConsoIdx; /* can only increase */ \
atomic_uint ConsoIdx; /* Can only increase until overflow */ \
char align2[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
M_C(name, _el_t) *Tab; \
unsigned int size; \
@@ -477,23 +644,26 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_C(name, _push)(buffer_t table, type x) \
{ \
QUEUEI_MPMC_CONTRACT(table); \
unsigned long long idx = atomic_load(&table->ProdIdx); \
unsigned int idx = atomic_load_explicit(&table->ProdIdx, \
memory_order_relaxed); \
const unsigned int i = idx & (table->size -1); \
const unsigned long long seq = atomic_load(&table->Tab[i].seq); \
const unsigned int seq = atomic_load_explicit(&table->Tab[i].seq, \
memory_order_acquire); \
if (M_UNLIKELY (2*(idx - table->size) + 1 != seq)) { \
/* Buffer full (or unlikely preemption). Can not push */ \
return false; \
} \
if (M_UNLIKELY (!atomic_compare_exchange_strong(&table->ProdIdx, &idx, idx+1))) { \
/* Thread has been preemptted by another one. */ \
if (M_UNLIKELY (!atomic_compare_exchange_strong_explicit(&table->ProdIdx, \
&idx, idx+1, memory_order_relaxed, memory_order_relaxed))) { \
/* Thread has been preempted by another one. */ \
return false; \
} \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
M_GET_SET oplist (table->Tab[i].x, x); \
M_CALL_SET(oplist, table->Tab[i].x, x); \
} else { \
M_GET_INIT_SET oplist (table->Tab[i].x, x); \
M_CALL_INIT_SET(oplist, table->Tab[i].x, x); \
} \
atomic_store(&table->Tab[i].seq, 2*idx); \
atomic_store_explicit(&table->Tab[i].seq, 2*idx, memory_order_release); \
QUEUEI_MPMC_CONTRACT(table); \
return true; \
} \
@@ -503,23 +673,26 @@ M_C(name, _init)(buffer_t v, size_t size) \
{ \
QUEUEI_MPMC_CONTRACT(table); \
assert (ptr != NULL); \
unsigned long long iC = atomic_load(&table->ConsoIdx); \
unsigned int iC = atomic_load_explicit(&table->ConsoIdx, \
memory_order_relaxed); \
const unsigned int i = (iC & (table->size -1)); \
const unsigned long long seq = atomic_load(&table->Tab[i].seq); \
const unsigned int seq = atomic_load_explicit(&table->Tab[i].seq, \
memory_order_acquire); \
if (seq != 2 * iC) { \
/* Nothing in buffer to consumme (or unlikely preemption) */ \
return false; \
} \
if (M_UNLIKELY (!atomic_compare_exchange_strong(&table->ConsoIdx, &iC, iC+1))) { \
if (M_UNLIKELY (!atomic_compare_exchange_strong_explicit(&table->ConsoIdx, \
&iC, iC+1, memory_order_relaxed, memory_order_relaxed))) { \
/* Thread has been preempted by another one */ \
return false; \
} \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
M_GET_SET oplist (*ptr , table->Tab[i].x); \
M_CALL_SET(oplist, *ptr, table->Tab[i].x); \
} else { \
M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \
} \
atomic_store(&table->Tab[i].seq, 2*iC + 1); \
atomic_store_explicit(&table->Tab[i].seq, 2*iC + 1, memory_order_release); \
QUEUEI_MPMC_CONTRACT(table); \
return true; \
} \
@@ -529,20 +702,20 @@ M_C(name, _init)(buffer_t v, size_t size) \
{ \
assert (buffer != NULL); \
assert( M_POWEROF2_P(size)); \
assert (size <= UINT_MAX); \
assert (size < UINT_MAX); \
assert(((policy) & (BUFFER_STACK|BUFFER_THREAD_UNSAFE|BUFFER_PUSH_OVERWRITE)) == 0); \
atomic_init(&buffer->ProdIdx, (unsigned long long) size); \
atomic_init(&buffer->ConsoIdx, (unsigned long long) size); \
atomic_init(&buffer->ProdIdx, (unsigned int) size); \
atomic_init(&buffer->ConsoIdx, (unsigned int) size); \
buffer->size = size; \
buffer->Tab = M_GET_REALLOC oplist (M_C(name, _el_t), NULL, size); \
buffer->Tab = M_CALL_REALLOC(oplist, M_C(name, _el_t), NULL, size); \
if (buffer->Tab == NULL) { \
M_MEMORY_FULL (size*sizeof(M_C(name, _el_t) )); \
return; \
} \
for(unsigned int j = 0; j < size; j++) { \
atomic_init(&buffer->Tab[j].seq, 2*j+1ULL); \
atomic_init(&buffer->Tab[j].seq, 2*j+1U); \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
M_GET_INIT oplist (buffer->Tab[j].x); \
M_CALL_INIT(oplist, buffer->Tab[j].x); \
} \
} \
QUEUEI_MPMC_CONTRACT(buffer); \
@@ -554,21 +727,21 @@ M_C(name, _init)(buffer_t v, size_t size) \
QUEUEI_MPMC_CONTRACT(buffer); \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
for(unsigned int j = 0; j < buffer->size; j++) { \
M_GET_CLEAR oplist (buffer->Tab[j].x); \
M_CALL_CLEAR(oplist, buffer->Tab[j].x); \
} \
} else { \
unsigned long long iP = atomic_load(&buffer->ProdIdx); \
unsigned int iP = atomic_load_explicit(&buffer->ProdIdx, memory_order_relaxed); \
unsigned int i = iP & (buffer->size -1); \
unsigned long long iC = atomic_load(&buffer->ConsoIdx); \
unsigned int iC = atomic_load_explicit(&buffer->ConsoIdx, memory_order_relaxed); \
unsigned int j = iC & (buffer->size -1); \
while (i != j) { \
M_GET_CLEAR oplist(buffer->Tab[j].x); \
M_CALL_CLEAR(oplist, buffer->Tab[j].x); \
j++; \
if (j >= buffer->size) \
j = 0; \
} \
} \
M_GET_FREE oplist (buffer->Tab); \
M_CALL_FREE(oplist, buffer->Tab); \
buffer->Tab = NULL; /* safer */ \
} \
\
@@ -576,16 +749,28 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_C(name, _size)(buffer_t table) \
{ \
QUEUEI_MPMC_CONTRACT(table); \
const unsigned long long iC = atomic_load(&table->ConsoIdx); \
const unsigned long long iP = atomic_load(&table->ProdIdx); \
/* We return an approximation as we can't read both iC & iP atomically*/ \
/* As we read producer index after consummer index, \
const unsigned int iC = atomic_load_explicit(&table->ConsoIdx, memory_order_relaxed); \
const unsigned int iP = atomic_load_explicit(&table->ProdIdx, memory_order_acquire); \
/* We return an approximation as we can't read both iC & iP atomically \
As we read producer index after consummer index, \
and they are atomic variables without reordering \
producer index is always greater or equal than consummer index */ \
assert (iP >= iC); \
producer index is always greater or equal than consumer index \
(or on overflow occurs, in which case as we compute with modulo \
arithmetic, the right result is computed). \
We may return a result which is greater than the size of the queue \
if the function is interrupted a long time between reading iC & \
iP. the function is not protected against it. \
*/ \
return iP-iC; \
} \
\
\
static inline size_t \
M_C(name, _capacity)(buffer_t v) \
{ \
QUEUEI_MPMC_CONTRACT(v); \
return v->size; \
} \
\
static inline bool \
M_C(name, _empty_p)(buffer_t v) \
{ \
@@ -595,7 +780,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
static inline bool \
M_C(name, _full_p)(buffer_t v) \
{ \
return M_C(name, _size)(v) == v->size; \
return M_C(name, _size)(v) >= v->size; \
} \
@@ -611,47 +796,51 @@ M_C(name, _init)(buffer_t v, size_t size) \
*/
#define QUEUEI_SPSC_DEF(arg) QUEUEI_SPSC_DEF2 arg
#ifdef NDEBUG
#define QUEUEI_SPSC_CONTRACT(table) do { } while (0)
#else
#define QUEUEI_SPSC_CONTRACT(table) do { \
assert (table != NULL); \
unsigned long long _r = atomic_load(&table->consoIdx); \
unsigned long long _w = atomic_load(&table->prodIdx); \
assert (_r <= _w); \
unsigned int _r = atomic_load(&table->consoIdx); \
unsigned int _w = atomic_load(&table->prodIdx); \
/* Due to overflow we don't have assert (_r <= _w); */ \
_r = atomic_load(&table->consoIdx); \
assert (_r > _w || _w-_r <= table->size); \
assert (M_POWEROF2_P(table->size)); \
} while (0)
#endif
#define QUEUEI_SPSC_DEF2(name, type, policy, oplist, buffer_t) \
\
/* Not sure if the alignment constraint is needed */ \
typedef struct M_C(name, _el_s) { \
type x; \
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(type) ? M_ALIGN_FOR_CACHELINE_EXCLUSION -sizeof(type) : 1]; \
} M_C(name, _el_t); \
\
typedef struct M_C(name, _s) { \
atomic_ullong consoIdx; \
size_t size; \
atomic_uint consoIdx; /* Can only increase until overflow */ \
unsigned int size; \
M_C(name, _el_t) *Tab; \
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(atomic_ullong) +sizeof(size_t) +sizeof(void*) ? M_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(atomic_ullong) -sizeof(size_t)-sizeof(void*): 1]; \
atomic_ullong prodIdx; \
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(atomic_uint) +sizeof(size_t) + sizeof(void*) ? M_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(atomic_uint) -sizeof(size_t)-sizeof(void*): 1]; \
atomic_uint prodIdx; /* Can only increase until overflow */ \
} buffer_t[1]; \
\
static inline bool \
M_C(name, _push)(buffer_t table, type x) \
{ \
QUEUEI_SPSC_CONTRACT(table); \
unsigned long long r = atomic_load(&table->consoIdx); \
unsigned long long w = atomic_load(&table->prodIdx); \
if (w-r == table->size) \
unsigned int r = atomic_load_explicit(&table->consoIdx, \
memory_order_relaxed); \
unsigned int w = atomic_load_explicit(&table->prodIdx, \
memory_order_acquire); \
if (w-r >= table->size) \
return false; \
size_t i = w & (table->size -1); \
unsigned int i = w & (table->size -1); \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
M_GET_SET oplist (table->Tab[i].x, x); \
M_CALL_SET(oplist, table->Tab[i].x, x); \
} else { \
M_GET_INIT_SET oplist (table->Tab[i].x, x); \
M_CALL_INIT_SET(oplist, table->Tab[i].x, x); \
} \
atomic_store(&table->prodIdx, w+1); \
atomic_store_explicit(&table->prodIdx, w+1, memory_order_release); \
QUEUEI_SPSC_CONTRACT(table); \
return true; \
} \
@@ -661,17 +850,19 @@ M_C(name, _init)(buffer_t v, size_t size) \
{ \
QUEUEI_SPSC_CONTRACT(table); \
assert (ptr != NULL); \
unsigned long long w = atomic_load(&table->prodIdx); \
unsigned long long r = atomic_load(&table->consoIdx); \
unsigned int w = atomic_load_explicit(&table->prodIdx, \
memory_order_relaxed); \
unsigned int r = atomic_load_explicit(&table->consoIdx, \
memory_order_acquire); \
if (w-r == 0) \
return false; \
size_t i = r & (table->size -1); \
unsigned int i = r & (table->size -1); \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
M_GET_SET oplist (*ptr , table->Tab[i].x); \
M_CALL_SET(oplist, *ptr , table->Tab[i].x); \
} else { \
M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \
} \
atomic_store(&table->consoIdx, r+1); \
atomic_store_explicit(&table->consoIdx, r+1, memory_order_release); \
QUEUEI_SPSC_CONTRACT(table); \
return true; \
} \
@@ -680,11 +871,29 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_C(name, _size)(buffer_t table) \
{ \
QUEUEI_SPSC_CONTRACT(table); \
unsigned long long r = atomic_load(&table->consoIdx); \
unsigned long long w = atomic_load(&table->prodIdx); \
unsigned int r = atomic_load_explicit(&table->consoIdx, \
memory_order_relaxed); \
unsigned int w = atomic_load_explicit(&table->prodIdx, \
memory_order_acquire); \
/* We return an approximation as we can't read both r & w atomically \
As we read producer index after consummer index, \
and they are atomic variables without reordering \
producer index is always greater or equal than consumer index \
(or on overflow occurs, in which case as we compute with modulo \
arithmetic, the right result is computed). \
We may return a result which is greater than the size of the queue \
if the function is interrupted a long time between reading the \
indexs. The function is not protected against it. \
*/ \
return w-r; \
} \
\
static inline size_t \
M_C(name, _capacity)(buffer_t v) \
{ \
return v->size; \
} \
\
static inline bool \
M_C(name, _empty_p)(buffer_t v) \
{ \
@@ -694,7 +903,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
static inline bool \
M_C(name, _full_p)(buffer_t v) \
{ \
return M_C(name, _size)(v) == v->size; \
return M_C(name, _size)(v) >= v->size; \
} \
\
static inline void \
@@ -702,18 +911,19 @@ M_C(name, _init)(buffer_t v, size_t size) \
{ \
assert (buffer != NULL); \
assert( M_POWEROF2_P(size)); \
assert (size < UINT_MAX); \
assert(((policy) & (BUFFER_STACK|BUFFER_THREAD_UNSAFE|BUFFER_PUSH_OVERWRITE)) == 0); \
atomic_init(&buffer->prodIdx, (unsigned long long) size); \
atomic_init(&buffer->consoIdx, (unsigned long long) size); \
atomic_init(&buffer->prodIdx, (unsigned int) size); \
atomic_init(&buffer->consoIdx, (unsigned int) size); \
buffer->size = size; \
buffer->Tab = M_GET_REALLOC oplist (M_C(name, _el_t), NULL, size); \
buffer->Tab = M_CALL_REALLOC(oplist, M_C(name, _el_t), NULL, size); \
if (buffer->Tab == NULL) { \
M_MEMORY_FULL (size*sizeof(M_C(name, _el_t) )); \
return; \
} \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
for(size_t j = 0; j < size; j++) { \
M_GET_INIT oplist (buffer->Tab[j].x); \
M_CALL_INIT(oplist, buffer->Tab[j].x); \
} \
} \
QUEUEI_SPSC_CONTRACT(buffer); \
@@ -725,21 +935,21 @@ M_C(name, _init)(buffer_t v, size_t size) \
QUEUEI_SPSC_CONTRACT(buffer); \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
for(unsigned int j = 0; j < buffer->size; j++) { \
M_GET_CLEAR oplist (buffer->Tab[j].x); \
M_CALL_CLEAR(oplist, buffer->Tab[j].x); \
} \
} else { \
unsigned long long iP = atomic_load(&buffer->prodIdx); \
unsigned int iP = atomic_load_explicit(&buffer->prodIdx, memory_order_relaxed); \
unsigned int i = iP & (buffer->size -1); \
unsigned long long iC = atomic_load(&buffer->consoIdx); \
unsigned int iC = atomic_load_explicit(&buffer->consoIdx, memory_order_relaxed); \
unsigned int j = iC & (buffer->size -1); \
while (i != j) { \
M_GET_CLEAR oplist(buffer->Tab[j].x); \
M_CALL_CLEAR(oplist, buffer->Tab[j].x); \
j++; \
if (j >= buffer->size) \
j = 0; \
} \
} \
M_GET_FREE oplist (buffer->Tab); \
M_CALL_FREE(oplist, buffer->Tab); \
buffer->Tab = NULL; /* safer */ \
} \
\
+716
View File
@@ -0,0 +1,716 @@
/*
* M*LIB - Basic Protected Concurrent module over container.
*
* Copyright (c) 2017-2018, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MSTARLIB_CONCURRENT_H
#define MSTARLIB_CONCURRENT_H
#include "m-core.h"
#include "m-mutex.h"
#include "m-atomic.h"
/* Define a protected concurrent container and its associated functions.
USAGE: CONCURRENT_DEF(name, type [, oplist_of_the_type]) */
#define CONCURRENT_DEF(name, ...) \
CONCURRENTI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name,_it_t) ), \
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t))))
/* Define the oplist of a protected concurrent container given its name and its oplist.
USAGE: CONCURRENT_OPLIST(name[, oplist of the type]) */
#define CONCURRENT_OPLIST(...) \
CONCURRENTI_OPLIST(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
(__VA_ARGS__ )))
/* Define a protected concurrent container and its associated functions with Read Preference.
USAGE: CONCURRENT_RP_DEF(name, type [, oplist_of_the_type]) */
#define CONCURRENT_RP_DEF(name, ...) \
CONCURRENTI_RP_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name,_it_t) ), \
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t))))
/********************************** INTERNAL ************************************/
// Deferred evaluation for the oplist definition.
#define CONCURRENTI_OPLIST(arg) CONCURRENTI_OPLIST2 arg
/* OPLIST definition
GET_KEY is not present as its interface is not compatible with a concurrent
container (_get returns a pointer to an internal data, data that may be
destroyed by another thread).
*/
#define CONCURRENTI_OPLIST2(name, oplist) \
(M_IF_METHOD(INIT, oplist)(INIT(M_C(name, _init)),) \
,M_IF_METHOD(INIT_SET, oplist)(INIT_SET(M_C(name, _init_set)),) \
,M_IF_METHOD(SET, oplist)(SET(M_C(name, _set)),) \
,M_IF_METHOD(CLEAR, oplist)(CLEAR(M_C(name, _clear)),) \
,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(M_C(name, _init_move)),) \
,M_IF_METHOD(MOVE, oplist)(MOVE(M_C(name, _move)),) \
,M_IF_METHOD(SWAP,oplist)(SWAP(M_C(name, _swap)),) \
,TYPE(M_C(name,_t)) \
,SUBTYPE(M_C(name, _type_t)) \
,OPLIST(oplist) \
,M_IF_METHOD(TEST_EMPTY, oplist)(TEST_EMPTY(M_C(name,_empty_p)),) \
,M_IF_METHOD(GET_SIZE, oplist)(GET_SIZE(M_C(name,_size)),) \
,M_IF_METHOD(CLEAN, oplist)(CLEAN(M_C(name,_clean)),) \
,M_IF_METHOD(KEY_TYPE, oplist)(KEY_TYPE(M_GET_KEY_TYPE oplist),) \
,M_IF_METHOD(VALUE_TYPE, oplist)(VALUE_TYPE(M_GET_VALUE_TYPE oplist),) \
,M_IF_METHOD(KEY_TYPE, oplist)(KEY_OPLIST(M_GET_KEY_OPLIST oplist),) \
,M_IF_METHOD(VALUE_TYPE, oplist)(VALUE_OPLIST(M_GET_VALUE_OPLIST oplist), ) \
,M_IF_METHOD(SET_KEY, oplist)(SET_KEY(M_C(name, _set_at)),) \
,M_IF_METHOD(ERASE_KEY, oplist)(ERASE_KEY(M_C(name, _erase)),) \
,M_IF_METHOD(PUSH, oplist)(PUSH(M_C(name,_push)),) \
,M_IF_METHOD(POP, oplist)(POP(M_C(name,_pop)),) \
,M_IF_METHOD(PUSH_MOVE, oplist)(PUSH_MOVE(M_C(name,_push_move)),) \
,M_IF_METHOD(POP_MOVE, oplist)(POP_MOVE(M_C(name,_pop_move)),) \
,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),) \
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),) \
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),) \
,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),) \
,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),) \
,M_IF_METHOD(HASH, oplist)(HASH(M_C(name, _hash)),) \
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
)
#define CONCURRENTI_CONTRACT(c) do { \
assert ((c) != NULL); \
} while (0)
// Deferred evaluation for the concurrent definition.
#define CONCURRENTI_DEF(arg) CONCURRENTI_DEF2 arg
// Internal definition.
#define CONCURRENTI_DEF2(name, type, oplist, concurrent_t, concurrent_it_t) \
\
typedef struct M_C(name, _s) { \
struct M_C(name, _s) *self; \
m_mutex_t lock; \
m_cond_t there_is_data; /* condition raised when there is data */ \
type data; \
} concurrent_t[1]; \
\
typedef struct M_C(name, _s) *M_C(name, _ptr); \
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
\
typedef type M_C(name, _type_t); \
\
/* Define the lock strategy (global & shared lock) */ \
static inline void \
M_C(name, _internal_init)(concurrent_t out) \
{ \
m_mutex_init(out->lock); \
m_cond_init(out->there_is_data); \
out->self = out; \
} \
\
static inline void \
M_C(name, _internal_clear)(concurrent_t out) \
{ \
assert (out->self == out); \
m_mutex_clear(out->lock); \
m_cond_clear(out->there_is_data); \
out->self = NULL; \
} \
\
static inline void \
M_C(name, _read_lock)(const concurrent_t out) \
{ \
assert (out->self == out); \
m_mutex_lock (out->self->lock); \
} \
\
static inline void \
M_C(name, _read_unlock)(const concurrent_t out) \
{ \
assert (out->self == out); \
m_mutex_unlock (out->self->lock); \
} \
\
static inline void \
M_C(name, _read_wait)(int *p, const concurrent_t out) \
{ \
assert (out->self == out); \
(void) p; \
m_cond_wait(out->self->there_is_data, out->self->lock); \
} \
\
static inline void \
M_C(name, _read_wait_unlock)(int *p, const concurrent_t out) \
{ \
(void) p; \
m_mutex_unlock (out->self->lock); \
} \
\
static inline void \
M_C(name, _write_lock)(concurrent_t out) \
{ \
m_mutex_lock (out->lock); \
} \
\
static inline void \
M_C(name, _write_unlock)(concurrent_t out) \
{ \
m_mutex_unlock (out->lock); \
} \
\
static inline void \
M_C(name, _write_wait)(const concurrent_t out) \
{ \
m_cond_wait(out->self->there_is_data, out->self->lock); \
} \
\
static inline void \
M_C(name, _write_signal)(concurrent_t out) \
{ \
m_cond_broadcast(out->there_is_data); \
} \
\
CONCURRENTI_DEF_FUNC(name, type, oplist, concurrent_t, concurrent_it_t)
// Internal definition of the functions.
#define CONCURRENTI_DEF_FUNC(name, type, oplist, concurrent_t, concurrent_it_t) \
M_IF_METHOD(INIT, oplist)( \
static inline void \
M_C(name, _init)(concurrent_t out) \
{ \
M_C(name, _internal_init)(out); \
M_CALL_INIT(oplist, out->data); \
CONCURRENTI_CONTRACT(out); \
} \
,) \
\
M_IF_METHOD(INIT_SET, oplist)( \
static inline void \
M_C(name, _init_set)(concurrent_t out, concurrent_t const src) \
{ \
CONCURRENTI_CONTRACT(src); \
assert (out != src); \
M_C(name, _internal_init)(out); \
M_C(name, _read_lock)(src); \
M_CALL_INIT_SET(oplist, out->data, src->data); \
M_C(name, _read_unlock)(src); \
CONCURRENTI_CONTRACT(out); \
} \
,) \
\
M_IF_METHOD(SET, oplist)( \
static inline void \
M_C(name, _set)(concurrent_t out, concurrent_t const src) \
{ \
CONCURRENTI_CONTRACT(out); \
if (out == src) return; \
if (out < src) { \
M_C(name, _write_lock)(out); \
M_C(name, _read_lock)(src); \
} else { \
M_C(name, _read_lock)(src); \
M_C(name, _write_lock)(out); \
} \
M_CALL_SET(oplist, out->data, src->data); \
if (out < src) { \
M_C(name, _read_lock)(src); \
M_C(name, _write_unlock)(out); \
} else { \
M_C(name, _write_unlock)(out); \
M_C(name, _read_unlock)(src); \
} \
CONCURRENTI_CONTRACT(out); \
} \
,) \
\
M_IF_METHOD(CLEAR, oplist)( \
static inline void \
M_C(name, _clear)(concurrent_t out) \
{ \
CONCURRENTI_CONTRACT(out); \
/* No need to lock */ \
M_CALL_CLEAR(oplist, out->data); \
M_C(name, _internal_clear)(out); \
} \
,) \
\
M_IF_METHOD(INIT_MOVE, oplist)( \
static inline void \
M_C(name, _init_move)(concurrent_t out, concurrent_t src) \
{ \
CONCURRENTI_CONTRACT(src); \
assert (out != src); \
/* No need to lock 'src' ? */ \
M_C(name, _internal_init)(out); \
M_CALL_INIT_MOVE(oplist, out->data, src->data); \
M_C(name, _internal_clear)(src); \
CONCURRENTI_CONTRACT(out); \
} \
,) \
\
M_IF_METHOD(MOVE, oplist)( \
static inline void \
M_C(name, _move)(concurrent_t out, concurrent_t src) \
{ \
CONCURRENTI_CONTRACT(out); \
CONCURRENTI_CONTRACT(src); \
/* No need to lock 'src' ? */ \
M_C(name, _write_lock)(out); \
M_CALL_MOVE(oplist, out->data, src->data); \
M_C(name, _write_unlock)(out); \
M_C(name, _internal_clear)(src); \
CONCURRENTI_CONTRACT(out); \
} \
,) \
\
M_IF_METHOD(SWAP, oplist)( \
static inline void \
M_C(name, _swap)(concurrent_t out, concurrent_t src) \
{ \
CONCURRENTI_CONTRACT(out); \
CONCURRENTI_CONTRACT(src); \
if (out < src) { \
M_C(name, _write_lock)(out); \
M_C(name, _write_lock)(src); \
} else { \
M_C(name, _write_lock)(src); \
M_C(name, _write_lock)(out); \
} \
M_CALL_SWAP(oplist, out->data, src->data); \
if (out < src) { \
M_C(name, _write_unlock)(src); \
M_C(name, _write_unlock)(out); \
} else { \
M_C(name, _write_unlock)(out); \
M_C(name, _write_unlock)(src); \
} \
} \
,) \
\
M_IF_METHOD(CLEAN, oplist)( \
static inline void \
M_C(name, _clean)(concurrent_t out) \
{ \
CONCURRENTI_CONTRACT(out); \
M_C(name, _write_lock)(out); \
M_CALL_CLEAN(oplist, out->data); \
M_C(name, _write_unlock)(out); \
} \
,) \
\
M_IF_METHOD(TEST_EMPTY, oplist)( \
static inline bool \
M_C(name, _empty_p)(concurrent_t const out) \
{ \
CONCURRENTI_CONTRACT(out); \
M_C(name, _read_lock)(out); \
bool b = M_CALL_TEST_EMPTY(oplist, out->data); \
M_C(name, _read_unlock)(out); \
return b; \
} \
,) \
\
M_IF_METHOD(GET_SIZE, oplist)( \
static inline size_t \
M_C(name, _size)(concurrent_t const out) \
{ \
CONCURRENTI_CONTRACT(out); \
M_C(name, _read_lock)(out); \
size_t r = M_CALL_GET_SIZE(oplist, out->data); \
M_C(name, _read_unlock)(out); \
return r; \
} \
,) \
\
M_IF_METHOD(SET_KEY, oplist)( \
static inline void \
M_C(name, _set_at)(concurrent_t out, M_GET_KEY_TYPE oplist const key, M_GET_VALUE_TYPE oplist const data) \
{ \
CONCURRENTI_CONTRACT(out); \
M_C(name, _write_lock)(out); \
M_CALL_SET_KEY(oplist, out->data, key, data); \
M_C(name, _write_signal)(out); \
M_C(name, _write_unlock)(out); \
} \
,) \
\
M_IF_METHOD(GET_KEY, oplist)( \
static inline bool \
M_C(name, _get_copy)(M_GET_VALUE_TYPE oplist *out_data, const concurrent_t out, M_GET_KEY_TYPE oplist const key) \
{ \
CONCURRENTI_CONTRACT(out); \
assert (out_data != NULL); \
M_C(name, _read_lock)(out); \
M_GET_VALUE_TYPE oplist *p = M_CALL_GET_KEY(oplist, out->data, key); \
if (p != NULL) { \
M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \
} \
M_C(name, _read_unlock)(out); \
return p != NULL; \
} \
,) \
\
M_IF_METHOD(GET_SET_KEY, oplist)( \
static inline void \
M_C(name, _get_at_copy)(M_GET_VALUE_TYPE oplist *out_data, concurrent_t out, M_GET_KEY_TYPE oplist const key) \
{ \
CONCURRENTI_CONTRACT(out); \
assert (out_data != NULL); \
M_C(name, _write_lock)(out); \
M_GET_VALUE_TYPE oplist *p = M_CALL_GET_SET_KEY(oplist, out->data, key); \
assert (p != NULL); \
M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \
M_C(name, _write_unlock)(out); \
} \
,) \
\
M_IF_METHOD(ERASE_KEY, oplist)( \
static inline bool \
M_C(name, _erase)(concurrent_t out, M_GET_KEY_TYPE oplist const key) \
{ \
CONCURRENTI_CONTRACT(out); \
M_C(name, _write_lock)(out); \
bool b = M_CALL_ERASE_KEY(oplist, out->data, key); \
M_C(name, _write_unlock)(out); \
return b; \
} \
,) \
\
M_IF_METHOD(PUSH, oplist)( \
static inline void \
M_C(name, _push)(concurrent_t out, M_GET_SUBTYPE oplist const data) \
{ \
CONCURRENTI_CONTRACT(out); \
M_C(name, _write_lock)(out); \
M_CALL_PUSH(oplist, out->data, data); \
M_C(name, _write_signal)(out); \
M_C(name, _write_unlock)(out); \
} \
,) \
\
M_IF_METHOD(POP, oplist)( \
static inline void \
M_C(name, _pop)(M_GET_SUBTYPE oplist *p, concurrent_t out) \
{ \
CONCURRENTI_CONTRACT(out); \
M_C(name, _write_lock)(out); \
M_CALL_POP(oplist, p, out->data); \
M_C(name, _write_unlock)(out); \
} \
,) \
\
M_IF_METHOD(PUSH_MOVE, oplist)( \
static inline void \
M_C(name, _push_move)(concurrent_t out, M_GET_SUBTYPE oplist *data) \
{ \
CONCURRENTI_CONTRACT(out); \
M_C(name, _write_lock)(out); \
M_CALL_PUSH_MOVE(oplist, out->data, data); \
M_C(name, _write_signal)(out); \
M_C(name, _write_unlock)(out); \
} \
,) \
\
M_IF_METHOD(POP_MOVE, oplist)( \
static inline void \
M_C(name, _pop_move)(M_GET_SUBTYPE oplist *p, concurrent_t out) \
{ \
CONCURRENTI_CONTRACT(out); \
M_C(name, _write_lock)(out); \
M_CALL_POP_MOVE(oplist, p, out->data); \
M_C(name, _write_unlock)(out); \
} \
,) \
\
M_IF_METHOD(GET_STR, oplist)( \
static inline void \
M_C(name, _get_str)(string_t str, concurrent_t const out, bool a) \
{ \
CONCURRENTI_CONTRACT(out); \
M_C(name, _read_lock)(out); \
M_CALL_GET_STR(oplist, str, out->data, a); \
M_C(name, _read_unlock)(out); \
} \
,) \
\
M_IF_METHOD(OUT_STR, oplist)( \
static inline void \
M_C(name, _out_str)(FILE *f, concurrent_t const out) \
{ \
CONCURRENTI_CONTRACT(out); \
M_C(name, _read_lock)(out); \
M_CALL_OUT_STR(oplist, f, out->data); \
M_C(name, _read_unlock)(out); \
} \
,) \
\
M_IF_METHOD(PARSE_STR, oplist)( \
static inline bool \
M_C(name, _parse_str)(concurrent_t out, const char str[], const char **e) \
{ \
CONCURRENTI_CONTRACT(out); \
M_C(name, _write_lock)(out); \
bool b = M_CALL_PARSE_STR(oplist, out->data, str, e); \
M_C(name, _write_signal)(out); \
M_C(name, _write_unlock)(out); \
return b; \
} \
,) \
\
M_IF_METHOD(IN_STR, oplist)( \
static inline bool \
M_C(name, _in_str)(concurrent_t out, FILE *f) \
{ \
CONCURRENTI_CONTRACT(out); \
M_C(name, _write_lock)(out); \
bool b = M_CALL_IN_STR(oplist, out->data, f); \
M_C(name, _write_signal)(out); \
M_C(name, _write_unlock)(out); \
return b; \
} \
,) \
\
M_IF_METHOD(EQUAL, oplist)( \
static inline bool \
M_C(name, _equal_p)(concurrent_t const out1, concurrent_t const out2) \
{ \
CONCURRENTI_CONTRACT(out1); \
CONCURRENTI_CONTRACT(out2); \
if (out1 == out2) return true; \
if (out1 < out2) { \
M_C(name, _read_lock)(out1); \
M_C(name, _read_lock)(out2); \
} else { \
M_C(name, _read_lock)(out2); \
M_C(name, _read_lock)(out1); \
} \
bool b = M_CALL_EQUAL(oplist, out1->data, out2->data); \
if (out1 < out2) { \
M_C(name, _read_unlock)(out2); \
M_C(name, _read_unlock)(out1); \
} else { \
M_C(name, _read_unlock)(out1); \
M_C(name, _read_unlock)(out2); \
} \
return b; \
} \
,) \
\
M_IF_METHOD(GET_KEY, oplist)( \
static inline bool \
M_C(name, _get_blocking)(M_GET_VALUE_TYPE oplist *out_data, const concurrent_t out, M_GET_KEY_TYPE oplist const key, bool blocking) \
{ \
CONCURRENTI_CONTRACT(out); \
assert (out_data != NULL); \
bool ret = false; \
int count = 0; \
M_C(name, _read_lock)(out); \
while (true) { \
M_GET_VALUE_TYPE oplist *p = M_CALL_GET_KEY(oplist, out->data, key); \
if (p != NULL) { \
M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \
ret = true; \
break; \
} \
if (blocking == false) break; \
M_C(name, _read_wait)(&count, out); \
} \
M_C(name, _read_wait_unlock)(&count, out); \
return ret; \
} \
,) \
\
M_IF_METHOD2(POP, TEST_EMPTY, oplist)( \
static inline bool \
M_C(name, _pop_blocking)(M_GET_SUBTYPE oplist *p, concurrent_t out, bool blocking) \
{ \
CONCURRENTI_CONTRACT(out); \
assert (p != NULL); \
bool ret = false; \
M_C(name, _write_lock)(out); \
while (true) { \
if (!M_CALL_TEST_EMPTY(oplist, out->data)) { \
M_CALL_POP(oplist, p, out->data); \
ret = true; \
break; \
} \
if (blocking == false) break; \
M_C(name, _write_wait)(out); \
} \
M_C(name, _write_unlock)(out); \
return ret; \
} \
,) \
\
M_IF_METHOD2(POP_MOVE, TEST_EMPTY, oplist)( \
static inline bool \
M_C(name, _pop_move_blocking)(M_GET_SUBTYPE oplist *p, concurrent_t out, bool blocking) \
{ \
CONCURRENTI_CONTRACT(out); \
assert (p != NULL); \
bool ret = false; \
M_C(name, _write_lock)(out); \
while (true) { \
if (!M_CALL_TEST_EMPTY(oplist, out->data)) { \
M_CALL_POP_MOVE(oplist, p, out->data); \
ret = true; \
break; \
} \
if (blocking == false) break; \
M_C(name, _write_wait)(out); \
} \
M_C(name, _write_unlock)(out); \
return ret; \
} \
,) \
\
M_IF_METHOD(HASH, oplist)( \
static inline size_t \
M_C(name, _hash)(concurrent_t const out) \
{ \
CONCURRENTI_CONTRACT(out); \
M_C(name, _read_lock)(out); \
size_t h = M_CALL_HASH(oplist, out->data); \
M_C(name, _read_unlock)(out); \
return h; \
} \
,) \
// Deferred evaluation for the concurrent definition.
#define CONCURRENTI_RP_DEF(arg) CONCURRENTI_RP_DEF2 arg
// Internal definition.
#define CONCURRENTI_RP_DEF2(name, type, oplist, concurrent_t, concurrent_it_t) \
\
typedef struct M_C(name, _s) { \
struct M_C(name, _s) *self; \
m_mutex_t lock; \
m_mutex_t read_lock; \
size_t read_count; \
m_cond_t there_is_data; /* condition raised when there is data */ \
type data; \
} concurrent_t[1]; \
\
typedef struct M_C(name, _s) *M_C(name, _ptr); \
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
\
typedef type M_C(name, _type_t); \
\
/* Define the lock strategy (multi lock) */ \
static inline void \
M_C(name, _internal_init)(concurrent_t out) \
{ \
m_mutex_init(out->lock); \
m_mutex_init(out->read_lock); \
m_cond_init(out->there_is_data); \
out->self = out; \
out->read_count = 0; \
} \
\
static inline void \
M_C(name, _internal_clear)(concurrent_t out) \
{ \
assert (out->self == out); \
m_mutex_clear(out->lock); \
m_mutex_clear(out->read_lock); \
m_cond_clear(out->there_is_data); \
out->self = NULL; \
} \
\
static inline void \
M_C(name, _read_lock)(const concurrent_t out) \
{ \
struct M_C(name, _s) *self = out->self; \
assert (self == out); \
m_mutex_lock (self->read_lock); \
self->read_count ++; \
if (self->read_count == 1) { \
m_mutex_lock (self->lock); \
} \
m_mutex_unlock (self->read_lock); \
} \
\
static inline void \
M_C(name, _read_unlock)(const concurrent_t out) \
{ \
struct M_C(name, _s) *self = out->self; \
assert (self == out); \
m_mutex_lock (self->read_lock); \
self->read_count --; \
if (self->read_count == 0) { \
m_mutex_unlock (self->lock); \
} \
m_mutex_unlock (self->read_lock); \
} \
\
static inline void \
M_C(name, _write_lock)(concurrent_t out) \
{ \
m_mutex_lock (out->lock); \
} \
\
static inline void \
M_C(name, _write_unlock)(concurrent_t out) \
{ \
m_mutex_unlock (out->lock); \
} \
\
static inline void \
M_C(name, _read_wait)(int *p, const concurrent_t out) \
{ \
struct M_C(name, _s) *self = out->self; \
assert (self == out); \
if (*p == 0) { \
m_mutex_unlock (self->read_lock); \
m_mutex_lock (self->lock); \
*p = 1; \
} else { \
m_cond_wait(self->there_is_data, self->lock); \
} \
} \
\
static inline void \
M_C(name, _read_wait_unlock)(int *p, const concurrent_t out) \
{ \
m_mutex_unlock (*p == 0 ? out->self->read_lock : out->self->lock); \
} \
\
static inline void \
M_C(name, _write_wait)(const concurrent_t out) \
{ \
m_cond_wait(out->self->there_is_data, out->self->lock); \
} \
\
static inline void \
M_C(name, _write_signal)(concurrent_t out) \
{ \
m_cond_broadcast(out->there_is_data); \
} \
\
CONCURRENTI_DEF_FUNC(name, type, oplist, concurrent_t, concurrent_it_t)
#endif
+636 -134
View File
File diff suppressed because it is too large. Load diff
+188 -61
View File
@@ -22,24 +22,24 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_DEQUE_H
#define __M_DEQUE_H
#ifndef MSTARLIB_DEQUE_H
#define MSTARLIB_DEQUE_H
#include "m-i-list.h"
/* Define a deque of a given type.
/* Define a deque of a given type and its associated functions.
USAGE: DEQUE_DEF(name, type [, oplist_of_the_type]) */
#define DEQUE_DEF(name, ...) \
DEQUEI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_DEFAULT_OPLIST, M_C(name,_t), M_C(name,_it_t), M_C(name, _node_t) ), \
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t), M_C(name, _node_t) )))
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name,_it_t), M_C(name, _node_t) ), \
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t), M_C(name, _node_t))))
/* Define the oplist of a deque of type.
/* Define the oplist of a deque of a type.
USAGE: DEQUE_OPLIST(name[, oplist of the type]) */
#define DEQUE_OPLIST(...) \
DEQUEI_OPLIST (M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
(__VA_ARGS__ )))
/********************************** INTERNAL ************************************/
@@ -77,6 +77,12 @@
type data[DEQUEI_MIN_ARRAY_SIZE]; \
} node_t; \
\
/* Each node is allocated with a variable size (so we use \
M_GET_REALLOC for the allocation). But we need to delete the nodes \
automatically with the intrusive list used for storing the nodes: \
so we register as a DEL operator the FREE operator of the oplist. \
The interfaces are compatible. \
*/ \
ILIST_DEF(M_C(name, _node_list), node_t, (DEL(M_GET_FREE oplist)) ) \
\
typedef struct M_C(name, _it2_s) { \
@@ -91,6 +97,8 @@
size_t default_size; \
size_t count; \
} deque_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, _it_s) { \
node_t *node; \
@@ -104,13 +112,13 @@
M_C(name, _int_new_node)(deque_t d) \
{ \
size_t def = d->default_size; \
if (M_UNLIKELY (def >SIZE_MAX / sizeof (type) - sizeof(M_C(name, _node_t)))) { \
if (M_UNLIKELY (def > SIZE_MAX / sizeof (type) - sizeof(M_C(name, _node_t)))) { \
M_MEMORY_FULL(sizeof(M_C(name, _node_t))+def * sizeof(type)); \
return NULL; \
} \
M_C(name, _node_t)*n = (M_C(name, _node_t)*) (void*) \
M_GET_REALLOC oplist (char, NULL, \
sizeof(M_C(name, _node_t)) + def * sizeof(type) ); \
M_CALL_REALLOC(oplist, char, NULL, \
sizeof(M_C(name, _node_t)) + def * sizeof(type) ); \
if (n==NULL) { \
M_MEMORY_FULL(sizeof(M_C(name, _node_t))+def * sizeof(type)); \
return NULL; \
@@ -119,7 +127,7 @@
M_C(name, _node_list_init_field)(n); \
/* Do not increase it too much if there are few items */ \
def = M_MIN(def, d->count); \
d->default_size = M_GET_INC_ALLOC oplist (def); \
d->default_size = M_CALL_INC_ALLOC(oplist, def); \
return n; \
} \
\
@@ -143,18 +151,17 @@
M_C(name, _clean)(deque_t d) \
{ \
DEQUEI_CONTRACT(d); \
M_C(name, _node_list_it_t) it; \
M_C(name, _node_t) *min_node = NULL; \
for(M_C(name, _node_list_it)(it, d->list) ; \
!M_C(name, _node_list_end_p)(it) ; \
M_C(name, _node_list_next)(it) ){ \
M_C(name, _node_t) *n = M_C(name, _node_list_ref)(it); \
size_t min = n == d->front->node ? d->back->index + 1 : 0; \
size_t max = n == d->back->node ? d->back->index + 1: n->size; \
for(M_C(name, _node_t) *n = d->front->node; \
n != NULL ; \
n = (n == d->back->node) ? NULL : \
M_C(name, _node_list_next_obj)(d->list, n) ){ \
size_t min = n == d->front->node ? d->front->index : 0; \
size_t max = n == d->back->node ? d->back->index : n->size; \
for(size_t i = min; i < max; i++) { \
M_GET_CLEAR oplist (n->data[i]); \
M_CALL_CLEAR(oplist, n->data[i]); \
} \
min_node = min_node == NULL || min_node->size > n->size ? n : min_node; \
min_node = (min_node == NULL || min_node->size > n->size) ? n : min_node; \
} \
assert (min_node != NULL); \
d->front->node = min_node; \
@@ -170,9 +177,9 @@
{ \
DEQUEI_CONTRACT(d); \
M_C(name, _clean)(d); \
/* We registered the delete operator to clear all objects */ \
/* We have registered the delete operator to clear all objects */ \
M_C(name, _node_list_clear)(d->list); \
/* It is safer to clean some variables*/ \
/* It is safer to clean some variables */ \
d->front->node = NULL; \
d->back->node = NULL; \
d->count = 0; \
@@ -207,18 +214,30 @@
{ \
type *p = M_C(name, _push_back_raw)(d); \
if (M_LIKELY(p != NULL)) { \
M_GET_INIT_SET oplist (*p, x); \
M_CALL_INIT_SET(oplist, *p, x); \
} \
} \
\
M_IF_METHOD(INIT, oplist)( \
static inline type * \
M_C(name, _push_back_new)(deque_t d) \
{ \
type *p = M_C(name, _push_back_raw)(d); \
if (M_LIKELY(p != NULL)) { \
M_GET_INIT oplist (*p); \
M_CALL_INIT(oplist, *p); \
} \
return p; \
} \
, ) \
\
static inline void \
M_C(name, _push_back_move)(deque_t d, type *x) \
{ \
assert (x != NULL); \
type *p = M_C(name, _push_back_raw)(d); \
if (M_UNLIKELY(p == NULL)) \
return; \
M_DO_INIT_MOVE (oplist, *p, *x); \
} \
\
static inline type* \
@@ -251,18 +270,30 @@
{ \
type *p = M_C(name, _push_front_raw)(d); \
if (M_LIKELY(p != NULL)) { \
M_GET_INIT_SET oplist (*p, x); \
M_CALL_INIT_SET(oplist, *p, x); \
} \
} \
\
M_IF_METHOD(INIT, oplist)( \
static inline type * \
M_C(name, _push_front_new)(deque_t d) \
{ \
type *p = M_C(name, _push_front_raw)(d); \
if (M_LIKELY(p != NULL)) { \
M_GET_INIT oplist (*p); \
M_CALL_INIT(oplist, *p); \
} \
return p; \
} \
,) \
\
static inline void \
M_C(name, _push_front_move)(deque_t d, type *x) \
{ \
assert (x != NULL); \
type *p = M_C(name, _push_front_raw)(d); \
if (M_UNLIKELY(p == NULL)) \
return; \
M_DO_INIT_MOVE (oplist, *p, *x); \
} \
\
static inline void \
@@ -290,16 +321,27 @@
} \
if (ptr != NULL) \
M_IF_METHOD(MOVE, oplist) ( \
M_GET_MOVE oplist(*ptr, n->data[index]); else \
M_CALL_MOVE(oplist, *ptr, n->data[index]); else \
, \
M_GET_SET oplist(*ptr, n->data[index]); \
M_CALL_SET(oplist, *ptr, n->data[index]); \
) \
M_GET_CLEAR oplist (n->data[index]); \
M_CALL_CLEAR(oplist, n->data[index]); \
d->count --; \
d->back->index = index; \
DEQUEI_CONTRACT(d); \
} \
\
M_IF_METHOD(INIT, oplist)( \
static inline void \
M_C(name, _pop_back_move)(type *ptr, deque_t d) \
{ \
assert(ptr != NULL); \
/* Note: Lazy implementation. Can be improved if needed */ \
M_CALL_INIT(oplist, *ptr); \
M_C(name, _pop_back)(ptr, d); \
} \
, ) \
\
static inline void \
M_C(name, _pop_front)(type *ptr, deque_t d) \
{ \
@@ -324,16 +366,27 @@
} \
if (ptr != NULL) \
M_IF_METHOD(MOVE, oplist) ( \
M_GET_MOVE oplist(*ptr, n->data[index]); else \
M_CALL_MOVE(oplist, *ptr, n->data[index]); else \
, \
M_GET_SET oplist(*ptr, n->data[index]); \
M_CALL_SET(oplist, *ptr, n->data[index]); \
) \
M_GET_CLEAR oplist (n->data[index]); \
M_CALL_CLEAR(oplist, n->data[index]); \
index++; \
d->count --; \
d->front->index = index; \
} \
\
M_IF_METHOD(INIT, oplist)( \
static inline void \
M_C(name, _pop_front_move)(type *ptr, deque_t d) \
{ \
assert(ptr != NULL); \
/* Note: Lazy implementation */ \
M_CALL_INIT(oplist, *ptr); \
M_C(name, _pop_front)(ptr, d); \
} \
,) \
\
static inline type * \
M_C(name, _back)(const deque_t d) \
{ \
@@ -370,6 +423,40 @@
DEQUEI_CONTRACT(d); \
return d->count; \
} \
\
static inline size_t \
M_C(name, _capacity_back)(const deque_t v) \
{ \
DEQUEI_CONTRACT(v); \
size_t s = 0; \
for(M_C(name, _node_t) *n = M_C(name, _node_list_back)(v->list); \
n != NULL ; \
n = (n == v->back->node) ? NULL : \
M_C(name, _node_list_previous_obj)(v->list, n) ){ \
s += (n == v->back->node ? v->back->index : n->size); \
} \
return s; \
} \
\
static inline size_t \
M_C(name, _capacity_front)(const deque_t v) \
{ \
DEQUEI_CONTRACT(v); \
size_t s = 0; \
for(M_C(name, _node_t) *n = M_C(name, _node_list_front)(v->list); \
n != NULL ; \
n = (n == v->front->node) ? NULL : \
M_C(name, _node_list_next_obj)(v->list, n) ){ \
s += n->size - (n == v->front->node ? v->front->index : 0); \
} \
return s; \
} \
\
static inline size_t \
M_C(name, _capacity)(const deque_t v) \
{ \
return M_C(name, _capacity_back)(v)+M_C(name, _capacity_front)(v); \
} \
\
static inline bool \
M_C(name, _empty_p)(const deque_t d) \
@@ -499,7 +586,7 @@
return &it->node->data[it->index]; \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cref)(it_t it) \
{ \
assert (it != NULL); \
@@ -526,8 +613,8 @@
it_t it; \
size_t i = DEQUEUI_DEFAULT_SIZE/2; \
for(M_C(name, _it)(it, src); !M_C(name, _end_p)(it) ; M_C(name, _next)(it)) { \
const type *obj = M_C(name, _cref)(it); \
M_GET_INIT_SET oplist (n->data[i], *obj); \
type const *obj = M_C(name, _cref)(it); \
M_CALL_INIT_SET(oplist, n->data[i], *obj); \
i++; \
assert (i <= d->back->index); \
} \
@@ -535,7 +622,7 @@
} \
\
static inline void \
M_C(name, _set)(deque_t d, deque_t src) \
M_C(name, _set)(deque_t d, deque_t const src) \
{ \
if (M_UNLIKELY (src == d)) \
return; \
@@ -549,7 +636,13 @@
{ \
DEQUEI_CONTRACT(src); \
assert (d!= NULL); \
memcpy(d, src, sizeof(deque_t)); \
M_C(name,_node_list_init_move)(d->list, src->list); \
d->front->node = src->front->node; \
d->front->index = src->front->index; \
d->back->node = src->back->node; \
d->back->index = src->back->index; \
d->default_size = src->default_size; \
d->count = src->count; \
memset(src, 0, sizeof(deque_t)); \
DEQUEI_CONTRACT(d); \
} \
@@ -587,12 +680,11 @@
assert (key < d->count); \
const size_t index0 = d->front->index; \
size_t count = 0; \
M_C(name, _node_list_it_t) it; \
/* This loop is in log(N) since the size increase exponentially.*/ \
for(M_C(name, _node_list_it)(it, d->list) ; \
!M_C(name, _node_list_end_p)(it) ; \
M_C(name, _node_list_next)(it) ){ \
M_C(name, _node_t) *n = M_C(name, _node_list_ref)(it); \
for(M_C(name, _node_t) *n = d->front->node; \
n != NULL ; \
n = (n == d->back->node) ? NULL : \
M_C(name, _node_list_next_obj)(d->list, n) ){ \
if (index0 + key < count + n->size) { \
return &n->data[index0 + key - count]; \
} \
@@ -602,7 +694,7 @@
return NULL; \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cget)(deque_t d, size_t key) \
{ \
return M_CONST_CAST(type, M_C(name, _get)(d, key)); \
@@ -614,7 +706,7 @@
DEQUEI_CONTRACT(d); \
assert (key < d->count); \
type *p = M_C(name, _get)(d, key); \
M_GET_SET oplist (*p, x); \
M_CALL_SET(oplist, *p, x); \
} \
\
M_IF_METHOD(EQUAL, oplist)( \
@@ -630,9 +722,9 @@
for(M_C(name, _it)(it1, d1), M_C(name,_it)(it2, d2); \
!M_C(name, _end_p)(it1) ; \
M_C(name, _next)(it1), M_C(name, _next)(it2)) { \
const type *obj1 = M_C(name, _cref)(it1); \
const type *obj2 = M_C(name, _cref)(it2); \
if (M_GET_EQUAL oplist (*obj1, *obj2) == false) \
type const *obj1 = M_C(name, _cref)(it1); \
type const *obj2 = M_C(name, _cref)(it2); \
if (M_CALL_EQUAL(oplist, *obj1, *obj2) == false) \
return false; \
} \
assert (M_C(name, _end_p)(it2)); \
@@ -648,8 +740,8 @@
M_HASH_DECL(hash); \
it_t it; \
for(M_C(name, _it)(it, d); !M_C(name, _end_p)(it); M_C(name, _next)(it)) { \
const type *obj = M_C(name, _cref)(it); \
M_HASH_UP (hash, M_GET_HASH oplist (*obj)); \
type const *obj = M_C(name, _cref)(it); \
M_HASH_UP (hash, M_CALL_HASH(oplist, *obj)); \
} \
return M_HASH_FINAL(hash); \
} \
@@ -664,14 +756,14 @@
assert (j < d->count); \
type *obj1 = M_C(name, _get)(d, i); \
type *obj2 = M_C(name, _get)(d, j); \
M_GET_SWAP oplist (*obj1, *obj2); \
M_CALL_SWAP(oplist, *obj1, *obj2); \
DEQUEI_CONTRACT(d); \
} \
, /* NO SWAP: TODO */) \
, /* NO SWAP */) \
\
M_IF_METHOD(GET_STR, oplist)( \
static inline void \
M_C(name, _get_str)(string_t str, deque_t deque, bool append) \
M_C(name, _get_str)(string_t str, deque_t const deque, bool append) \
{ \
STRINGI_CONTRACT(str); \
DEQUEI_CONTRACT(deque); \
@@ -680,8 +772,8 @@
for (M_C(name, _it)(it, deque) ; \
!M_C(name, _end_p)(it); \
M_C(name, _next)(it)){ \
const type *item = M_C(name, _cref)(it); \
M_GET_GET_STR oplist (str, *item, true); \
type const *item = M_C(name, _cref)(it); \
M_CALL_GET_STR(oplist, str, *item, true); \
if (!M_C(name, _last_p)(it)) \
string_push_back (str, M_GET_SEPARATOR oplist); \
} \
@@ -701,8 +793,8 @@
for (M_C(name, _it)(it, deque) ; \
!M_C(name, _end_p)(it); \
M_C(name, _next)(it)) { \
const type *item = M_C(name, _cref)(it); \
M_GET_OUT_STR oplist (file, *item); \
type const *item = M_C(name, _cref)(it); \
M_CALL_OUT_STR(oplist, file, *item); \
if (!M_C(name, _last_p)(it)) \
fputc (M_GET_SEPARATOR oplist, file); \
} \
@@ -710,7 +802,38 @@
} \
, /* no OUT_STR */ ) \
\
M_IF_METHOD(IN_STR, oplist)( \
M_IF_METHOD2(PARSE_STR, INIT, oplist)( \
static inline bool \
M_C(name, _parse_str)(deque_t deque, const char str[], const char **endp) \
{ \
DEQUEI_CONTRACT(deque); \
assert (str != NULL); \
M_C(name,_clean)(deque); \
bool success = false; \
int c = *str++; \
if (M_UNLIKELY (c != '[')) goto exit; \
c = *str++; \
if (M_UNLIKELY (c == ']')) {success = true; goto exit;} \
if (M_UNLIKELY (c == 0)) goto exit; \
str--; \
type item; \
M_CALL_INIT(oplist, item); \
do { \
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
do { c = *str++; } while (isspace(c)); \
if (b == false || c == 0) { goto exit; } \
M_C(name, _push_back)(deque, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_CALL_CLEAR(oplist, item); \
DEQUEI_CONTRACT(deque); \
success = (c == ']'); \
exit: \
if (endp) *endp = str; \
return success; \
} \
, /* no PARSE_STR */ ) \
\
M_IF_METHOD2(IN_STR, INIT, oplist)( \
static inline bool \
M_C(name, _in_str)(deque_t deque, FILE *file) \
{ \
@@ -724,14 +847,14 @@
if (M_UNLIKELY (c == EOF)) return false; \
ungetc(c, file); \
type item; \
M_GET_INIT oplist (item); \
M_CALL_INIT(oplist, item); \
do { \
bool b = M_GET_IN_STR oplist (item, file); \
c = fgetc(file); \
bool b = M_CALL_IN_STR(oplist, item, file); \
do { c = fgetc(file); } while (isspace(c)); \
if (b == false || c == EOF) { break; } \
M_C(name, _push_back)(deque, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_GET_CLEAR oplist (item); \
M_CALL_CLEAR(oplist, item); \
DEQUEI_CONTRACT(deque); \
return c == ']'; \
} \
@@ -743,6 +866,7 @@
#define DEQUEI_OPLIST2(name, oplist) \
(INIT(M_C(name, _init)) \
,INIT_SET(M_C(name, _init_set)) \
,INIT_WITH(API_1(M_INIT_VAI)) \
,SET(M_C(name, _set)) \
,CLEAR(M_C(name, _clear)) \
,INIT_MOVE(M_C(name, _init_move)) \
@@ -750,6 +874,7 @@
,SWAP(M_C(name, _swap)) \
,TYPE(M_C(name,_t)) \
,SUBTYPE(M_C(name, _type_t)) \
,TEST_EMPTY(M_C(name,_empty_p)) \
,IT_TYPE(M_C(name,_it_t)) \
,IT_FIRST(M_C(name,_it)) \
,IT_LAST(M_C(name,_it_last)) \
@@ -763,10 +888,12 @@
,IT_REF(M_C(name,_ref)) \
,IT_CREF(M_C(name,_cref)) \
,CLEAN(M_C(name,_clean)) \
,GET_SIZE(M_C(name, _size)) \
,PUSH(M_C(name,_push_back)) \
,POP(M_C(name,_pop_back)) \
,OPLIST(oplist) \
,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),) \
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),) \
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),) \
,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),) \
,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),) \
+561 -156
View File
File diff suppressed because it is too large. Load diff
+29 -16
View File
@@ -22,8 +22,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_GENINT_H
#define __M_GENINT_H
#ifndef MSTARLIB_GENINT_H
#define MSTARLIB_GENINT_H
#include "m-core.h"
#include "m-atomic.h"
@@ -57,33 +57,43 @@ typedef struct genint_s {
atomic_ullong *data; // the bitfield which informs if an integer
} genint_t[1];
// Define the max 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_CONTRACT(s) do { \
assert (s != NULL); \
assert (s->n > 0 && s->n <= GENINT_LIMBSIZE * GENINT_LIMBSIZE); \
assert (s->n > 0 && s->n <= GENINT_MAX_ALLOC); \
assert ((s->max+1) * GENINT_LIMBSIZE >= s->n); \
assert (s->data != NULL); \
} while (0)
#define GENINT_ONE ((genint_limb_t)1)
// Value returned in case of error.
#define GENINT_ERROR (-1U)
// 32 bits of master are kept for handling the ABA problems.
#define GENINT_ABA_CPT 32
#define GENINT_ABA_CPT_T uint32_t
// Set the bit i of master
#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))) \
|((GENINT_ABA_CPT_T)((master) + 1)))
static inline void genint_init(genint_t s, size_t n)
static inline void genint_init(genint_t s, unsigned int n)
{
assert (s != NULL && n > 0 && n <= GENINT_LIMBSIZE * (GENINT_LIMBSIZE - GENINT_ABA_CPT));
assert (s != NULL && n > 0 && n <= GENINT_MAX_ALLOC);
const size_t alloc = (n + GENINT_LIMBSIZE - 1) / GENINT_LIMBSIZE;
const size_t index = n % GENINT_LIMBSIZE;
const unsigned int index = n % GENINT_LIMBSIZE;
atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, alloc);
if (M_UNLIKELY (ptr == NULL)) {
M_MEMORY_FULL(alloc);
@@ -95,7 +105,7 @@ static inline void genint_init(genint_t s, size_t n)
s->mask0 = (index == 0) ? -GENINT_ONE : ~((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);
for(size_t i = 0; i < alloc; i++)
for(unsigned int i = 0; i < alloc; i++)
atomic_init(&s->data[i], (genint_limb_t)0);
GENINT_CONTRACT(s);
}
@@ -113,8 +123,8 @@ static inline size_t genint_size(genint_t s)
return s->n;
}
// Typical case: one CAS per pop.
static inline size_t genint_pop(genint_t s)
// 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.
@@ -122,7 +132,8 @@ static inline size_t genint_pop(genint_t s)
// 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_clz(~master);
unsigned int i = m_core_clz64(~master);
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;
@@ -133,8 +144,10 @@ static inline size_t genint_pop(genint_t s)
// If it is now full, we have been preempted by another.
if (M_UNLIKELY (org == mask))
goto next_element;
assert (org != -GENINT_ONE);
// At least one bit is free in the limb. Find one.
bit = GENINT_LIMBSIZE - 1 - m_core_clz(~org);
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);
// Set the integer as being used.
@@ -165,16 +178,16 @@ static inline size_t genint_pop(genint_t s)
master = atomic_load(&s->master);
}
GENINT_CONTRACT(s);
return -(size_t)1; // No more resource available
return GENINT_ERROR; // No more resource available
}
// Typical usage: one CAS per push
static inline void genint_push(genint_t s, size_t n)
// 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);
const size_t i = n / GENINT_LIMBSIZE;
const size_t bit = GENINT_LIMBSIZE - 1 - (n % GENINT_LIMBSIZE);
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);
// Load the limb
genint_limb_t next, org = atomic_load(&s->data[i]);
+152 -33
View File
@@ -22,16 +22,17 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_I_LIST_H
#define __M_I_LIST_H
#ifndef MSTARLIB_I_LIST_H
#define MSTARLIB_I_LIST_H
#include "m-core.h"
#include "m-list.h" // For LISTI_ITBASE_DEF
/* Interface to add to a structure to allow intrusive support.
/* Interface to add to a structure to enable intrusive doubly-linked support.
name: name of the intrusive list.
type: name of the type of the structure (aka. struct test_s) - not used currently
USAGE:
struct tmp_str_s {
typedef struct tmp_str_s {
...
ILIST_INTERFACE(tmpstr, struct tmp_str_s);
...
@@ -40,20 +41,21 @@
#define ILIST_INTERFACE(name, type) \
struct ilist_head_s name
/* Define a list of a given type.
/* Define a doubly-linked intrusive list of a given type.
The type needs to have ILIST_INTERFACE().
USAGE:
LIST_DEF(name, type [, oplist_of_the_type]) */
ILIST_DEF(name, type [, oplist_of_the_type]) */
#define ILIST_DEF(name, ...) \
ILISTI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name, _t), M_C(name, _it_t) ), \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t), M_C(name, _it_t) ), \
(name, __VA_ARGS__, M_C(name, _t), M_C(name, _it_t) )))
/* Define the oplist of a ilist of type.
/* Define the oplist of a doubly-linked instrusive list of type.
USAGE:
LIST_OPLIST(name [, oplist_of_the_type]) */
ILIST_OPLIST(name [, oplist_of_the_type]) */
#define ILIST_OPLIST(...) \
ILISTI_OPLIST(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
(__VA_ARGS__ )))
@@ -65,15 +67,19 @@ typedef struct ilist_head_s {
struct ilist_head_s *prev;
} ilist_head_t;
/* Indirection call to allow expanding all arguments (TBC) */
/* Indirection call to allow expanding all arguments */
#define ILISTI_OPLIST(arg) ILISTI_OPLIST2 arg
/* Define the oplist of an ilist of type */
#define ILISTI_OPLIST2(name,oplist) \
(INIT(M_C(name, _init)), \
CLEAR(M_C(name, _clear)), \
INIT_MOVE(M_C(name, _init_move)), \
MOVE(M_C(name, _move)), \
TYPE(M_C(name,_t)), \
CLEAN(M_C(name,_clean)), \
SUBTYPE(M_C(name,_type_t)), \
TEST_EMPTY(M_C(name,_empty_p)), \
IT_TYPE(M_C(name,_it_t)), \
IT_FIRST(M_C(name,_it)), \
IT_SET(M_C(name,_it_set)), \
@@ -91,21 +97,32 @@ typedef struct ilist_head_s {
OPLIST(oplist), \
PUSH(M_C(name,_push_back)), \
POP(M_C(name,_pop_back)) \
SPLICE_BACK(M_C(name,_splice_back)) \
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
)
/* Contract respected by all intrusive lists */
#define ILISTI_CONTRACT(name, list) do { \
assert (list != NULL); \
assert(list->name.next->prev == &list->name); \
assert(list->name.prev->next == &list->name); \
assert(list != NULL); \
assert(list->name.prev != NULL); \
assert(list->name.next != NULL); \
assert(list->name.next->prev == &list->name); \
assert(list->name.prev->next == &list->name); \
} while (0)
#define ILISTI_NODE_CONTRACT(node) do { \
assert((node) != NULL); \
assert((node)->prev != NULL); \
assert((node)->next != NULL); \
assert((node)->next->prev == node); \
assert((node)->prev->next == node); \
} while (0)
/* Indirection call to allow expanding all arguments (TBC) */
#define ILISTI_DEF(arg) ILISTI_DEF2 arg
/* Definition of the type and function for an intrusive list.
/* Definition of the type and function for an intrusive doubly-linked list.
USAGE:
name: name of the intrusive list
type: type of the object
@@ -118,6 +135,8 @@ typedef struct ilist_head_s {
typedef struct M_C(name, _s) { \
struct ilist_head_s name; \
} list_t[1]; \
typedef struct M_C(name, _s) *M_C(name, _ptr); \
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
\
typedef type M_C(name, _type_t); \
\
@@ -141,14 +160,15 @@ typedef struct ilist_head_s {
ILISTI_CONTRACT(name, list); \
for(struct ilist_head_s *it = list->name.next, *next ; \
it != &list->name; it = next) { \
/* Cannot check node contract as previous node may be deleted */ \
type *obj = M_TYPE_FROM_FIELD(type, it, \
struct ilist_head_s, name); \
/* Read next now before the object is destroyed */ \
next = it->next; \
assert (next != NULL); \
M_GET_CLEAR oplist (*obj); \
M_CALL_CLEAR(oplist, *obj); \
/* Delete also the object if a DELETE operand is registered */ \
M_IF_METHOD(DEL, oplist)(M_GET_DEL oplist (obj), (void) 0); \
M_IF_METHOD(DEL, oplist)(M_CALL_DEL(oplist, obj), (void) 0); \
} \
/* Nothing remains in the list anymore */ \
list->name.next = &list->name; \
@@ -165,6 +185,29 @@ typedef struct ilist_head_s {
{ \
ILISTI_CONTRACT(name, list); \
return list->name.next == &list->name; \
} \
\
\
static inline void M_C(name, _init_move)(list_t list, list_t ref) \
{ \
ILISTI_CONTRACT(name, ref); \
assert (list != ref); \
M_C(name,_init)(list); \
if (!M_C(name,_empty_p)(ref)) { \
list->name.next = ref->name.next; \
list->name.prev = ref->name.prev; \
list->name.next->prev = &list->name; \
list->name.prev->next = &list->name; \
} \
ref->name.next = NULL; \
ref->name.prev = NULL; \
ILISTI_CONTRACT(name, list); \
} \
\
static inline void M_C(name, _move)(list_t list, list_t ref) \
{ \
M_C(name, _clear)(list); \
M_C(name, _init_move)(list, ref); \
} \
\
static inline size_t M_C(name, _size)(const list_t list) \
@@ -172,8 +215,10 @@ typedef struct ilist_head_s {
ILISTI_CONTRACT(name, list); \
size_t s = 0; \
for(const struct ilist_head_s *it = list->name.next ; \
it != &list->name; it = it->next) \
it != &list->name; it = it->next) { \
ILISTI_NODE_CONTRACT(it); \
s++; \
} \
return s; \
} \
\
@@ -249,34 +294,37 @@ typedef struct ilist_head_s {
} \
\
static inline type * \
M_C(name, _next_obj)(const list_t list, const type *obj) \
M_C(name, _next_obj)(const list_t list, type const *obj) \
{ \
ILISTI_CONTRACT(name, list); \
assert (obj != NULL); \
ILISTI_NODE_CONTRACT(&obj->name); \
return obj->name.next == &list->name ? NULL : \
M_TYPE_FROM_FIELD(type, obj->name.next, \
struct ilist_head_s, name); \
} \
\
static inline type * \
M_C(name, _previous_obj)(const list_t list, const type *obj) \
M_C(name, _previous_obj)(const list_t list, type const *obj) \
{ \
ILISTI_CONTRACT(name, list); \
assert (obj != NULL); \
ILISTI_NODE_CONTRACT(&obj->name); \
return obj->name.prev == &list->name ? NULL : \
M_TYPE_FROM_FIELD(type, obj->name.prev, \
struct ilist_head_s, name); \
} \
\
static inline void \
M_C(name, _it)(list_it_t it, list_t list) \
M_C(name, _it)(list_it_t it, const list_t list) \
{ \
ILISTI_CONTRACT(name, list); \
assert (it != NULL); \
it->head = &list->name; \
it->head = list->name.next->prev; \
it->current = list->name.next; \
it->next = list->name.next->next; \
it->previous = &list->name; \
it->previous = it->head; \
ILISTI_NODE_CONTRACT(it->current); \
} \
\
static inline void \
@@ -287,6 +335,7 @@ typedef struct ilist_head_s {
it->current = cit->current; \
it->next = cit->next; \
it->previous = cit->previous; \
ILISTI_NODE_CONTRACT(it->current); \
} \
\
static inline void \
@@ -298,6 +347,7 @@ typedef struct ilist_head_s {
it->current = list->name.prev; \
it->next = &list->name; \
it->previous = list->name.prev->prev; \
ILISTI_NODE_CONTRACT(it->current); \
} \
\
static inline void \
@@ -308,12 +358,14 @@ typedef struct ilist_head_s {
it->current = &list->name; \
it->next = list->name.next; \
it->previous = list->name.prev; \
ILISTI_NODE_CONTRACT(it->current); \
} \
\
static inline bool \
M_C(name, _end_p)(const list_it_t it) \
{ \
assert (it != NULL); \
ILISTI_NODE_CONTRACT(it->current); \
return it->current == it->head; \
} \
\
@@ -321,6 +373,7 @@ typedef struct ilist_head_s {
M_C(name, _last_p)(const list_it_t it) \
{ \
assert (it != NULL); \
ILISTI_NODE_CONTRACT(it->current); \
return it->next == it->head || it->current == it->head; \
} \
\
@@ -328,6 +381,7 @@ typedef struct ilist_head_s {
M_C(name, _next)(list_it_t it) \
{ \
assert (it != NULL); \
/* Cannot check node for it->current: it may have been deleted! */ \
/* Note: Can't set it->previous to it->current. \
it->current may have been unlinked from the list */ \
it->current = it->next; \
@@ -335,12 +389,14 @@ typedef struct ilist_head_s {
it->next = it->current->next; \
it->previous = it->current->prev; \
assert (it->next != NULL && it->previous != NULL); \
ILISTI_NODE_CONTRACT(it->current); \
} \
\
static inline void \
M_C(name, _previous)(list_it_t it) \
{ \
assert (it != NULL); \
/* Cannot check node for it->current: it may have been deleted! */ \
/* Note: Can't set it->next to it->current. \
it->current may have been unlinked from the list */ \
it->current = it->previous; \
@@ -348,6 +404,7 @@ typedef struct ilist_head_s {
it->next = it->current->next; \
it->previous = it->current->prev; \
assert (it->next != NULL && it->previous != NULL); \
ILISTI_NODE_CONTRACT(it->current); \
} \
\
static inline bool \
@@ -362,6 +419,7 @@ typedef struct ilist_head_s {
M_C(name, _ref)(const list_it_t it) \
{ \
assert (it != NULL && it->current != NULL); \
ILISTI_NODE_CONTRACT(it->current); \
/* check if 'it' was not deleted */ \
assert (it->current->next == it->next); \
assert (it->current->prev == it->previous); \
@@ -370,7 +428,7 @@ typedef struct ilist_head_s {
struct ilist_head_s, name); \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cref)(const list_it_t it) \
{ \
type *ptr = M_C(name, _ref)(it); \
@@ -381,12 +439,13 @@ typedef struct ilist_head_s {
M_C(name, _remove)(list_t list, list_it_t it) \
{ \
ILISTI_CONTRACT(name, list); \
ILISTI_NODE_CONTRACT(it->current); \
(void)list; /* list param is not used */ \
type *obj = M_TYPE_FROM_FIELD(type, it->current, \
struct ilist_head_s, name); \
M_C(name, _unlink)(obj); \
M_GET_CLEAR oplist (obj); \
M_IF_METHOD(DEL, oplist)(M_GET_DEL oplist (obj), (void) 0); \
M_CALL_CLEAR(oplist, obj); \
M_IF_METHOD(DEL, oplist)(M_CALL_DEL(oplist, obj), (void) 0); \
M_C(name, _next)(it); \
} \
\
@@ -395,12 +454,13 @@ typedef struct ilist_head_s {
M_C(name, _insert)(list_t list, list_it_t it, type x) \
{ \
ILISTI_CONTRACT(name, list); \
type *p = M_GET_NEW oplist (type); \
ILISTI_NODE_CONTRACT(it->current); \
type *p = M_CALL_NEW(oplist, type); \
if (M_UNLIKELY (p == NULL)) { \
M_MEMORY_FULL (sizeof (type)); \
return ; \
} \
M_GET_INIT_SET oplist (*p, x); \
M_CALL_INIT_SET(oplist, *p, x); \
type *obj = M_C(name, _ref)(it); \
M_C(name, _push_after)(obj, p); \
(void) list; \
@@ -452,26 +512,85 @@ typedef struct ilist_head_s {
{ \
ILISTI_CONTRACT(name, nv); \
ILISTI_CONTRACT(name, ov); \
ILISTI_NODE_CONTRACT(it->current); \
assert (it != NULL); \
(void) ov; \
type *obj = M_C(name, _ref)(it); \
M_C(name, _unlink)(obj); \
M_C(name, _push_back)(nv, obj); \
M_C(name, _next)(it); \
ILISTI_CONTRACT(name, nv); \
ILISTI_CONTRACT(name, ov); \
} \
\
static inline void \
M_C(name, _splice_at)(list_t nlist, list_it_t npos, \
list_t olist, list_it_t opos) \
{ \
ILISTI_CONTRACT(name, nlist); \
ILISTI_CONTRACT(name, olist); \
assert (npos != NULL && opos != NULL); \
assert (!M_C(name, _end_p)(opos)); \
/* npos may be end */ \
(void) olist, (void) nlist; \
type *obj = M_C(name, _ref)(opos); \
struct ilist_head_s *ref = npos->current; \
/* Remove object */ \
M_C(name, _unlink)(obj); \
/* Push 'obj' after 'ref' */ \
struct ilist_head_s *next = ref->next; \
ref->next = &obj->name; \
obj->name.next = next; \
obj->name.prev = ref; \
next->prev = &obj->name; \
/* Move iterator in old list */ \
M_C(name, _next)(opos); \
/* Set npos iterator to new position of object */ \
npos->previous = ref; \
npos->current = &obj->name; \
npos->next = next; \
ILISTI_CONTRACT(name, nlist); \
ILISTI_CONTRACT(name, olist); \
} \
\
static inline void \
M_C(name, _swap)(list_t d, list_t e) \
{ \
ILISTI_CONTRACT(name, d); \
ILISTI_CONTRACT(name, e); \
M_SWAP(struct ilist_head_s *, d->name.next, e->name.next); \
M_SWAP(struct ilist_head_s *, d->name.prev, e->name.prev); \
M_SWAP(struct ilist_head_s *, d->name.next->prev, e->name.next->prev); \
M_SWAP(struct ilist_head_s *, d->name.prev->next, e->name.prev->next); \
struct ilist_head_s *d_item = d->name.next; \
struct ilist_head_s *e_item = e->name.next; \
d->name.next = e_item == &e->name ? &d->name : e_item; \
e->name.next = d_item == &d->name ? &e->name : d_item; \
d_item = d->name.prev; \
e_item = e->name.prev; \
d->name.prev = e_item == &e->name ? &d->name : e_item; \
e->name.prev = d_item == &d->name ? &e->name : d_item; \
d->name.next->prev = &d->name; \
d->name.prev->next = &d->name; \
e->name.next->prev = &e->name; \
e->name.prev->next = &e->name; \
ILISTI_CONTRACT(name, d); \
ILISTI_CONTRACT(name, e); \
} \
\
static inline void \
M_C(name, _reverse)(list_t list) \
{ \
ILISTI_CONTRACT(name, list); \
struct ilist_head_s *next, *it; \
for(it = list->name.next ; it != &list->name; it = next) { \
next = it->next; \
it->next = it->prev; \
it->prev = next; \
} \
next = it->next; \
it->next = it->prev; \
it->prev = next; \
ILISTI_CONTRACT(name, list); \
} \
\
LISTI_ITBASE_DEF(name, type, oplist, list_t, list_it_t)
#endif
+8 -8
View File
@@ -22,8 +22,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_I_SHARED_PTR__H
#define __M_I_SHARED_PTR__H
#ifndef MSTARLIB_I_SHARED_PTR_H
#define MSTARLIB_I_SHARED_PTR_H
#include "m-core.h"
#include "m-atomic.h"
@@ -32,7 +32,7 @@
USAGE: ISHARED_OPLIST(name [, oplist_of_the_type]) */
#define ISHARED_PTR_OPLIST(...) \
ISHAREDI_PTR_OPLIST(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
(__VA_ARGS__ )))
/* Interface to add to a structure to allow intrusive support.
@@ -46,7 +46,7 @@
USAGE: ISHARED_PTR_DEF(name[, oplist]) */
#define ISHARED_PTR_DEF(name, ...) \
ISHAREDI_PTR_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
(name, __VA_ARGS__ )))
@@ -103,12 +103,12 @@
static inline M_C(name,_t) \
M_C(name, _init_new)(void) \
{ \
type *ptr = M_GET_NEW oplist (type); \
type *ptr = M_CALL_NEW(oplist, type); \
if (ptr == NULL) { \
M_MEMORY_FULL(sizeof(type)); \
return NULL; \
} \
M_GET_INIT oplist (*ptr); \
M_CALL_INIT(oplist, *ptr); \
atomic_init (&ptr->M_C(name, _cpt), 1); \
return ptr; \
} \
@@ -118,8 +118,8 @@
{ \
if (shared != NULL) { \
if (atomic_fetch_sub(&(shared->M_C(name, _cpt)), 1) == 1) { \
M_GET_CLEAR oplist (*shared); \
M_IF_DISABLED_METHOD(DEL, oplist)(, M_GET_DEL oplist (shared);) \
M_CALL_CLEAR(oplist, *shared); \
M_IF_DISABLED_METHOD(DEL, oplist)(, M_CALL_DEL(oplist, shared);) \
} \
} \
} \
+266 -67
View File
@@ -22,8 +22,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_LIST_H
#define __M_LIST_H
#ifndef MSTARLIB_LIST_H
#define MSTARLIB_LIST_H
#include "m-core.h"
@@ -31,21 +31,21 @@
USAGE: LIST_DEF(name, type [, oplist_of_the_type]) */
#define LIST_DEF(name, ...) \
LISTI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t), M_C(name, _it_t) ), \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name, _it_t) ), \
(name, __VA_ARGS__, M_C(name,_t), M_C(name, _it_t) )))
/* Define a dual-push singly linked list of a given type.
USAGE: LIST_DEF(name, type [, oplist_of_the_type]) */
#define LIST_DUAL_PUSH_DEF(name, ...) \
LISTI_DUAL_PUSH_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t), M_C(name, _it_t) ), \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name, _it_t) ), \
(name, __VA_ARGS__, M_C(name,_t), M_C(name, _it_t) )))
/* Define the oplist of a list of type.
USAGE: LIST_OPLIST(name [, oplist_of_the_type]) */
#define LIST_OPLIST(...) \
LISTI_OPLIST(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
(__VA_ARGS__ )))
@@ -54,8 +54,9 @@
#define LISTI_OPLIST(arg) LISTI_OPLIST2 arg
#define LISTI_OPLIST2(name, oplist) \
(INIT(M_C(name, _init)), \
(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)), \
MOVE(M_C(name, _move)), \
@@ -63,6 +64,7 @@
SWAP(M_C(name, _swap)), \
TYPE(M_C(name,_t)), \
SUBTYPE(M_C(name, _type_t)), \
TEST_EMPTY(M_C(name,_empty_p)), \
IT_TYPE(M_C(name, _it_t)), \
IT_FIRST(M_C(name,_it)), \
IT_END(M_C(name,_it_end)), \
@@ -73,14 +75,20 @@
IT_NEXT(M_C(name,_next)), \
IT_REF(M_C(name,_ref)), \
IT_CREF(M_C(name,_cref)), \
IT_INSERT(M_C(name, _insert)), \
IT_REMOVE(M_C(name,_remove)), \
CLEAN(M_C(name,_clean)), \
PUSH(M_C(name,_push_back)), \
POP(M_C(name,_pop_back)) \
POP(M_C(name,_pop_back)), \
PUSH_MOVE(M_C(name,_push_move)), \
POP_MOVE(M_C(name,_pop_move)) \
,SPLICE_BACK(M_C(name,_splice_back)) \
,SPLICE_AT(M_C(name,_splice_at)) \
,REVERSE(M_C(name,_reverse)) \
,OPLIST(oplist) \
,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),) \
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),) \
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),) \
,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),) \
,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),) \
,M_IF_METHOD(HASH, oplist)(HASH(M_C(name, _hash)),) \
@@ -107,10 +115,10 @@
, /* No mempool allocation */ \
\
static inline struct M_C(name, _s) *M_C(name, _int_new)(void) { \
return M_GET_NEW oplist (struct M_C(name, _s)); \
return M_CALL_NEW(oplist, struct M_C(name, _s)); \
} \
static inline void M_C(name,_int_del)(struct M_C(name, _s) *ptr) { \
M_GET_DEL oplist (ptr); \
M_CALL_DEL(oplist, ptr); \
} \
) \
@@ -120,6 +128,8 @@
struct M_C(name, _s) *next; \
type data; \
} *list_t[1]; \
typedef struct M_C(name, _s) *M_C(name, _ptr); \
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
\
typedef type M_C(name, _type_t); \
\
@@ -153,7 +163,7 @@
*v = NULL; \
while (it != NULL) { \
struct M_C(name, _s) *next = it->next; \
M_GET_CLEAR oplist(it->data); \
M_CALL_CLEAR(oplist, it->data); \
M_C(name,_int_del)(it); \
it = next; \
} \
@@ -166,7 +176,7 @@
M_C(name, _clean)(v); \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _back)(const list_t v) \
{ \
LISTI_CONTRACT(v); \
@@ -197,18 +207,20 @@
type *data = M_C(name, _push_raw)(v); \
if (M_UNLIKELY (data == NULL)) \
return; \
M_GET_INIT_SET oplist(*data, x); \
M_CALL_INIT_SET(oplist, *data, x); \
} \
\
M_IF_METHOD(INIT, oplist)( \
static inline type * \
M_C(name, _push_new)(list_t v) \
{ \
type *data = M_C(name, _push_raw)(v); \
if (M_UNLIKELY (data == NULL)) \
return NULL; \
M_GET_INIT oplist(*data); \
M_CALL_INIT(oplist, *data); \
return data; \
} \
, /* No INIT */) \
\
static inline void \
M_C(name, _pop_back)(type *data, list_t v) \
@@ -216,9 +228,32 @@
LISTI_CONTRACT(v); \
assert(*v != NULL); \
if (data != NULL) { \
M_GET_SET oplist(*data, (*v)->data); \
M_DO_MOVE (oplist, *data, (*v)->data); \
} else { \
M_CALL_CLEAR(oplist, (*v)->data); \
} \
M_GET_CLEAR oplist((*v)->data); \
struct M_C(name, _s) *tofree = *v; \
*v = (*v)->next; \
M_C(name,_int_del)(tofree); \
LISTI_CONTRACT(v); \
} \
\
static inline void \
M_C(name, _push_move)(list_t v, type *x) \
{ \
assert (x != NULL); \
type *data = M_C(name, _push_raw)(v); \
if (M_UNLIKELY (data == NULL)) \
return; \
M_DO_INIT_MOVE (oplist, *data, *x); \
} \
\
static inline void \
M_C(name, _pop_move)(type *data, list_t v) \
{ \
LISTI_CONTRACT(v); \
assert(*v != NULL && data != NULL); \
M_DO_INIT_MOVE (oplist, *data, (*v)->data); \
struct M_C(name, _s) *tofree = *v; \
*v = (*v)->next; \
M_C(name,_int_del)(tofree); \
@@ -304,10 +339,10 @@
M_C(name, _ref)(const list_it_t it) \
{ \
assert(it != NULL && it->current != NULL); \
return &(it->current->data); \
return &(it->current->data); \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cref)(const list_it_t it) \
{ \
assert(it != NULL && it->current != NULL); \
@@ -357,7 +392,7 @@
} \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cget)(const list_t l, size_t i) \
{ \
return M_CONST_CAST(type, M_C(name, _get)(l,i)); \
@@ -375,7 +410,7 @@
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
return; \
} \
M_GET_INIT_SET oplist(next->data, x); \
M_CALL_INIT_SET(oplist, next->data, x); \
struct M_C(name, _s) *current = insertion_point->current; \
if (M_UNLIKELY (current == NULL)) { \
next->next = *list; \
@@ -400,21 +435,18 @@
} else { \
removing_point->previous->next = next; \
} \
M_GET_CLEAR oplist(removing_point->current->data); \
M_CALL_CLEAR(oplist, removing_point->current->data); \
M_C(name,_int_del) (removing_point->current); \
removing_point->current = next; \
LISTI_CONTRACT(list); \
} \
\
static inline void \
M_C(name, _set)(list_t list, const list_t org) \
M_C(name, _init_set)(list_t list, const list_t org) \
{ \
LISTI_CONTRACT(list); \
LISTI_CONTRACT(org); \
struct M_C(name, _s) *next, *it_org; \
struct M_C(name, _s) **update_list; \
if (list == org) return; \
M_C(name, _clean)(list); \
update_list = list; \
it_org = *org; \
while (it_org != NULL) { \
@@ -426,17 +458,19 @@
return; \
} \
update_list = &next->next; \
M_GET_INIT_SET oplist(next->data, it_org->data); \
M_CALL_INIT_SET(oplist, next->data, it_org->data); \
it_org = it_org->next; \
} \
*update_list = NULL; \
LISTI_CONTRACT(list); \
} \
\
static inline void \
M_C(name, _init_set)(list_t list, const list_t org) \
M_C(name, _set)(list_t list, const list_t org) \
{ \
M_C(name, _init)(list); \
M_C(name, _set)(list, org); \
if (M_UNLIKELY (list == org)) return; \
M_C(name, _clear)(list); \
M_C(name, _init_set)(list, org); \
} \
\
static inline void \
@@ -461,10 +495,10 @@
{ \
LISTI_CONTRACT(nv); \
LISTI_CONTRACT(ov); \
assert (it != NULL && nv != ov); \
assert (it != NULL); \
assert (it->current != NULL); \
assert (M_C(name, _sublist_p)(ov, it)); \
/* Remove it from ov */ \
/* Remove the item 'it' from the list 'ov' */ \
struct M_C(name, _s) *current = it->current; \
struct M_C(name, _s) *next = current->next; \
if (it->previous == NULL) { \
@@ -472,11 +506,48 @@
} else { \
it->previous->next = next; \
} \
/* Update it to next element */ \
/* Update the item 'it' to point to the next element */ \
/* it->previous doesn't need to be updated */ \
it->current = next; \
/* Move current in nv */ \
current->next = *nv; \
*nv = current; \
} \
\
static inline void \
M_C(name, _splice_at)(list_t nlist, list_it_t npos, \
list_t olist, list_it_t opos) \
{ \
LISTI_CONTRACT(nlist); \
LISTI_CONTRACT(olist); \
assert (npos != NULL); \
assert (opos != NULL); \
assert (M_C(name, _sublist_p)(nlist, npos)); \
assert (M_C(name, _sublist_p)(olist, opos)); \
/* Remove the item 'opos' from the list 'olist' */ \
struct M_C(name, _s) *current = opos->current; \
struct M_C(name, _s) *next = current->next; \
if (opos->previous == NULL) { \
*olist = next; \
} else { \
opos->previous->next = next; \
} \
/* Update 'opos' to point to the next element */ \
opos->current = next; \
/* Insert 'current' into 'nlist' just after 'npos' */ \
struct M_C(name, _s) *previous = npos->current; \
if (M_UNLIKELY (previous == NULL)) { \
current->next = *nlist; \
*nlist = current; \
} else { \
current->next = previous->next; \
previous->next = current; \
} \
/* Update 'npos' to point to the new current element */ \
npos->previous = npos->current; \
npos->current = current; \
LISTI_CONTRACT(nlist); \
LISTI_CONTRACT(olist); \
} \
\
static inline void \
@@ -521,8 +592,8 @@
for (M_C(name, _it)(it, list) ; \
!M_C(name, _end_p)(it); \
M_C(name, _next)(it)){ \
const type *item = M_C(name, _cref)(it); \
M_GET_GET_STR oplist (str, *item, true); \
type const *item = M_C(name, _cref)(it); \
M_CALL_GET_STR(oplist, str, *item, true); \
if (!M_C(name, _last_p)(it)) \
string_push_back (str, M_GET_SEPARATOR oplist); \
} \
@@ -540,8 +611,8 @@
for (M_C(name, _it)(it, list) ; \
!M_C(name, _end_p)(it); \
M_C(name, _next)(it)){ \
const type *item = M_C(name, _cref)(it); \
M_GET_OUT_STR oplist (file, *item); \
type const *item = M_C(name, _cref)(it); \
M_CALL_OUT_STR(oplist, file, *item); \
if (!M_C(name, _last_p)(it)) \
fputc (M_GET_SEPARATOR oplist, file); \
} \
@@ -549,7 +620,37 @@
} \
, /* no out_str */ ) \
\
M_IF_METHOD(IN_STR, oplist)( \
M_IF_METHOD2(PARSE_STR, INIT, oplist)( \
static inline bool \
M_C(name, _parse_str)(list_t list, const char str[], const char **endp) \
{ \
assert (str != NULL && list != NULL); \
M_C(name,_clean)(list); \
bool success = false; \
int c = *str++; \
if (M_UNLIKELY (c != '[')) goto exit; \
c = *str++; \
if (M_UNLIKELY (c == ']')) { success = true; goto exit;} \
if (M_UNLIKELY (c == 0)) goto exit; \
str--; \
type item; \
M_CALL_INIT(oplist, item); \
do { \
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
do { c = *str++; } while (isspace(c)); \
if (b == false || c == 0) { goto exit; } \
M_C(name, _push_back)(list, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_CALL_CLEAR(oplist, item); \
M_C(name, _reverse)(list); \
success = (c == ']'); \
exit: \
if (endp) *endp = str; \
return success; \
} \
, /* no PARSE_STR & INIT */ ) \
\
M_IF_METHOD2(IN_STR, INIT, oplist)( \
static inline bool \
M_C(name, _in_str)(list_t list, FILE *file) \
{ \
@@ -562,18 +663,18 @@
if (M_UNLIKELY (c == EOF)) return false; \
ungetc(c, file); \
type item; \
M_GET_INIT oplist (item); \
M_CALL_INIT(oplist, item); \
do { \
bool b = M_GET_IN_STR oplist (item, file); \
c = fgetc(file); \
bool b = M_CALL_IN_STR(oplist, item, file); \
do { c = fgetc(file); } while (isspace(c)); \
if (b == false || c == EOF) { break; } \
M_C(name, _push_back)(list, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_GET_CLEAR oplist (item); \
M_CALL_CLEAR(oplist, item); \
M_C(name, _reverse)(list); \
return c == ']'; \
} \
, /* no in_str */ ) \
, /* no IN_STR & INIT */ ) \
\
M_IF_METHOD(EQUAL, oplist)( \
static inline bool \
@@ -587,9 +688,9 @@
M_C(name, _it)(it2, list2); \
while (!M_C(name, _end_p)(it1) \
&&!M_C(name, _end_p)(it2)) { \
const type *item1 = M_C(name, _cref)(it1); \
const type *item2 = M_C(name, _cref)(it2); \
bool b = M_GET_EQUAL oplist (*item1, *item2); \
type const *item1 = M_C(name, _cref)(it1); \
type const *item2 = M_C(name, _cref)(it2); \
bool b = M_CALL_EQUAL(oplist, *item1, *item2); \
if (!b) return false; \
M_C(name, _next)(it1); \
M_C(name, _next)(it2); \
@@ -609,8 +710,8 @@
for(M_C(name, _it)(it, list) ; \
!M_C(name, _end_p)(it); \
M_C(name, _next)(it)) { \
const type *item = M_C(name, _cref)(it); \
size_t hi = M_GET_HASH oplist (*item); \
type const *item = M_C(name, _cref)(it); \
size_t hi = M_CALL_HASH(oplist, *item); \
M_HASH_UP(hash, hi); \
} \
return M_HASH_FINAL (hash); \
@@ -631,10 +732,12 @@
type data; \
}; \
\
typedef struct { \
typedef struct M_C(name, _head_s) { \
struct M_C(name, _s) *front; \
struct M_C(name, _s) *back; \
} list_t[1]; \
typedef struct M_C(name, _head_s) *M_C(name, _ptr); \
typedef const struct M_C(name, _head_s) *M_C(name, _srcptr); \
\
typedef type M_C(name, _type_t); \
\
@@ -671,7 +774,7 @@
struct M_C(name, _s) *it = v->back; \
while (it != NULL) { \
struct M_C(name, _s) *next = it->next; \
M_GET_CLEAR oplist(it->data); \
M_CALL_CLEAR(oplist, it->data); \
M_C(name,_int_del)(it); \
it = next; \
} \
@@ -686,7 +789,7 @@
M_C(name, _clean)(v); \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _back)(const list_t v) \
{ \
LISTI_DUAL_PUSH_CONTRACT(v); \
@@ -721,17 +824,35 @@
type *data = M_C(name, _push_back_raw)(v); \
if (M_UNLIKELY (data == NULL)) \
return; \
M_GET_INIT_SET oplist(*data, x); \
M_CALL_INIT_SET(oplist, *data, x); \
} \
\
M_IF_METHOD(INIT, oplist)( \
static inline type * \
M_C(name, _push_back_new)(list_t v) \
{ \
type *data = M_C(name, _push_back_raw)(v); \
if (M_UNLIKELY (data == NULL)) \
return NULL; \
M_GET_INIT oplist(*data); \
M_CALL_INIT(oplist, *data); \
return data; \
} \
, /* No INIT */ ) \
\
static inline void \
M_C(name, _push_back_move)(list_t v, type *x) \
{ \
assert (x != NULL); \
type *data = M_C(name, _push_back_raw)(v); \
if (M_UNLIKELY (data == NULL)) \
return; \
M_DO_INIT_MOVE (oplist, *data, *x); \
} \
\
static inline void \
M_C(name, _push_move)(list_t v, type *x) \
{ \
M_C(name, _push_back_move)(v, x); \
} \
\
static inline void \
@@ -741,9 +862,10 @@
assert (v->back != NULL); \
struct M_C(name, _s) *tofree = v->back; \
if (data != NULL) { \
M_GET_SET oplist(*data, tofree->data); \
M_DO_MOVE(oplist, *data, tofree->data); \
} else { \
M_CALL_CLEAR(oplist, tofree->data); \
} \
M_GET_CLEAR oplist(tofree->data); \
v->back = tofree->next; \
M_C(name,_int_del)(tofree); \
/* Update front too if the list became empty */ \
@@ -754,7 +876,25 @@
LISTI_DUAL_PUSH_CONTRACT(v); \
} \
\
static inline const type * \
static inline void \
M_C(name, _pop_move)(type *data, list_t v) \
{ \
LISTI_DUAL_PUSH_CONTRACT(v); \
assert (v->back != NULL); \
assert (data != NULL); \
struct M_C(name, _s) *tofree = v->back; \
M_DO_INIT_MOVE (oplist, *data, tofree->data); \
v->back = tofree->next; \
M_C(name,_int_del)(tofree); \
/* Update front too if the list became empty */ \
/* This C code shall generate branchless code */ \
struct M_C(name, _s) *front = v->front; \
front = (front == tofree) ? NULL : front; \
v->front = front; \
LISTI_DUAL_PUSH_CONTRACT(v); \
} \
\
static inline type const * \
M_C(name, _front)(list_t v) \
{ \
LISTI_DUAL_PUSH_CONTRACT(v); \
@@ -790,18 +930,30 @@
type *data = M_C(name, _push_front_raw)(v); \
if (M_UNLIKELY (data == NULL)) \
return; \
M_GET_INIT_SET oplist(*data, x); \
M_CALL_INIT_SET(oplist, *data, x); \
} \
\
static inline void \
M_C(name, _push_front_move)(list_t v, type *x) \
{ \
assert (x != NULL); \
type *data = M_C(name, _push_front_raw)(v); \
if (M_UNLIKELY (data == NULL)) \
return; \
M_DO_INIT_MOVE (oplist, *data, *x); \
} \
\
M_IF_METHOD(INIT, oplist)( \
static inline type * \
M_C(name, _push_front_new)(list_t v) \
{ \
type *data = M_C(name, _push_back_raw)(v); \
if (M_UNLIKELY (data == NULL)) \
return NULL; \
M_GET_INIT oplist(*data); \
M_CALL_INIT(oplist, *data); \
return data; \
} \
, /* No INIT */) \
\
static inline bool \
M_C(name, _empty_p)(const list_t v) \
@@ -882,7 +1034,7 @@
return &(it->current->data); \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cref)(const list_it_t it) \
{ \
assert(it != NULL && it->current != NULL); \
@@ -913,7 +1065,7 @@
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
return; \
} \
M_GET_INIT_SET oplist(next->data, x); \
M_CALL_INIT_SET(oplist, next->data, x); \
if (M_UNLIKELY (insertion_point->current == NULL)) { \
next->next = list->back; \
list->back = next; \
@@ -949,7 +1101,7 @@
front = (next == NULL) ? previous : front; \
list->front = front; \
/* Remove node */ \
M_GET_CLEAR oplist(removing_point->current->data); \
M_CALL_CLEAR(oplist, removing_point->current->data); \
M_C(name,_int_del) (removing_point->current); \
removing_point->current = next; \
} \
@@ -974,7 +1126,7 @@
return; \
} \
update_list = &next->next; \
M_GET_INIT_SET oplist(next->data, it_org->data); \
M_CALL_INIT_SET(oplist, next->data, it_org->data); \
it_org = it_org->next; \
} \
list->front = next; \
@@ -1011,9 +1163,8 @@
{ \
LISTI_DUAL_PUSH_CONTRACT(list1); \
LISTI_DUAL_PUSH_CONTRACT(list2); \
assert (list1 != list2); \
assert(it->current != NULL); \
/* First remove 'it' from list2 */ \
assert (it->current != NULL); \
/* First remove the item 'it' from the list 'list2' */ \
struct M_C(name, _s) *current = it->current; \
struct M_C(name, _s) *next = current->next; \
if (it->previous == NULL) { \
@@ -1021,20 +1172,68 @@
} else { \
it->previous->next = next; \
} \
/* Update front */ \
/* Update the front of 'list2' if it was the last element */ \
struct M_C(name, _s) *front = list2->front; \
front = (next == NULL) ? it->previous : front; \
list2->front = front; \
/* Update it to next element */ \
/* Update 'it' to point to the next element */ \
it->current = next; \
/* Move current in nv */ \
/* Move the extracted 'current' into the list 'nv' */ \
current->next = list1->back; \
list1->back = current; \
/* Update front too if the list was empty */ \
/* Update the front field if the list 'nv' was empty */ \
/* This C code shall generate branchless code */ \
front = list1->front; \
front = (front == NULL) ? current : front; \
list1->front = front; \
LISTI_DUAL_PUSH_CONTRACT(list1); \
LISTI_DUAL_PUSH_CONTRACT(list2); \
} \
\
static inline void \
M_C(name, _splice_at)(list_t nlist, list_it_t npos, \
list_t olist, list_it_t opos) \
{ \
LISTI_DUAL_PUSH_CONTRACT(nlist); \
LISTI_DUAL_PUSH_CONTRACT(olist); \
assert (npos != NULL && opos != NULL); \
/* First remove the item 'opos' from the list 'olist' */ \
struct M_C(name, _s) *current = opos->current; \
struct M_C(name, _s) *next = current->next; \
if (opos->previous == NULL) { \
olist->back = next; \
} else { \
opos->previous->next = next; \
} \
/* Update the front of 'olist' if it was the last element */ \
struct M_C(name, _s) *front = olist->front; \
front = (next == NULL) ? opos->previous : front; \
olist->front = front; \
/* Update 'opos' to point to the next element */ \
opos->current = next; \
/* opos->previous is still valid & doesn't need to be updated */ \
/* Insert into 'nlist' */ \
struct M_C(name, _s) *npos_current = npos->current; \
if (M_UNLIKELY (npos_current == NULL)) { \
current->next = nlist->back; \
nlist->back = current; \
/* update 'front' if the list was empty (branchless) */ \
front = nlist->front; \
front = (front == NULL) ? current : front; \
nlist->front = front; \
} else { \
current->next = npos_current->next; \
npos_current->next = current; \
/* update front if current == front (branchless) */ \
front = nlist->front; \
front = (front == npos_current) ? current : front; \
nlist->front = front; \
} \
/* Update 'npos' to point to 'current'. */ \
npos->previous = npos_current; \
npos->current = current; \
LISTI_DUAL_PUSH_CONTRACT(nlist); \
LISTI_DUAL_PUSH_CONTRACT(olist); \
} \
\
static inline void \
+14 -10
View File
@@ -22,12 +22,12 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_MEMPOOL_H
#define __M_MEMPOOL_H
#ifndef MSTARLIB_MEMPOOL_H
#define MSTARLIB_MEMPOOL_H
#include "m-core.h"
/* Fast Fixed Size thread unsafe allocator.
/* Fast Fixed Size thread unsafe allocator based on memory region.
USAGE:
MEMPOOL_DEF(memppol_uint, unsigned int)
...
@@ -50,7 +50,7 @@
typedef struct M_C(name,_segment_s) { \
unsigned int count; \
struct M_C(name,_segment_s) *next; \
M_C(name,_union_t) tab[MEMPOOLI_MAX_PER_SEGMENT(type)]; \
M_C(name,_union_t) tab[MEMPOOL_MAX_PER_SEGMENT(type)]; \
} M_C(name,_segment_t); \
\
typedef struct M_C(name, _s) { \
@@ -99,7 +99,7 @@
M_C(name,_segment_t) *segment = mem->current_segment; \
assert(segment != NULL); \
unsigned int count = segment->count; \
if (M_UNLIKELY (count >= MEMPOOLI_MAX_PER_SEGMENT(type))) { \
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))); \
@@ -129,17 +129,21 @@
MEMPOOLI_CONTRACT(mem, type); \
} \
/* User shall be able to cutomize the size of the segment and/or
the minimun number of elements.
*/
#ifndef MEMPOOL_MAX_PER_SEGMENT
#define MEMPOOL_MAX_PER_SEGMENT(type) \
M_MAX((16*1024-sizeof(unsigned int) - 2*sizeof(void*)) / sizeof (type), 256U)
#endif
/********************************** INTERNAL ************************************/
// TODO: user shall be able to cutomize the size of the segment and/or
// the minimun number of elements... i.e. all the formula!
#define MEMPOOLI_MAX_PER_SEGMENT(type) \
M_MAX((16*1024-sizeof(unsigned int) - 2*sizeof(void*)) / sizeof (type), 256U)
#define MEMPOOLI_CONTRACT(mempool, type) do { \
assert((mempool) != NULL); \
assert((mempool)->current_segment != NULL); \
assert((mempool)->current_segment->count <= MEMPOOLI_MAX_PER_SEGMENT(type)); \
assert((mempool)->current_segment->count <= MEMPOOL_MAX_PER_SEGMENT(type)); \
} while (0)
#endif
+118 -51
View File
@@ -22,12 +22,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_MUTEX_H
#define __M_MUTEX_H
#include <assert.h>
#include <stdbool.h>
#include "m-core.h"
#ifndef MSTARLIB_MUTEX_H
#define MSTARLIB_MUTEX_H
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \
&& !defined(__STDC_NO_THREADS__)
@@ -35,6 +31,9 @@
/****************************** C11 version ********************************/
#include <threads.h>
#include <assert.h>
#include <stdbool.h>
#include "m-core.h"
typedef mtx_t m_mutex_t[1];
typedef cnd_t m_cond_t[1];
@@ -72,11 +71,6 @@ static inline void m_cond_clear(m_cond_t c)
cnd_destroy(c);
}
static inline void m_cond_clear(m_cond_t c)
{
cnd_signal(c);
}
static inline void m_cond_signal(m_cond_t c)
{
cnd_signal(c);
@@ -94,16 +88,30 @@ static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void* arg)
{
int rc = thrd_create(t, ((int)(*)(void*))func, arg);
int rc = thrd_create(t, (int(*)(void*))(void(*)(void))func, arg);
M_ASSERT_INIT (rc == thrd_success);
}
static inline void m_thread_join(m_thread_t t)
{
int rc = thrd_join(t, NULL);
int rc = thrd_join(*t, NULL);
assert (rc == thrd_success);
}
static inline void m_thread_yield(void)
{
thrd_yield();
}
static inline bool m_thread_sleep(unsigned long long usec)
{
struct timespec tv;
tv.tv_sec = usec / 1000000ULL;
tv.tv_nsec = (usec % 1000000ULL) * 1000UL;
int retval = thrd_sleep(&tv, NULL);
return retval == 0;
}
// Internal type, not exported.
typedef once_flag m_oncei_t[1];
#define M_ONCEI_INIT_VALUE { ONCE_FLAG_INIT }
@@ -112,86 +120,73 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
call_once(o,func);
}
#define M_THREAD_ATTR _Thread_local
#elif defined(WIN32) || defined(_WIN32)
// MSYS2 doesn't define _WIN32 by default.
#elif defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
/****************************** WIN32 version ******************************/
/* CriticalSection & ConditionVariable are available from Windows Vista */
#ifndef WINVER
#define WINVER _WIN32_WINNT_VISTA
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT _WIN32_WINNT_VISTA
#endif
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include "m-core.h"
typedef HANDLE m_mutex_t[1];
typedef HANDLE m_cond_t[1];
typedef HANDLE m_thread_t[1];
typedef CRITICAL_SECTION m_mutex_t[1];
typedef CONDITION_VARIABLE m_cond_t[1];
static inline void m_mutex_init(m_mutex_t m)
{
*m = CreateMutex(NULL, FALSE, NULL);
M_ASSERT_INIT(*m != NULL);
InitializeCriticalSection(m);
}
static inline void m_mutex_clear(m_mutex_t m)
{
CloseHandle(*m);
DeleteCriticalSection(m);
}
static inline void m_mutex_lock(m_mutex_t m)
{
DWORD dwWaitResult = WaitForSingleObject(*m, INFINITE);
assert (dwWaitResult == WAIT_OBJECT_0);
EnterCriticalSection(m);
}
static inline void m_mutex_unlock(m_mutex_t m)
{
ReleaseMutex(*m);
LeaveCriticalSection(m);
}
// Internal function, not exported
#define M_MUTEXI_INIT_VALUE { NULL }
static inline void m_mutexi_lazy_lock (m_mutex_t m)
{
HANDLE *addr = m;
if (*addr == NULL) {
/* Try to create one, affect it atomicaly and otherwise clears it */
HANDLE h = CreateMutex(NULL, FALSE, NULL);
if (InterlockedCompareExchangePointer((PVOID*)addr, (PVOID)h, NULL) != NULL)
CloseHandle(h);
/* FIXME: there is no way to clean the mutex at program exit... */
}
DWORD dwWaitResult = WaitForSingleObject(*addr, INFINITE);
assert (dwWaitResult == WAIT_OBJECT_0);
}
// TODO: Use cond var described here
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682052(v=vs.85).aspx
static inline void m_cond_init(m_cond_t c)
{
*c = CreateEvent (NULL, FALSE, FALSE, NULL);
M_ASSERT_INIT (*c != NULL);
InitializeConditionVariable(c);
}
static inline void m_cond_clear(m_cond_t c)
{
CloseHandle(*c);
(void) c; // There is no destructor for this object.
}
static inline void m_cond_signal(m_cond_t c)
{
PulseEvent(*c);
WakeConditionVariable(c);
}
static inline void m_cond_broadcast(m_cond_t c)
{
PulseEvent(*c);
WakeAllConditionVariable(c);
}
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
{
DWORD dwWaitResult = SignalObjectAndWait(*m, *c, INFINITE,FALSE);
assert (dwWaitResult == WAIT_OBJECT_0);
dwWaitResult = WaitForSingleObject(*m, INFINITE);
assert (dwWaitResult == WAIT_OBJECT_0);
SleepConditionVariableCS(c, m, INFINITE);
}
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void *arg)
@@ -203,17 +198,66 @@ 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)
{
DWORD dwWaitResult = WaitForSingleObject(*t, INFINITE);
(void) dwWaitResult;
assert (dwWaitResult == WAIT_OBJECT_0);
CloseHandle(*t);
}
static inline void m_thread_yield(void)
{
Sleep(0);
}
static inline bool m_thread_sleep(unsigned long long usec)
{
LARGE_INTEGER ft;
ft.QuadPart = -(10ULL*usec);
HANDLE hd = CreateWaitableTimer(NULL, TRUE, NULL);
M_ASSERT_INIT (hd != NULL);
SetWaitableTimer(hd, &ft, 0, NULL, NULL, 0);
DWORD dwWaitResult = WaitForSingleObject(hd, INFINITE);
CloseHandle(hd);
return dwWaitResult == WAIT_OBJECT_0;
}
// Internal type, not exported.
typedef INIT_ONCE m_oncei_t[1];
#define M_ONCEI_INIT_VALUE { INIT_ONCE_STATIC_INIT }
static inline BOOL CALLBACK m_oncei_callback( PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext)
{
void (*func)(void);
(void) InitOnce;
(void) lpContext;
func = (void (*)(void))(uintptr_t) Parameter;
(*func)();
return TRUE;
}
static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
{
InitOnceExecuteOnce(o, m_oncei_callback, (void*)(intptr_t)func, NULL);
}
#if defined(_MSC_VER)
# define M_THREAD_ATTR __declspec( thread )
#else
# define M_THREAD_ATTR __thread
#endif
#else
/**************************** PTHREAD version ******************************/
#include <pthread.h>
#ifdef _POSIX_PRIORITY_SCHEDULING
#include <sched.h>
#endif
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include <stdbool.h>
#include "m-core.h"
typedef pthread_mutex_t m_mutex_t[1];
typedef pthread_cond_t m_cond_t[1];
@@ -274,7 +318,7 @@ static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void *arg)
{
int _rc = pthread_create(t, NULL, (void*(*)(void*))func, arg);
int _rc = pthread_create(t, NULL, (void*(*)(void*))(void(*)(void))func, arg);
M_ASSERT_INIT (_rc == 0);
}
@@ -285,6 +329,24 @@ static inline void m_thread_join(m_thread_t t)
assert (_rc == 0);
}
static inline void m_thread_yield(void)
{
#ifdef _POSIX_PRIORITY_SCHEDULING
sched_yield();
#endif
}
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;
int retval = select(1, NULL, NULL, NULL, &tv);
return retval == 0;
}
// Internal type, not exported.
typedef pthread_once_t m_oncei_t[1];
#define M_ONCEI_INIT_VALUE { PTHREAD_ONCE_INIT }
@@ -293,8 +355,13 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
pthread_once(o,func);
}
#define M_THREAD_ATTR __thread
#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.
USAGE:
static M_LOCK_DECL(name);
+90 -15
View File
@@ -22,26 +22,26 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_PRIOQUEUE_H
#define __M_PRIOQUEUE_H
#ifndef MSTARLIB_PRIOQUEUE_H
#define MSTARLIB_PRIOQUEUE_H
#include "m-core.h"
#include "m-array.h"
/* Priority queue based on binary heap implementation */
/* Define an prioqueue of a given type.
/* Define a prioqueue of a given type and its associated functions.
USAGE: PRIOQUEUE_DEF(name, type [, oplist_of_the_type]) */
#define PRIOQUEUE_DEF(name, ...) \
PRIOQUEUEI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t), M_C(name,_it_t) ), \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name,_it_t) ), \
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t))))
/* Define the oplist of an prioqueue of type.
/* Define the oplist of a prioqueue of type.
USAGE: PRIOQUEUE_OPLIST(name[, oplist of the type]) */
#define PRIOQUEUE_OPLIST(...) \
PRIOQUEUEI_OPLIST(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
(__VA_ARGS__ )))
@@ -53,6 +53,7 @@
#define PRIOQUEUEI_OPLIST2(name, oplist) \
(INIT(M_C(name, _init)) \
,INIT_SET(M_C(name, _init_set)) \
,INIT_WITH(API_1(M_INIT_VAI)) \
,SET(M_C(name, _set)) \
,CLEAR(M_C(name, _clear)) \
,INIT_MOVE(M_C(name, _init_move)) \
@@ -64,6 +65,8 @@
,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_DEF2(name, type, oplist, prioqueue_t, it_t) \
@@ -74,6 +77,8 @@
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; \
\
@@ -147,20 +152,20 @@
} \
\
static inline int \
M_C(name, _i_cmp)(prioqueue_t p, size_t i, size_t j) \
M_C(name, _i_cmp)(const prioqueue_t p, size_t i, size_t j) \
{ \
return M_GET_CMP oplist (*M_C(name, _array_get)(p->array, i), \
*M_C(name, _array_get)(p->array, 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 p) \
M_C(name, _empty_p)(const prioqueue_t p) \
{ \
return M_C(name, _array_empty_p)(p->array); \
} \
\
static inline size_t \
M_C(name, _size)(prioqueue_t p) \
M_C(name, _size)(const prioqueue_t p) \
{ \
return M_C(name, _array_size)(p->array); \
} \
@@ -180,10 +185,10 @@
} \
} \
\
static inline type * \
static inline type const * \
M_C(name, _front)(prioqueue_t p) \
{ \
return M_C(name, _array_get)(p->array, 0); \
return M_C(name, _array_cget)(p->array, 0); \
} \
\
static inline void \
@@ -263,11 +268,81 @@
M_C(name, _array_previous)(it); \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cref)(const it_t it) \
{ \
return M_C(name, _array_cref)(it); \
} \
\
M_IF_METHOD(EQUAL, oplist) \
( \
/* EQUAL & CMP may be uncorrelated */ \
static inline bool \
M_C(name, _erase)(prioqueue_t p, type x) \
{ \
/* First pass: search for an item EQUAL to x */ \
size_t size = M_C(name, _array_size)(p->array); \
size_t i = 0; \
for(i = 0; i < size; i++) { \
if (M_CALL_EQUAL(oplist, *M_C(name, _array_cget)(p->array, i), x)) \
break; \
} \
/* If x is not found, then stop */ \
if (i >= size) \
return false; \
/* Swap the found item and the last element */ \
size--; \
M_C(name, _array_swap_at) (p->array, i, size); \
M_C(name, _array_pop_back)(NULL, p->array); \
/* 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 */ \) \
#endif
+104 -83
View File
@@ -22,8 +22,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_RBTREE_H
#define __M_RBTREE_H
#ifndef MSTARLIB_RBTREE_H
#define MSTARLIB_RBTREE_H
#include "m-core.h"
@@ -31,7 +31,7 @@
USAGE: RBTREE_DEF(name, type [, oplist_of_the_type]) */
#define RBTREE_DEF(name, ...) \
RBTREEI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), \
M_C(name, _t), struct M_C(name, _node_s), M_C(name, _it_t)), \
(name, __VA_ARGS__ , \
M_C(name, _t), struct M_C(name, _node_s), M_C(name, _it_t))))
@@ -40,7 +40,7 @@
USAGE: RBTREE_OPLIST(name [, oplist_of_the_type]) */
#define RBTREE_OPLIST(...) \
RBTREEI_OPLIST(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
((__VA_ARGS__, M_DEFAULT_OPLIST), \
(__VA_ARGS__ )))
@@ -52,6 +52,7 @@
#define RBTREEI_OPLIST2(name, oplist) \
(INIT(M_C(name, _init)), \
INIT_SET(M_C(name, _init_set)), \
INIT_WITH(API_1(M_INIT_VAI)), \
SET(M_C(name, _set)), \
CLEAR(M_C(name, _clear)), \
INIT_MOVE(M_C(name, _init_move)), \
@@ -59,6 +60,8 @@
SWAP(M_C(name, _swap)), \
TYPE(M_C(name,_t)), \
SUBTYPE(M_C(name, _type_t)), \
TEST_EMPTY(M_C(name,_empty_p)), \
GET_SIZE(M_C(name, _size)), \
IT_TYPE(M_C(name, _it_t)), \
IT_FIRST(M_C(name,_it)), \
IT_SET(M_C(name,_it_set)), \
@@ -72,10 +75,10 @@
IT_CREF(M_C(name,_cref)), \
CLEAN(M_C(name,_clean)), \
PUSH(M_C(name,_push)), \
POP(M_C(name,_pop)) \
GET_MIN(M_C(name,_min)), \
GET_MAX(M_C(name,_max)), \
M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),), \
M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),), \
M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),), \
M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),), \
M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),), \
@@ -88,7 +91,7 @@
/* Max depth of the binary tree
It is at worst twice the depth of a perfectly even tree with maximum elements.
The maximum number of elements is the max of size_t.
A perfectly even tree is therefore log2(max(size_t))=CHAR_BIT*sizeof(size_t)
A perfectly even tree is of depth log2(max(size_t))=CHAR_BIT*sizeof(size_t)
*/
#define RBTREEI_MAX_STACK (2*CHAR_BIT*sizeof (size_t))
@@ -123,6 +126,8 @@ typedef enum {
&& ((node)->child[1] == NULL || RBTREEI_IS_BLACK(node->child[1])))); \
} while (0)
//TODO: UPDATE shall use a separate method than push
// deferred evaluation
#define RBTREEI_DEF(arg) RBTREEI_DEF2 arg
@@ -138,6 +143,8 @@ typedef enum {
size_t size; \
node_t *node; \
} tree_t[1]; \
typedef struct M_C(name, _s) *M_C(name, _ptr); \
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
\
typedef struct M_C(name, _it_s) { \
node_t *stack[RBTREEI_MAX_STACK]; \
@@ -160,10 +167,10 @@ typedef enum {
, /* No mempool allocation */ \
\
static inline node_t *M_C(name,_int_new)(void) { \
return M_GET_NEW oplist (node_t); \
return M_CALL_NEW(oplist, node_t); \
} \
static inline void M_C(name,_int_del)(node_t *ptr) { \
M_GET_DEL oplist (ptr); \
M_CALL_DEL(oplist, ptr); \
} ) \
\
RBTREEI_DEF3(name, type, oplist, tree_t, node_t, tree_it_t)
@@ -205,7 +212,7 @@ typedef enum {
break; \
} \
assert (n == stack[cpt - 1]); \
M_GET_CLEAR oplist (n->data); \
M_CALL_CLEAR(oplist, n->data); \
M_C(name,_int_del) (n); \
assert((stack[cpt-1] = NULL) == NULL); \
cpt--; \
@@ -235,7 +242,7 @@ typedef enum {
M_MEMORY_FULL(sizeof (node_t)); \
return; \
} \
M_GET_INIT_SET oplist (n->data, data); \
M_CALL_INIT_SET(oplist, n->data, data); \
n->child[0] = n->child[1] = NULL; \
RBTREEI_SET_BLACK (n); \
tree->node = n; \
@@ -248,7 +255,7 @@ typedef enum {
tab[cpt] = n; \
while (n != NULL) { \
RBTREEI_CONTRACT_NODE(n); \
int cmp = M_GET_CMP oplist (n->data, data); \
int cmp = M_CALL_CMP(oplist, n->data, data); \
if (cmp == 0) { \
break; \
} else if (cmp > 0) { \
@@ -263,8 +270,8 @@ typedef enum {
} \
/* If found, update the data (default is set) */ \
if (n != NULL) { \
M_IF_METHOD (UPDATE, oplist)(M_GET_UPDATE oplist, M_GET_SET oplist) \
(n->data, data); \
M_IF_METHOD (UPDATE, oplist)(M_CALL_UPDATE(oplist, n->data, data) \
, M_CALL_SET(oplist, n->data, data)); \
RBTREEI_CONTRACT (tree); \
return; \
} \
@@ -274,7 +281,7 @@ typedef enum {
M_MEMORY_FULL (sizeof (node_t)); \
return; \
} \
M_GET_INIT_SET oplist (n->data, data); \
M_CALL_INIT_SET(oplist, n->data, data); \
n->child[0] = n->child[1] = NULL; \
RBTREEI_SET_RED (n); \
assert (tab[cpt] == NULL); \
@@ -303,50 +310,33 @@ typedef enum {
node_t *pp = tab[cpt-2]; \
node_t *p = tab[cpt-1]; \
node_t *x = tab[cpt]; \
int i = which[cpt-2]; \
int j = 1 - i; \
assert (i == 0 || i == 1); \
/* We need to do some rotations */ \
if (which[cpt-2] == 0) { \
/* The parent is the left child of the grand-parent */ \
if (which[cpt-1] == 0) { \
/* The child is the left child of its parent */ \
/* Right rotation: cpt is the new grand-parent. \
x is its left child, the grand-parent is the right one */ \
pp->child[0] = p->child[1]; \
p->child[0] = x; \
p->child[1] = pp; \
RBTREEI_SET_BLACK(p); \
RBTREEI_SET_RED(pp); \
} else { \
/* The child is the right child of its parent */ \
/* Left rotation */ \
pp->child[0] = x->child[1]; \
p->child[1] = x->child[0]; \
x->child[0] = p; \
x->child[1] = pp; \
RBTREEI_SET_BLACK(x); \
RBTREEI_SET_RED(p); \
RBTREEI_SET_RED(pp); \
p = x; \
} \
if (i == which[cpt-1]) { \
/* The child is the left child of its parent */ \
/* OR The child is the right child of its parent */ \
/* Right rotation: cpt is the new grand-parent. \
x is its left child, the grand-parent is the right one */ \
pp->child[i] = p->child[j]; \
p->child[i] = x; \
p->child[j] = pp; \
RBTREEI_SET_BLACK(p); \
RBTREEI_SET_RED(pp); \
} else { \
/* The parent is the right child of the grand-parent */ \
if (which[cpt-1] == 0) { \
/* The child is the left child of its parent */ \
pp->child[1] = x->child[0]; \
p->child[0] = x->child[1]; \
x->child[1] = p; \
x->child[0] = pp; \
RBTREEI_SET_BLACK(x); \
RBTREEI_SET_RED(p); \
RBTREEI_SET_RED(pp); \
p = x; \
} else { \
/* The child is the right child of its parent */ \
pp->child[1] = p->child[0]; \
p->child[1] = x; \
p->child[0] = pp; \
RBTREEI_SET_BLACK(p); \
RBTREEI_SET_RED(pp); \
} \
assert (j == which[cpt-1]); \
/* The child is the right child of its parent */ \
/* OR The child is the left child of its parent */ \
/* Left rotation */ \
pp->child[i] = x->child[j]; \
p->child[j] = x->child[i]; \
x->child[i] = p; \
x->child[j] = pp; \
RBTREEI_SET_BLACK(x); \
RBTREEI_SET_RED(p); \
RBTREEI_SET_RED(pp); \
p = x; \
} \
/* Insert the new grand parent */ \
if (cpt == 2) { \
@@ -472,7 +462,7 @@ typedef enum {
return &(it->stack[it->cpt-1]->data); \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cref)(const tree_it_t it) \
{ \
return M_CONST_CAST(type, M_C(name, _ref)(it)); \
@@ -497,7 +487,7 @@ typedef enum {
node_t *n = tree->node; \
it->stack[cpt] = n; \
while (n != NULL) { \
int cmp = M_GET_CMP oplist (n->data, data); \
int cmp = M_CALL_CMP(oplist, n->data, data); \
if (cmp == 0) \
break; \
int child = (cmp < 0); \
@@ -516,7 +506,7 @@ typedef enum {
if (it->cpt == 0) return true; \
assert (it->cpt > 0 && it->cpt < RBTREEI_MAX_STACK); \
node_t *n = it->stack[it->cpt-1]; \
int cmp = M_GET_CMP oplist (n->data, data); \
int cmp = M_CALL_CMP(oplist, n->data, data); \
return (cmp >= 0); \
} \
\
@@ -546,13 +536,13 @@ typedef enum {
return &n->data; \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cmin)(const tree_t tree) \
{ \
return M_CONST_CAST(type, M_C(name, _min)(tree)); \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cmax)(const tree_t tree) \
{ \
return M_CONST_CAST(type, M_C(name, _max)(tree)); \
@@ -565,7 +555,7 @@ typedef enum {
node_t *n = tree->node; \
while (n != NULL) { \
RBTREEI_CONTRACT_NODE (n); \
int cmp = M_GET_CMP oplist (n->data, data); \
int cmp = M_CALL_CMP(oplist, n->data, data); \
if (cmp == 0) { \
return &n->data; \
} else if (cmp > 0) { \
@@ -577,7 +567,7 @@ typedef enum {
return NULL; \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cget)(const tree_t tree, type const data) \
{ \
return M_CONST_CAST(type, M_C(name, _get)(tree, data)); \
@@ -592,7 +582,7 @@ typedef enum {
M_MEMORY_FULL (sizeof (node_t)); \
return NULL; \
} \
M_GET_INIT_SET oplist (n->data, o->data); \
M_CALL_INIT_SET(oplist, n->data, o->data); \
n->child[0] = M_C(name, _int_copyn)(o->child[0]); \
n->child[1] = M_C(name, _int_copyn)(o->child[1]); \
RBTREEI_COPY_COLOR (n, o); \
@@ -699,7 +689,7 @@ typedef enum {
) \
\
static inline bool \
M_C(name, _pop)(type *data_ptr, tree_t tree, type const key) \
M_C(name, _pop_at)(type *data_ptr, tree_t tree, type const key) \
{ \
RBTREEI_CONTRACT (tree); \
node_t *tab[RBTREEI_MAX_STACK]; \
@@ -714,7 +704,7 @@ typedef enum {
RBTREEI_CONTRACT_NODE (n); \
assert(M_C(name, _int_depth)(n->child[0]) \
== M_C(name, _int_depth)(n->child[1])); \
int cmp = M_GET_CMP oplist (n->data, key); \
int cmp = M_CALL_CMP(oplist, n->data, key); \
if (cmp == 0) { \
break; \
} \
@@ -846,8 +836,9 @@ typedef enum {
assert (tree->node == NULL || RBTREEI_IS_BLACK(tree->node)); \
/* delete it */ \
if (data_ptr != NULL) \
M_GET_SET oplist (*data_ptr, n->data); \
M_GET_CLEAR oplist (n->data); \
M_DO_MOVE(oplist, *data_ptr, n->data); \
else \
M_CALL_CLEAR(oplist, n->data); \
M_C(name,_int_del) (n); \
tree->size --; \
RBTREEI_CONTRACT (tree); \
@@ -869,9 +860,9 @@ typedef enum {
M_C(name, _it)(it2, t2); \
while (!M_C(name, _end_p)(it1) \
&& !M_C(name, _end_p)(it2)) { \
const type *ref1 = M_C(name, _cref)(it1); \
const type *ref2 = M_C(name, _cref)(it2); \
if (M_GET_EQUAL oplist (*ref1, *ref2) == false) \
type const *ref1 = M_C(name, _cref)(it1); \
type const *ref2 = M_C(name, _cref)(it2); \
if (M_CALL_EQUAL(oplist, *ref1, *ref2) == false) \
return false; \
M_C(name, _next)(it1); \
M_C(name, _next)(it2); \
@@ -890,8 +881,8 @@ typedef enum {
tree_it_t it1; \
M_C(name, _it)(it1, t1); \
while (!M_C(name, _end_p)(it1)) { \
const type *ref1 = M_C(name, _cref)(it1); \
M_HASH_UP(hash, M_GET_HASH oplist (*ref1)); \
type const *ref1 = M_C(name, _cref)(it1); \
M_HASH_UP(hash, M_CALL_HASH(oplist, *ref1)); \
M_C(name, _next)(it1); \
} \
return M_HASH_FINAL (hash); \
@@ -900,7 +891,7 @@ typedef enum {
\
M_IF_METHOD(GET_STR, oplist)( \
static inline void M_C(name, _get_str)(string_t str, \
const tree_t t1, bool append) { \
tree_t const t1, bool append) { \
RBTREEI_CONTRACT(t1); \
assert(str != NULL); \
(append ? string_cat_str : string_set_str) (str, "["); \
@@ -912,8 +903,8 @@ typedef enum {
if (commaToPrint) \
string_push_back (str, M_GET_SEPARATOR oplist); \
commaToPrint = true; \
const type *ref1 = M_C(name, _cref)(it1); \
M_GET_GET_STR oplist(str, *ref1, true); \
type const *ref1 = M_C(name, _cref)(it1); \
M_CALL_GET_STR(oplist, str, *ref1, true); \
M_C(name, _next)(it1); \
} \
string_push_back (str, ']'); \
@@ -922,7 +913,7 @@ typedef enum {
\
M_IF_METHOD(OUT_STR, oplist)( \
static inline void \
M_C(name, _out_str)(FILE *file, tree_t rbtree) \
M_C(name, _out_str)(FILE *file, tree_t const rbtree) \
{ \
RBTREEI_CONTRACT(rbtree); \
assert (file != NULL); \
@@ -935,13 +926,43 @@ typedef enum {
if (commaToPrint) \
fputc (M_GET_SEPARATOR oplist, file); \
commaToPrint = true; \
const type *item = M_C(name, _cref)(it); \
M_GET_OUT_STR oplist (file, *item); \
type const *item = M_C(name, _cref)(it); \
M_CALL_OUT_STR(oplist, file, *item); \
} \
fputc (']', file); \
} \
, /* no out_str */ ) \
\
M_IF_METHOD(PARSE_STR, oplist)( \
static inline bool \
M_C(name, _parse_str)(tree_t rbtree, const char str[], const char **endp) \
{ \
RBTREEI_CONTRACT(rbtree); \
assert (str != NULL); \
M_C(name,_clean)(rbtree); \
bool success = false; \
int c = *str++; \
if (M_UNLIKELY (c != '[')) goto exit; \
c = *str++; \
if (M_UNLIKELY (c == ']')) { success = true; goto exit; } \
if (M_UNLIKELY (c == 0)) goto exit; \
str--; \
type item; \
M_CALL_INIT(oplist, item); \
do { \
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
do { c = *str++; } while (isspace(c)); \
if (b == false || c == 0) goto exit; \
M_C(name, _push)(rbtree, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_CALL_CLEAR(oplist, item); \
success = (c == ']'); \
exit: \
if (endp) *endp = str; \
return success; \
} \
, /* no parse_str */ ) \
\
M_IF_METHOD(IN_STR, oplist)( \
static inline bool \
M_C(name, _in_str)(tree_t rbtree, FILE *file) \
@@ -956,14 +977,14 @@ typedef enum {
if (M_UNLIKELY (c == EOF)) return false; \
ungetc(c, file); \
type item; \
M_GET_INIT oplist (item); \
M_CALL_INIT(oplist, item); \
do { \
bool b = M_GET_IN_STR oplist (item, file); \
c = fgetc(file); \
bool b = M_CALL_IN_STR(oplist, item, file); \
do { c = fgetc(file); } while (isspace(c)); \
if (b == false || c == EOF) break; \
M_C(name, _push)(rbtree, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_GET_CLEAR oplist (item); \
M_CALL_CLEAR(oplist, item); \
return c == ']'; \
} \
, /* no in_str */ ) \
+32 -30
View File
@@ -22,8 +22,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_SHARED_PTR__H
#define __M_SHARED_PTR__H
#ifndef MSTARLIB_SHARED_PTR_H
#define MSTARLIB_SHARED_PTR_H
#include "m-core.h"
#include "m-atomic.h"
@@ -33,21 +33,21 @@
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
#define SHARED_PTR_OPLIST(...) \
SHAREDI_PTR_OPLIST(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
_OPLIST(__VA_ARGS__ )))
/* Define shared pointer and its function.
USAGE: SHARED_PTR_DEF(name, type, [, oplist]) */
#define SHARED_PTR_DEF(name, ...) \
SHAREDI_PTR_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), SHAREDI_ATOMIC_OPLIST ), \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_ATOMIC_OPLIST ), \
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST)))
/* Define relaxed shared pointer and its function (thread unsafe).
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
#define SHARED_PTR_RELAXED_DEF(name, ...) \
SHAREDI_PTR_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), SHAREDI_INTEGER_OPLIST ), \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_INTEGER_OPLIST ), \
(name, __VA_ARGS__ , SHAREDI_INTEGER_OPLIST)))
/* Define shared resource and its function.
@@ -102,7 +102,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
#define SHAREDI_CONTRACT(shared, cpt_oplist) do { \
assert(shared != NULL); \
assert(*shared == NULL || M_GET_IT_CREF cpt_oplist ( &(*shared)->cpt) >= 1); \
assert(*shared == NULL || M_CALL_IT_CREF(cpt_oplist, &(*shared)->cpt) >= 1); \
} while (0)
#define SHAREDI_PTR_DEF2(name, type, oplist, cpt_oplist) \
@@ -112,6 +112,8 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
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; \
@@ -134,13 +136,13 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
*shared = NULL; \
return; \
} \
ptr = M_GET_NEW oplist (struct M_C(name, _s)); \
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_GET_INIT_SET cpt_oplist (&ptr->cpt, 1); \
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
ptr->combineAlloc = false; \
*shared = ptr; \
SHAREDI_CONTRACT(shared, cpt_oplist); \
@@ -151,16 +153,16 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
{ \
/* NOTE: Alloc 1 struct with both structures. */ \
struct M_C(name, combine_s) *p = \
M_GET_NEW oplist (struct M_C(name, combine_s)); \
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_GET_INIT oplist(*data); \
M_CALL_INIT( oplist, *data); \
ptr->data = data; \
M_GET_INIT_SET cpt_oplist (&ptr->cpt, 1); \
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
ptr->combineAlloc = true; \
*shared = ptr; \
SHAREDI_CONTRACT(shared, cpt_oplist); \
@@ -181,7 +183,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
assert (dest != shared); \
*dest = *shared; \
if (*dest != NULL) { \
int n = M_GET_ADD cpt_oplist ( &((*dest)->cpt), 1); \
int n = M_CALL_ADD(cpt_oplist, &((*dest)->cpt), 1); \
(void) n; /* unused return value */ \
} \
SHAREDI_CONTRACT(dest, cpt_oplist); \
@@ -192,16 +194,16 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
{ \
SHAREDI_CONTRACT(dest, cpt_oplist); \
if (*dest != NULL) { \
if (M_GET_SUB cpt_oplist ( &((*dest)->cpt), 1) == 1) { \
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_GET_CLEAR oplist (*(*dest)->data); \
M_GET_DEL oplist ((*dest)->data); \
M_CALL_CLEAR(oplist, *(*dest)->data); \
M_CALL_DEL(oplist, (*dest)->data); \
if (combineAlloc == false) \
M_GET_DEL oplist (*dest); \
M_CALL_DEL(oplist, *dest); \
} \
*dest = NULL; \
} \
@@ -267,7 +269,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
return *p1 == *p2; \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cref)(const M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(shared, cpt_oplist); \
@@ -321,14 +323,14 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
{ \
assert(s != NULL); \
assert (n > 0); \
s->buffer = M_GET_REALLOC oplist (M_C(name, _atype_t), NULL, n); \
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_GET_INIT oplist (s->buffer[i].x); \
atomic_init (&s->buffer[i].cpt, 0U); \
M_CALL_INIT(oplist, s->buffer[i].x); \
atomic_init (&s->buffer[i].cpt, 0U); \
} \
genint_init(s->core, n); \
SHAREDI_RESOURCE_CONTRACT(s); \
@@ -340,9 +342,9 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
SHAREDI_RESOURCE_CONTRACT(s); \
size_t n = genint_size(s->core); \
for(size_t i = 0; i < n; i++) { \
M_GET_CLEAR oplist (s->buffer[i].x); \
M_CALL_CLEAR(oplist, s->buffer[i].x); \
} \
M_GET_FREE oplist (s->buffer); \
M_CALL_FREE(oplist, s->buffer); \
s->buffer = NULL; \
genint_clear(s->core); \
} \
@@ -355,7 +357,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
unsigned int idx = genint_pop(s->core); \
it->idx = idx; \
it->ref = s; \
if (M_LIKELY (idx != -1U)) { \
if (M_LIKELY (idx != GENINT_ERROR)) { \
assert(atomic_load(&s->buffer[idx].cpt) == 0); \
atomic_store(&s->buffer[idx].cpt, 1U); \
} \
@@ -365,21 +367,21 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
M_C(name, _end_p)(M_C(name, _it_t) it) \
{ \
assert (it != NULL); \
return it->idx == -1U; \
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 != -1U); \
assert (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
SHAREDI_RESOURCE_CONTRACT(it->ref); \
return &it->ref->buffer[it->idx].x; \
} \
\
static inline const type * \
static inline type const * \
M_C(name, _cref)(M_C(name, _it_t) it) \
{ \
assert (it != NULL && it->ref != NULL && it->idx != -1U); \
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); \
} \
@@ -391,12 +393,12 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
assert (it != NULL); \
assert (it->ref == s); \
unsigned int idx = it->idx; \
if (M_LIKELY (idx != -1U)) { \
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 = -1U; \
it->idx = GENINT_ERROR; \
} \
} \
\
@@ -408,7 +410,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
itd->ref = its->ref; \
unsigned int idx = its->idx; \
itd->idx = idx; \
if (M_LIKELY (idx != -1U)) { \
if (M_LIKELY (idx != GENINT_ERROR)) { \
unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \
assert (c >= 1); \
} \
+108 -104
View File
@@ -22,65 +22,62 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_SNAPSHOT
#define __M_SNAPSHOT
#ifndef MSTARLIB_SNAPSHOT
#define MSTARLIB_SNAPSHOT
#include "m-atomic.h"
#include "m-core.h"
#include "m-genint.h"
// For compatibility with previous version
#define SNAPSHOT_DEF SNAPSHOT_SPSC_DEF
/* Define a SRSW snapshot and it function
/* Define a Single Producer Single Consummer snapshot and its functions
USAGE: SNAPSHOT_SPSC_DEF(name, type[, oplist]) */
#define SNAPSHOT_SPSC_DEF(name, ...) \
SNAPSHOTI_SRSW_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
SNAPSHOTI_SPSC_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
(name, __VA_ARGS__ )))
/* Define a SPMC snapshot and it function
/* Define a Single Producer Multiple Consummer snapshot and its functions
USAGE: SNAPSHOT_SPMC_DEF(name, type[, oplist]) */
#define SNAPSHOT_SPMC_DEF(name, ...) \
SNAPSHOTI_SPMC_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
(name, __VA_ARGS__ )))
/* Define a MPMC snapshot and it function
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
USAGE: SNAPSHOT_MPMC_DEF(name, type[, oplist]) */
#define SNAPSHOT_MPMC_DEF(name, ...) \
SNAPSHOTI_MPMC_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
(name, __VA_ARGS__ )))
/* Define the oplist of a snapshot.
/* Define the oplist of a snapshot (SPSC, SPMC or MPMC).
USAGE: SNAPSHOT_OPLIST(name[, oplist]) */
#define SNAPSHOT_OPLIST(...) \
SNAPSHOTI_OPLIST(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
((__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
(__VA_ARGS__ )))
/********************************** INTERNAL ************************************/
// deferred
// deferred evaluation of the input
#define SNAPSHOTI_OPLIST(arg) SNAPSHOTI_OPLIST2 arg
/* Define the oplist of a snapshot */
#define SNAPSHOTI_OPLIST2(name, oplist) \
(INIT(M_C(name, _init)), \
INIT_SET(M_C(name, _init_set)), \
SET(M_C(name, _set)), \
CLEAR(M_C(name, _clear)), \
TYPE(M_C(name, _t)), \
SUBTYPE(M_C(name_, type_t)) \
(INIT(M_C(name, _init)) \
,INIT_SET(M_C(name, _init_set)) \
,SET(M_C(name, _set)) \
,CLEAR(M_C(name, _clear)) \
,TYPE(M_C(name, _t)) \
,SUBTYPE(M_C(name_, type_t)) \
,OPLIST(oplist) \
,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(M_C(name, _init_move)),) \
,M_IF_METHOD(MOVE, oplist)(MOVE(M_C(name, _move)),) \
)
/******************************** INTERNAL SRSW **********************************/
/******************************** INTERNAL SPSC **********************************/
/* Flag defining the atomic state of a snapshot:
* - r: Index of the read buffer Range [0..2]
@@ -88,37 +85,37 @@
* - f: Next index of the write buffer when a shot is taken Range [0..2]
* - b: Boolean indicating that the read buffer shall be updated
*/
#define SNAPSHOTI_SRSW_FLAG(r, w, f, b) \
#define SNAPSHOTI_SPSC_FLAG(r, w, f, b) \
((unsigned char)( ( (r) << 4) | ((w) << 2) | ((f)) | ((b) << 6)))
#define SNAPSHOTI_SRSW_R(flags) \
#define SNAPSHOTI_SPSC_R(flags) \
(((flags) >> 4) & 0x03u)
#define SNAPSHOTI_SRSW_W(flags) \
#define SNAPSHOTI_SPSC_W(flags) \
(((flags) >> 2) & 0x03u)
#define SNAPSHOTI_SRSW_F(flags) \
#define SNAPSHOTI_SPSC_F(flags) \
(((flags) >> 0) & 0x03u)
#define SNAPSHOTI_SRSW_B(flags) \
#define SNAPSHOTI_SPSC_B(flags) \
(((flags) >> 6) & 0x01u)
/* NOTE: Due to atomic_load only accepting non-const pointer,
we can't have any const in the interface. */
#define SNAPSHOTI_SRSW_FLAGS_CONTRACT(flags) \
assert(SNAPSHOTI_SRSW_R(flags) != SNAPSHOTI_SRSW_W(flags) \
&& SNAPSHOTI_SRSW_R(flags) != SNAPSHOTI_SRSW_F(flags) \
&& SNAPSHOTI_SRSW_W(flags) != SNAPSHOTI_SRSW_F(flags))
#define SNAPSHOTI_SRSW_CONTRACT(snap) do { \
#define SNAPSHOTI_SPSC_FLAGS_CONTRACT(flags) \
assert(SNAPSHOTI_SPSC_R(flags) != SNAPSHOTI_SPSC_W(flags) \
&& SNAPSHOTI_SPSC_R(flags) != SNAPSHOTI_SPSC_F(flags) \
&& SNAPSHOTI_SPSC_W(flags) != SNAPSHOTI_SPSC_F(flags))
#define SNAPSHOTI_SPSC_CONTRACT(snap) do { \
assert((snap) != NULL); \
unsigned char f = atomic_load (&(snap)->flags); \
SNAPSHOTI_SRSW_FLAGS_CONTRACT(f); \
SNAPSHOTI_SPSC_FLAGS_CONTRACT(f); \
} while (0)
// Defered evaluation (TBC if it really helps).
#define SNAPSHOTI_SRSW_DEF(arg) SNAPSHOTI_SRSW_DEF2 arg
#define SNAPSHOTI_SPSC_DEF(arg) SNAPSHOTI_SPSC_DEF2 arg
// This is basically an atomic triple buffer (Lock Free)
// between a produced thread and a consummer thread.
#define SNAPSHOTI_SRSW_MAX_BUFFER 3
#define SNAPSHOTI_SPSC_MAX_BUFFER 3
#define SNAPSHOTI_SRSW_DEF2(name, type, oplist) \
#define SNAPSHOTI_SPSC_DEF2(name, type, oplist) \
\
/* Create an aligned type to avoid false sharing between threads */ \
typedef struct M_C(name, _aligned_type_s) { \
@@ -127,66 +124,68 @@
} M_C(name, _aligned_type_t); \
\
typedef struct M_C(name, _s) { \
M_C(name, _aligned_type_t) data[SNAPSHOTI_SRSW_MAX_BUFFER]; \
M_C(name, _aligned_type_t) data[SNAPSHOTI_SPSC_MAX_BUFFER]; \
atomic_uchar flags; \
} 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 type M_C(name, _type_t); \
\
static inline void M_C(name, _init)(M_C(name, _t) snap) \
{ \
assert(snap != NULL); \
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
M_GET_INIT oplist(snap->data[i].x); \
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
M_CALL_INIT(oplist, snap->data[i].x); \
} \
atomic_init (&snap->flags, SNAPSHOTI_SRSW_FLAG(0, 1, 2, 0)); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
atomic_init (&snap->flags, SNAPSHOTI_SPSC_FLAG(0, 1, 2, 0)); \
SNAPSHOTI_SPSC_CONTRACT(snap); \
} \
\
static inline void M_C(name, _clear)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_SRSW_CONTRACT(snap); \
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
M_GET_CLEAR oplist(snap->data[i].x); \
SNAPSHOTI_SPSC_CONTRACT(snap); \
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
M_CALL_CLEAR(oplist, snap->data[i].x); \
} \
} \
\
static inline void M_C(name, _init_set)(M_C(name, _t) snap, \
M_C(name, _t) org) \
{ \
SNAPSHOTI_SRSW_CONTRACT(org); \
SNAPSHOTI_SPSC_CONTRACT(org); \
assert(snap != NULL && snap != org); \
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
M_GET_INIT_SET oplist(snap->data[i].x, org->data[i].x); \
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
M_CALL_INIT_SET(oplist, snap->data[i].x, org->data[i].x); \
} \
atomic_init (&snap->flags, atomic_load(&org->flags)); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
SNAPSHOTI_SPSC_CONTRACT(snap); \
} \
\
static inline void M_C(name, _set)(M_C(name, _t) snap, \
M_C(name, _t) org) \
{ \
SNAPSHOTI_SRSW_CONTRACT(snap); \
SNAPSHOTI_SRSW_CONTRACT(org); \
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
M_GET_SET oplist(snap->data[i].x, org->data[i].x); \
SNAPSHOTI_SPSC_CONTRACT(snap); \
SNAPSHOTI_SPSC_CONTRACT(org); \
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
M_CALL_SET(oplist, snap->data[i].x, org->data[i].x); \
} \
atomic_init (&snap->flags, atomic_load(&org->flags)); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
SNAPSHOTI_SPSC_CONTRACT(snap); \
} \
\
M_IF_METHOD(INIT_MOVE, oplist)( \
static inline void M_C(name, _init_move)(M_C(name, _t) snap, \
M_C(name, _t) org) \
{ \
SNAPSHOTI_SRSW_CONTRACT(org); \
SNAPSHOTI_SPSC_CONTRACT(org); \
assert(snap != NULL && snap != org); \
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
M_GET_INIT_MOVE oplist(snap->data[i].x, org->data[i].x); \
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
M_CALL_INIT_MOVE(oplist, snap->data[i].x, org->data[i].x); \
} \
atomic_store (&snap->flags, atomic_load(&org->flags)); \
atomic_store (&org->flags, SNAPSHOTI_SRSW_FLAG(0,0,0,0) ); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
atomic_store (&org->flags, SNAPSHOTI_SPSC_FLAG(0,0,0,0) ); \
SNAPSHOTI_SPSC_CONTRACT(snap); \
} \
,) /* IF_METHOD (INIT_MOVE) */ \
\
@@ -194,79 +193,79 @@
static inline void M_C(name, _move)(M_C(name, _t) snap, \
M_C(name, _t) org) \
{ \
SNAPSHOTI_SRSW_CONTRACT(snap); \
SNAPSHOTI_SRSW_CONTRACT(org); \
SNAPSHOTI_SPSC_CONTRACT(snap); \
SNAPSHOTI_SPSC_CONTRACT(org); \
assert(snap != org); \
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
M_GET_MOVE oplist(snap->data[i].x, org->data[i].x); \
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
M_CALL_MOVE(oplist, snap->data[i].x, org->data[i].x); \
} \
atomic_store (&snap->flags, atomic_load(&org->flags)); \
atomic_store (&org->flags, SNAPSHOTI_SRSW_FLAG(0,0,0,0) ); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
atomic_store (&org->flags, SNAPSHOTI_SPSC_FLAG(0,0,0,0) ); \
SNAPSHOTI_SPSC_CONTRACT(snap); \
} \
,) /* IF_METHOD (MOVE) */ \
\
\
static inline type *M_C(name, _write)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_SRSW_CONTRACT(snap); \
SNAPSHOTI_SPSC_CONTRACT(snap); \
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
/* Atomic CAS operation */ \
do { \
/* Swap F and W buffer, setting exchange flag */ \
nextFlags = SNAPSHOTI_SRSW_FLAG(SNAPSHOTI_SRSW_R(origFlags), \
SNAPSHOTI_SRSW_F(origFlags), \
SNAPSHOTI_SRSW_W(origFlags), 1); \
nextFlags = SNAPSHOTI_SPSC_FLAG(SNAPSHOTI_SPSC_R(origFlags), \
SNAPSHOTI_SPSC_F(origFlags), \
SNAPSHOTI_SPSC_W(origFlags), 1); \
/* exponential backoff is not needed as there can't be more \
than 2 threads which try to update the data. */ \
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
nextFlags)); \
/* Return new write buffer for new updating */ \
return &snap->data[SNAPSHOTI_SRSW_W(nextFlags)].x; \
return &snap->data[SNAPSHOTI_SPSC_W(nextFlags)].x; \
} \
\
static inline const type *M_C(name, _read)(M_C(name, _t) snap) \
static inline type const *M_C(name, _read)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_SRSW_CONTRACT(snap); \
SNAPSHOTI_SPSC_CONTRACT(snap); \
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
/* Atomic CAS operation */ \
do { \
/* If no exchange registered, do nothing and keep the same */ \
if (!SNAPSHOTI_SRSW_B(origFlags)) { \
if (!SNAPSHOTI_SPSC_B(origFlags)) { \
nextFlags = origFlags; \
break; \
} \
/* Swap R and F buffer, clearing exchange flag */ \
nextFlags = SNAPSHOTI_SRSW_FLAG(SNAPSHOTI_SRSW_F(origFlags), \
SNAPSHOTI_SRSW_W(origFlags), \
SNAPSHOTI_SRSW_R(origFlags), 0); \
nextFlags = SNAPSHOTI_SPSC_FLAG(SNAPSHOTI_SPSC_F(origFlags), \
SNAPSHOTI_SPSC_W(origFlags), \
SNAPSHOTI_SPSC_R(origFlags), 0); \
/* exponential backoff is not needed as there can't be more \
than 2 threads which try to update the data. */ \
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
nextFlags)); \
/* Return current read buffer */ \
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SRSW_R(nextFlags)].x); \
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SPSC_R(nextFlags)].x); \
} \
\
static inline bool M_C(name, _updated_p)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_SRSW_CONTRACT(snap); \
SNAPSHOTI_SPSC_CONTRACT(snap); \
unsigned char flags = atomic_load (&snap->flags); \
return SNAPSHOTI_SRSW_B(flags); \
return SNAPSHOTI_SPSC_B(flags); \
} \
\
static inline type *M_C(name, _get_write_buffer)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_SRSW_CONTRACT(snap); \
SNAPSHOTI_SPSC_CONTRACT(snap); \
unsigned char flags = atomic_load(&snap->flags); \
return &snap->data[SNAPSHOTI_SRSW_W(flags)].x; \
return &snap->data[SNAPSHOTI_SPSC_W(flags)].x; \
} \
\
static inline const type *M_C(name, _get_read_buffer)(M_C(name, _t) snap) \
static inline type const *M_C(name, _get_read_buffer)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_SRSW_CONTRACT(snap); \
SNAPSHOTI_SPSC_CONTRACT(snap); \
unsigned char flags = atomic_load(&snap->flags); \
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SRSW_R(flags)].x); \
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SPSC_R(flags)].x); \
} \
@@ -279,8 +278,7 @@
// 2 more buffer than the number of readers are needed
#define SNAPSHOTI_SPMC_EXTRA_BUFFER 2
// due to genint
#define SNAPSHOTI_SPMC_MAX_READER (4096-SNAPSHOTI_SPMC_EXTRA_BUFFER)
#define SNAPSHOTI_SPMC_MAX_READER (GENINT_MAX_ALLOC-SNAPSHOTI_SPMC_EXTRA_BUFFER)
// structure to handle SPMC snapshot but return a unique index in a buffer array.
typedef struct snapshot_mrsw_int_s {
@@ -295,7 +293,7 @@ typedef struct snapshot_mrsw_int_s {
#define SNAPSHOTI_SPMC_INT_CONTRACT(s) do { \
assert (s != NULL); \
assert (s->n > 0 && s->n <= SNAPSHOTI_SPMC_MAX_READER); \
assert (SNAPSHOTI_SPMC_INT_FLAG_W(atomic_load(&s->lastNext)) \
assert ((size_t)SNAPSHOTI_SPMC_INT_FLAG_W(atomic_load(&s->lastNext)) \
<= s->n + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
assert (s->cptTab != NULL); \
} while (0)
@@ -317,12 +315,12 @@ static inline void snapshot_mrsw_int_init(snapshot_mrsw_int_t s, size_t n)
genint_init (s->freeList, n);
// Get a free buffer and set it as available for readers
unsigned int w = genint_pop(s->freeList);
assert (w != -1U);
assert (w != GENINT_ERROR);
atomic_store(&s->cptTab[w], 1U);
atomic_init(&s->lastNext, SNAPSHOTI_SPMC_INT_FLAG(w, true));
// Get working buffer
s->currentWrite = genint_pop(s->freeList);
assert (s->currentWrite != -1U);
assert (s->currentWrite != GENINT_ERROR);
atomic_store(&s->cptTab[s->currentWrite], 1U);
SNAPSHOTI_SPMC_INT_CONTRACT(s);
}
@@ -342,6 +340,12 @@ static inline unsigned int snapshot_mrsw_int_get_write_idx(snapshot_mrsw_int_t s
return s->currentWrite;
}
static inline unsigned int snapshot_mrsw_int_size(snapshot_mrsw_int_t s)
{
SNAPSHOTI_SPMC_INT_CONTRACT(s);
return s->n - SNAPSHOTI_SPMC_EXTRA_BUFFER;
}
static inline unsigned int snapshot_mrsw_int_write_idx(snapshot_mrsw_int_t s, unsigned int idx)
{
SNAPSHOTI_SPMC_INT_CONTRACT(s);
@@ -365,8 +369,7 @@ static inline unsigned int snapshot_mrsw_int_write_idx(snapshot_mrsw_int_t s, un
// If someone else keeps a ref on the buffer, we can't reuse it
// get another free one.
idx = genint_pop(s->freeList);
// TODO: sometimes fails...
assert(idx != -1U);
assert(idx != GENINT_ERROR);
}
assert (idx < s->n + SNAPSHOTI_SPMC_EXTRA_BUFFER);
assert (atomic_load(&s->cptTab[idx]) == 0);
@@ -388,7 +391,7 @@ static inline unsigned int snapshot_mrsw_int_write_start(snapshot_mrsw_int_t s)
SNAPSHOTI_SPMC_INT_CONTRACT(s);
// Get a new buffer.
unsigned int idx = genint_pop(s->freeList);
assert (idx != -1U);
assert (idx != GENINT_ERROR);
assert (idx < s->n + SNAPSHOTI_SPMC_EXTRA_BUFFER);
assert (atomic_load(&s->cptTab[idx]) == 0);
atomic_store(&s->cptTab[idx], 1U);
@@ -498,16 +501,15 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in
{ \
assert (snap != NULL); \
assert (nReader > 0 && nReader <= SNAPSHOTI_SPMC_MAX_READER); \
snap->data = M_GET_REALLOC oplist (M_C(name, _aligned_type_t), \
NULL, \
nReader+SNAPSHOTI_SPMC_EXTRA_BUFFER); \
snap->data = M_CALL_REALLOC(oplist, M_C(name, _aligned_type_t), \
NULL, nReader+SNAPSHOTI_SPMC_EXTRA_BUFFER); \
if (M_UNLIKELY (snap->data == NULL)) { \
M_MEMORY_FULL(sizeof(M_C(name, _aligned_type_t)) * \
(nReader+SNAPSHOTI_SPMC_EXTRA_BUFFER)); \
return; \
} \
for(size_t i = 0; i < nReader + SNAPSHOTI_SPMC_EXTRA_BUFFER; i++) { \
M_GET_INIT oplist(snap->data[i].x); \
M_CALL_INIT(oplist, snap->data[i].x); \
} \
snapshot_mrsw_int_init(snap->core, nReader); \
SNAPSHOTI_SPMC_CONTRACT(snap); \
@@ -516,10 +518,11 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in
static inline void M_C(name, _clear)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_SPMC_CONTRACT(snap); \
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
M_GET_CLEAR oplist(snap->data[i].x); \
size_t nReader = snapshot_mrsw_int_size(snap->core); \
for(size_t i = 0; i < nReader + SNAPSHOTI_SPMC_EXTRA_BUFFER; i++) { \
M_CALL_CLEAR(oplist, snap->data[i].x); \
} \
M_GET_FREE oplist (snap->data); \
M_CALL_FREE(oplist, snap->data); \
snapshot_mrsw_int_clear(snap->core); \
} \
\
@@ -530,14 +533,14 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in
return &snap->data[idx].x; \
} \
\
static inline const type *M_C(name, _read_start)(M_C(name, _t) snap) \
static inline type const *M_C(name, _read_start)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_SPMC_CONTRACT(snap); \
const unsigned int idx = snapshot_mrsw_int_read_start(snap->core); \
return M_CONST_CAST(type, &snap->data[idx].x); \
} \
\
static inline void M_C(name, _read_end)(M_C(name, _t) snap, const type *old) \
static inline void M_C(name, _read_end)(M_C(name, _t) snap, type const *old) \
{ \
SNAPSHOTI_SPMC_CONTRACT(snap); \
assert (old != NULL); \
@@ -556,7 +559,8 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in
return &snap->data[idx].x; \
} \
\
//TODO: _set_, _init_set
//FIXME: Evaluate the needs for the methods _set_, _init_set.
/******************************** INTERNAL MPMC **********************************/
@@ -580,7 +584,7 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in
{ \
M_C(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \
unsigned int idx = snap->core->core->currentWrite; \
snap->core->core->currentWrite = -1; \
snap->core->core->currentWrite = GENINT_ERROR; \
snapshot_mrsw_int_write_end(snap->core->core, idx); \
} \
\
@@ -607,12 +611,12 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in
snapshot_mrsw_int_write_end(snap->core->core, idx); \
} \
\
static inline const type *M_C(name, _read_start)(M_C(name, _t) snap) \
static inline type const *M_C(name, _read_start)(M_C(name, _t) snap) \
{ \
return M_C(name, _mrsw_read_start)(snap->core); \
} \
\
static inline void M_C(name, _read_end)(M_C(name, _t) snap, const type *old) \
static inline void M_C(name, _read_end)(M_C(name, _t) snap, type const *old) \
{ \
M_C(name, _mrsw_read_end)(snap->core, old); \
} \
+254 -69
View File
@@ -22,12 +22,13 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_STRING_H
#define __M_STRING_H
#ifndef MSTARLIB_STRING_H
#define MSTARLIB_STRING_H
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "m-core.h"
@@ -40,6 +41,9 @@
# define STRINGI_ASSUME(n) (void) 0
#endif
/* Minimum allocated string is at least 16 chars */
#define STRINGI_MIN_ALLOC_SIZE 16
// This macro defines the contract of a string.
// Note: A ==> B is represented as not(A) or B
// Note: use of strlen can slow down a lot the program in some cases.
@@ -60,13 +64,17 @@
/* */
/***********************************************************************/
/* Index returned in case of error */
/* Index returned in case of error instead of the position within the string */
#define STRING_FAILURE ((size_t)-1)
/* This is the main structure of this module.
It is not designed to be memory efficient. */
typedef struct string_s {
size_t size, alloc;
char *ptr;
} string_t[1];
typedef struct string_s *string_ptr;
typedef const struct string_s *string_srcptr;
/* Input option for the fgets function */
typedef enum string_fgets_s {
@@ -76,8 +84,9 @@ typedef enum string_fgets_s {
static inline void
string_init(string_t v)
{
v->size = v->alloc = 0;
v->ptr = NULL;
v->size = 0;
v->alloc = 0;
v->ptr = NULL;
STRINGI_CONTRACT(v);
}
@@ -86,20 +95,23 @@ string_clear(string_t v)
{
STRINGI_CONTRACT(v);
M_MEMORY_FREE(v->ptr);
v->size = v->alloc = 0;
v->ptr = NULL;
/* This is not needed but is safer. size is not set to make
the string more or less invalid so that it can be detected. */
v->alloc = 0;
v->ptr = NULL;
}
/* NOTE: Internaly used by STRING_DECL_INIT */
static inline void stringi_clear2(string_t *v) { string_clear(*v); }
/* NOTE: Returned pointer has to be released by M_MEMORY_FREE. */
/* NOTE: The ownership of the data is transfered back to the caller
and the returned pointer has to be released by M_MEMORY_FREE. */
static inline char *
string_clear_get_str(string_t v)
{
STRINGI_CONTRACT(v);
char *p = v->ptr;
v->size = v->alloc = 0;
v->alloc = 0;
v->ptr = NULL;
return p;
}
@@ -147,24 +159,29 @@ string_empty_p(const string_t v)
static inline void
stringi_fit2size (string_t v, size_t size)
{
assert (size > 0);
// Note: this function may be called in context where the contract
// is not fullfilled.
if (size > v->alloc) {
size_t alloc = size < 16 ? 16 : (size + size / 2);
size_t alloc = size < STRINGI_MIN_ALLOC_SIZE ? STRINGI_MIN_ALLOC_SIZE : (size + size / 2);
if (M_UNLIKELY (alloc <= v->alloc)) {
/* Overflow in alloc computation */
M_MEMORY_FULL(sizeof (char) * alloc);
// NOTE: Return is broken...
abort();
return;
}
char *ptr = M_MEMORY_REALLOC (char, v->ptr, alloc);
if (M_UNLIKELY (ptr == NULL)) {
M_MEMORY_FULL(sizeof (char) * alloc);
// NOTE: Return is broken...
abort();
return;
}
v->ptr = ptr;
v->alloc = alloc;
}
assert(v->ptr != NULL);
}
static inline void
@@ -179,8 +196,9 @@ string_reserve(string_t v, size_t alloc)
if (M_UNLIKELY (alloc == 1)) {
// Only 1 byte reserved for the NUL char ==> free
M_MEMORY_FREE(v->ptr);
v->size = v->alloc = 0;
v->ptr = NULL;
v->size = 0;
v->alloc = 0;
v->ptr = NULL;
} else {
char *ptr = M_MEMORY_REALLOC (char, v->ptr, alloc);
if (M_UNLIKELY (ptr == NULL) ) {
@@ -251,7 +269,6 @@ string_set_n(string_t v, const string_t ref, size_t offset, size_t length)
STRINGI_CONTRACT (v);
STRINGI_CONTRACT (ref);
assert (offset <= ref->size);
assert (v != ref); // Not supported yet
if (M_UNLIKELY (ref->size == 0)) {
v->size = 0;
if (v->ptr) {
@@ -259,8 +276,13 @@ string_set_n(string_t v, const string_t ref, size_t offset, size_t length)
}
} else {
assert (ref->ptr != NULL);
string_set_strn(v, ref->ptr + offset, length);
size_t size = M_MIN (ref->size - offset, length);
stringi_fit2size(v, size+1);
memmove(v->ptr, ref->ptr + offset, size);
v->ptr[size] = 0;
v->size = size;
}
STRINGI_CONTRACT (v);
}
static inline void
@@ -285,7 +307,6 @@ string_init_move(string_t v1, string_t v2)
v1->alloc = v2->alloc;
v1->ptr = v2->ptr;
// Note: nullify v2 to be safer
v2->size = 0;
v2->alloc = 0;
v2->ptr = NULL;
STRINGI_CONTRACT (v1);
@@ -391,8 +412,10 @@ string_cmpi_str(const string_t v1, const char p2[])
int c1, c2;
do {
// To avoid locale without 1 per 1 mapping.
c1 = tolower((unsigned char) toupper((unsigned char) *p1++));
c2 = tolower((unsigned char) toupper((unsigned char) *p2++));
c1 = toupper((unsigned char) *p1++);
c2 = toupper((unsigned char) *p2++);
c1 = tolower((unsigned char) c1);
c2 = tolower((unsigned char) c2);
} while (c1 == c2 && c1 != 0);
return c1 - c2;
}
@@ -534,6 +557,7 @@ string_replace_str (string_t v, const char str1[], const char str2[], size_t sta
if (i != STRING_FAILURE) {
size_t str1_l = strlen(str1);
size_t str2_l = strlen(str2);
assert(v->size + 1 + str2_l > str1_l);
stringi_fit2size (v, v->size + str2_l - str1_l + 1);
if (str1_l != str2_l)
memmove(&v->ptr[i+str2_l], &v->ptr[i+str1_l], v->size - i - str1_l + 1);
@@ -602,6 +626,8 @@ string_cat_printf (string_t v, const char format[], ...)
va_list args;
int size;
va_start (args, format);
/* If v->ptr is NULL, then v->alloc-v->size is 0, and the
function shall does nothing. TBC if not undefined behavior however */
size = vsnprintf (&v->ptr[v->size], v->alloc - v->size, format, args);
if (size > 0 && (v->size+(size_t)size+1 >= v->alloc) ) {
// We have to realloc our string to fit the needed size
@@ -610,9 +636,14 @@ string_cat_printf (string_t v, const char format[], ...)
va_end (args);
va_start (args, format);
size = vsnprintf (&v->ptr[v->size], v->alloc - v->size, format, args);
assert (size >= 0);
}
if (size >= 0) {
v->size += (size_t) size;
} else if (v->ptr != NULL) {
// vsnprintf may have output some characters before returning an error.
// Undo this to have a clean state
v->ptr[v->size] = 0;
}
va_end (args);
STRINGI_CONTRACT (v);
@@ -655,6 +686,7 @@ string_fget_word (string_t v, const char separator[], FILE *f)
{
char buffer[128];
char c = 0;
int d;
STRINGI_CONTRACT(v);
assert (f != NULL);
assert (1+20+2+strlen(separator)+3 < sizeof buffer);
@@ -662,6 +694,14 @@ string_fget_word (string_t v, const char separator[], FILE *f)
v->size = 0;
v->ptr[0] = 0;
bool retcode = false;
/* Skip separator first */
do {
d = fgetc(f);
if (d == EOF) {
return false;
}
} while (strchr(separator, d) != NULL);
ungetc(d, f);
/* NOTE: We generate a buffer which we give to scanf to parse the string,
that it is to say, we generate the format dynamically!
The format is like " %49[^ \t.\n]%c"
@@ -671,7 +711,7 @@ string_fget_word (string_t v, const char separator[], FILE *f)
The user shall give a constant string as the separator argument,
as a control over this argument may give an attacker
an opportunity for stack overflow */
while (snprintf(buffer, sizeof buffer -1, " %%%lu[^%s]%%c", (unsigned long) v->alloc-1-v->size, separator) > 0
while (snprintf(buffer, sizeof buffer -1, " %%%zu[^%s]%%c", (size_t) v->alloc-1-v->size, separator) > 0
&& fscanf(f, buffer, &v->ptr[v->size], &c) == 2) {
retcode = true;
v->size += strlen(&v->ptr[v->size]);
@@ -724,20 +764,32 @@ string_hash(const string_t v)
return m_core_hash(v->ptr, v->size);
}
// Return true if c is a character from charac
static bool
stringi_strim_char(char c, const char charac[])
{
for(const char *s = charac; *s; s++) {
if (c == *s)
return true;
}
return false;
}
static inline void
string_strim(string_t v)
string_strim(string_t v, const char charac[])
{
STRINGI_CONTRACT (v);
char *b = v->ptr;
size_t size = v->size;
while (size > 0 && (b[size-1] == ' ' || b[size-1] == '\n' || b[size-1] == '\r' || b[size-1] == '\t'))
while (size > 0 && stringi_strim_char(b[size-1], charac))
size --;
if (size == 0) {
v->ptr[0] = 0;
if (v->ptr != NULL)
v->ptr[0] = 0;
v->size = size;
return;
}
while (*b == ' ' || *b == '\n' || *b == '\r' || *b == '\t')
while (stringi_strim_char(*b, charac))
b++;
M_ASSUME (b >= v->ptr && size >= (size_t) (b - v->ptr) );
size -= (b - v->ptr);
@@ -747,30 +799,55 @@ string_strim(string_t v)
STRINGI_CONTRACT (v);
}
/* I/O */
/* Output: "string" with quote around
Replace " by \" within the string (and \ to \\)
\n, \t & \r by their standard representation
and other not printable character with \0xx */
static inline void
string_get_str(string_t v, const string_t v2, bool append)
{
/* Output: "string" with quote around
Replace " by \" within the string */
STRINGI_CONTRACT(v2);
STRINGI_CONTRACT(v);
M_ASSUME (v != v2); // Limitation
if(append==false) v->size = 0;
size_t targetSize = v->size + v2->size + 3;
size_t size = append ? v->size : 0;
size_t targetSize = size + v2->size + 3;
stringi_fit2size(v, targetSize);
v->ptr[v->size ++] = '"';
v->ptr[size ++] = '"';
for(size_t i = 0 ; i < v2->size; i++) {
const char c = v2->ptr[i];
if (c == '"') {
targetSize ++ ;
stringi_fit2size(v, targetSize);
v->ptr[v->size ++] = '\\';
switch (c) {
case '\\':
case '"':
case '\n':
case '\t':
case '\r':
// Special characters which can be displayed in a short form.
stringi_fit2size(v, ++targetSize);
v->ptr[size ++] = '\\';
// This string acts as a perfect hashmap which supposes an ASCII mapping
// and (c^(c>>5)) is the hash function
v->ptr[size ++] = " tn\" r\\"[(c ^ (c >>5)) & 0x07];
break;
default:
if (M_UNLIKELY (!isprint(c))) {
targetSize += 3;
stringi_fit2size(v, targetSize);
int d1 = c & 0x07, d2 = (c>>3) & 0x07, d3 = (c>>6) & 0x07;
v->ptr[size ++] = '\\';
v->ptr[size ++] = '0' + d3;
v->ptr[size ++] = '0' + d2;
v->ptr[size ++] = '0' + d1;
} else {
v->ptr[size ++] = c;
}
break;
}
v->ptr[v->size ++] = c;
}
v->ptr[v->size ++] = '"';
v->ptr[v->size] = 0;
v->ptr[size ++] = '"';
v->ptr[size] = 0;
v->size = size;
M_ASSUME (v->size <= targetSize);
STRINGI_CONTRACT (v);
}
@@ -778,17 +855,32 @@ string_get_str(string_t v, const string_t v2, bool append)
static inline void
string_out_str(FILE *f, const string_t v)
{
/* Output: "string" with quote around
Replace " by \" within the string */
STRINGI_CONTRACT(v);
M_ASSUME (f != NULL);
fputc('"', f);
for(size_t i = 0 ; i < v->size; i++) {
const char c = v->ptr[i];
if (c == '"') {
switch (c) {
case '\\':
case '"':
case '\n':
case '\t':
case '\r':
fputc('\\', f);
fputc(" tn\" r\\"[(c ^ c >>5) & 0x07], f);
break;
default:
if (M_UNLIKELY (!isprint(c))) {
int d1 = c & 0x07, d2 = (c>>3) & 0x07, d3 = (c>>6) & 0x07;
fputc('\\', f);
fputc('0' + d3, f);
fputc('0' + d2, f);
fputc('0' + d1, f);
} else {
fputc(c, f);
}
break;
}
fputc(c, f);
}
fputc('"', f);
}
@@ -803,9 +895,33 @@ string_in_str(string_t v, FILE *f)
string_clean(v);
c = fgetc(f);
while (c != '"' && c != EOF) {
if (c == '\\') {
if (M_UNLIKELY (c == '\\')) {
c = fgetc(f);
if (c != '"') string_push_back (v, '\\');
switch (c) {
case 'n':
case 't':
case 'r':
case '\\':
case '\"':
// This string acts as a perfect hashmap which supposes an ASCII mapping
// and (c^(c>>5)) is the hash function
c = " \r \" \n\\\t"[(c^(c>>5))& 0x07];
break;
default:
if (!(c >= '0' && c <= '7'))
return false;
int d1 = c - '0';
c = fgetc(f);
if (!(c >= '0' && c <= '7'))
return false;
int d2 = c - '0';
c = fgetc(f);
if (!(c >= '0' && c <= '7'))
return false;
int d3 = c - '0';
c = (d1 << 6) + (d2 << 3) + d3;
break;
}
}
string_push_back (v, c);
c = fgetc(f);
@@ -813,16 +929,65 @@ string_in_str(string_t v, FILE *f)
return c == '"';
}
static inline bool
string_parse_str(string_t v, const char str[], const char **endptr)
{
STRINGI_CONTRACT(v);
M_ASSUME (str != NULL);
bool success = false;
int c = *str++;
if (c != '"') goto exit;
string_clean(v);
c = *str++;
while (c != '"' && c != 0) {
if (M_UNLIKELY (c == '\\')) {
c = *str++;
switch (c) {
case 'n':
case 't':
case 'r':
case '\\':
case '\"':
// This string acts as a perfect hashmap which supposes an ASCII mapping
// and (c^(c>>5)) is the hash function
c = " \r \" \n\\\t"[(c^(c>>5))& 0x07];
break;
default:
if (!(c >= '0' && c <= '7'))
goto exit;
int d1 = c - '0';
c = *str++;
if (!(c >= '0' && c <= '7'))
goto exit;
int d2 = c - '0';
c = *str++;
if (!(c >= '0' && c <= '7'))
goto exit;
int d3 = c - '0';
c = (d1 << 6) + (d2 << 3) + d3;
break;
}
}
string_push_back (v, c);
c = *str++;
}
success = (c == '"');
exit:
if (endptr != NULL) *endptr = str;
return success;
}
/* UTF8 Handling */
typedef enum {
STRINGI_UTF8_STARTING = 0,
STRINGI_UTF8_DECODING_1 = 1,
STRINGI_UTF8_DECODING_2 = 2,
STRINGI_UTF8_DOCODING_3 = 3,
STRINGI_UTF8_ERROR = 4
STRINGI_UTF8_DECODING_1 = 8,
STRINGI_UTF8_DECODING_2 = 16,
STRINGI_UTF8_DOCODING_3 = 24,
STRINGI_UTF8_ERROR = 32
} stringi_utf8_state_e;
typedef unsigned int string_unicode_t;
#define STRING_UNICODE_ERROR (-1U)
/* UTF8 character classification:
*
@@ -844,11 +1009,11 @@ typedef unsigned int string_unicode_t;
*/
/* The use of a string allows the compiler/linker to factorize it. */
#define STRINGI_UTF8_STATE_TAB \
"\000\004\001\002\003\004\004\004" \
"\004\000\004\004\004\004\004\004" \
"\004\001\004\004\004\004\004\004" \
"\004\002\004\004\004\004\004\004" \
"\004\004\004\004\004\004\004\004"
"\000\040\010\020\030\040\040\040" \
"\040\000\040\040\040\040\040\040" \
"\040\010\040\040\040\040\040\040" \
"\040\020\040\040\040\040\040\040" \
"\040\040\040\040\040\040\040\040"
/* Main generic UTF8 decoder
It shall be (nearly) branchless on any CPU.
@@ -859,12 +1024,12 @@ typedef unsigned int string_unicode_t;
static inline void stringi_utf8_decode(char c, stringi_utf8_state_e *state,
string_unicode_t *unicode)
{
const int type = m_core_clz((unsigned char)~c) - (sizeof(unsigned long) - 1) * CHAR_BIT;
const int type = m_core_clz32((unsigned char)~c) - (sizeof(uint32_t) - 1) * CHAR_BIT;
const string_unicode_t mask1 = -(string_unicode_t)(*state != STRINGI_UTF8_STARTING);
const string_unicode_t mask2 = (0xFFU >> type);
*unicode = ((*unicode << 6) & mask1) | (c & mask2);
*state = M_ASSIGN_CAST(stringi_utf8_state_e,
STRINGI_UTF8_STATE_TAB[*state * 8 + type]);
STRINGI_UTF8_STATE_TAB[*state + type]);
}
/* Check if the given array of characters is a valid UTF8 stream */
@@ -893,8 +1058,8 @@ static inline size_t stringi_utf8_length(const char str[])
string_unicode_t u = 0;
while (*str) {
stringi_utf8_decode(*str, &s, &u);
if (s == STRINGI_UTF8_ERROR) return -1;
if (s == STRINGI_UTF8_STARTING) size++;
if (M_UNLIKELY (s == STRINGI_UTF8_ERROR)) return -1;
size += (s == STRINGI_UTF8_STARTING);
str++;
}
return size;
@@ -929,7 +1094,7 @@ static inline int stringi_utf8_encode(char buffer[5], string_unicode_t u)
}
/* Iterator on a string over UTF8 encoded characters */
typedef struct {
typedef struct string_it_s {
string_unicode_t u;
const char *ptr;
const char *next_ptr;
@@ -960,7 +1125,7 @@ string_end_p (string_it_t it)
str++;
} while (state != STRINGI_UTF8_STARTING && state != STRINGI_UTF8_ERROR && *str != 0);
it->next_ptr = str;
it->u = M_UNLIKELY (state == STRINGI_UTF8_ERROR) ? -1U : u;
it->u = M_UNLIKELY (state == STRINGI_UTF8_ERROR) ? STRING_UNICODE_ERROR : u;
return false;
}
@@ -1005,7 +1170,8 @@ string_utf8_p(string_t str)
}
/* Define the split function for algorithm inclusion */
/* Define the split & the join functions
in case of usage with the algorithm module */
#define STRING_SPLIT(name, oplist, type_oplist) \
static inline void M_C(name, _split)(M_GET_TYPE oplist cont, \
const string_t str, const char sep) \
@@ -1013,20 +1179,26 @@ string_utf8_p(string_t str)
size_t begin = 0; \
string_t tmp; \
string_init(tmp); \
M_GET_CLEAN oplist (cont); \
M_CALL_CLEAN(oplist, cont); \
for(size_t i = 0 ; i < string_size(str); i++) { \
char c = string_get_char(str, i); \
if (c == sep) { \
string_set_strn(tmp, &str->ptr[begin], i - begin); \
M_GET_PUSH oplist (cont, tmp); \
begin = i + 1; \
/* If push move method is available, use it */ \
M_IF_METHOD(PUSH_MOVE,oplist)( \
M_CALL_PUSH_MOVE(oplist, cont, &tmp); \
string_init(tmp); \
, \
M_CALL_PUSH(oplist, cont, tmp); \
) \
begin = i + 1; \
} \
} \
string_set_strn(tmp, &str->ptr[begin], string_size(str) - begin); \
M_GET_PUSH oplist (cont, tmp); \
M_CALL_PUSH(oplist, cont, tmp); \
/* HACK: if method reverse is defined, it is likely that we have */ \
/* inserted the items in the wrong order (aka for a list) */ \
M_IF_METHOD(REVERSE, oplist) (M_GET_REVERSE oplist (cont);, ) \
M_IF_METHOD(REVERSE, oplist) (M_CALL_REVERSE(oplist, cont);, ) \
string_clear(tmp); \
} \
\
@@ -1084,12 +1256,10 @@ namespace m_string {
m_string::m_aligned_string<sizeof (s)>(s).string
#endif
#define STRING_INIT_PRINTF(v, format, ...) do { \
string_init (v); \
string_printf (v, format, __VA_ARGS__) ; \
} while (0)
#define STRING_INIT_PRINTF(v, ...) \
(string_init (v), string_printf (v, __VA_ARGS__) )
/* NOTE: Use GCC extension */
/* NOTE: Use GCC extension FIXME: To keep? */
#define STRING_DECL_INIT(v) \
string_t v __attribute__((cleanup(stringi_clear2))) = {{ 0, 0, NULL}}
@@ -1101,18 +1271,22 @@ namespace m_string {
/* Define the OPLIST of a STRING */
#define STRING_OPLIST \
(INIT(string_init),INIT_SET(string_init_set), SET(string_set), \
INIT_WITH(STRING_INIT_PRINTF), \
INIT_MOVE(string_init_move), MOVE(string_move), \
SWAP(string_swap), \
SWAP(string_swap), CLEAN(string_clean), \
TEST_EMPTY(string_empty_p), \
CLEAR(string_clear), HASH(string_hash), EQUAL(string_equal_p), \
CMP(string_cmp), TYPE(string_t), GET_STR(string_get_str), \
CMP(string_cmp), TYPE(string_t), \
PARSE_STR(string_parse_str), GET_STR(string_get_str), \
OUT_STR(string_out_str), IN_STR(string_in_str), \
EXT_ALGO(STRING_SPLIT) \
)
/* Register the OPLIST as a global one */
#define M_OPL_string_t() STRING_OPLIST
/* Macro encapsulation to give default value for start offset */
/* Macro encapsulation to give a default value of 0 for start offset */
#define string_search_char(v, ...) \
M_APPLY(string_search_char, v, M_IF_DEFAULT1(0, __VA_ARGS__))
@@ -1134,6 +1308,9 @@ namespace m_string {
#define string_replace(v, s1, ...) \
M_APPLY(string_replace, v, s1, M_IF_DEFAULT1(0, __VA_ARGS__))
#define string_strim(...) \
M_APPLY(string_strim, M_IF_DEFAULT1(" \n\r\t", __VA_ARGS__))
/* Macro encapsulation for C11 */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
@@ -1166,6 +1343,10 @@ namespace m_string {
M_APPLY(STRINGI_SELECT3, string_search, string_search_str, \
v, M_IF_DEFAULT1(0, __VA_ARGS__))
/* Provide GET_STR method to default type */
#undef M_GET_STR_METHOD_FOR_DEFAULT_TYPE
#define M_GET_STR_METHOD_FOR_DEFAULT_TYPE GET_STR(M_GET_STRING_ARG)
#endif
@@ -1395,5 +1576,9 @@ namespace m_string {
EQUAL(M_C(name,_equal_p)), CMP(M_C(name,_cmp)), TYPE(M_C(name,_t)), \
)
/* Init a constant bounded string.
Try to do a clean cast */
#define BOUNDED_STRING_CTE(name, string) \
((const struct M_C(name, _s) *)M_ASSIGN_CAST(const char*, string))
#endif
+234 -79
View File
@@ -20,8 +20,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_TUPLE_H
#define __M_TUPLE_H
#ifndef MSTARLIB_TUPLE_H
#define MSTARLIB_TUPLE_H
#include "m-core.h"
@@ -29,47 +29,105 @@
/* Define the tuple type and functions.
USAGE:
TUPLE_DEF2(name, [(field1, type1, oplist1), (field2, type2, oplist2), ...] ) */
#define TUPLE_DEF2(name, ...) \
TUPLE_DEFINE_TYPE(name, __VA_ARGS__) \
TUPLE_DEFINE_INIT(name, __VA_ARGS__) \
TUPLE_DEFINE_INIT_SET(name, __VA_ARGS__) \
TUPLE_DEFINE_INIT_SET2(name, __VA_ARGS__) \
TUPLE_DEFINE_SET(name, __VA_ARGS__) \
TUPLE_DEFINE_CLEAR(name, __VA_ARGS__) \
TUPLE_DEFINE_GETTER(name, __VA_ARGS__) \
TUPLE_DEFINE_SETTER(name, __VA_ARGS__) \
M_IF(TUPLE_ALL_CMP(__VA_ARGS__)) \
(TUPLE_DEFINE_CMP(name, __VA_ARGS__),) \
M_IF(TUPLE_ALL_HASH(__VA_ARGS__)) \
(TUPLE_DEFINE_HASH(name, __VA_ARGS__),) \
M_IF(TUPLE_ALL_EQUAL(__VA_ARGS__)) \
(TUPLE_DEFINE_EQUAL(name, __VA_ARGS__),) \
M_IF(TUPLE_ALL_GET_STR(__VA_ARGS__)) \
(TUPLE_DEFINE_GET_STR(name, __VA_ARGS__),) \
M_IF(TUPLE_ALL_OUT_STR(__VA_ARGS__)) \
(TUPLE_DEFINE_OUT_STR(name, __VA_ARGS__),) \
M_IF(TUPLE_ALL_IN_STR(__VA_ARGS__)) \
(TUPLE_DEFINE_IN_STR(name, __VA_ARGS__),) \
M_IF(TUPLE_ALL_INIT_MOVE(__VA_ARGS__)) \
(TUPLE_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \
M_IF(TUPLE_ALL_MOVE(__VA_ARGS__)) \
(TUPLE_DEFINE_MOVE(name, __VA_ARGS__),) \
M_IF(TUPLE_ALL_SWAP(__VA_ARGS__)) \
(TUPLE_DEFINE_SWAP(name, __VA_ARGS__),)
TUPLE_DEF2(name, [(field1, type1[, oplist1]), (field2, type2[, oplist2]), ...] ) */
#define TUPLE_DEF2(name, ...) \
TUPLEI_DEF2_A( (name, TUPLEI_INJECT_GLOBAL(__VA_ARGS__)) )
/* Define the oplist of a tuple.
USAGE: TUPLE_OPLIST(name[, oplist of the first type, ...]) */
#define TUPLE_OPLIST(...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(TUPLEI_OPLIST(__VA_ARGS__, () ), \
(TUPLEI_OPLIST(__VA_ARGS__, M_DEFAULT_OPLIST ), \
TUPLEI_OPLIST(__VA_ARGS__ ))
/* Return an array suitable for the _cmp_order function.
As compound literals are not supported in C++,
provide a separate definition for C++ using initializer_list
(shall be constexpr, but only supported in C++14).
*/
#ifndef __cplusplus
#define TUPLE_ORDER(name, ...) \
( (const int[]) {M_MAP2_C(TUPLE_ORDER_CONVERT, name, __VA_ARGS__), 0})
#else
#include <initializer_list>
namespace m_tuple {
template <int N>
struct m_int_array {
int data[N];
/*constexpr*/ inline m_int_array(std::initializer_list<int> init){
int j = 0;
for(auto i:init) {
data[j++] = i;
}
}
};
}
#define TUPLE_ORDER(name, ...) \
(m_tuple::m_int_array<M_NARGS(__VA_ARGS__,0)>({M_MAP2_C(TUPLE_ORDER_CONVERT, name, __VA_ARGS__), 0}).data)
#endif
/********************************** INTERNAL ************************************/
#define TUPLE_GET_FIELD(f,t,o) f
#define TUPLE_GET_TYPE(f,t,o) t
#define TUPLEI_INJECT_GLOBAL(...) \
M_MAP_C(TUPLEI_INJECT_OPLIST_A, __VA_ARGS__)
#define TUPLEI_INJECT_OPLIST_A( duo_or_trio ) \
TUPLEI_INJECT_OPLIST_B duo_or_trio
#define TUPLEI_INJECT_OPLIST_B( f, ... ) \
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
#define TUPLEI_DEF2_A(...) \
TUPLEI_DEF2_B __VA_ARGS__
#define TUPLEI_DEF2_B(name, ...) \
TUPLE_DEFINE_TYPE(name, __VA_ARGS__) \
TUPLE_DEFINE_ENUM(name, __VA_ARGS__) \
TUPLEI_IF_ALL(INIT, __VA_ARGS__) \
(TUPLE_DEFINE_INIT(name, __VA_ARGS__),) \
TUPLE_DEFINE_INIT_SET(name, __VA_ARGS__) \
TUPLE_DEFINE_INIT_SET2(name, __VA_ARGS__) \
TUPLE_DEFINE_SET(name, __VA_ARGS__) \
TUPLE_DEFINE_SET2(name, __VA_ARGS__) \
TUPLE_DEFINE_CLEAR(name, __VA_ARGS__) \
TUPLE_DEFINE_GETTER_FIELD(name, __VA_ARGS__) \
TUPLE_DEFINE_SETTER_FIELD(name, __VA_ARGS__) \
TUPLEI_IF_ALL(CMP, __VA_ARGS__) \
(TUPLE_DEFINE_CMP(name, __VA_ARGS__),) \
TUPLEI_IF_ALL(CMP, __VA_ARGS__) \
(TUPLE_DEFINE_CMP_ORDER(name, __VA_ARGS__),) \
TUPLE_DEFINE_CMP_FIELD(name, __VA_ARGS__) \
TUPLEI_IF_ALL(HASH, __VA_ARGS__) \
(TUPLE_DEFINE_HASH(name, __VA_ARGS__),) \
TUPLEI_IF_ALL(EQUAL, __VA_ARGS__) \
(TUPLE_DEFINE_EQUAL(name, __VA_ARGS__),) \
TUPLEI_IF_ALL(GET_STR, __VA_ARGS__) \
(TUPLE_DEFINE_GET_STR(name, __VA_ARGS__),) \
TUPLEI_IF_ALL(OUT_STR, __VA_ARGS__) \
(TUPLE_DEFINE_OUT_STR(name, __VA_ARGS__),) \
TUPLEI_IF_ALL(IN_STR, __VA_ARGS__) \
(TUPLE_DEFINE_IN_STR(name, __VA_ARGS__),) \
TUPLEI_IF_ALL(PARSE_STR, __VA_ARGS__) \
(TUPLE_DEFINE_PARSE_STR(name, __VA_ARGS__),) \
TUPLEI_IF_ALL(INIT_MOVE, __VA_ARGS__) \
(TUPLE_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \
TUPLEI_IF_ALL(MOVE, __VA_ARGS__) \
(TUPLE_DEFINE_MOVE(name, __VA_ARGS__),) \
TUPLEI_IF_ALL(SWAP, __VA_ARGS__) \
(TUPLE_DEFINE_SWAP(name, __VA_ARGS__),) \
TUPLEI_IF_ALL(CLEAN, __VA_ARGS__) \
(TUPLE_DEFINE_CLEAN(name, __VA_ARGS__),)
#define TUPLE_ORDER_CONVERT(name, x) M_C(name, M_C(TUPLE_ORDER_CONVERT_, x))
#define TUPLE_ORDER_CONVERT_ASC(x) M_C3(_,x,_value)
#define TUPLE_ORDER_CONVERT_DSC(x) M_C3(_,x,_value)*-1
/* Get the field name, the type, the oplist or the methods
based on the tuple (field, type, oplist) */
#define TUPLE_GET_FIELD(f,t,o) f
#define TUPLE_GET_TYPE(f,t,o) t
#define TUPLE_GET_OPLIST(f,t,o) o
#define TUPLE_GET_INIT(f,t,o) M_GET_INIT o
#define TUPLE_GET_INIT_SET(f,t,o) M_GET_INIT_SET o
#define TUPLE_GET_INIT_MOVE(f,t,o) M_GET_INIT_MOVE o
@@ -82,8 +140,25 @@
#define TUPLE_GET_STR(f,t,o) M_GET_GET_STR o
#define TUPLE_GET_OUT_STR(f,t,o) M_GET_OUT_STR o
#define TUPLE_GET_IN_STR(f,t,o) M_GET_IN_STR o
#define TUPLE_GET_PARSE_STR(f,t,o) M_GET_PARSE_STR o
#define TUPLE_GET_SWAP(f,t,o) M_GET_SWAP o
#define TUPLE_GET_CLEAN(f,t,o) M_GET_CLEAN o
#define TUPLE_CALL_INIT(t, ...) M_APPLY_API(TUPLE_GET_INIT t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_CALL_INIT_SET(t, ...) M_APPLY_API(TUPLE_GET_INIT_SET t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_CALL_INIT_MOVE(t, ...) M_APPLY_API(TUPLE_GET_INIT_MOVE t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_CALL_MOVE(t, ...) M_APPLY_API(TUPLE_GET_MOVE t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_CALL_SET(t, ...) M_APPLY_API(TUPLE_GET_SET t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_CALL_CLEAR(t, ...) M_APPLY_API(TUPLE_GET_CLEAR t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_CALL_CMP(t, ...) M_APPLY_API(TUPLE_GET_CMP t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_CALL_HASH(t, ...) M_APPLY_API(TUPLE_GET_HASH t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_CALL_EQUAL(t, ...) M_APPLY_API(TUPLE_GET_EQUAL t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_CALL_GET_STR(t, ...) M_APPLY_API(TUPLE_GET_STR t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_CALL_OUT_STR(t, ...) M_APPLY_API(TUPLE_GET_OUT_STR t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_CALL_IN_STR(t, ...) M_APPLY_API(TUPLE_GET_IN_STR t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_CALL_PARSE_STR(t, ...) M_APPLY_API(TUPLE_GET_PARSE_STR t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_CALL_SWAP(t, ...) M_APPLY_API(TUPLE_GET_SWAP t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_CALL_CLEAN(t, ...) M_APPLY_API(TUPLE_GET_CLEAN t, TUPLE_GET_OPLIST t, __VA_ARGS__)
#define TUPLE_DEFINE_TYPE(name, ...) \
typedef struct M_C(name, _s) { \
@@ -95,12 +170,21 @@
TUPLE_GET_TYPE a TUPLE_GET_FIELD a ;
#define TUPLE_DEFINE_ENUM(name, ...) \
typedef enum { \
M_C(name, _first_one_val), \
M_MAP2_C(TUPLE_DEFINE_ENUM_ELE , name, __VA_ARGS__) \
} M_C(name,_field_e);
#define TUPLE_DEFINE_ENUM_ELE(name, a) \
M_C4(name, _, TUPLE_GET_FIELD a, _value)
#define TUPLE_DEFINE_INIT(name, ...) \
static inline void M_C(name, _init)(M_C(name,_t) my) { \
M_MAP(TUPLE_DEFINE_INIT_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_INIT_FUNC(a) \
TUPLE_GET_INIT a ( my -> TUPLE_GET_FIELD a );
TUPLE_CALL_INIT(a, my -> TUPLE_GET_FIELD a );
#define TUPLE_DEFINE_INIT_SET(name, ...) \
@@ -108,7 +192,7 @@
M_MAP(TUPLE_DEFINE_INIT_SET_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_INIT_SET_FUNC(a) \
TUPLE_GET_INIT_SET a ( my -> TUPLE_GET_FIELD a , org -> TUPLE_GET_FIELD a );
TUPLE_CALL_INIT_SET(a, my -> TUPLE_GET_FIELD a , org -> TUPLE_GET_FIELD a );
#define TUPLE_DEFINE_INIT_SET2(name, ...) \
@@ -120,7 +204,7 @@
#define TUPLE_DEFINE_INIT_SET2_PROTO(a) \
, TUPLE_GET_TYPE a const TUPLE_GET_FIELD a
#define TUPLE_DEFINE_INIT_SET2_FUNC(a) \
TUPLE_GET_INIT_SET a ( my -> TUPLE_GET_FIELD a , TUPLE_GET_FIELD a );
TUPLE_CALL_INIT_SET(a, my -> TUPLE_GET_FIELD a , TUPLE_GET_FIELD a );
#define TUPLE_DEFINE_SET(name, ...) \
@@ -129,7 +213,19 @@
M_MAP(TUPLE_DEFINE_SET_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_SET_FUNC(a) \
TUPLE_GET_SET a ( my -> TUPLE_GET_FIELD a , org -> TUPLE_GET_FIELD a );
TUPLE_CALL_SET(a, my -> TUPLE_GET_FIELD a , org -> TUPLE_GET_FIELD a );
#define TUPLE_DEFINE_SET2(name, ...) \
static inline void M_C(name, _set2)(M_C(name,_t) my \
M_MAP(TUPLE_DEFINE_SET2_PROTO, __VA_ARGS__) \
) { \
M_MAP(TUPLE_DEFINE_SET2_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_SET2_PROTO(a) \
, TUPLE_GET_TYPE a const TUPLE_GET_FIELD a
#define TUPLE_DEFINE_SET2_FUNC(a) \
TUPLE_CALL_SET(a, my -> TUPLE_GET_FIELD a , TUPLE_GET_FIELD a );
#define TUPLE_DEFINE_CLEAR(name, ...) \
@@ -137,23 +233,26 @@
M_MAP(TUPLE_DEFINE_CLEAR_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_CLEAR_FUNC(a) \
TUPLE_GET_CLEAR a ( my -> TUPLE_GET_FIELD a );
TUPLE_CALL_CLEAR(a, my -> TUPLE_GET_FIELD a );
#define TUPLE_DEFINE_GETTER(name, ...) \
M_MAP2(TUPLE_DEFINE_GETTER_PROTO, name, __VA_ARGS__)
#define TUPLE_DEFINE_GETTER_PROTO(name, a) \
static inline TUPLE_GET_TYPE a const * M_C3(name, _get_, TUPLE_GET_FIELD a) \
(M_C(name,_t) const my) { \
return (TUPLE_GET_TYPE a const * ) &(my->TUPLE_GET_FIELD a);}
#define TUPLE_DEFINE_GETTER_FIELD(name, ...) \
M_MAP2(TUPLE_DEFINE_GETTER_FIELD_PROTO, name, __VA_ARGS__)
#define TUPLE_DEFINE_GETTER_FIELD_PROTO(name, a) \
static inline TUPLE_GET_TYPE a * M_C3(name, _get_at_, TUPLE_GET_FIELD a) \
(M_C(name,_t) my) { \
return &(my->TUPLE_GET_FIELD a);} \
static inline TUPLE_GET_TYPE a const * M_C3(name, _cget_at_, TUPLE_GET_FIELD a) \
(M_C(name,_t) const my) { \
return &(my->TUPLE_GET_FIELD a);}
#define TUPLE_DEFINE_SETTER(name, ...) \
M_MAP2(TUPLE_DEFINE_SETTER_PROTO, name, __VA_ARGS__)
#define TUPLE_DEFINE_SETTER_PROTO(name, a) \
#define TUPLE_DEFINE_SETTER_FIELD(name, ...) \
M_MAP2(TUPLE_DEFINE_SETTER_FIELD_PROTO, name, __VA_ARGS__)
#define TUPLE_DEFINE_SETTER_FIELD_PROTO(name, a) \
static inline void M_C3(name, _set_, TUPLE_GET_FIELD a) \
(M_C(name,_t) my, TUPLE_GET_TYPE a TUPLE_GET_FIELD a) { \
TUPLE_GET_SET a (my ->TUPLE_GET_FIELD a, TUPLE_GET_FIELD a);}
(M_C(name,_t) my, TUPLE_GET_TYPE a const TUPLE_GET_FIELD a) { \
TUPLE_CALL_SET(a, my ->TUPLE_GET_FIELD a, TUPLE_GET_FIELD a);}
#define TUPLE_DEFINE_CMP(name, ...) \
@@ -164,10 +263,44 @@
return 0; \
}
#define TUPLE_DEFINE_CMP_FUNC(a) \
i = TUPLE_GET_CMP a ( e1 -> TUPLE_GET_FIELD a , e2 -> TUPLE_GET_FIELD a );\
i = TUPLE_CALL_CMP(a, e1 -> TUPLE_GET_FIELD a , e2 -> TUPLE_GET_FIELD a ); \
if (i != 0) return i;
#define TUPLE_DEFINE_CMP_ORDER(name, ...) \
static inline int M_C(name, _cmp_order)(M_C(name,_t) const e1 , \
M_C(name,_t) const e2, \
const int order[]) { \
int i, r; \
while ((i=*order++) != 0) { \
switch (i) { \
M_MAP2(TUPLE_DEFINE_CMP_ORDER_FUNC , name, __VA_ARGS__) \
default: assert(0); \
} \
} \
return 0; \
}
#define TUPLE_DEFINE_CMP_ORDER_FUNC(name, a) \
case M_C4(name, _, TUPLE_GET_FIELD a, _value): \
case -M_C4(name, _, TUPLE_GET_FIELD a, _value): \
r = TUPLE_CALL_CMP(a, e1 -> TUPLE_GET_FIELD a , e2 -> TUPLE_GET_FIELD a ); \
if (r != 0) return i < 0 ? -r : r; \
break;
#define TUPLE_DEFINE_CMP_FIELD(name, ...) \
M_MAP2(TUPLE_MAP_CMP_FIELD, name, __VA_ARGS__)
#define TUPLE_MAP_CMP_FIELD(name, a) \
M_IF_METHOD(CMP, TUPLE_GET_OPLIST a)( \
TUPLE_DEFINE_CMP_FIELD_FUNC(name, TUPLE_GET_FIELD a, TUPLE_GET_CMP a), \
)
#define TUPLE_DEFINE_CMP_FIELD_FUNC(name, field, func_cmp) \
static inline int M_C3(name, _cmp_, field)(M_C(name,_t) const e1 , \
M_C(name,_t) const e2) { \
return func_cmp ( e1 -> field , e2 -> field ); \
}
#define TUPLE_DEFINE_EQUAL(name, ...) \
static inline bool M_C(name, _equal_p)(M_C(name,_t) const e1 , \
M_C(name,_t) const e2) { \
@@ -176,7 +309,7 @@
return true; \
}
#define TUPLE_DEFINE_EQUAL_FUNC(a) \
b = TUPLE_GET_EQUAL a ( e1 -> TUPLE_GET_FIELD a , e2 -> TUPLE_GET_FIELD a ); \
b = TUPLE_CALL_EQUAL(a, e1 -> TUPLE_GET_FIELD a , e2 -> TUPLE_GET_FIELD a ); \
if (!b) return false;
@@ -187,7 +320,7 @@
return M_HASH_FINAL (hash); \
}
#define TUPLE_DEFINE_HASH_FUNC(a) \
M_HASH_UP(hash, TUPLE_GET_HASH a ( e1 -> TUPLE_GET_FIELD a) );
M_HASH_UP(hash, TUPLE_CALL_HASH(a, e1 -> TUPLE_GET_FIELD a) );
#define TUPLE_DEFINE_GET_STR(name, ...) \
@@ -203,7 +336,7 @@
#define TUPLE_DEFINE_GET_STR_FUNC(a) \
if (comma) string_push_back (str, ','); \
comma = true; \
TUPLE_GET_STR a (str, el -> TUPLE_GET_FIELD a, true); \
TUPLE_CALL_GET_STR(a, str, el -> TUPLE_GET_FIELD a, true); \
#define TUPLE_DEFINE_OUT_STR(name, ...) \
@@ -218,7 +351,7 @@
#define TUPLE_DEFINE_OUT_STR_FUNC(a) \
if (comma) fputc (',', f); \
comma = true; \
TUPLE_GET_OUT_STR a (f, el -> TUPLE_GET_FIELD a); \
TUPLE_CALL_OUT_STR(a, f, el -> TUPLE_GET_FIELD a); \
#define TUPLE_DEFINE_IN_STR(name, ...) \
@@ -237,16 +370,42 @@
if (c != ',' || c == EOF) return false; \
} \
comma = true; \
if (TUPLE_GET_IN_STR a (el -> TUPLE_GET_FIELD a, f) == false) \
if (TUPLE_CALL_IN_STR(a, el -> TUPLE_GET_FIELD a, f) == false) \
return false ; \
#define TUPLE_DEFINE_PARSE_STR(name, ...) \
static inline bool M_C(name, _parse_str)(M_C(name,_t) el, \
const char str[], \
const char **endptr) { \
assert (str != NULL && el != NULL); \
bool success = false; \
bool comma = false; \
int c = *str++; \
if (c != '(') goto exit; \
M_MAP(TUPLE_DEFINE_PARSE_STR_FUNC , __VA_ARGS__) \
c = *str++; \
success = (c == ')'); \
exit: \
if (endptr) *endptr = str; \
return success; \
}
#define TUPLE_DEFINE_PARSE_STR_FUNC(a) \
if (comma) { \
c = *str++; \
if (c != ',' || c == 0) goto exit; \
} \
comma = true; \
if (TUPLE_CALL_PARSE_STR(a, el -> TUPLE_GET_FIELD a, str, &str) == false) \
goto exit ; \
#define TUPLE_DEFINE_INIT_MOVE(name, ...) \
static inline void M_C(name, _init_move)(M_C(name,_t) el, M_C(name,_t) org) { \
M_MAP(TUPLE_DEFINE_INIT_MOVE_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_INIT_MOVE_FUNC(a) \
TUPLE_GET_INIT_MOVE a (el -> TUPLE_GET_FIELD a, org -> TUPLE_GET_FIELD a);
TUPLE_CALL_INIT_MOVE(a, el -> TUPLE_GET_FIELD a, org -> TUPLE_GET_FIELD a);
#define TUPLE_DEFINE_MOVE(name, ...) \
@@ -254,7 +413,7 @@
M_MAP(TUPLE_DEFINE_MOVE_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_MOVE_FUNC(a) \
TUPLE_GET_MOVE a (el -> TUPLE_GET_FIELD a, org -> TUPLE_GET_FIELD a);
TUPLE_CALL_MOVE(a, el -> TUPLE_GET_FIELD a, org -> TUPLE_GET_FIELD a);
#define TUPLE_DEFINE_SWAP(name, ...) \
@@ -262,7 +421,16 @@
M_MAP(TUPLE_DEFINE_SWAP_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_SWAP_FUNC(a) \
TUPLE_GET_SWAP a (el1 -> TUPLE_GET_FIELD a, el2 -> TUPLE_GET_FIELD a);
TUPLE_CALL_SWAP(a, el1 -> TUPLE_GET_FIELD a, el2 -> TUPLE_GET_FIELD a);
#define TUPLE_DEFINE_CLEAN(name, ...) \
static inline void M_C(name, _clean)(M_C(name,_t) el1) { \
M_MAP(TUPLE_DEFINE_CLEAN_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_CLEAN_FUNC(a) \
TUPLE_CALL_CLEAN(a, el1 -> TUPLE_GET_FIELD a);
/* Macros for testing for method presence */
#define TUPLE_TEST_METHOD2_P(method, f, t, op) \
@@ -270,28 +438,13 @@
#define TUPLE_TEST_METHOD_P(method, trio) \
M_APPLY(TUPLE_TEST_METHOD2_P, method, M_OPFLAT trio)
#define TUPLE_ALL_CMP(...) \
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, CMP, __VA_ARGS__)
#define TUPLE_ALL_EQUAL(...) \
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, EQUAL, __VA_ARGS__)
#define TUPLE_ALL_HASH(...) \
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, HASH, __VA_ARGS__)
#define TUPLE_ALL_GET_STR(...) \
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, GET_STR, __VA_ARGS__)
#define TUPLE_ALL_OUT_STR(...) \
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, OUT_STR, __VA_ARGS__)
#define TUPLE_ALL_IN_STR(...) \
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, IN_STR, __VA_ARGS__)
#define TUPLE_ALL_INIT_MOVE(...) \
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, INIT_MOVE, __VA_ARGS__)
#define TUPLE_ALL_MOVE(...) \
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, MOVE, __VA_ARGS__)
#define TUPLE_ALL_SWAP(...) \
M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, SWAP, __VA_ARGS__)
#define TUPLEI_IF_ALL(method, ...) \
M_IF(M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, method, __VA_ARGS__))
#define TUPLEI_OPLIST(name, ...) \
(INIT(M_C(name,_init)), \
(M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
INIT_SET(M_C(name, _init_set)), \
INIT_WITH(M_C(name, _init_set2)), \
SET(M_C(name,_set)), \
CLEAR(M_C(name, _clear)), \
TYPE(M_C(name,_t)), \
@@ -299,11 +452,13 @@
M_IF_METHOD_ALL(HASH, __VA_ARGS__)(HASH(M_C(name, _hash)),), \
M_IF_METHOD_ALL(EQUAL, __VA_ARGS__)(EQUAL(M_C(name, _equal_p)),), \
M_IF_METHOD_ALL(GET_STR, __VA_ARGS__)(GET_STR(M_C(name, _get_str)),), \
M_IF_METHOD_ALL(PARSE_STR, __VA_ARGS__)(PARSE_STR(M_C(name, _parse_str)),), \
M_IF_METHOD_ALL(IN_STR, __VA_ARGS__)(IN_STR(M_C(name, _in_str)),), \
M_IF_METHOD_ALL(OUT_STR, __VA_ARGS__)(OUT_STR(M_C(name, _out_str)),), \
M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(INIT_MOVE(M_C(name, _init_move)),), \
M_IF_METHOD_ALL(MOVE, __VA_ARGS__)(MOVE(M_C(name, _move)),), \
M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(MOVE(M_C(name, _swap)),), \
M_IF_METHOD_ALL(MOVE, __VA_ARGS__)(MOVE(M_C(name, _move)),), \
M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(SWAP(M_C(name, _swap)),), \
M_IF_METHOD_ALL(CLEAN, __VA_ARGS__)(CLEAN(M_C(name, _clean)),), \
M_IF_METHOD(NEW, M_RET_ARG1(__VA_ARGS__,))(NEW(M_DELAY2(M_GET_NEW) M_RET_ARG1(__VA_ARGS__,)),), \
M_IF_METHOD(REALLOC, M_RET_ARG1(__VA_ARGS__,))(REALLOC(M_DELAY2(M_GET_REALLOC) M_RET_ARG1(__VA_ARGS__,)),), \
M_IF_METHOD(DEL, M_RET_ARG1(__VA_ARGS__,))(DEL(M_DELAY2(M_GET_DEL) M_RET_ARG1(__VA_ARGS__,)),), \
+210 -104
View File
@@ -22,8 +22,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_VARIANT_H
#define __M_VARIANT_H
#ifndef MSTARLIB_VARIANT_H
#define MSTARLIB_VARIANT_H
#include "m-core.h"
@@ -33,60 +33,99 @@
/* Define the variant type and functions.
USAGE:
VARIANT_DEF2(name, [(field1, type1, oplist1), (field2, type2, oplist2), ...] ) */
#define VARIANT_DEF2(name, ...) \
#define VARIANT_DEF2(name, ...) \
VARIANTI_DEF2_A( (name, VARIANTI_INJECT_GLOBAL(__VA_ARGS__)) )
/* Define the oplist of a variant.
USAGE: VARIANT_OPLIST(name[, oplist of the first type, ...]) */
#define VARIANT_OPLIST(...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(VARIANTI_OPLIST(__VA_ARGS__, M_DEFAULT_OPLIST), \
VARIANTI_OPLIST(__VA_ARGS__ ))
/********************************** INTERNAL ************************************/
#define VARIANTI_INJECT_GLOBAL(...) \
M_MAP_C(VARIANTI_INJECT_OPLIST_A, __VA_ARGS__)
#define VARIANTI_INJECT_OPLIST_A( duo_or_trio ) \
VARIANTI_INJECT_OPLIST_B duo_or_trio
#define VARIANTI_INJECT_OPLIST_B( f, ... ) \
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
#define VARIANTI_DEF2_A(...) \
VARIANTI_DEF2_B __VA_ARGS__
#define VARIANTI_DEF2_B(name, ...) \
VARIANTI_DEFINE_TYPE(name, __VA_ARGS__) \
VARIANTI_DEFINE_INIT(name, __VA_ARGS__) \
VARIANTI_DEFINE_CLEAR(name, __VA_ARGS__) \
VARIANTI_DEFINE_INIT_SET(name, __VA_ARGS__) \
VARIANTI_DEFINE_SET(name, __VA_ARGS__) \
VARIANTI_DEFINE_TEST_P(name, __VA_ARGS__) \
VARIANTI_DEFINE_SETTER(name, __VA_ARGS__) \
VARIANTI_DEFINE_GETTER(name, __VA_ARGS__) \
VARIANTI_IF_ALL(INIT, __VA_ARGS__) \
(VARIANTI_DEFINE_INIT_FIELD(name, __VA_ARGS__),) \
VARIANTI_DEFINE_INIT_SETTER_FIELD(name, __VA_ARGS__) \
VARIANTI_DEFINE_SETTER_FIELD(name, __VA_ARGS__) \
VARIANTI_DEFINE_GETTER_FIELD(name, __VA_ARGS__) \
VARIANTI_DEFINE_CLEAN_FUNC(name, __VA_ARGS__) \
M_IF(VARIANTI_ALL_HASH(__VA_ARGS__)) \
VARIANTI_IF_ALL(HASH, __VA_ARGS__) \
(VARIANTI_DEFINE_HASH(name, __VA_ARGS__),) \
M_IF(VARIANTI_ALL_EQUAL(__VA_ARGS__)) \
VARIANTI_IF_ALL(EQUAL, __VA_ARGS__) \
(VARIANTI_DEFINE_EQUAL(name, __VA_ARGS__),) \
M_IF(VARIANTI_ALL_GET_STR(__VA_ARGS__)) \
VARIANTI_IF_ALL(GET_STR, __VA_ARGS__) \
(VARIANTI_DEFINE_GET_STR(name, __VA_ARGS__),) \
M_IF(VARIANTI_ALL_OUT_STR(__VA_ARGS__)) \
VARIANTI_IF_ALL2(PARSE_STR, INIT, __VA_ARGS__) \
(VARIANTI_DEFINE_PARSE_STR(name, __VA_ARGS__),) \
VARIANTI_IF_ALL(OUT_STR, __VA_ARGS__) \
(VARIANTI_DEFINE_OUT_STR(name, __VA_ARGS__),) \
M_IF(VARIANTI_ALL_IN_STR(__VA_ARGS__)) \
VARIANTI_IF_ALL2(IN_STR, INIT, __VA_ARGS__) \
(VARIANTI_DEFINE_IN_STR(name, __VA_ARGS__),) \
M_IF(VARIANTI_ALL_INIT_MOVE(__VA_ARGS__)) \
VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \
(VARIANTI_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \
M_IF(VARIANTI_ALL_INIT_MOVE(__VA_ARGS__)) \
VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \
(VARIANTI_DEFINE_MOVE(name, __VA_ARGS__),) \
M_IF(VARIANTI_ALL_INIT_MOVE(__VA_ARGS__)) \
VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \
(VARIANTI_DEFINE_MOVER(name, __VA_ARGS__),) \
M_IF(VARIANTI_ALL_SWAP(__VA_ARGS__)) \
VARIANTI_IF_ALL(SWAP, __VA_ARGS__) \
(VARIANTI_DEFINE_SWAP(name, __VA_ARGS__),)
/* Define the oplist of a tuple.
USAGE: VARIANT_OPLIST(name[, oplist of the first type, ...]) */
#define VARIANT_OPLIST(...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(VARIANTI_OPLIST(__VA_ARGS__, () ), \
VARIANTI_OPLIST(__VA_ARGS__ ))
/********************************** INTERNAL ************************************/
#define VARIANTI_GET_FIELD(f,t,o) f
#define VARIANTI_GET_TYPE(f,t,o) t
#define VARIANTI_GET_INIT(f,t,o) M_GET_INIT o
#define VARIANTI_GET_INIT_SET(f,t,o) M_GET_INIT_SET o
/* Get the field name, the type, the oplist or the methods
based on the variant (field, type, oplist) */
#define VARIANTI_GET_FIELD(f,t,o) f
#define VARIANTI_GET_TYPE(f,t,o) t
#define VARIANTI_GET_OPLIST(f,t,o) o
#define VARIANTI_GET_INIT(f,t,o) M_GET_INIT o
#define VARIANTI_GET_INIT_SET(f,t,o) M_GET_INIT_SET o
#define VARIANTI_GET_INIT_MOVE(f,t,o) M_GET_INIT_MOVE o
#define VARIANTI_GET_MOVE(f,t,o) M_GET_MOVE o
#define VARIANTI_GET_SET(f,t,o) M_GET_SET o
#define VARIANTI_GET_CLEAR(f,t,o) M_GET_CLEAR o
#define VARIANTI_GET_CMP(f,t,o) M_GET_CMP o
#define VARIANTI_GET_HASH(f,t,o) M_GET_HASH o
#define VARIANTI_GET_EQUAL(f,t,o) M_GET_EQUAL o
#define VARIANTI_GET_STR(f,t,o) M_GET_GET_STR o
#define VARIANTI_GET_OUT_STR(f,t,o) M_GET_OUT_STR o
#define VARIANTI_GET_IN_STR(f,t,o) M_GET_IN_STR o
#define VARIANTI_GET_SWAP(f,t,o) M_GET_SWAP o
#define VARIANTI_GET_MOVE(f,t,o) M_GET_MOVE o
#define VARIANTI_GET_SET(f,t,o) M_GET_SET o
#define VARIANTI_GET_CLEAR(f,t,o) M_GET_CLEAR o
#define VARIANTI_GET_CMP(f,t,o) M_GET_CMP o
#define VARIANTI_GET_HASH(f,t,o) M_GET_HASH o
#define VARIANTI_GET_EQUAL(f,t,o) M_GET_EQUAL o
#define VARIANTI_GET_STR(f,t,o) M_GET_GET_STR o
#define VARIANTI_GET_OUT_STR(f,t,o) M_GET_OUT_STR o
#define VARIANTI_GET_IN_STR(f,t,o) M_GET_IN_STR o
#define VARIANTI_GET_PARSE_STR(f,t,o) M_GET_PARSE_STR o
#define VARIANTI_GET_SWAP(f,t,o) M_GET_SWAP o
#define VARIANTI_CALL_INIT(t, ...) M_APPLY_API(VARIANTI_GET_INIT t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
#define VARIANTI_CALL_INIT_SET(t, ...) M_APPLY_API(VARIANTI_GET_INIT_SET t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
#define VARIANTI_CALL_INIT_MOVE(t, ...) M_APPLY_API(VARIANTI_GET_INIT_MOVE t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
#define VARIANTI_CALL_MOVE(t, ...) M_APPLY_API(VARIANTI_GET_MOVE t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
#define VARIANTI_CALL_SET(t, ...) M_APPLY_API(VARIANTI_GET_SET t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
#define VARIANTI_CALL_CLEAR(t, ...) M_APPLY_API(VARIANTI_GET_CLEAR t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
#define VARIANTI_CALL_CMP(t, ...) M_APPLY_API(VARIANTI_GET_CMP t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
#define VARIANTI_CALL_HASH(t, ...) M_APPLY_API(VARIANTI_GET_HASH t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
#define VARIANTI_CALL_EQUAL(t, ...) M_APPLY_API(VARIANTI_GET_EQUAL t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
#define VARIANTI_CALL_GET_STR(t, ...) M_APPLY_API(VARIANTI_GET_STR t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
#define VARIANTI_CALL_OUT_STR(t, ...) M_APPLY_API(VARIANTI_GET_OUT_STR t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
#define VARIANTI_CALL_IN_STR(t, ...) M_APPLY_API(VARIANTI_GET_IN_STR t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
#define VARIANTI_CALL_PARSE_STR(t, ...) M_APPLY_API(VARIANTI_GET_PARSE_STR t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
#define VARIANTI_CALL_SWAP(t, ...) M_APPLY_API(VARIANTI_GET_SWAP t, VARIANTI_GET_OPLIST t, __VA_ARGS__)
#define VARIANTI_DEFINE_TYPE(name, ...) \
enum M_C(name, _enum) { M_C(name, _EMPTY) \
@@ -97,9 +136,12 @@
union { \
M_MAP(VARIANTI_DEFINE_TYPE_ELE , __VA_ARGS__) \
} value; \
} M_C(name,_t)[1];
} 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);
#define VARIANTI_DEFINE_UNION_ELE(name, a) \
, M_C3(name, _, VARIANTI_GET_FIELD a)
, M_C4(name, _, VARIANTI_GET_FIELD a, _value)
#define VARIANTI_DEFINE_TYPE_ELE(a) \
VARIANTI_GET_TYPE a VARIANTI_GET_FIELD a ;
@@ -119,9 +161,9 @@
} \
}
#define VARIANTI_DEFINE_INIT_SET_FUNC(name, a) \
case M_C3(name, _, VARIANTI_GET_FIELD a): \
VARIANTI_GET_INIT_SET a (my -> value. VARIANTI_GET_FIELD a , \
org -> value.VARIANTI_GET_FIELD a ); \
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
VARIANTI_CALL_INIT_SET(a, my -> value. VARIANTI_GET_FIELD a , \
org -> value.VARIANTI_GET_FIELD a ); \
break;
@@ -141,9 +183,9 @@
} \
}
#define VARIANTI_DEFINE_SET_FUNC(name, a) \
case M_C3(name, _, VARIANTI_GET_FIELD a): \
VARIANTI_GET_SET a (my -> value. VARIANTI_GET_FIELD a , \
org -> value.VARIANTI_GET_FIELD a ); \
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
VARIANTI_CALL_SET(a, my -> value. VARIANTI_GET_FIELD a , \
org -> value.VARIANTI_GET_FIELD a ); \
break;
@@ -157,8 +199,8 @@
my->type = M_C(name, _EMPTY); \
}
#define VARIANTI_DEFINE_CLEAR_FUNC(name, a) \
case M_C3(name, _, VARIANTI_GET_FIELD a): \
VARIANTI_GET_CLEAR a (my -> value. VARIANTI_GET_FIELD a); \
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
VARIANTI_CALL_CLEAR(a, my -> value. VARIANTI_GET_FIELD a); \
break;
@@ -173,34 +215,61 @@
M_MAP2(VARIANTI_DEFINE_TEST_FUNC, name, __VA_ARGS__)
#define VARIANTI_DEFINE_TEST_FUNC(name, a) \
static inline bool M_C4(name, _, VARIANTI_GET_FIELD a, _p)(M_C(name,_t) my) { \
return my->type == M_C3(name, _, VARIANTI_GET_FIELD a); \
return my->type == M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
}
#define VARIANTI_DEFINE_SETTER(name, ...) \
M_MAP2(VARIANTI_DEFINE_SETTER_FUNC, name, __VA_ARGS__)
#define VARIANTI_DEFINE_SETTER_FUNC(name, a) \
#define VARIANTI_DEFINE_INIT_FIELD(name, ...) \
M_MAP2(VARIANTI_DEFINE_INIT_FIELD_FUNC, name, __VA_ARGS__)
#define VARIANTI_DEFINE_INIT_FIELD_FUNC(name, a) \
static inline void M_C3(name, _init_, VARIANTI_GET_FIELD a)(M_C(name,_t) my) { \
/* Reinit variable with the given value */ \
my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
VARIANTI_CALL_INIT(a, my -> value. VARIANTI_GET_FIELD a); \
}
#define VARIANTI_DEFINE_INIT_SETTER_FIELD(name, ...) \
M_MAP2(VARIANTI_DEFINE_INIT_SETTER_FIELD_FUNC, name, __VA_ARGS__)
#define VARIANTI_DEFINE_INIT_SETTER_FIELD_FUNC(name, a) \
static inline void M_C3(name, _init_set_, VARIANTI_GET_FIELD a)(M_C(name,_t) my, \
VARIANTI_GET_TYPE a VARIANTI_GET_FIELD a ) { \
my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
VARIANTI_CALL_INIT_SET(a, my -> value. VARIANTI_GET_FIELD a, \
VARIANTI_GET_FIELD a); \
}
#define VARIANTI_DEFINE_SETTER_FIELD(name, ...) \
M_MAP2(VARIANTI_DEFINE_SETTER_FIELD_FUNC, name, __VA_ARGS__)
#define VARIANTI_DEFINE_SETTER_FIELD_FUNC(name, a) \
static inline void M_C3(name, _set_, VARIANTI_GET_FIELD a)(M_C(name,_t) my, \
VARIANTI_GET_TYPE a VARIANTI_GET_FIELD a ) { \
if (my->type == M_C3(name, _, VARIANTI_GET_FIELD a) ) { \
VARIANTI_GET_SET a (my -> value. VARIANTI_GET_FIELD a, \
VARIANTI_GET_FIELD a); \
if (my->type == M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \
VARIANTI_CALL_SET(a, my -> value. VARIANTI_GET_FIELD a, \
VARIANTI_GET_FIELD a); \
} else { \
M_C(name, _clear)(my); \
/* Reinit variable with the given value */ \
my->type = M_C3(name, _, VARIANTI_GET_FIELD a); \
VARIANTI_GET_INIT_SET a(my -> value. VARIANTI_GET_FIELD a, \
VARIANTI_GET_FIELD a); \
my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
VARIANTI_CALL_INIT_SET(a, my -> value. VARIANTI_GET_FIELD a, \
VARIANTI_GET_FIELD a); \
} \
}
#define VARIANTI_DEFINE_GETTER(name, ...) \
M_MAP2(VARIANTI_DEFINE_GETTER_FUNC, name, __VA_ARGS__)
#define VARIANTI_DEFINE_GETTER_FUNC(name, a) \
#define VARIANTI_DEFINE_GETTER_FIELD(name, ...) \
M_MAP2(VARIANTI_DEFINE_GETTER_FIELD_FUNC, name, __VA_ARGS__)
#define VARIANTI_DEFINE_GETTER_FIELD_FUNC(name, a) \
static inline VARIANTI_GET_TYPE a * \
M_C3(name, _get_, VARIANTI_GET_FIELD a)(M_C(name,_t) my) { \
if (my->type != M_C3(name, _, VARIANTI_GET_FIELD a) ) { \
if (my->type != M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \
return NULL; \
} \
return &my -> value . VARIANTI_GET_FIELD a; \
} \
static inline VARIANTI_GET_TYPE a const * \
M_C3(name, _cget_, VARIANTI_GET_FIELD a)(M_C(name,_t) const my) { \
if (my->type != M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \
return NULL; \
} \
return &my -> value . VARIANTI_GET_FIELD a; \
@@ -220,9 +289,9 @@
return true; \
}
#define VARIANTI_DEFINE_EQUAL_FUNC(name, a) \
case M_C3(name, _, VARIANTI_GET_FIELD a): \
b = VARIANTI_GET_EQUAL a ( e1 -> value . VARIANTI_GET_FIELD a , \
e2 -> value . VARIANTI_GET_FIELD a ); \
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
b = VARIANTI_CALL_EQUAL(a, e1 -> value . VARIANTI_GET_FIELD a , \
e2 -> value . VARIANTI_GET_FIELD a ); \
if (!b) return false; \
break;
@@ -239,8 +308,8 @@
return M_HASH_FINAL (hash); \
}
#define VARIANTI_DEFINE_HASH_FUNC(name, a) \
case M_C3(name, _, VARIANTI_GET_FIELD a): \
M_HASH_UP(hash, VARIANTI_GET_HASH a ( e1 -> value . VARIANTI_GET_FIELD a) ); \
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
M_HASH_UP(hash, VARIANTI_CALL_HASH(a, e1 -> value . VARIANTI_GET_FIELD a) ); \
break;
@@ -255,9 +324,9 @@
org -> type = M_C(name, _EMPTY); \
}
#define VARIANTI_DEFINE_INIT_MOVE_FUNC(name, a) \
case M_C3(name, _, VARIANTI_GET_FIELD a): \
VARIANTI_GET_INIT_MOVE a (el -> value . VARIANTI_GET_FIELD a, \
org -> value . VARIANTI_GET_FIELD a); \
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
VARIANTI_CALL_INIT_MOVE(a, el -> value . VARIANTI_GET_FIELD a, \
org -> value . VARIANTI_GET_FIELD a); \
break;
@@ -275,9 +344,9 @@
VARIANTI_GET_TYPE a VARIANTI_GET_FIELD a ) { \
M_C(name, _clear)(my); \
/* Reinit variable with the given value */ \
my->type = M_C3(name, _, VARIANTI_GET_FIELD a); \
VARIANTI_GET_INIT_MOVE a(my -> value. VARIANTI_GET_FIELD a, \
VARIANTI_GET_FIELD a); \
my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
VARIANTI_CALL_INIT_MOVE(a, my -> value. VARIANTI_GET_FIELD a, \
VARIANTI_GET_FIELD a); \
}
@@ -291,7 +360,7 @@
} \
} else { \
M_C(name,_t) tmp; \
M_IF(VARIANTI_ALL_INIT_MOVE(__VA_ARGS__)) \
VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \
( /* NOTE: Slow implementation */ \
M_C(name, _init_move)(tmp, el1); \
M_C(name, _init_move)(el1, el2); \
@@ -306,9 +375,9 @@
} \
}
#define VARIANTI_DEFINE_INIT_SWAP_FUNC(name, a) \
case M_C3(name, _, VARIANTI_GET_FIELD a): \
VARIANTI_GET_SWAP a (el1 -> value . VARIANTI_GET_FIELD a, \
el2 -> value . VARIANTI_GET_FIELD a); \
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
VARIANTI_CALL_SWAP(a, el1 -> value . VARIANTI_GET_FIELD a, \
el2 -> value . VARIANTI_GET_FIELD a); \
break;
@@ -327,9 +396,9 @@
string_push_back (str, '@'); \
}
#define VARIANTI_DEFINE_GET_STR_FUNC(name, a) \
case M_C3(name, _, VARIANTI_GET_FIELD a): \
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
func(str, "@" M_APPLY (M_AS_STR, VARIANTI_GET_FIELD a) "@"); \
VARIANTI_GET_STR a (str, el -> value . VARIANTI_GET_FIELD a, true); \
VARIANTI_CALL_GET_STR(a, str, el -> value . VARIANTI_GET_FIELD a, true); \
break;
@@ -345,9 +414,9 @@
fputc ('@', f); \
}
#define VARIANTI_DEFINE_OUT_STR_FUNC(name, a) \
case M_C3(name, _, VARIANTI_GET_FIELD a): \
fprintf(f, "@" M_APPLY(M_AS_STR, VARIANTI_GET_FIELD a) "@"); \
VARIANTI_GET_OUT_STR a (f, el -> value . VARIANTI_GET_FIELD a); \
case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \
fprintf(f, "@" M_APPLY(M_AS_STR, VARIANTI_GET_FIELD a) "@"); \
VARIANTI_CALL_OUT_STR(a, f, el -> value . VARIANTI_GET_FIELD a); \
break;
@@ -379,13 +448,54 @@
}
#define VARIANTI_DEFINE_IN_STR_FUNC(name, a) \
else if (strcmp (variantTypeBuf, M_APPLY (M_AS_STR, VARIANTI_GET_FIELD a)) == 0) { \
el->type = M_C3(name, _, VARIANTI_GET_FIELD a); \
VARIANTI_GET_INIT a (el ->value . VARIANTI_GET_FIELD a ); \
bool b = VARIANTI_GET_IN_STR a (el -> value . VARIANTI_GET_FIELD a, f); \
el->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
VARIANTI_CALL_INIT(a, el ->value . VARIANTI_GET_FIELD a ); \
bool b = VARIANTI_CALL_IN_STR(a, el -> value . VARIANTI_GET_FIELD a, f); \
if (!b) return false; \
}
#define VARIANTI_DEFINE_PARSE_STR(name, ...) \
static inline bool M_C(name, _parse_str)(M_C(name,_t) el, \
const char str[], \
const char **endp) { \
assert (str != NULL && el != NULL); \
bool success = false; \
/* A buffer of 400 bytes should be more than enough for all variant names... */ \
char variantTypeBuf[400]; \
int c = *str++; \
unsigned int i = 0; \
if (c != '@') goto exit; \
/* First read the name of the type */ \
c = *str++; \
while (c != '@' && c != 0 && i < sizeof(variantTypeBuf) - 1) { \
variantTypeBuf[i++] = c; \
c = *str++; \
} \
if (c != '@') goto exit; \
variantTypeBuf[i++] = 0; \
assert(i < sizeof(variantTypeBuf)); \
M_C(name, _clear)(el); \
/* In function of the type */ \
if (strcmp(variantTypeBuf, "EMPTY") == 0) { \
el->type = M_C(name, _EMPTY); \
} \
M_MAP2(VARIANTI_DEFINE_PARSE_STR_FUNC , name, __VA_ARGS__) \
else goto exit; \
success = (*str++ == '@'); \
exit: \
if (endp) *endp = str; \
return success; \
}
#define VARIANTI_DEFINE_PARSE_STR_FUNC(name, a) \
else if (strcmp (variantTypeBuf, M_APPLY (M_AS_STR, VARIANTI_GET_FIELD a)) == 0) { \
el->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
VARIANTI_CALL_INIT(a, el ->value . VARIANTI_GET_FIELD a ); \
bool b = VARIANTI_CALL_PARSE_STR(a, el -> value . VARIANTI_GET_FIELD a, str, &str); \
if (!b) goto exit; \
}
#define VARIANTI_DEFINE_CLEAN_FUNC(name, ...) \
static inline void M_C(name, _clean)(M_C(name,_t) my) \
{ \
@@ -399,11 +509,14 @@
INIT_SET(M_C(name, _init_set)), \
SET(M_C(name,_set)), \
CLEAR(M_C(name, _clear)), \
CLEAN(M_C(name, _clean)), \
TYPE(M_C(name,_t)), \
TEST_EMPTY(M_C(name,_empty_p)), \
M_IF_METHOD_ALL(HASH, __VA_ARGS__)(HASH(M_C(name, _hash)),), \
M_IF_METHOD_ALL(EQUAL, __VA_ARGS__)(EQUAL(M_C(name, _equal_p)),), \
M_IF_METHOD_ALL(GET_STR, __VA_ARGS__)(GET_STR(M_C(name, _get_str)),), \
M_IF_METHOD_ALL(IN_STR, __VA_ARGS__)(IN_STR(M_C(name, _in_str)),), \
M_IF_METHOD2_ALL(PARSE_STR, INIT, __VA_ARGS__)(PARSE_STR(M_C(name, _parse_str)),), \
M_IF_METHOD2_ALL(IN_STR, INIT, __VA_ARGS__)(IN_STR(M_C(name, _in_str)),), \
M_IF_METHOD_ALL(OUT_STR, __VA_ARGS__)(OUT_STR(M_C(name, _out_str)),), \
M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(INIT_MOVE(M_C(name, _init_move)),), \
M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(MOVE(M_C(name, _move)),), \
@@ -414,25 +527,18 @@
)
/* Macros for testing for method presence */
#define VARIANTI_TEST_METHOD2_P(method, f, t, op) \
#define VARIANTI_TEST_METHOD_P2(method, f, t, op) \
M_TEST_METHOD_P(method, op)
#define VARIANTI_TEST_METHOD_P(method, trio) \
M_APPLY(VARIANTI_TEST_METHOD2_P, method, M_OPFLAT trio)
#define VARIANTI_ALL_EQUAL(...) \
M_REDUCE2(VARIANTI_TEST_METHOD_P, M_AND, EQUAL, __VA_ARGS__)
#define VARIANTI_ALL_HASH(...) \
M_REDUCE2(VARIANTI_TEST_METHOD_P, M_AND, HASH, __VA_ARGS__)
#define VARIANTI_ALL_GET_STR(...) \
M_REDUCE2(VARIANTI_TEST_METHOD_P, M_AND, GET_STR, __VA_ARGS__)
#define VARIANTI_ALL_OUT_STR(...) \
M_REDUCE2(VARIANTI_TEST_METHOD_P, M_AND, OUT_STR, __VA_ARGS__)
#define VARIANTI_ALL_IN_STR(...) \
M_REDUCE2(VARIANTI_TEST_METHOD_P, M_AND, IN_STR, __VA_ARGS__)
#define VARIANTI_ALL_INIT_MOVE(...) \
M_REDUCE2(VARIANTI_TEST_METHOD_P, M_AND, INIT_MOVE, __VA_ARGS__)
#define VARIANTI_ALL_SWAP(...) \
M_REDUCE2(VARIANTI_TEST_METHOD_P, M_AND, SWAP, __VA_ARGS__)
M_APPLY(VARIANTI_TEST_METHOD_P2, method, M_OPFLAT trio)
#define VARIANTI_IF_ALL(method, ...) \
M_IF(M_REDUCE2(VARIANTI_TEST_METHOD_P, M_AND, method, __VA_ARGS__))
#define VARIANTI_TEST_METHOD2_P2(method1, method2, f, t, op) \
M_AND(M_TEST_METHOD_P(method1, op), M_TEST_METHOD_P(method2, op))
#define VARIANTI_TEST_METHOD2_P(method, trio) \
M_APPLY(VARIANTI_TEST_METHOD2_P2, M_PAIR_1 method, M_PAIR_2 method, M_OPFLAT trio)
#define VARIANTI_IF_ALL2(method1, method2, ...) \
M_IF(M_REDUCE2(VARIANTI_TEST_METHOD2_P, M_AND, (method1, method2), __VA_ARGS__))
#endif
+65 -40
View File
@@ -22,8 +22,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __M_WORKER_H
#define __M_WORKER_H
#ifndef MSTARLIB_WORKER_H
#define MSTARLIB_WORKER_H
#ifndef WORKER_DISABLE
@@ -71,7 +71,7 @@
# define WORKER_USE_CPP_FUNCTION 0
#endif
/* Control that not both options are selected at the same times.
/* Control that not both options are selected at the same time.
Note: there are not really incompatible, but if we use C++ we shall go to
lambda directly (there is no need to support blocks)! */
#if WORKER_USE_CLANG_BLOCK && WORKER_USE_CPP_FUNCTION
@@ -108,12 +108,6 @@ typedef struct worker_thread_s {
m_thread_t id;
} worker_thread_t;
/* This type defines a synchronization point for workers */
typedef struct worker_sync_s {
atomic_int num_spawn;
atomic_int num_terminated_spawn;
} worker_sync_t[1];
/* Let's define the queue which will manage all work orders */
BUFFER_DEF(worker_queue, worker_order_t, 0, BUFFER_QUEUE|BUFFER_UNBLOCKING_PUSH|BUFFER_BLOCKING_POP|BUFFER_THREAD_SAFE|BUFFER_DEFERRED_POP, M_POD_OPLIST)
@@ -131,8 +125,19 @@ typedef struct worker_s {
/* The global clear function */
void (*clearFunc_g)(void);
m_mutex_t lock;
m_cond_t a_thread_ends;
} worker_t[1];
/* This type defines a synchronization point for workers */
typedef struct worker_sync_s {
atomic_int num_spawn;
atomic_int num_terminated_spawn;
struct worker_s *worker;
} worker_sync_t[1];
/* Return the number of CPU of the system */
static inline int
workeri_get_cpu_count(void)
@@ -156,7 +161,7 @@ workeri_get_cpu_count(void)
#endif
}
/* Execute a work order */
/* Execute the registered work order synchronously */
static inline void
workeri_exec(worker_order_t *w)
{
@@ -175,6 +180,7 @@ workeri_exec(worker_order_t *w)
else
#endif
w->func(w->data);
/* Increment the number of terminated work order for the synchronous point */
atomic_fetch_add (&w->block->num_terminated_spawn, 1);
}
@@ -193,6 +199,9 @@ workeri_thread(void *arg)
if (w.block == NULL) break;
workeri_exec(&w);
worker_queue_pop_release(g->queue_g);
m_mutex_lock(g->lock);
m_cond_broadcast(g->a_thread_ends);
m_mutex_unlock(g->lock);
}
if (g->clearFunc_g != NULL)
g->clearFunc_g();
@@ -200,25 +209,32 @@ workeri_thread(void *arg)
/* Initialization of the worker module
Input:
@numWorker: number of worker to create
@numWorker: number of worker to create (0=autodetect, -1=2*autodetect)
@extraQueue: number of extra work order we can get if all workers are full
@resetFunc: function to reset the state of a worker between work orders (or NULL if none)
@clearFunc: function to clear the state of a worker before terminaning (or NULL if none)
*/
static inline void
worker_init(worker_t g, unsigned int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
worker_init(worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
{
if (numWorker == 0)
numWorker = workeri_get_cpu_count()-1;
assert (numWorker >= -1);
if (numWorker <= 0)
numWorker = (1 + (numWorker == -1))*workeri_get_cpu_count()-1;
//printf ("Starting queue with: %d\n", numWorker + extraQueue);
worker_queue_init(g->queue_g, numWorker + extraQueue);
size_t numWorker_st = numWorker;
g->worker = M_MEMORY_REALLOC(worker_thread_t, NULL, numWorker_st);
M_ASSERT_INIT (g->worker != NULL);
g->numWorker_g = numWorker;
if (g->worker == NULL) {
M_MEMORY_FULL(sizeof (worker_thread_t) * numWorker_st);
return;
}
g->numWorker_g = numWorker_st;
g->resetFunc_g = resetFunc;
g->clearFunc_g = clearFunc;
for(size_t i = 0; i < numWorker; i++) {
m_mutex_init(g->lock);
m_cond_init(g->a_thread_ends);
for(size_t i = 0; i < numWorker_st; i++) {
m_thread_create(g->worker[i].id, workeri_thread, M_ASSIGN_CAST(void*, g));
}
}
@@ -229,6 +245,7 @@ worker_init(worker_t g, unsigned int numWorker, unsigned int extraQueue, void (*
static inline void
worker_clear(worker_t g)
{
assert (worker_queue_empty_p (g->queue_g));
for(unsigned int i = 0; i < g->numWorker_g; i++) {
worker_order_t w = WORKER_EMPTY_ORDER;
// Normaly all worker threads shall be waiting at this
@@ -242,26 +259,29 @@ worker_clear(worker_t g)
}
M_MEMORY_FREE(g->worker);
m_mutex_clear(g->lock);
m_cond_clear(g->a_thread_ends);
worker_queue_clear(g->queue_g);
}
/* Start a new collaboration between workers
and define the synchronization point 'block' */
static inline void
worker_start(worker_sync_t block)
worker_start(worker_sync_t block, worker_t g)
{
atomic_init (&block->num_spawn, 0);
atomic_init (&block->num_terminated_spawn, 0);
block->worker = g;
}
/* Spawn or not the given work order to workers,
or do it ourself if no worker is available */
static inline void
worker_spawn(worker_t g, worker_sync_t block, void (*func)(void *data), void *data)
worker_spawn(worker_sync_t block, void (*func)(void *data), void *data)
{
const worker_order_t w = { block, data, func WORKER_EXTRA_ORDER };
if (M_UNLIKELY (!worker_queue_full_p(g->queue_g))
&& worker_queue_push (g->queue_g, w) == true) {
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
&& worker_queue_push (block->worker->queue_g, w) == true) {
//printf ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
atomic_fetch_add (&block->num_spawn, 1);
return;
@@ -275,11 +295,11 @@ worker_spawn(worker_t g, worker_sync_t block, void (*func)(void *data), void *da
/* Spawn or not the given work order to workers,
or do it ourself if no worker is available */
static inline void
worker_spawn_block(worker_t g, worker_sync_t block, void (^func)(void *data), void *data)
worker_spawn_block(worker_sync_t block, void (^func)(void *data), void *data)
{
const worker_order_t w = { block, data, NULL, func };
if (M_UNLIKELY (!worker_queue_full_p(g->queue_g))
&& worker_queue_push (g->queue_g, w) == true) {
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
&& worker_queue_push (block->worker->queue_g, w) == true) {
//printf ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
atomic_fetch_add (&block->num_spawn, 1);
return;
@@ -294,11 +314,11 @@ worker_spawn_block(worker_t g, worker_sync_t block, void (^func)(void *data), vo
/* Spawn or not the given work order to workers,
or do it ourself if no worker is available */
static inline void
worker_spawn_function(worker_t g, worker_sync_t block, std::function<void(void *data)> func, void *data)
worker_spawn_function(worker_sync_t block, std::function<void(void *data)> func, void *data)
{
const worker_order_t w = { block, data, NULL, func };
if (M_UNLIKELY (!worker_queue_full_p(g->queue_g))
&& worker_queue_push (g->queue_g, w) == true) {
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
&& worker_queue_push (block->worker->queue_g, w) == true) {
//printf ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
atomic_fetch_add (&block->num_spawn, 1);
return;
@@ -324,7 +344,12 @@ static inline void
worker_sync(worker_sync_t block)
{
//printf ("Waiting for thread terminasion.\n");
while (!worker_sync_p(block)) ;
if (worker_sync_p(block)) return;
m_mutex_lock(block->worker->lock);
while (!worker_sync_p(block)) {
m_cond_wait(block->worker->a_thread_ends, block->worker->lock);
}
m_mutex_unlock(block->worker->lock);
}
/* Flush any work order in the queue if some remains.*/
@@ -353,19 +378,19 @@ worker_count(worker_t g)
'output' is the list of output variables of the 'core' block within "( )"
Output variables are only available after a synchronisation block. */
#if WORKER_USE_CLANG_BLOCK
#define WORKER_SPAWN(_worker, _block, _input, _core, _output) \
#define WORKER_SPAWN(_block, _input, _core, _output) \
WORKER_DEF_DATA(_input, _output) \
WORKER_DEF_SUBBLOCK(_input, _output, _core) \
worker_spawn_block ((_worker), (_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
worker_spawn_block ((_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
#elif WORKER_USE_CPP_FUNCTION
// TODO: Explicit pass all arguments by reference.
#define WORKER_SPAWN(_worker, _block, _input, _core, _output) \
worker_spawn_function ((_worker), (_block), [&](void *param) {(void)param ; _core } , NULL)
#define WORKER_SPAWN(_block, _input, _core, _output) \
worker_spawn_function ((_block), [&](void *param) {(void)param ; _core } , NULL)
#else
#define WORKER_SPAWN(_worker, _block, _input, _core, _output) \
#define WORKER_SPAWN(_block, _input, _core, _output) \
WORKER_DEF_DATA(_input, _output) \
WORKER_DEF_SUBFUNC(_input, _output, _core) \
worker_spawn ((_worker), (_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
worker_spawn ((_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
#endif
#define WORKER_SPAWN_STRUCT_NAME M_C(worker_data_s_, __LINE__)
@@ -383,7 +408,7 @@ worker_count(worker_t g)
#define WORKER_DEF_DATA_INPUT(...) \
M_MAP(WORKER_DEF_SINGLE_INPUT, __VA_ARGS__)
#define WORKER_DEF_SINGLE_OUTPUT(var) \
__typeof__(var) *M_C(var, __ptr);
__typeof__(var) *M_C(var, _ptr);
#define WORKER_DEF_DATA_OUTPUT(...) \
M_MAP(WORKER_DEF_SINGLE_OUTPUT, __VA_ARGS__)
#define WORKER_INIT_SINGLE_INPUT(var) \
@@ -391,7 +416,7 @@ worker_count(worker_t g)
#define WORKER_INIT_DATA_INPUT(...) \
M_MAP(WORKER_INIT_SINGLE_INPUT, __VA_ARGS__)
#define WORKER_INIT_SINGLE_OUTPUT(var) \
.M_C(var, __ptr) = &var,
.M_C(var, _ptr) = &var,
#define WORKER_INIT_DATA_OUTPUT(...) \
M_MAP(WORKER_INIT_SINGLE_OUTPUT, __VA_ARGS__)
#define WORKER_DEF_SUBFUNC(_input, _output, _core) \
@@ -422,7 +447,7 @@ worker_count(worker_t g)
#define WORKER_INIT_LOCAL_OUTPUT(...) \
M_MAP(WORKER_INIT_SINGLE_LOCAL_OUTPUT, __VA_ARGS__)
#define WORKER_PROPAGATE_SINGLE_OUTPUT(var) \
*(_s_data->M_C(var, __ptr)) = var;
*(_s_data->M_C(var, _ptr)) = var;
#define WORKER_PROPAGATE_LOCAL_OUTPUT(...) \
M_MAP(WORKER_PROPAGATE_SINGLE_OUTPUT, __VA_ARGS__)
@@ -444,11 +469,11 @@ typedef struct worker_s {
#define worker_init(g, numWorker, extraQueue, resetFunc) do { (void) g; } while (0)
#define worker_clear(g) do { (void) g; } while (0)
#define worker_start(b) do { (void) b; } while (0)
#define worker_spawn(w, b, f, d) do { f(d); } while (0)
#define worker_start(b, w) do { (void) b; } while (0)
#define worker_spawn(b, f, d) do { f(d); } while (0)
#define worker_sync(b) do { (void) b; } while (0)
#define worker_count(w) 1
#define WORKER_SPAWN(w, b, i, c, o) do { c } while (0)
#define WORKER_SPAWN(b, i, c, o) do { c } while (0)
#endif /* WORKER_DISABLE */
+40 -8
View File
@@ -5,6 +5,7 @@ CFLAGS=$(WCFLAGS) $(XCFLAGS)
CPPFLAGS=-I..
LDFLAGS=-pthread
RM=rm -f
LOG_COMPILER=
all:
@echo "Nothing to be done."
@@ -22,7 +23,7 @@ all:
$(CC) $(CFLAGS) $(CPPFLAGS) -MM -MT `echo $< |sed -e 's/\.c/\.exe/g'` $< > $@
.exe.log:
./$<
$(LOG_COMPILER) ./$<
.exe.valgrind:
valgrind ./$<
@@ -30,10 +31,10 @@ all:
.c.gcov:
awk '/START_COVERAGE/ { printit=1} (printit == 0) { print }' $< > $<.first.c
awk ' printit { print } /END_COVERAGE/ { printit=1}' $< > $<.end.c
$(CC) $(CPPFLAGS) -E -DNDEBUG -DWITHIN_COVERAGE $< |grep -v '^#' |awk ' /END_COVERAGE/ { printit=0} printit { print } /START_COVERAGE/ { printit=1 }' |perl -pi -e "s/;(?![\"'])/;\n/g ; s/}(?![\"'])/}\n/g ; s/{(?![\"'])/{\n/g" > $<.middle.c
$(CC) $(CPPFLAGS) -E -DNDEBUG -DWITHIN_COVERAGE $< |grep -v '^#' |awk ' /END_COVERAGE/ { printit=0} printit { print } /START_COVERAGE/ { printit=1 }' |perl -p -e "s/;(?![\"'])/;\n/g ; s/}(?![\"'])/}\n/g ; s/{(?![\"'])/{\n/g" > $<.middle.c
cat $<.first.c $<.middle.c $<.end.c > $<.c
$(CC) $(CPPFLAGS) $(LDFLAGS) -ftest-coverage -fprofile-arcs -g $<.c -o $<.exe
./$<.exe
$(LOG_COMPILER) ./$<.exe
gcov $<.gcno > `basename $< .c`.synt
cat `basename $< .c`.synt
mv $<.c.gcov `basename $< .c`.gcov
@@ -68,17 +69,25 @@ distclean: clean
#####################################################################################################
gene-list:
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -DNDEBUG -S tgen-mlist.c && less tgen-mlist.s
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -march=native -DNDEBUG -S tgen-mlist.c && less tgen-mlist.s
gene-array:
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -DNDEBUG -S tgen-marray.c && less tgen-marray.s
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -march=native -DNDEBUG -S tgen-marray.c && less tgen-marray.s
gene-shared:
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -DNDEBUG -S tgen-shared.c && less tgen-shared.s
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -march=native -DNDEBUG -S tgen-shared.c && less tgen-shared.s
gene-bitset:
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -DNDEBUG -S tgen-bitset.c && less tgen-bitset.s
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -march=native -DNDEBUG -S tgen-bitset.c && less tgen-bitset.s
gene-dict:
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -march=native -DNDEBUG -S tgen-mdict.c && less tgen-mdict.s
gene-queue:
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -march=native -DNDEBUG -S tgen-queue.c && less tgen-queue.s
gene-string:
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -march=native -DNDEBUG -S tgen-mstring.c && less tgen-mstring.s
#####################################################################################################
# Coverage
@@ -91,6 +100,7 @@ coverage:
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-CORE test-mcore.c.c test-mcore.synt \
M-DEQUE test-mdeque.c.c test-mdeque.synt \
@@ -127,10 +137,32 @@ synthesis:
valgrind:
$(MAKE) `ls test-*.c|sed -e 's/\.c/\.valgrind/g'`
scan-build:
scan-build: clean
$(RM) -rf ./mlib-report
scan-build -o ./mlib-report $(MAKE) check XCFLAGS="-std=c99"
sanitize:
$(MAKE) clean check XCFLAGS="-fsanitize=address,undefined"
$(MAKE) clean check XCFLAGS="-fsanitize=thread -pie -fPIE"
#####################################################################################################
# Test All
#####################################################################################################
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 -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wno-unused-function -ftrapv
checkall:
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c99"
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c99 -m32"
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c11"
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c11 -m32"
@if which clang ; then $(MAKE) clean ; $(MAKE) check CC="clang -std=c99" WCFLAGS="$(WCFLAGS_CLANG)" ; else echo "SYSTEM CLANG not found: SKIP TEST" ; fi
@if which g++ ; then $(MAKE) clean ; $(MAKE) check CC="g++ -std=c++11" WCFLAGS="$(WCFLAGS_CPP)" ; else echo "SYSTEM G++ not found: SKIP TEST" ; fi
@if which clang++ ; then $(MAKE) clean ; $(MAKE) check CC="clang++ -std=c++11" WCFLAGS="$(WCFLAGS_CLANG)" ; else echo "SYSTEM CLANG++ not found: SKIP TEST" ; fi
@if which tcc ; then $(MAKE) clean ; $(MAKE) check CC="tcc -std=c99" ; else echo "SYSTEM TCC not found: SKIP TEST" ; fi
@if which musl-gcc ; then $(MAKE) clean ; $(MAKE) check CC="musl-gcc -std=c11" ; else echo "SYSTEM MUSL-GCC not found: SKIP TEST" ; fi
@for f in /opt/gcc* ; do if test -x "$$f/bin/gcc" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/gcc -std=c99" ; fi ; done
@for f in /opt/clang* ; do if test -x "$$f/bin/clang" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/clang -std=c99" WCFLAGS="$(WCFLAGS_CLANG)" ; fi ; done
@for f in /opt/tcc* ; do if test -x "$$f/bin/tcc" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/tcc -std=c99" ; fi ; done
+4
View File
@@ -63,12 +63,16 @@
#undef QUEUEI_MPMC_CONTRACT
#undef RBTREEI_CONTRACT_NODE
#undef RBTREEI_CONTRACT
#undef BPTREEI_NODE_CONTRACT
#undef BPTREEI_CONTRACT
#undef LISTI_CONTRACT
#undef LISTI_DUAL_PUSH_CONTRACT
#undef NDEBUG
#undef atomic_init
#undef atomic_load
#undef atomic_store
#undef M_CONST_CAST
#undef M_ASSIGN_CAST
#else
/* For normal builds, empty macros which does nothing */
#define START_COVERAGE
-105
View File
@@ -1,105 +0,0 @@
#ifndef MY_MPZ_T
#define MY_MPZ_T
#include "m-string.h"
/* This is a trivial encapsulation of an opquae structure.
Used for test purpose only.*/
typedef struct my_mpz_s {
unsigned int n;
unsigned int a;
unsigned int *ptr;
} my_mpz_t[1];
static void my_mpz_init(my_mpz_t z)
{
z->n = 1;
z->a = 1;
z->ptr = (unsigned int*) calloc(1, sizeof(unsigned int));
if (!z->ptr) abort();
}
static void my_mpz_clear(my_mpz_t z)
{
free(z->ptr);
z->ptr = NULL;
}
static void my_mpz_init_set(my_mpz_t d, const my_mpz_t s)
{
d->n = s->n;
d->a = s->n;
d->ptr = (unsigned int *) calloc (s->n, sizeof(unsigned int));
memcpy(d->ptr, s->ptr, sizeof(unsigned int) * s->n);
}
static void my_mpz_set(my_mpz_t d, const my_mpz_t s)
{
my_mpz_clear(d);
my_mpz_init_set(d, s);
}
static void my_mpz_set_ui(my_mpz_t d, unsigned int v)
{
d->n = 1;
d->ptr[0] = v;
}
static void my_mpz_init_set_ui(my_mpz_t d, unsigned int v)
{
my_mpz_init(d);
my_mpz_set_ui(d, v);
}
static unsigned int my_mpz_get_ui(const my_mpz_t z)
{
return z->ptr[0];
}
static void my_mpz_add(my_mpz_t d, const my_mpz_t a, const my_mpz_t b)
{
d->ptr[0] = a->ptr[0] + b->ptr[0];
}
static void my_mpz_out_str(FILE *f, const my_mpz_t z)
{
assert(z->n == 1);
fprintf(f, "%u", z->ptr[0]);
}
static bool my_mpz_in_str(my_mpz_t z, FILE *f)
{
z->n = 1;
return fscanf(f, "%u", &z->ptr[0]) == 1;
}
static bool my_mpz_equal_p(const my_mpz_t z1, const my_mpz_t z2)
{
if (z1->n != z2->n) return false;
return memcmp(z1->ptr, z2->ptr, z1->n*sizeof(unsigned int)) == 0;
}
static int my_mpz_cmp(const my_mpz_t z1, const my_mpz_t z2)
{
if (z1->n != z2->n) return z1-> n < z2->n ? -1 : 1;
return memcmp(z1->ptr, z2->ptr, z1->n*sizeof(unsigned int));
}
static int my_mpz_cmp_ui(const my_mpz_t z1, unsigned int z2)
{
if (z1->n != 1) return z1-> n < 1 ? -1 : 1;
return memcmp(z1->ptr, &z2, sizeof(unsigned int));
}
static void my_mpz_str(string_t str, const my_mpz_t z, bool append)
{
if (append) string_cat_printf (str, "%u", z->ptr[0]);
else string_printf (str, "%u", z->ptr[0]);
}
#define MYMPZ_OPLIST \
(INIT(my_mpz_init), INIT_SET(my_mpz_init_set), SET(my_mpz_set), CLEAR(my_mpz_clear), \
OUT_STR(my_mpz_out_str), IN_STR(my_mpz_in_str), EQUAL(my_mpz_equal_p), \
GET_STR(my_mpz_str) )
#endif
+151 -11
View File
@@ -21,21 +21,35 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "m-list.h"
#include "m-i-list.h"
#include "m-array.h"
#include "m-string.h"
#include "m-deque.h"
#include "test-obj.h"
#include "m-algo.h"
typedef struct over_s {
unsigned long data;
ILIST_INTERFACE(ilist_over, over_s);
} over_t;
// TODO: Test Intrusive List
// HASHMAP, RBTREE, B+TREE: Is this useful?
ARRAY_DEF(array_int, int)
#define M_OPL_array_int_t() ARRAY_OPLIST(array_int)
LIST_DEF(list_int, int)
ILIST_DEF(ilist_over, over_t, M_POD_OPLIST)
LIST_DEF(list_string, string_t, STRING_OPLIST)
DEQUE_DEF(deque_obj, testobj_t, TESTOBJ_CMP_OPLIST)
#define M_OPL_deque_obj_t() DEQUE_OPLIST(deque_obj, TESTOBJ_CMP_OPLIST)
#include "coverage.h"
START_COVERAGE
ALGO_DEF(algo_array, ARRAY_OPLIST(array_int))
ALGO_DEF(algo_array, array_int_t)
ALGO_DEF(algo_list, LIST_OPLIST(list_int))
ALGO_DEF(algo_over, ILIST_OPLIST(ilist_over, M_POD_OPLIST))
ALGO_DEF(algo_string, LIST_OPLIST(list_string, STRING_OPLIST))
ALGO_DEF(algo_deque, deque_obj_t)
END_COVERAGE
int g_min, g_max, g_count;
@@ -57,24 +71,57 @@ static void func_reduce(int *d, int n)
*d += n;
}
static bool func_test_42(int d)
{
return d == 42;
}
static bool func_test_101(int d)
{
return d == 101;
}
static bool func_test_pos(int d)
{
return d >= 0;
}
static bool func_test_both_even_or_odd(int a, int b)
{
return (a&1) == (b&1);
}
static void test_list(void)
{
list_int_t l;
list_int_init(l);
for(int i = 0; i < 100; i++)
list_int_push_back (l, i);
assert( algo_list_contains(l, 62) == true);
assert( algo_list_contains(l, -1) == false);
assert( algo_list_contain_p(l, 62) == true);
assert( algo_list_contain_p(l, -1) == false);
assert( algo_list_count(l, 1) == 1);
list_int_push_back (l, 17);
assert( algo_list_count(l, 17) == 2);
assert( algo_list_count(l, -1) == 0);
assert (algo_list_all_of_p(l, func_test_42) == false);
assert (algo_list_any_of_p(l, func_test_42) == true);
assert (algo_list_none_of_p(l, func_test_42) == false);
assert (algo_list_all_of_p(l, func_test_101) == false);
assert (algo_list_any_of_p(l, func_test_101) == false);
assert (algo_list_none_of_p(l, func_test_101) == true);
assert (algo_list_all_of_p(l, func_test_pos) == true);
assert (algo_list_any_of_p(l, func_test_pos) == true);
assert (algo_list_none_of_p(l, func_test_pos) == false);
#define f(x) assert((x) >= 0 && (x) < 100);
ALGO_MAP(l, LIST_OPLIST(list_int), f);
ALGO_FOR_EACH(l, LIST_OPLIST(list_int), f);
#define g(y, x) assert((x) >= 0 && (x) < y);
ALGO_MAP(l, LIST_OPLIST(list_int), g, 100);
ALGO_FOR_EACH(l, LIST_OPLIST(list_int), g, 100);
assert( algo_list_count_if(l, func_test_42) == 1);
assert( algo_list_count_if(l, func_test_101) == 0);
int *p = algo_list_min(l);
assert(p != NULL && *p == 0);
@@ -92,6 +139,16 @@ static void test_list(void)
algo_list_find_last (it2, l, 3);
assert (!list_int_end_p (it2));
assert (!list_int_it_equal_p(it1, it2));
algo_list_find_if(it1, l, func_test_101);
assert (list_int_end_p (it1));
algo_list_find_if(it1, l, func_test_42);
assert (!list_int_end_p (it1));
assert (*list_int_cref(it1) == 42);
algo_list_mismatch(it1, it2, l, l);
assert (list_int_end_p (it1));
assert (list_int_end_p (it2));
for(int i = -100; i < 100; i+=2)
list_int_push_back (l, i);
@@ -113,16 +170,29 @@ static void test_array(void)
array_int_init(l);
for(int i = 0; i < 100; i++)
array_int_push_back (l, i);
assert( algo_array_contains(l, 62) == true);
assert( algo_array_contains(l, -1) == false);
assert( algo_array_contain_p(l, 62) == true);
assert( algo_array_contain_p(l, -1) == false);
assert( algo_array_sort_p(l) == true);
assert (algo_array_all_of_p(l, func_test_42) == false);
assert (algo_array_any_of_p(l, func_test_42) == true);
assert (algo_array_none_of_p(l, func_test_42) == false);
assert (algo_array_all_of_p(l, func_test_101) == false);
assert (algo_array_any_of_p(l, func_test_101) == false);
assert (algo_array_none_of_p(l, func_test_101) == true);
assert (algo_array_all_of_p(l, func_test_pos) == true);
assert (algo_array_any_of_p(l, func_test_pos) == true);
assert (algo_array_none_of_p(l, func_test_pos) == false);
assert( algo_array_count(l, 1) == 1);
array_int_push_back (l, 17);
assert( algo_array_count(l, 17) == 2);
assert( algo_array_count(l, -1) == 0);
assert( algo_array_sort_p(l) == false);
assert( algo_array_count_if(l, func_test_42) == 1);
assert( algo_array_count_if(l, func_test_101) == 0);
array_int_it_t it;
algo_array_find_last(it, l, 17);
assert (!array_int_end_p (it));
@@ -133,12 +203,13 @@ static void test_array(void)
assert (array_int_end_p (it));
#define f(x) assert((x) >= 0 && (x) < 100);
ALGO_MAP(l, ARRAY_OPLIST(array_int), f);
ALGO_FOR_EACH(l, ARRAY_OPLIST(array_int), f);
ALGO_FOR_EACH(l, array_int_t, f);
g_min = 0;
g_max = 99;
g_count = 0;
algo_array_map(l, g_f);
algo_array_for_each(l, g_f);
assert(g_count == 101);
int n;
@@ -174,6 +245,31 @@ static void test_array(void)
assert (array_int_size(l) == 102);
assert( algo_array_sort_p(l) == true);
M_LET(l2, array_int_t) {
array_int_set(l2, l);
array_int_it_t it1, it2;
algo_array_mismatch(it1, it2, l, l2);
assert (array_int_end_p (it1));
assert (array_int_end_p (it2));
array_int_pop_back(NULL, l2);
array_int_push_back(l2, 159);
algo_array_mismatch(it1, it2, l, l2);
assert (!array_int_end_p (it1));
assert (!array_int_end_p (it2));
assert (*array_int_cref(it1) == 1742);
assert (*array_int_cref(it2) == 159);
algo_array_mismatch_if(it1, it2, l, l2, func_test_both_even_or_odd);
assert (!array_int_end_p (it1));
assert (!array_int_end_p (it2));
assert (*array_int_cref(it1) == 1742);
assert (*array_int_cref(it2) == 159);
array_int_pop_back(NULL, l2);
array_int_push_back(l2, 152);
algo_array_mismatch_if(it1, it2, l, l2, func_test_both_even_or_odd);
assert (array_int_end_p (it1));
assert (array_int_end_p (it2));
}
array_int_clean(l);
assert (algo_array_min(l) == NULL);
assert (algo_array_max(l) == NULL);
@@ -197,7 +293,19 @@ static void test_array(void)
ALGO_INIT_VA(l, ARRAY_OPLIST(array_int), 1, 2, 3, 4, 5);
assert (array_int_size(l) == 5);
assert (algo_array_sort_p(l) == true);
assert (algo_array_sort_dsc_p(l) == false);
algo_array_sort_dsc(l);
assert (algo_array_sort_p(l) == false);
assert (algo_array_sort_dsc_p(l) == true);
array_int_clear(l);
ALGO_LET_INIT_VA(arr, array_int_t, 1, 5, 34) {
assert (array_int_size(arr) == 3);
assert (algo_array_sort_p(arr) == true);
assert (algo_array_sort_dsc_p(arr) == false);
}
}
static void test_string(void)
@@ -215,6 +323,16 @@ static void test_string(void)
assert (string_equal_str_p(s, " John"));
assert (list_string_empty_p(l));
string_set_str(s, "Hello,,John");
algo_string_split(l, s, ',');
list_string_pop_back (&s, l);
assert (string_equal_str_p(s, "Hello"));
list_string_pop_back (&s, l);
assert (string_equal_str_p(s, ""));
list_string_pop_back (&s, l);
assert (string_equal_str_p(s, "John"));
assert (list_string_empty_p(l));
list_string_push_back (l, STRING_CTE("John"));
list_string_push_back (l, STRING_CTE("Who"));
list_string_push_back (l, STRING_CTE("Is"));
@@ -246,6 +364,8 @@ static void test_extract(void)
#define inc(d, c) (d) += (c)
ALGO_REDUCE(dst, a, ARRAY_OPLIST(array_int), inc);
assert (dst == 100*99/2-10*11/2);
ALGO_REDUCE(dst, a, array_int_t, inc);
assert (dst == 100*99/2-10*11/2);
#define sqr(d, c) (d) = (c)*(c)
ALGO_REDUCE(dst, a, ARRAY_OPLIST(array_int), inc, sqr);
assert (dst == 327965);
@@ -266,11 +386,31 @@ static void test_extract(void)
list_int_clear(l);
}
ARRAY_DEF(aint, int)
LIST_DEF(lint, int)
#define M_OPL_aint_t() ARRAY_OPLIST(aint)
#define M_OPL_lint_t() LIST_OPLIST(lint)
static void test_insert(void)
{
ALGO_LET_INIT_VA(a, lint_t, 1, 2, 3, 4)
ALGO_LET_INIT_VA(b, aint_t, -1, -2, -3) {
lint_it_t i;
lint_it(i, a);
ALGO_INSERT_AT(a, lint_t, i, b, aint_t);
// TBC: order ok for the list (the reverse is confusing...)?
ALGO_LET_INIT_VA(c, lint_t, 1, 2, 3, -3, -2, -1, 4) {
assert (lint_equal_p (c, a));
}
}
}
int main(void)
{
test_list();
test_array();
test_string();
test_extract();
test_insert();
exit(0);
}
+73 -10
View File
@@ -21,16 +21,19 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "mympz.h"
#include "test-obj.h"
#include "m-array.h"
#include "coverage.h"
START_COVERAGE
ARRAY_DEF(array_uint, unsigned int)
ARRAY_DEF(array_mpz, my_mpz_t, MYMPZ_OPLIST)
ARRAY_DEF(array_mpz, testobj_t, TESTOBJ_OPLIST)
END_COVERAGE
#define ARRAY_UINT_OPLIST ARRAY_OPLIST(array_uint)
// 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)))
static void test_uint(void)
{
array_uint_t v;
@@ -125,7 +128,15 @@ static void test_uint(void)
assert(*array_uint_cget(v2, 500) == 0);
assert(array_uint_size(v2) == 1005);
assert(*array_uint_cget(v2, 1004) == 0);
array_uint_set_at(v2, 1004, 465487);
array_uint_insert_v (v2, 500, 0);
assert(array_uint_size(v2) == 1005);
assert(*array_uint_cget(v2, 1004) == 465487);
array_uint_insert_v (v2, 1004, 10000);
assert(array_uint_size(v2) == 11005);
assert(*array_uint_cget(v2, 11004) == 465487);
array_uint_resize(v2, 1005);
array_uint_init(v);
array_uint_swap(v,v2);
assert(array_uint_size(v) == 1005);
@@ -146,6 +157,39 @@ static void test_uint(void)
assert (array_uint_capacity(v) > 0);
array_uint_reserve(v, 0);
assert (array_uint_capacity(v) == 0);
array_uint_clean(v2);
array_uint_splice(v, v2);
assert (array_uint_size(v) == 0);
assert (array_uint_size(v2) == 0);
for(unsigned i = 0; i < 100; i++) {
array_uint_push_back(v, i);
array_uint_push_back(v2, 100+i);
}
array_uint_splice(v, v2);
assert (array_uint_size(v) == 200);
assert (array_uint_size(v2) == 0);
for(unsigned i = 0; i < 200; i++) {
assert (i == *array_uint_get(v, i));
}
x = 1478963;
s = *array_uint_back(v);
array_uint_push_move(v, &x);
assert (*array_uint_back(v) == 1478963);
x = 0;
array_uint_pop_move(&x, v);
assert (x == 1478963);
assert (s == *array_uint_back(v));
s = array_uint_size (v);
bool b = array_uint_erase (v, 12459);
assert (b == false);
assert (s == array_uint_size (v));
b = array_uint_erase (v, 0);
assert (b == true);
assert (s == array_uint_size (v)+1);
array_uint_clear(v);
array_uint_clear(v2);
@@ -154,11 +198,11 @@ static void test_uint(void)
static void test_mpz(void)
{
array_mpz_t array1, array2;
my_mpz_t z;
testobj_t z;
array_mpz_init (array1);
array_mpz_init (array2);
my_mpz_init (z);
testobj_init (z);
// Test empty
FILE *f = fopen ("a-marray.dat", "wt");
@@ -175,7 +219,7 @@ static void test_mpz(void)
// Test non empty
for(int n = 0; n < 1000; n++) {
my_mpz_set_ui (z, n);
testobj_set_ui (z, n);
array_mpz_push_back (array1, z);
}
@@ -196,18 +240,37 @@ static void test_mpz(void)
M_LET(str, STRING_OPLIST) {
array_mpz_get_str(str, array1, false);
assert (string_cmp_str (str, "[]") == 0);
my_mpz_set_ui (z, 17);
const char *sp;
b = array_mpz_parse_str(array2, string_get_cstr(str), &sp);
assert(b);
assert(*sp == 0);
assert(array_mpz_equal_p(array1, array2));
testobj_set_ui (z, 17);
array_mpz_push_back (array1, z);
array_mpz_get_str(str, array1, false);
assert (string_cmp_str (str, "[17]") == 0);
my_mpz_set_ui (z, 42);
b = array_mpz_parse_str(array2, string_get_cstr(str), &sp);
assert(b);
assert(*sp == 0);
assert(array_mpz_equal_p(array1, array2));
testobj_set_ui (z, 42);
array_mpz_push_back (array1, z);
array_mpz_get_str(str, array1, true);
assert (string_cmp_str (str, "[17][17,42]") == 0);
b = array_mpz_parse_str(array2, string_get_cstr(str), &sp);
assert(b);
assert(strcmp(sp, "[17,42]") == 0);
assert(!array_mpz_equal_p(array1, array2));
b = array_mpz_parse_str(array2, sp, &sp);
assert(b);
assert(strcmp(sp, "") == 0);
assert(array_mpz_equal_p(array1, array2));
// NOTE: Not the same order than list...
}
my_mpz_clear (z);
testobj_clear (z);
array_mpz_clear(array2);
array_mpz_clear(array1);
}
@@ -237,7 +300,7 @@ static void test_d(void)
for(int i = 9; i < 19; i++)
assert (*array_uint_get (a1, i) == 18U-i);
array_uint_set_at2(a1, 100, 100);
*array_uint_get_at(a1, 100) = 100;
assert (*array_uint_back(a1) == 100);
assert (array_uint_size(a1) == 101);
array_uint_pop_back (NULL, a1);
+45 -4
View File
@@ -30,6 +30,7 @@ static void test1(void)
bitset_t set;
bitset_init(set);
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));
@@ -39,7 +40,9 @@ static void test1(void)
}
assert(bitset_size(set) == 100);
assert(bitset_empty_p(set) == false);
assert(bitset_front(set) == false);
assert(bitset_back(set) == true);
bitset_t set2;
bitset_init_set(set2, set);
@@ -105,15 +108,17 @@ static void test1(void)
assert (b == false);
assert (bitset_size(set) == 196);
bitset_set_str(set, "[1010101010101010101000000000000000000000000000000000000000000000000000001111]");
bitset_parse_str(set, "[1010101010101010101000000000000000000000000000000000000000000000000000001111]", NULL);
bitset_push_at(set, 23, true);
bitset_t set3;
bitset_init(set3);
bitset_set_str(set3, "[10101010101010101010000100000000000000000000000000000000000000000000000001111]");
bitset_parse_str(set3, "[10101010101010101010000100000000000000000000000000000000000000000000000001111]", NULL);
assert(bitset_equal_p(set, set3));
bitset_push_at(set, 25, true);
bitset_set_str(set3, "[101010101010101010100001010000000000000000000000000000000000000000000000001111]");
const char *sp;
bitset_parse_str(set3, "[101010101010101010100001010000000000000000000000000000000000000000000000001111]", &sp);
assert(bitset_equal_p(set, set3));
assert (*sp == 0);
bitset_clear(set3);
bitset_clean(set);
@@ -308,6 +313,41 @@ static void test_let(void)
}
}
static void test_clz(void)
{
M_LET(s1, bitset_t) {
bitset_push_back(s1, false);
assert (bitset_clz(s1) == 1);
bitset_push_back(s1, false);
assert (bitset_clz(s1) == 2);
bitset_set_at(s1, 0, true);
assert (bitset_clz(s1) == 1);
bitset_set_at(s1, 1, true);
assert (bitset_clz(s1) == 0);
for(int i = 0; i < 62; i++)
bitset_push_back(s1, false);
assert (bitset_clz(s1) == 62);
bitset_set_at(s1, 63, true);
assert (bitset_clz(s1) == 0);
bitset_push_back(s1, false);
assert (bitset_clz(s1) == 1);
bitset_set_at(s1, 64, true);
assert (bitset_clz(s1) == 0);
for(size_t i = 0; i < 620; i++) {
bitset_push_back(s1, false);
assert (bitset_clz(s1) == i+1);
}
bitset_set_at(s1, 64+620, true);
assert (bitset_clz(s1) == 0);
for(size_t i = 1; i < 64+1+620; i++) {
bitset_set_at(s1, i, false);
}
assert (bitset_clz(s1) == 64+620);
bitset_set_at(s1, 0, false);
assert (bitset_clz(s1) == 64+620+1);
}
}
int main(void)
{
test1();
@@ -315,5 +355,6 @@ int main(void)
test_str();
test_logic();
test_let();
test_clz();
exit(0);
}
+427
View File
@@ -0,0 +1,427 @@
/*
* Copyright (c) 2017-2018, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include "m-string.h"
#include "m-bptree.h"
#include "test-obj.h"
#include "coverage.h"
START_COVERAGE
BPTREE_DEF2(btree, 3, int, M_DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
END_COVERAGE
BPTREE_DEF2(btree_my, 3, testobj_t, TESTOBJ_CMP_OPLIST, testobj_t, TESTOBJ_CMP_OPLIST)
BPTREE_DEF2(btree_int, 17, int, int)
BPTREE_DEF(btree_intset, 13, int)
BPTREE_DEF(btree_myset, 15, testobj_t, TESTOBJ_CMP_OPLIST)
static void test1(void)
{
btree_t b;
btree_init(b);
assert (btree_empty_p(b));
btree_set_at(b, 12, 34);
assert (!btree_empty_p(b));
assert (btree_size(b) == 1);
assert (btree_get(b, 12) != NULL);
assert (*btree_get(b, 12) == 34);
btree_set_at(b, 11, 35);
assert (!btree_empty_p(b));
assert (btree_size(b) == 2);
assert (btree_get(b, 11) != NULL);
assert (*btree_get(b, 11) == 35);
btree_set_at(b, 1, 36);
assert (!btree_empty_p(b));
assert (btree_size(b) == 3);
assert (btree_get(b, 1) != NULL);
assert (*btree_get(b, 1) == 36);
btree_set_at(b, 25, 37);
assert (!btree_empty_p(b));
assert (btree_size(b) == 4);
assert (btree_get(b, 25) != NULL);
assert (*btree_get(b, 25) == 37);
btree_set_at(b, -25, 38);
assert (btree_size(b) == 5);
assert (btree_get(b, -25) != NULL);
assert (*btree_get(b, -25) == 38);
btree_set_at(b, 5, 39);
assert (btree_size(b) == 6);
assert (*btree_get(b, -25) == 38);
btree_set_at(b, 5, 40);
assert (btree_size(b) == 6);
assert (*btree_get(b, 5) == 40);
btree_set_at(b, -5, 41);
assert (*btree_get(b, -5) == 41);
for(int i = -1000; i < 1000; i+=3) {
btree_set_at(b, i, 2*i);
assert (btree_get(b, i) != NULL);
assert (*btree_get(b, i) == 2*i);
}
for(int i = -1000+1; i < 1000; i+=3) {
btree_set_at(b, i, 2*i);
assert (btree_get(b, i) != NULL);
assert (*btree_get(b, i) == 2*i);
}
for(int i = -1000+2; i < 1000; i+=3) {
btree_set_at(b, i, 2*i);
assert (btree_get(b, i) != NULL);
assert (*btree_get(b, i) == 2*i);
}
for(int i = -1000; i < 1000; i++) {
assert (btree_get(b, i) != NULL);
assert (*btree_get(b, i) == 2*i);
}
assert (btree_size(b) == 2000);
bool r = btree_erase(b, 0);
assert (r == true);
assert (btree_get(b, 0) == NULL);
assert (btree_size(b) == 1999);
r = btree_erase(b, 1);
assert (r == true);
assert (btree_get(b, 1) == NULL);
assert (btree_size(b) == 1998);
r = btree_erase(b, 2);
assert (r == true);
assert (btree_get(b, 2) == NULL);
assert (btree_size(b) == 1997);
r = btree_erase(b, 0);
assert (r == false);
assert (btree_get(b, 0) == NULL);
assert (btree_size(b) == 1997);
btree_erase(b, -1);
assert (btree_get(b, -1) == NULL);
btree_erase(b, -2);
assert (btree_get(b, -2) == NULL);
btree_erase(b, 3);
assert (btree_get(b, 3) == NULL);
btree_erase(b, 4);
assert (btree_get(b, 4) == NULL);
btree_erase(b, -3);
assert (btree_get(b, -3) == NULL);
btree_erase(b, 5);
assert (btree_get(b, 5) == NULL);
btree_erase(b, -5);
assert (btree_get(b, -5) == NULL);
btree_erase(b, -4);
assert (btree_get(b, -4) == NULL);
btree_erase(b, 6);
assert (btree_get(b, 6) == NULL);
btree_erase(b, 7);
assert (btree_get(b, 7) == NULL);
for(int i = -1000; i < 0; i++) {
btree_erase(b, i);
assert (btree_get(b, i) == NULL);
}
for(int i = 0; i < 1000; i++) {
btree_erase(b, i);
assert (btree_get(b, i) == NULL);
}
assert (btree_size(b) == 0);
assert (btree_empty_p(b));
btree_clear(b);
}
static void test2(void)
{
btree_t b;
btree_init(b);
for(int i = 0; i < 100; i++)
btree_set_at(b, i, 100*i);
for(int i = 0; i < 100; i++)
assert (*btree_cget(b, i) == 100*i);
assert (btree_size(b) == 100);
int k;
bool r = btree_pop_at(NULL, b, 0);
assert (r == true);
assert (btree_size(b) == 99);
r = btree_pop_at(&k, b, 1);
assert (r == true);
assert (btree_size(b) == 98);
assert (k == 100);
k = -2;
r = btree_pop_at(&k, b, 1);
assert (r == false);
assert (k == -2);
r = btree_pop_at(NULL, b, 0);
assert (r == false);
btree_clean(b);
assert (btree_size(b) == 0);
assert (btree_empty_p(b));
btree_clear(b);
}
static void test3(void)
{
btree_t b;
btree_init(b);
for(int i = 0; i < 1000; i++)
btree_set_at(b, i, 1000*i);
assert(btree_size(b) == 1000);
for(int i = 0; i < 1000; i++) {
bool r = btree_erase(b, i);
assert (r == true);
}
assert(btree_size(b) == 0);
for(int i = 1000-1; i >= 0; i--)
btree_set_at(b, i, 1000*i);
assert(btree_size(b) == 1000);
for(int i = 1000-1; i >= 0; i--) {
bool r = btree_erase(b, i);
assert (r == true);
}
assert(btree_size(b) == 0);
btree_clear(b);
}
static void test4(void)
{
btree_t b1, b2;
btree_init(b1);
for(int i = 0; i < 1000; i++)
btree_set_at(b1, i, 1000*i);
assert(btree_size(b1) == 1000);
btree_init_set(b2, b1);
assert (btree_size(b2) == 1000);
assert (btree_equal_p(b1, b2));
for(int i = 0; i < 1000; i++) {
bool r = btree_erase(b2, i);
assert (r == true);
assert (!btree_equal_p(b1, b2));
}
assert(btree_size(b2) == 0);
for(int i = 5000; i < 10000; i++)
btree_set_at(b2, i, 1000*i);
assert(btree_size(b2) == 5000);
btree_set(b2, b1);
assert(btree_size(b2) == 1000);
assert (btree_equal_p(b1, b2));
for(int i = 0; i < 1000; i++) {
bool r = btree_erase(b2, i);
assert (r == true);
}
assert(btree_size(b2) == 0);
btree_set(b1, b2);
assert(btree_size(b1) == 0);
assert (btree_equal_p(b1, b2));
btree_clear(b1);
btree_clear(b2);
btree_init(b1);
btree_init(b2);
for(int i = -50; i < 50; i++)
btree_set_at(b1, i, 1000*i);
assert (btree_size(b1) == 100);
for(int i = -10; i < 10; i++)
btree_set_at(b2, i, 1000*i);
assert (btree_size(b2) == 20);
btree_swap(b1, b2);
assert (btree_size(b1) == 20);
assert (btree_size(b2) == 100);
btree_move(b1, b2);
btree_clear(b1);
}
static void test5(void)
{
btree_t b;
btree_init(b);
for(int i = 0; i < 1000; i+=3)
btree_set_at(b, i, 1000*i);
for(int i = 1; i < 1000; i+=3)
btree_set_at(b, i, 1000*i);
for(int i = 2; i < 1000; i+=3)
btree_set_at(b, i, 1000*i);
assert(btree_size(b) == 1000);
assert (*btree_cmin(b) == 0*1000);
assert (*btree_cmax(b) == 999*1000);
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);
assert (*item->key_ptr == i);
assert (*item->value_ptr == 1000*i);
i++;
}
assert (i == 1000);
assert (!btree_it_equal_p(it, it2));
btree_it_end(it2, b);
assert (btree_it_equal_p(it, it2));
i = 500;
for(btree_it_from(it, b, 500); !btree_it_to_p(it, 600); btree_next(it)) {
const btree_type_t *item = btree_cref(it);
assert (*item->key_ptr == i);
assert (*item->value_ptr == 1000*i);
i++;
}
assert (i == 600);
btree_erase (b, 500);
i = 501;
for(btree_it_from(it, b, 500); !btree_it_to_p(it, 600); btree_next(it)) {
const btree_type_t *item = btree_cref(it);
assert (*item->key_ptr == i);
assert (*item->value_ptr == 1000*i);
i++;
}
assert (i == 600);
btree_it_from(it, b, 1000);
assert (btree_end_p(it));
assert (btree_it_to_p(it, 1001));
btree_clear(b);
}
static void test_io(void)
{
M_LET(mpz1, mpz2, TESTOBJ_CMP_OPLIST)
M_LET(str, STRING_OPLIST)
M_LET(tree1, tree2, BPTREE_OPLIST2(btree_my, TESTOBJ_CMP_OPLIST, TESTOBJ_CMP_OPLIST)) {
btree_my_get_str(str, tree1, false);
assert(string_equal_str_p(str, "[]"));
const char *endp;
bool b = btree_my_parse_str(tree2, string_get_cstr(str), &endp);
assert(b);
assert(*endp == 0);
assert (btree_my_equal_p (tree1, tree2));
FILE *f = fopen ("a-mbptree.dat", "wt");
if (!f) abort();
btree_my_out_str(f, tree1);
fclose (f);
f = fopen ("a-mbptree.dat", "rt");
if (!f) abort();
b = btree_my_in_str (tree2, f);
assert (b == true);
assert (btree_my_equal_p (tree1, tree2));
fclose(f);
testobj_set_ui(mpz1, 67);
testobj_set_ui(mpz2, 670);
btree_my_set_at(tree1, mpz1, mpz2);
testobj_set_ui(mpz1, 17);
testobj_set_ui(mpz2, 170);
btree_my_set_at(tree1, mpz1, mpz2);
btree_my_get_str(str, tree1, false);
assert(string_equal_str_p(str, "[17:170,67:670]"));
b = btree_my_parse_str(tree2, string_get_cstr(str), &endp);
assert(b);
assert(*endp == 0);
assert (btree_my_equal_p (tree1, tree2));
f = fopen ("a-mbptree.dat", "wt");
if (!f) abort();
btree_my_out_str(f, tree1);
fclose (f);
f = fopen ("a-mbptree.dat", "rt");
if (!f) abort();
b = btree_my_in_str (tree2, f);
assert (b == true);
assert (btree_my_equal_p (tree1, tree2));
fclose(f);
}
}
static void test_io_set(void)
{
M_LET(mpz1, TESTOBJ_CMP_OPLIST)
M_LET(str, STRING_OPLIST)
M_LET(tree1, tree2, BPTREE_OPLIST(btree_myset, TESTOBJ_CMP_OPLIST)) {
btree_myset_get_str(str, tree1, false);
assert(string_equal_str_p(str, "[]"));
const char *endp;
bool b = btree_myset_parse_str(tree2, string_get_cstr(str), &endp);
assert(b);
assert(*endp == 0);
assert (btree_myset_equal_p (tree1, tree2));
FILE *f = fopen ("a-mbptree.dat", "wt");
if (!f) abort();
btree_myset_out_str(f, tree1);
fclose (f);
f = fopen ("a-mbptree.dat", "rt");
if (!f) abort();
b = btree_myset_in_str (tree2, f);
assert (b == true);
assert (btree_myset_equal_p (tree1, tree2));
fclose(f);
testobj_set_ui(mpz1, 67);
btree_myset_push(tree1, mpz1);
testobj_set_ui(mpz1, 670);
btree_myset_push(tree1, mpz1);
testobj_set_ui(mpz1, 17);
btree_myset_push(tree1, mpz1);
testobj_set_ui(mpz1, 170);
btree_myset_push(tree1, mpz1);
btree_myset_get_str(str, tree1, false);
assert(string_equal_str_p(str, "[17,67,170,670]"));
b = btree_myset_parse_str(tree2, string_get_cstr(str), &endp);
assert(b);
assert(*endp == 0);
assert (btree_myset_equal_p (tree1, tree2));
f = fopen ("a-mbptree.dat", "wt");
if (!f) abort();
btree_myset_out_str(f, tree1);
fclose (f);
f = fopen ("a-mbptree.dat", "rt");
if (!f) abort();
b = btree_myset_in_str (tree2, f);
assert (b == true);
assert (btree_myset_equal_p (tree1, tree2));
fclose(f);
}
}
int main(void)
{
test1();
test2();
test3();
test4();
test5();
test_io();
test_io_set();
exit(0);
}
+57 -11
View File
@@ -22,6 +22,7 @@
*/
#include "m-buffer.h"
#include "test-obj.h"
#include "coverage.h"
START_COVERAGE
// Define a fixed queue of unsigned int
@@ -39,10 +40,17 @@ BUFFER_DEF(buffer_char, char, 10, BUFFER_STACK|BUFFER_UNBLOCKING)
// Define a fixed queue of long long
BUFFER_DEF(buffer_llong, long long, 16, BUFFER_QUEUE|BUFFER_THREAD_UNSAFE|BUFFER_UNBLOCKING)
#include <gmp.h>
BUFFER_DEF(buffer_mpz, mpz_t, 32, BUFFER_QUEUE, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear)))
// Define a buffer of complex structure.
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)
buffer_uint_t g_buff;
buffer_uint_t g_buffB;
// Number of thread created by the test (twice this amount).
#define MAX_TEST_THREAD 100
#define MAX_TEST_THREAD2 (MAX_TEST_THREAD*2/3)
static void conso(void *arg)
{
@@ -63,16 +71,17 @@ static void prod(void *arg)
static void test_global(void)
{
m_thread_t idx_p[100];
m_thread_t idx_c[100];
m_thread_t idx_p[MAX_TEST_THREAD];
m_thread_t idx_c[MAX_TEST_THREAD];
buffer_uint_init(g_buff, 10);
assert (buffer_uint_capacity(g_buff) == 10);
for(int i = 0; i < 100; i++) {
for(int i = 0; i < MAX_TEST_THREAD; i++) {
m_thread_create (idx_p[i], conso, NULL);
m_thread_create (idx_c[i], prod, NULL);
}
for(int i = 0; i < 100;i++) {
for(int i = 0; i < MAX_TEST_THREAD;i++) {
m_thread_join(idx_p[i]);
m_thread_join(idx_c[i]);
}
@@ -109,6 +118,36 @@ static void test_global(void)
assert (buffer_uint_overwrite(g_buff) == 0);
buffer_uint_init_set(g_buffB, g_buff);
assert (buffer_uint_empty_p(g_buffB));
buffer_uint_clear(g_buffB);
for(unsigned int i = 0; i < 5;i++)
buffer_uint_push(g_buff, i);
buffer_uint_init_set(g_buffB, g_buff);
assert (!buffer_uint_empty_p(g_buffB));
assert (!buffer_uint_full_p(g_buffB));
assert (buffer_uint_size(g_buffB) == 5);
for(unsigned int i = 0; i < 5;i++) {
unsigned int j;
bool b= buffer_uint_pop(&j, g_buffB);
assert(b);
assert(j == i);
}
assert (buffer_uint_empty_p(g_buffB));
buffer_uint_set(g_buffB, g_buff);
assert (!buffer_uint_empty_p(g_buffB));
assert (!buffer_uint_full_p(g_buffB));
assert (buffer_uint_size(g_buffB) == 5);
for(unsigned int i = 0; i < 5;i++) {
unsigned int j;
bool b= buffer_uint_pop(&j, g_buffB);
assert(b);
assert(j == i);
}
assert (buffer_uint_empty_p(g_buffB));
buffer_uint_clear(g_buffB);
buffer_uint_clear(g_buff);
}
@@ -116,6 +155,7 @@ static void test_stack(void)
{
buffer_floats_t buff;
buffer_floats_init(buff, 100);
assert (buffer_floats_capacity(buff) == 100);
for(unsigned int i = 0; i < 100; i++) {
float f = i;
buffer_floats_push(buff, f);
@@ -190,6 +230,8 @@ static void test_no_thread(void)
buffer_llong_clear(buff);
}
/********************************************************************************************/
/* Test intrusive shared pointer + buffer */
#include "m-i-shared.h"
// Tiny test structure
@@ -258,19 +300,19 @@ static void test_prod(void *arg)
static void test_global_ishared(void)
{
m_thread_t idx_p[100];
m_thread_t idx_c1[100];
m_thread_t idx_c2[100];
m_thread_t idx_p[MAX_TEST_THREAD2];
m_thread_t idx_c1[MAX_TEST_THREAD2];
m_thread_t idx_c2[MAX_TEST_THREAD2];
buffer_itest_init(comm1, 16);
buffer_itest_init(comm2, 16);
for(int i = 0; i < 100; i++) {
for(int i = 0; i < MAX_TEST_THREAD2; i++) {
m_thread_create (idx_c1[i], test_conso1, NULL);
m_thread_create (idx_c2[i], test_conso2, NULL);
m_thread_create (idx_p[i], test_prod, NULL);
}
for(int i = 0; i < 100;i++) {
for(int i = 0; i < MAX_TEST_THREAD2;i++) {
m_thread_join(idx_p[i]);
m_thread_join(idx_c1[i]);
m_thread_join(idx_c2[i]);
@@ -333,6 +375,8 @@ static void test_queue(size_t n, int cpu_count, unsigned long long ref)
// Init
queue_uint_init(g_buff2, 64*2);
queue_ull_init (g_final2, 64*2);
assert (queue_uint_capacity(g_buff2) == 64*2);
assert (queue_ull_capacity(g_final2) == 64*2);
// Create thread
m_thread_t idx_p[64];
@@ -363,6 +407,8 @@ static void test_queue(size_t n, int cpu_count, unsigned long long ref)
queue_uint_clear(g_buff2);
}
/********************************************************************************************/
int main(void)
{
unsigned int x, y;
+164
View File
@@ -0,0 +1,164 @@
/*
* Copyright (c) 2017-2018, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "test-obj.h"
#include "coverage.h"
#include "m-tuple.h"
#include "m-array.h"
#include "m-dict.h"
#include "m-list.h"
#include "m-deque.h"
#include "m-bptree.h"
#include "m-rbtree.h"
#include "m-concurrent.h"
TUPLE_DEF2(point, (x, int), (y, int))
#define M_OPL_point_t() TUPLE_OPLIST(point, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
CONCURRENT_DEF(ppoint, point_t)
ARRAY_DEF(array1, int)
CONCURRENT_DEF(parray1, array1_t, ARRAY_OPLIST(array1))
DICT_DEF2(dict1, int, int)
CONCURRENT_DEF(pdict1, dict1_t, DICT_OPLIST(dict1))
DICT_SET_DEF(dict2, int)
CONCURRENT_DEF(pdict2, dict2_t, DICT_SET_OPLIST(dict2))
LIST_DEF(list1, int)
CONCURRENT_DEF(plist1, list1_t, LIST_OPLIST(list1))
LIST_DUAL_PUSH_DEF(list2, int)
CONCURRENT_DEF(plist2, list2_t, LIST_OPLIST(list2))
DEQUE_DEF(deque1, int)
CONCURRENT_DEF(pdeque1, deque1_t, DEQUE_OPLIST(deque1))
BPTREE_DEF2(bptree1, 10, int, int)
CONCURRENT_DEF(pbtree1, bptree1_t, BPTREE_OPLIST2(bptree1, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
BPTREE_DEF(bptree2, 10, int)
CONCURRENT_DEF(pbtree2, bptree2_t, BPTREE_OPLIST(bptree2))
RBTREE_DEF(rbtree1, int)
CONCURRENT_DEF(prbtree1, rbtree1_t, RBTREE_OPLIST(rbtree1))
DICT_DEF2(string_pool, string_t, string_t)
#define STRING_POOL_OPLIST \
DICT_OPLIST(string_pool, STRING_OPLIST, STRING_OPLIST)
#define M_OPL_string_pool_t() STRING_POOL_OPLIST
CONCURRENT_DEF(string_pool_ts, string_pool_t, STRING_POOL_OPLIST)
#define STRING_POOL_TS_OPLIST \
CONCURRENT_OPLIST(string_pool_ts, STRING_POOL_OPLIST)
#define M_OPL_string_pool_ts_t() STRING_POOL_TS_OPLIST
TUPLE_DEF2(my_tuple, (pool, string_pool_ts_t))
#define MY_TUPLE_OPLIST TUPLE_OPLIST(my_tuple, STRING_POOL_TS_OPLIST)
#define M_OPL_my_tuple_t() MY_TUPLE_OPLIST
ARRAY_DEF(key_list, string_t)
#define M_OPL_key_list_t() ARRAY_OPLIST(key_list, STRING_OPLIST)
CONCURRENT_DEF(key_list_ts, key_list_t)
CONCURRENT_RP_DEF(rpdict1, dict1_t, DICT_OPLIST(dict1))
/********************************/
parray1_t arr;
static void conso(void *p)
{
assert (p == NULL);
for(int i = 0; i < 1000; i++) {
int j;
bool b = parray1_pop_blocking(&j, arr, true);
assert (b);
assert (j == i);
}
}
static void test(void)
{
m_thread_t idx;
parray1_init(arr);
m_thread_create (idx, conso, NULL);
m_thread_sleep(1000);
for(int i = 0; i < 1000; i++) {
parray1_push (arr, i);
while (!parray1_empty_p(arr));
}
m_thread_join(idx);
parray1_clear(arr);
}
static void test_basic(void)
{
pdict1_t dict;
pdict1_init(dict);
int z;
pdict1_set_at(dict, 2, 3);
pdict1_get_copy(&z, dict, 2);
assert (z == 3);
z = 1;
bool b = pdict1_get_blocking(&z, dict, 2, false);
assert (b);
assert (z == 3);
assert (pdict1_size(dict) == 1);
pdict1_clear(dict);
M_LET(str, string_t)
M_LET(pool, string_pool_ts_t) {
string_pool_ts_set_at (pool, STRING_CTE("A"), STRING_CTE("B"));
b = string_pool_ts_get_copy (&str, pool, STRING_CTE("A"));
assert (b);
assert (string_equal_str_p (str, "B"));
}
M_LET(tuple, my_tuple_t) {
assert (string_pool_ts_empty_p(tuple->pool));
}
}
static void test_rp_basic(void)
{
rpdict1_t dict;
rpdict1_init(dict);
int z;
rpdict1_set_at(dict, 2, 3);
rpdict1_get_copy(&z, dict, 2);
assert (z == 3);
z = 1;
bool b = rpdict1_get_blocking(&z, dict, 2, false);
assert (b);
assert (z == 3);
assert (rpdict1_size(dict) == 1);
rpdict1_clear(dict);
}
int main(void)
{
test_basic();
test_rp_basic();
test();
exit(0);
}
+99 -3
View File
@@ -23,7 +23,7 @@
#include <stdbool.h>
#include <assert.h>
#include "mympz.h"
#include "test-obj.h"
#include "m-core.h"
@@ -120,6 +120,9 @@ static void test_return(void)
assert (M_RET_ARG2(0, 1, 0));
assert (M_RET_ARG3(0, 0, 1, 0));
assert (M_RET_ARG27(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0));
assert (M_GET_AT((0,1,0),1));
assert (M_GET_AT((1,0,0),0));
assert (M_GET_AT((0,0,0,1),3));
}
static void test_invert(void)
@@ -145,22 +148,50 @@ static void test_empty(void)
assert (M_EMPTY_P(,) == false);
assert (M_EMPTY_P(()) == false);
assert (M_EMPTY_P("123") == false);
assert (M_EMPTY_P(,1,2,3) == false);
}
#define f(n) (n)*(n) +
#define f2(d,n) (d)*(n) +
#define f3(d,i,n) (d)*(i)*(n) +
static void test_map(void)
{
assert (M_MAP (f, 1) 0 == 1);
assert (M_MAP (f, 1, 2) 0 == 5);
assert (M_MAP (f, 1, 2, 3) 0 == 14);
assert (M_MAP2 (f2, 2, 1) 0 == 2);
assert (M_MAP2 (f2, 3, 1, 2) 0 == 9);
assert (M_MAP2 (f2, 4, 1, 2, 3) 0 == 24);
assert (M_MAP3 (f3, 2, 2) 0 == 4);
assert (M_MAP3 (f3, 3, 2, 4) 0 == 30);
assert (M_MAP3 (f3, 4, 2, 4, 6) 0 == 8+32+12*6);
}
static void test_let(void)
{
M_LET(z, M_CLASSIC_OPLIST(my_mpz)) {
my_mpz_add(z,z,z);
bool b = false;
M_LET(z, M_CLASSIC_OPLIST(testobj)) {
testobj_set_ui(z, 12);
M_LET((zz,z), M_CLASSIC_OPLIST(testobj)) {
assert( testobj_cmp_ui(zz, 12) == 0);
}
M_LET((zz,42), M_OPEXTEND(M_CLASSIC_OPLIST(testobj), INIT_WITH(testobj_init_set_ui))) {
assert( testobj_cmp_ui(zz, 42) == 0);
}
M_LET((zz,z), z2, M_CLASSIC_OPLIST(testobj)) {
assert( testobj_cmp_ui(zz, 12) == 0);
}
M_LET(z3, (zz,42), M_OPEXTEND(M_CLASSIC_OPLIST(testobj), INIT_WITH(testobj_init_set_ui))) {
assert( testobj_cmp_ui(zz, 42) == 0);
}
b = true;
break;
assert(0);
}
assert(b);
}
static void test_va(void)
@@ -251,6 +282,16 @@ static void test_oplist(void)
#define M_OPL_op() (INIT(1), CLEAR(0))
assert(M_GET_INIT M_GLOBAL_OPLIST(op));
assert(!M_GET_INIT M_GLOBAL_OPLIST(a));
#define MAKE_OPLIST(op) (OPLIST(M_GLOBAL_OPLIST_OR_DEF(op)()))
#define M_OPL_uint() (INIT(0), CLEAR(1))
#define M_OPL_array_uint() (OPLIST(M_GLOBAL_OPLIST_OR_DEF(uint)()))
#define M_OPL_list_array_uint() MAKE_OPLIST(array_uint)
#define A1 A2(M_OPL_list_array_uint())
#define A2(op) A3(M_GET_OPLIST op)
#define A3(op) A4(M_GET_OPLIST op)
#define A4(op) M_GET_CLEAR op
assert (A1);
}
static void test_cast(void)
@@ -276,6 +317,60 @@ static void test_reduce(void)
== M_REDUCE(M_ID, add, M_SEQ(1, 10)));
}
static void test_parse_standard_c_type(void)
{
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
char c = 0;
M_PARSE_DEFAULT_TYPE(&c, "C", NULL);
assert (c == 'C');
short s = 0;
M_PARSE_DEFAULT_TYPE(&s, "-2", NULL);
assert (s == -2);
int i = 0;
M_PARSE_DEFAULT_TYPE(&i, "2", NULL);
assert (i == 2);
long l = 0;
M_PARSE_DEFAULT_TYPE(&l, "1742", NULL);
assert (l == 1742);
long long ll = 0;
M_PARSE_DEFAULT_TYPE(&ll, "-1742548676843540", NULL);
assert (ll == -1742548676843540LL);
unsigned short us = 0;
M_PARSE_DEFAULT_TYPE(&us, "3", NULL);
assert (us == 3);
unsigned int ui = 0;
M_PARSE_DEFAULT_TYPE(&ui, "2", NULL);
assert (ui == 2);
unsigned long ul = 0;
M_PARSE_DEFAULT_TYPE(&ul, "1742", NULL);
assert (ul == 1742);
unsigned long long ull = 0;
M_PARSE_DEFAULT_TYPE(&ull, "1742548676843540", NULL);
assert (ull == 1742548676843540ULL);
float f;
M_PARSE_DEFAULT_TYPE(&f, "-0.5", NULL);
assert (f == -0.5);
double d;
M_PARSE_DEFAULT_TYPE(&d, "2.5", NULL);
assert (d == 2.5);
long double ld;
M_PARSE_DEFAULT_TYPE(&ld, "2.5", NULL);
assert (ld == 2.5);
#endif
}
int main(void)
{
test_cat();
@@ -293,5 +388,6 @@ int main(void)
test_oplist();
test_cast();
test_reduce();
test_parse_standard_c_type();
exit(0);
}
+123 -4
View File
@@ -21,7 +21,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "mympz.h"
#include "test-obj.h"
#include "m-string.h"
#include "m-deque.h"
@@ -31,7 +31,10 @@
START_COVERAGE
DEQUE_DEF(deque, int)
END_COVERAGE
DEQUE_DEF(deque_mpz, my_mpz_t, MYMPZ_OPLIST)
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)))
#define OPL DEQUE_OPLIST(deque)
@@ -40,7 +43,8 @@ static void test_ti1(int n)
deque_t d;
deque_init(d);
assert(deque_capacity(d) == DEQUEUI_DEFAULT_SIZE);
for(int i =0; i < n ;i++) {
deque_push_back(d, i);
assert(*deque_back(d) == i);
@@ -70,6 +74,7 @@ static void test_ti1(int n)
static void test1(void)
{
deque_t d;
int j;
deque_init(d);
assert (deque_empty_p(d));
@@ -98,12 +103,24 @@ 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);
for(int i = 0; i < 50; i++) {
for(int i = 0; i < 98; i++) {
deque_pop_back(NULL, d);
assert (*deque_back(d) == i - 98);
deque_pop_front(NULL, d);
assert (*deque_front(d) == 98 - i);
}
deque_pop_back(&j, d);
assert (j == -1);
deque_pop_front(&j, d);
assert (j == 1);
assert (deque_empty_p(d));
assert (deque_size(d) == 0);
deque_push_back(d, 1914);
deque_push_front(d, 1918);
assert (*deque_get(d, 0) == 1918);
assert (*deque_get(d, 1) == 1914);
deque_clear(d);
}
@@ -199,6 +216,16 @@ static void test_set(void)
assert (*deque_back(e) == 3000);
deque_clear(d);
deque_init_move (d, e);
assert (*deque_back(d) == 3000);
assert (*deque_front(d) == 2000);
assert (deque_size (d) == 1997);
deque_push_back(d, 10000);
deque_push_front(d, -10000);
assert (deque_size (d) == 1999);
for(size_t i = 0; i < 1999; i ++)
deque_pop_back(NULL, d);
for(size_t i = 0; i < 3001; i ++)
deque_push_back(d, i);
deque_init (e);
deque_move (e, d);
deque_init (d);
@@ -223,6 +250,96 @@ static void test_advance(void)
deque_clear(d);
}
static void test_z(void)
{
M_LET(d, DEQUE_OPLIST(deque_mpz, TESTOBJ_OPLIST))
M_LET(z, TESTOBJ_OPLIST) {
testobj_set_ui(z, 1742);
deque_mpz_push_back_move(d, &z);
assert (testobj_cmp_ui (*deque_mpz_back(d), 1742) == 0);
testobj_init(z);
testobj_set_ui(z, 4217);
deque_mpz_push_front_move(d, &z);
assert (testobj_cmp_ui (*deque_mpz_front(d), 4217) == 0);
deque_mpz_pop_back_move(&z, d);
assert (testobj_cmp_ui (z, 1742) == 0);
testobj_clear(z);
deque_mpz_pop_front_move(&z, d);
assert (testobj_cmp_ui (z, 4217) == 0);
}
}
static void test_io(void)
{
M_LET(d1, d2, DEQUE_OPLIST(deque_mpz, TESTOBJ_OPLIST))
M_LET(z, TESTOBJ_OPLIST)
M_LET(str, STRING_OPLIST) {
// Test empty
FILE *f = fopen ("a-marray.dat", "wt");
if (!f) abort();
deque_mpz_out_str(f, d1);
fclose (f);
f = fopen ("a-marray.dat", "rt");
if (!f) abort();
bool b = deque_mpz_in_str (d2, f);
assert (b == true);
assert (deque_mpz_equal_p (d1, d2));
fclose(f);
// Test non empty
for(int n = 0; n < 1000; n++) {
testobj_set_ui (z, n);
deque_mpz_push_back (d1, z);
}
f = fopen ("a-marray.dat", "wt");
if (!f) abort();
deque_mpz_out_str(f, d1);
fclose (f);
f = fopen ("a-marray.dat", "rt");
if (!f) abort();
b = deque_mpz_in_str (d2, f);
assert (b == true);
assert (deque_mpz_equal_p (d1, d2));
fclose(f);
deque_mpz_clean(d1);
deque_mpz_get_str(str, d1, false);
assert (string_cmp_str (str, "[]") == 0);
const char *sp;
b = deque_mpz_parse_str(d2, string_get_cstr(str), &sp);
assert(b);
assert(*sp == 0);
assert(deque_mpz_equal_p(d1, d2));
testobj_set_ui (z, 17);
deque_mpz_push_back (d1, z);
deque_mpz_get_str(str, d1, false);
assert (string_cmp_str (str, "[17]") == 0);
b = deque_mpz_parse_str(d2, string_get_cstr(str), &sp);
assert(b);
assert(*sp == 0);
assert(deque_mpz_equal_p(d1, d2));
testobj_set_ui (z, 42);
deque_mpz_push_back (d1, z);
deque_mpz_get_str(str, d1, true);
assert (string_cmp_str (str, "[17][17,42]") == 0);
b = deque_mpz_parse_str(d2, string_get_cstr(str), &sp);
assert(b);
assert(strcmp(sp, "[17,42]") == 0);
assert(!deque_mpz_equal_p(d1, d2));
b = deque_mpz_parse_str(d2, sp, &sp);
assert(b);
assert(strcmp(sp, "") == 0);
assert(deque_mpz_equal_p(d1, d2));
}
}
int main(void)
{
test1();
@@ -232,6 +349,8 @@ int main(void)
test_ti1(10000);
test_it();
test_set();
test_io();
test_z();
test_advance();
exit(0);
}
+91 -32
View File
@@ -20,30 +20,26 @@
* (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 <limits.h>
#include <time.h>
#include <stdint.h>
#include <assert.h>
#include "m-dict.h"
#include "m-array.h"
#include "m-string.h"
#include "test-obj.h"
static inline bool oor_equal_p(int k, unsigned char n)
{
return k == (int)-n-1;
}
static inline void oor_set(int *k, unsigned char n)
{
*k = (int)-n-1;
}
static inline bool oor_equal_p(int k, unsigned char n) { return k == (int)-n-1; }
static inline void oor_set(int *k, unsigned char n) { *k = (int)-n-1; }
static inline void update_value (int *p, const int val) { *p += val; }
#include "coverage.h"
START_COVERAGE
DICT_DEF2(dict_str, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
DICT_OA_DEF2(dict_oa_int, int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)), int, M_DEFAULT_OPLIST)
DICT_OA_DEF2(dict_oa_int, int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)), int, M_OPEXTEND(M_DEFAULT_OPLIST, UPDATE(update_value M_IPTR)))
END_COVERAGE
DICT_STOREHASH_DEF2(dict_str2, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
DICT_SET_DEF2(dict_setstr, string_t, STRING_OPLIST)
DICT_SET_DEF(dict_setstr, string_t, STRING_OPLIST)
DICT_DEF2(dict_int, int, M_DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
DICT_DEF2(dict_mpz, string_t, STRING_OPLIST, testobj_t, TESTOBJ_OPLIST)
/* Helper structure */
ARRAY_DEF(array_string, string_t, STRING_OPLIST)
@@ -73,10 +69,12 @@ static void test_data(void)
{
dict_str_t dict;
int data_size = (int) array_string_size(v_str);
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));
assert(!dict_str_empty_p(dict));
}
assert(dict_str_size(dict) == 1227176);
@@ -93,9 +91,15 @@ static void test_data(void)
static void check_io(void)
{
M_LET(str, STRING_OPLIST)
M_LET(dict, DICT_OPLIST(dict_str)) {
M_LET(dict, dict2, DICT_OPLIST(dict_str)) {
dict_str_get_str(str, dict, false);
assert (string_cmp_str (str, "{}") == 0);
const char *sp;
bool b = dict_str_parse_str(dict2, string_get_cstr(str), &sp);
assert (b);
assert (*sp == 0);
assert (dict_str_equal_p(dict, dict2));
dict_str_set_at (dict, STRING_CTE("LICENCE"), STRING_CTE("BSD3"));
dict_str_get_str(str, dict, false);
assert (string_cmp_str (str, "{\"LICENCE\":\"BSD3\"}") == 0);
@@ -103,17 +107,20 @@ static void check_io(void)
dict_str_get_str(str, dict, false);
//NOTE: order is dependent on the hash system.
assert (string_cmp_str (str, "{\"LICENCE\":\"BSD3\",\"AUTHOR\":\"PP\"}") == 0 || string_cmp_str (str, "{\"AUTHOR\":\"PP\",\"LICENCE\":\"BSD3\"}") == 0);
b = dict_str_parse_str(dict2, string_get_cstr(str), &sp);
assert (b);
assert (*sp == 0);
assert (dict_str_equal_p(dict, dict2));
FILE *f = fopen ("a-mdict.dat", "wt");
if (!f) abort();
dict_str_out_str(f, dict);
fclose (f);
f = fopen ("a-mdict.dat", "rt");
if (!f) abort();
M_LET(dict2, DICT_OPLIST(dict_str)) {
bool b = dict_str_in_str(dict2, f);
assert (b == true);
assert (dict_str_equal_p (dict, dict2));
}
b = dict_str_in_str(dict2, f);
assert (b == true);
assert (dict_str_equal_p (dict, dict2));
fclose (f);
}
}
@@ -124,13 +131,19 @@ static void test_set(void)
M_LET(set, DICT_SET_OPLIST(dict_setstr, STRING_OPLIST)) {
for(int i = 0; i < 100; i++) {
string_printf(str, "%d", i);
dict_setstr_set_at(set, str);
dict_setstr_push(set, str);
}
assert(dict_setstr_size(set) == 100);
for(int i = 0; i < 100; i++) {
string_printf(str, "%d", i);
string_t *p = dict_setstr_get(set, str);
assert (p != NULL);
assert(string_equal_p (*p, str));
p = dict_setstr_get_at(set, str);
assert (p != NULL);
assert(string_equal_p (*p, str));
}
assert(dict_setstr_size(set) == 100);
}
}
@@ -144,6 +157,18 @@ static void test_init(void)
dict_str_set_at (d1, str1, str2);
}
assert (dict_str_size (d1) == 100);
for(size_t 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);
assert (p != NULL);
assert (string_equal_p(*p, str2));
p = dict_str_get_at (d1, str1);
assert (p != NULL);
assert (string_equal_p(*p, str2));
}
dict_str_t d3;
dict_str_init_set (d3, d1);
assert (dict_str_equal_p (d3, d1));
@@ -155,14 +180,14 @@ static void test_init(void)
dict_str_set_at (d1, STRING_CTE("x"), STRING_CTE("y"));
assert (dict_str_size (d1) == 101);
assert (!dict_str_equal_p (d2, d1));
bool b = dict_str_remove (d1, STRING_CTE("0"));
bool b = dict_str_erase (d1, STRING_CTE("0"));
assert (dict_str_size (d1) == 100);
assert (b);
assert (!dict_str_equal_p (d2, d1));
for(size_t i = 1; i < 100; i++) {
string_printf(str1, "%d", 2*i);
b = dict_str_remove (d1, str1);
b = dict_str_erase (d1, str1);
assert (b);
}
assert (dict_str_size (d1) == 1);
@@ -186,6 +211,23 @@ static void test_init(void)
dict_str_clean (d2);
assert (dict_str_size (d2) == 0);
assert (dict_str_size (d1) == 100);
for(size_t 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++) {
string_printf(str1, "%d", 2*i);
string_printf(str2, "%d", 2*i+1);
string_t *p = dict_str_get (d1, str1);
assert (p != NULL);
assert (string_equal_p(*p, str2));
p = dict_str_get_at (d1, str1);
assert (p != NULL);
assert (string_equal_p(*p, str2));
}
//assert (dict_str_hash (d2) != 0);
}
}
@@ -204,7 +246,7 @@ static void test_equal(void)
string_printf(str1, "%d", i);
dict_str_set_at(d2, str1, str1);
string_printf(str1, "%d", n-1-i);
dict_str_remove(d1, str1);
dict_str_erase(d1, str1);
assert(dict_str_equal_p(d1, d2) == ((i+1) == (n+1)/2));
assert(dict_str_equal_p(d2, d1) == ((i+1) == (n+1)/2));
}
@@ -224,6 +266,8 @@ static void test1(void)
FILE *f = 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")));
while (!feof(f) && !ferror(f)) {
string_fgets(key, f, STRING_READ_PURE_LINE);
size_t idx = string_search_char(key, ':');
@@ -294,6 +338,21 @@ static void test_oa(void)
assert (p == NULL);
}
}
assert(dict_oa_int_size(d) == 50);
for(size_t 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++) {
int *p = dict_oa_int_get(d, i);
if ((i % 3) != 2) {
assert (p != NULL);
assert (*p == M_ASSIGN_CAST(int, i*i));
} else {
assert (p == NULL);
}
}
assert(dict_oa_int_size(d) == 100);
dict_oa_int_clear(d);
}
@@ -306,16 +365,16 @@ static void test_init_oa(void)
}
assert (dict_oa_int_size (d1) == 100);
dict_oa_int_set_at (d1, 17, 42);
dict_oa_int_remove (d1, 17);
dict_oa_int_erase (d1, 17);
dict_oa_int_t d3;
dict_oa_int_init_set (d3, d1);
//assert (dict_oa_int_equal_p (d3, d1));
assert (dict_oa_int_equal_p (d3, d1));
dict_oa_int_set (d2, d1);
assert (dict_oa_int_get (d2, -10) == NULL);
assert (*dict_oa_int_get (d2, 10) == 11);
//assert (dict_oa_int_equal_p (d2, d1));
//assert (dict_oa_int_equal_p (d2, d3));
assert (dict_oa_int_equal_p (d2, d1));
assert (dict_oa_int_equal_p (d2, d3));
dict_oa_int_clear (d3);
dict_oa_int_set_at (d1, -10, -20);
@@ -325,14 +384,14 @@ static void test_init_oa(void)
assert (dict_oa_int_size (d1) == 101);
assert (*dict_oa_int_get (d1, -10) == -22);
//assert (!dict_oa_int_equal_p (d2, d1));
bool b = dict_oa_int_remove (d1, 0);
assert (!dict_oa_int_equal_p (d2, d1));
bool b = dict_oa_int_erase (d1, 0);
assert (dict_oa_int_size (d1) == 100);
assert (b);
//assert (!dict_oa_int_equal_p (d2, d1));
assert (!dict_oa_int_equal_p (d2, d1));
for(size_t i = 1; i < 100; i++) {
b = dict_oa_int_remove (d1, 2*i);
b = dict_oa_int_erase (d1, 2*i);
assert (b);
}
assert (dict_oa_int_size (d1) == 1);
+4 -4
View File
@@ -40,8 +40,8 @@ static void test(size_t n)
assert (i == j);
}
i = genint_pop(s);
assert (i == -1UL);
assert (genint_pop(s) == -1UL);
assert (i == GENINT_ERROR);
assert (genint_pop(s) == GENINT_ERROR);
for(size_t j = 0; j< n ; j++) {
genint_push(s, (j+k) % n );
@@ -63,14 +63,14 @@ static void conso(void *p)
unsigned int tab[4];
for(int j= 0; j < 4; j++) {
tab[j] = genint_pop(global);
if (tab[j] != -1U) {
if (tab[j] != GENINT_ERROR) {
assert (tab[j] < n);
assert (atomic_load(&tab_g[tab[j]]) == false);
atomic_store(&tab_g[tab[j]], true);
}
}
for(int j = 0; j < 4; j++) {
if (tab[j] != -1U) {
if (tab[j] != GENINT_ERROR) {
assert (tab[j] < n);
assert (atomic_load(&tab_g[tab[j]]) == true);
atomic_store(&tab_g[tab[j]], false);
+108 -3
View File
@@ -32,9 +32,10 @@ typedef struct test_s {
ILIST_INTERFACE (ilist_free, struct test_s);
} test_t;
#include "coverage.h"
START_COVERAGE
ILIST_DEF(ilist_tname, test_t)
ILIST_DEF(ilist_tname, test_t, M_POD_OPLIST)
END_COVERAGE
ILIST_DEF(ilist_free, test_t, (DEL(free)))
@@ -47,7 +48,10 @@ static void test(void)
x1.n = 1;
x2.n = 2;
x3.n = 3;
ilist_tname_init_field(&x1);
ilist_tname_init_field(&x2);
ilist_tname_init_field(&x3);
ilist_tname_init(list);
assert (ilist_tname_size (list) == 0);
@@ -59,7 +63,9 @@ static void test(void)
assert (ilist_tname_size (list) == 3);
assert (ilist_tname_front (list)->n == 1);
assert (ilist_tname_back (list)->n == 3);
assert (ilist_tname_next_obj(list, &x1) == &x2);
assert (ilist_tname_previous_obj(list, &x2) == &x1);
int n = 1;
for M_EACH(item, list, ILIST_OPLIST(ilist_tname)) {
assert (n == item->n);
@@ -83,6 +89,13 @@ static void test(void)
ilist_tname_it_set(it2, it1);
assert (ilist_tname_it_equal_p(it1, it2));
ilist_tname_t list2;
ilist_tname_init(list2);
ilist_tname_move(list2, list);
assert (ilist_tname_size (list2) == 3);
ilist_tname_init_move(list, list2);
assert (ilist_tname_size (list) == 3);
for M_EACH(item, list, ILIST_OPLIST(ilist_tname)) {
if (item->n == 2)
ilist_tname_unlink(item);
@@ -108,9 +121,100 @@ static void test(void)
assert (ilist_tname_front (list)->n == 1);
assert (ilist_tname_back (list)->n == 3);
ilist_tname_it(it1, list);
ilist_tname_next(it1);
ilist_tname_remove(list, it1);
assert (ilist_tname_size (list) == 2);
assert (ilist_tname_cref(it1) == &x3);
assert (ilist_tname_previous_obj(list, &x3) == &x1);
ilist_tname_clear(list);
}
#define NUM 10
static void test2(void)
{
test_t x[NUM];
M_LET(list1, list2, ILIST_OPLIST(ilist_tname)) {
for(int i = 0; i < NUM; i++)
x[i].n = i;
for(int i = 0; i < NUM; i++) {
ilist_tname_push_back(list1, &x[i]);
}
assert (ilist_tname_size(list1) == NUM);
assert (ilist_tname_size(list2) == 0);
assert (ilist_tname_equal_p(list1, list2) == false);
ilist_tname_it_t it;
ilist_tname_it (it, list1);
for(int i = 0; i < NUM; i++) {
assert (ilist_tname_cref(it)->n == i);
ilist_tname_splice_back (list2, list1, it);
}
assert (ilist_tname_size(list1) == 0);
assert (ilist_tname_size(list2) == NUM);
assert (ilist_tname_equal_p(list1, list2) == false);
int n = 0;
for M_EACH(item, list2, ILIST_OPLIST(ilist_tname)) {
assert (n == item->n);
n++;
}
assert (n == NUM);
ilist_tname_it_t it2;
ilist_tname_it_end (it, list1);
ilist_tname_it (it2, list2);
for(int i = 0; i < NUM; i++) {
assert (ilist_tname_cref(it2)->n == i);
ilist_tname_splice_at (list1, it, list2, it2);
assert (ilist_tname_cref(it)->n == i);
}
assert (ilist_tname_size(list1) == NUM);
assert (ilist_tname_size(list2) == 0);
n = 0;
for M_EACH(item, list1, ILIST_OPLIST(ilist_tname)) {
assert (n == item->n);
n++;
}
assert (n == NUM);
ilist_tname_reverse(list1);
for M_EACH(item, list1, ILIST_OPLIST(ilist_tname)) {
n--;
assert (n == item->n);
}
assert (n == 0);
}
M_LET(list1, list2, ILIST_OPLIST(ilist_tname)) {
for(int i = 0; i < NUM; i++)
x[i].n = i;
for(int i = 0; i < NUM/2; i++) {
ilist_tname_push_back(list1, &x[i]);
}
for(int i = NUM/2; i < NUM; i++) {
ilist_tname_push_back(list2, &x[i]);
}
ilist_tname_splice(list1, list2);
assert (ilist_tname_size(list1) == NUM);
assert (ilist_tname_size(list2) == 0);
int n = 0;
for M_EACH(item, list1, ILIST_OPLIST(ilist_tname)) {
assert (n == item->n);
n++;
}
assert (n == NUM);
ilist_tname_swap(list1, list2);
assert (ilist_tname_size(list2) == NUM);
assert (ilist_tname_size(list1) == 0);
n = 0;
for M_EACH(item, list2, ILIST_OPLIST(ilist_tname)) {
assert (n == item->n);
n++;
}
assert (n == NUM);
}
}
static void test_free(void)
{
ilist_free_t list;
@@ -138,6 +242,7 @@ static void test_free(void)
int main(void)
{
test();
test2();
test_free();
exit(0);
}
+132 -20
View File
@@ -21,18 +21,24 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "mympz.h"
#include "test-obj.h"
#include "m-string.h"
#include "m-list.h"
#include "coverage.h"
START_COVERAGE
LIST_DEF(list_uint, unsigned int)
LIST_DEF(list_mpz, my_mpz_t, MYMPZ_OPLIST)
LIST_DEF(list_mpz, testobj_t, TESTOBJ_OPLIST)
LIST_DUAL_PUSH_DEF(list2_double, double)
END_COVERAGE
LIST_DUAL_PUSH_DEF(list2_mpz, my_mpz_t, MYMPZ_OPLIST)
LIST_DUAL_PUSH_DEF(list2_mpz, testobj_t, TESTOBJ_OPLIST)
#define LIST_UINT_OPLIST LIST_OPLIST(list_uint)
#define LIST2_DOUBLE_OPLIST LIST_OPLIST(list2_double)
// Array with the minimum number of methods.
LIST_DEF(list_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear)))
LIST_DUAL_PUSH_DEF(list2_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear)))
static void test_uint(void)
{
@@ -180,7 +186,33 @@ static void test_uint(void)
assert (!list_uint_equal_p(v,v2));
assert (list_uint_hash(v) != 0);
x = 1478963;
s = *list_uint_back(v);
list_uint_push_move(v, &x);
assert (*list_uint_back(v) == 1478963);
x = 0;
list_uint_pop_move(&x, v);
assert (x == 1478963);
assert (s == *list_uint_back(v));
list_uint_clean(v);
list_uint_clean(v2);
for(unsigned int i = 0; i < 10; i++)
list_uint_push_back (v, i);
list_uint_it (u, v);
list_uint_it_end (u2, v2);
for(unsigned int i = 0; i < 10; i++) {
list_uint_splice_at (v2, u2, v, u);
}
assert (list_uint_empty_p(v));
assert (list_uint_size (v2) == 10);
s = 9;
for M_EACH(item, v2, LIST_UINT_OPLIST) {
assert (*item == s);
s --;
}
list_uint_clear(v);
list_uint_clear(v2);
}
@@ -188,36 +220,36 @@ static void test_uint(void)
static void test_mpz(void)
{
list_mpz_t v;
my_mpz_t z, x, s;
testobj_t z, x, s;
my_mpz_init (z);
my_mpz_init (x);
my_mpz_init (s);
testobj_init (z);
testobj_init (x);
testobj_init (s);
list_mpz_init(v);
assert (list_mpz_empty_p(v) == true);
my_mpz_set_ui (z, 2);
testobj_set_ui (z, 2);
list_mpz_push_back(v, z);
assert (list_mpz_empty_p(v) == false);
list_mpz_pop_back(&x, v);
assert( my_mpz_equal_p (x, z));
assert( testobj_equal_p (x, z));
assert (list_mpz_empty_p(v) == true);
assert (list_mpz_size(v) == 0);
for(unsigned int i = 0; i < 1000; i ++) {
my_mpz_set_ui (z, i);
testobj_set_ui (z, i);
list_mpz_push_back(v, z);
}
assert (list_mpz_size(v) == 1000);
list_mpz_it_t u;
my_mpz_set_ui (s, 0);
testobj_set_ui (s, 0);
for(list_mpz_it(u, v); !list_mpz_end_p(u); list_mpz_next(u)) {
my_mpz_add (s, s, *list_mpz_cref(u));
testobj_add (s, s, *list_mpz_cref(u));
}
assert (my_mpz_get_ui(s) == 1000*999/2);
assert (testobj_get_ui(s) == 1000*999/2);
FILE *f = fopen ("a-mlist.dat", "wt");
if (!f) abort();
@@ -234,24 +266,45 @@ static void test_mpz(void)
list_mpz_clear(list2);
list_mpz_clean(v);
list_mpz_init(list2);
M_LET(str, STRING_OPLIST) {
list_mpz_get_str(str, v, false);
assert (string_cmp_str (str, "[]") == 0);
my_mpz_set_ui (z, 17);
const char *sp;
b = list_mpz_parse_str(list2, string_get_cstr(str), &sp);
assert(b);
assert(*sp == 0);
assert(list_mpz_equal_p(v, list2));
testobj_set_ui (z, 17);
list_mpz_push_back (v, z);
list_mpz_get_str(str, v, false);
assert (string_cmp_str (str, "[17]") == 0);
my_mpz_set_ui (z, 42);
b = list_mpz_parse_str(list2, string_get_cstr(str), &sp);
assert(b);
assert(*sp == 0);
assert(list_mpz_equal_p(v, list2));
testobj_set_ui (z, 42);
list_mpz_push_back (v, z);
list_mpz_get_str(str, v, true);
assert (string_cmp_str (str, "[17][42,17]") == 0);
b = list_mpz_parse_str(list2, string_get_cstr(str), &sp);
assert(b);
assert(strcmp(sp, "[42,17]") == 0);
assert(!list_mpz_equal_p(v, list2));
b = list_mpz_parse_str(list2, sp, &sp);
assert(b);
assert(strcmp(sp, "") == 0);
assert(list_mpz_equal_p(v, list2));
}
list_mpz_clear(v);
my_mpz_clear (z);
my_mpz_clear (x);
my_mpz_clear (s);
list_mpz_clear(list2);
testobj_clear (z);
testobj_clear (x);
testobj_clear (s);
}
static void test_dual_push1(void)
@@ -520,16 +573,75 @@ static void test_dual_it1(void)
list2_double_next(it2);
assert(*list2_double_cref(it2) == 1.0);
list2_double_clean(list);
list2_double_clean(list2);
for(double i = 0; i < 10; i++)
list2_double_push_back (list, i);
list2_double_it (it, list);
list2_double_it_end (it2, list2);
for(double i = 0; i < 10; i++) {
list2_double_splice_at (list2, it2, list, it);
}
assert (list2_double_empty_p(list));
assert (list2_double_size (list2) == 10);
double s = 9.0;
for M_EACH(item, list2, LIST2_DOUBLE_OPLIST) {
assert (*item == s);
s -= 1.0;
}
list2_double_clear(list2);
list2_double_clear(list);
}
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
LIST_DEF(list_int, uint32_t)
#define M_OPL_list_int_t() LIST_OPLIST(list_int)
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");
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");
if (!f) abort();
char buffer[1024];
assert (fgets(buffer, 1024, f) == buffer);
assert (strcmp(buffer, "[3,2]") == 0);
fclose(f);
list_int_get_str(str, list, false);
assert (string_equal_str_p(str, "[3,2]"));
f = fopen("a-mlist.dat", "rt");
if (!f) abort();
assert (list_int_in_str(l2, f) == true);
assert (list_int_equal_p(l2, list));
fclose(f);
}
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]"));
}
}
#else
static void test_out_default_oplist(void)
{
}
#endif
int main(void)
{
test_uint();
test_mpz();
test_dual_push1();
test_dual_it1();
test_out_default_oplist();
exit(0);
}
+7 -1
View File
@@ -22,12 +22,14 @@
*/
#include <stdio.h>
#include <assert.h>
#include "test-obj.h"
#include "m-prioqueue.h"
#include "coverage.h"
START_COVERAGE
PRIOQUEUE_DEF(int_pqueue, int)
END_COVERAGE
PRIOQUEUE_DEF(mpz_pqueue, testobj_t, TESTOBJ_CMP_OPLIST)
static void test1(void)
{
@@ -66,7 +68,11 @@ static void test1(void)
int_pqueue_push(p, 5);
int_pqueue_pop(&x, p);
assert (x == 5);
int_pqueue_push(p, 17);
bool b = int_pqueue_erase(p, 17);
assert(b);
b = int_pqueue_erase(p, 1742);
assert(!b);
int_pqueue_clear(p);
}
+24 -5
View File
@@ -21,7 +21,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <gmp.h> // For testing purpose only.
#include "test-obj.h"
#include "m-string.h"
#include "m-rbtree.h"
@@ -31,10 +31,19 @@ static bool uint_in_str(unsigned int *u, FILE *f)
return n == 1;
}
static bool uint_parse_str(unsigned int *u, const char str[], const char **endptr)
{
char *end;
*u = strtol(str, &end, 0);
if (endptr) { *endptr = (const char*) end; }
return (uintptr_t) end != (uintptr_t) str;
}
static void uint_out_str(FILE *f, unsigned int u)
{
fprintf(f, "%u", u);
}
static void uint_get_str(string_t str, unsigned int u, bool append)
{
(append ? string_cat_printf : string_printf) (str, "%u", u);
@@ -42,10 +51,11 @@ static void uint_get_str(string_t str, unsigned int u, bool append)
#include "coverage.h"
START_COVERAGE
RBTREE_DEF(rbtree_uint, unsigned int, M_OPEXTEND(M_DEFAULT_OPLIST, IN_STR(uint_in_str M_IPTR), OUT_STR(uint_out_str), GET_STR(uint_get_str)) )
RBTREE_DEF(rbtree_uint, unsigned int, M_OPEXTEND(M_DEFAULT_OPLIST, IN_STR(uint_in_str M_IPTR), OUT_STR(uint_out_str), GET_STR(uint_get_str), PARSE_STR(uint_parse_str M_IPTR)) )
END_COVERAGE
RBTREE_DEF(rbtree_float, float)
RBTREE_DEF(rbtree_mpz, testobj_t, TESTOBJ_OPLIST)
#define UINT_OPLIST RBTREE_OPLIST(rbtree_uint)
#define FLOAT_OP RBTREE_OPLIST(rbtree_float)
@@ -125,16 +135,16 @@ static void test_uint(void)
assert (*cptr == num/2);
rbtree_uint_clear(tree);
bool b = rbtree_uint_pop(NULL, tree2, num+1);
bool b = rbtree_uint_pop_at(NULL, tree2, num+1);
assert (b == false);
for(unsigned int i = 0; i < num; i+=3) {
b = rbtree_uint_pop(NULL, tree2, i);
b = rbtree_uint_pop_at(NULL, tree2, i);
assert(b);
ptr = rbtree_uint_get(tree2, i);
assert (ptr == NULL);
}
for(unsigned int i = 1; i < num; i+=3) {
b = rbtree_uint_pop(NULL, tree2, i);
b = rbtree_uint_pop_at(NULL, tree2, i);
assert(b);
ptr = rbtree_uint_get(tree2, i);
assert (ptr == NULL);
@@ -218,6 +228,11 @@ static void test_io(void)
rbtree_uint_get_str(str, tree1, false);
assert(string_equal_str_p(str, "[]"));
const char *sp;
b = rbtree_uint_parse_str(tree2, string_get_cstr(str), &sp);
assert(b);
assert(*sp == 0);
assert(rbtree_uint_equal_p(tree1, tree2));
// Fill in data
for(unsigned int i = 0 ; i < 10; i++)
@@ -237,6 +252,10 @@ static void test_io(void)
rbtree_uint_get_str(str, tree1, false);
assert(string_equal_str_p(str, "[0,1,2,3,4,5,6,7,8,9]"));
b = rbtree_uint_parse_str(tree2, string_get_cstr(str), &sp);
assert(b);
assert(*sp == 0);
assert(rbtree_uint_equal_p(tree1, tree2));
}
}
+8 -8
View File
@@ -21,16 +21,16 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <assert.h>
#include "mympz.h"
#include "test-obj.h"
#include "m-shared.h"
#include "coverage.h"
START_COVERAGE
SHARED_PTR_DEF(shared_int, int)
SHARED_RESOURCE_DEF(shared_ressource, my_mpz_t, M_CLASSIC_OPLIST(my_mpz))
SHARED_RESOURCE_DEF(shared_ressource, testobj_t, TESTOBJ_OPLIST)
END_COVERAGE
SHARED_PTR_DEF(shared_mpz, my_mpz_t, M_CLASSIC_OPLIST(my_mpz))
SHARED_PTR_DEF(shared_mpz, testobj_t, TESTOBJ_OPLIST)
SHARED_PTR_RELAXED_DEF(shared_relaxed_int, int)
static int f(const shared_int_t p)
@@ -143,18 +143,18 @@ static void test_ressource(int n)
for(int i = 0; i < n ; i++) {
shared_ressource_it (it[i], ressource);
assert (!shared_ressource_end_p(it[i]));
my_mpz_t *z = shared_ressource_ref(it[i]);
testobj_t *z = shared_ressource_ref(it[i]);
assert (z != NULL);
my_mpz_set_ui(*z, i);
testobj_set_ui(*z, i);
}
shared_ressource_it (onemore, ressource);
assert (shared_ressource_end_p(onemore));
for(int i = 0; i < n ; i++) {
shared_ressource_it_set (copy[i], it[i]);
assert (!shared_ressource_end_p(copy[i]));
const my_mpz_t *z = shared_ressource_cref(copy[i]);
const testobj_t *z = shared_ressource_cref(copy[i]);
assert (z != NULL);
assert (my_mpz_cmp_ui(*z, i) == 0);
assert (testobj_cmp_ui(*z, i) == 0);
}
shared_ressource_it (onemore, ressource);
assert (shared_ressource_end_p(onemore));
@@ -164,7 +164,7 @@ static void test_ressource(int n)
shared_ressource_it (onemore, ressource);
assert (shared_ressource_end_p(onemore));
for(int i = n-1; i >= 0 ; i--) {
const my_mpz_t *z = shared_ressource_cref(copy[i]);
const testobj_t *z = shared_ressource_cref(copy[i]);
assert (z != NULL);
shared_ressource_end (copy[i], ressource);
assert (shared_ressource_end_p(copy[i]));
+3 -4
View File
@@ -20,7 +20,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <gmp.h> // For testing purpose only.
#include "test-obj.h"
#include "m-snapshot.h"
#include "m-mutex.h"
@@ -47,12 +47,11 @@ static void data_set(data_t *p, data_t o) { p->n = o.n; data_crc(p); }
START_COVERAGE
SNAPSHOT_SPSC_DEF(snapshot_uint, unsigned int)
SNAPSHOT_SPSC_DEF(snapshot_mpz, mpz_t,
(INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear)))
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_DEF(snapshot_data, data_t, DATA_OPLIST )
SNAPSHOT_SPSC_DEF(snapshot_data, data_t, DATA_OPLIST )
static void test_uint(void)
+43 -1
View File
@@ -33,6 +33,12 @@ static void test1(void)
string_set(s2, s1);
assert(string_equal_p(s1, s2));
}
M_LET((s1,"OK"),string_t) {
assert(string_equal_str_p(s1, "OK"));
}
M_LET((s1,"OK S=%d", 16),string_t) {
assert(string_equal_str_p(s1, "OK S=16"));
}
}
static void test_utf8_basic(void)
@@ -224,6 +230,7 @@ static void test0(void)
string_clear (s1);
string_init (s1);
string_strim(s1);
assert (string_cmp_str (s1, "") == 0);
assert (string_cmpi (s1, s1) == 0);
@@ -277,6 +284,10 @@ static void test0(void)
string_strim(s1);
assert (string_cmp_str (s1, "") == 0);
string_set_str(s1, " \r\n\t++\t YES ++ \n\r\t");
string_strim(s1, "\r\n\t +");
assert (string_cmp_str (s1, "YES") == 0);
string_set_str(s1, "Hello world");
string_get_str(s2, s1, false);
assert (string_cmp_str (s2, "\"Hello world\"") == 0);
@@ -284,6 +295,16 @@ static void test0(void)
string_get_str(s2, s1, true);
assert (string_cmp_str (s2, "\"Hello world\"\"Hello \\\"world\\\"\"") == 0);
const char *sp = string_get_cstr(s2);
b = string_parse_str(s1, sp, &sp);
assert (b == true);
assert (strcmp(sp, "\"Hello \\\"world\\\"\"") == 0);
assert (string_cmp_str(s1, "Hello world") == 0);
b = string_parse_str(s1, sp, &sp);
assert (b == true);
assert (strcmp(sp, "") == 0);
assert (string_cmp_str(s1, "Hello \"world\"") == 0);
string_set_str(s1, "Hello \"world\"");
FILE *f = fopen ("a-mstring.dat", "wt");
assert (f != NULL);
@@ -296,6 +317,21 @@ static void test0(void)
fclose(f);
assert (string_equal_p(s1, s2));
string_set_str(s1, "\tHell\\o\n\"World\"\r\001");
string_get_str(s2, s1, false);
assert (string_cmp_str(s2, "\"\\tHell\\\\o\\n\\\"World\\\"\\r\\001\"") == 0);
f = fopen ("a-mstring.dat", "wt");
assert (f != NULL);
string_out_str (f, s1);
fclose (f);
f = fopen("a-mstring.dat", "rt");
assert (f != NULL);
b = string_in_str(s2, f);
assert(b);
fclose(f);
assert (string_equal_p(s1, s2));
string_set_str(s1, "AZERTY");
string_set_str(s2, "QWERTY");
string_swap (s1, s2);
@@ -380,7 +416,7 @@ static void test0(void)
string_init(s1);
f = fopen("a-mstring.dat", "wt");
assert(f != NULL);
fprintf(f, "hello world.\n\tHowwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww do you do?");
fprintf(f, "hello world...\n\tHowwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww do you do?");
fclose(f);
f = fopen("a-mstring.dat", "rt");
b = string_fget_word(s1, " \t.\n?", f);
@@ -422,6 +458,12 @@ static void test0(void)
h = string_search_pbrk(s1, "oO");
assert(h==4);
string_clean(s1);
string_reserve(s1, 0);
string_cat_printf(s1, "%d little %s.", 42, "suns");
string_set_str(s2, "42 little suns.");
assert(string_equal_p(s1, s2) == true);
string_clear (s1);
string_clear (s2);
}
+82 -15
View File
@@ -21,7 +21,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "mympz.h"
#include "test-obj.h"
#include "m-string.h"
#include "m-tuple.h"
@@ -30,26 +30,48 @@
START_COVERAGE
TUPLE_DEF2(pair,
(key, string_t, (INIT(string_init), INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear))),
(value, my_mpz_t, MYMPZ_OPLIST) )
(value, testobj_t, TESTOBJ_OPLIST) )
END_COVERAGE
// Minimum definition
TUPLE_DEF2(pair_min,
(key1, string_t, (INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear))),
(key2, string_t, (INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear))))
// No cmp defined
TUPLE_DEF2(triple,
(key, string_t, (INIT(string_init), INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear), CMP(string_cmp))),
(value, my_mpz_t, MYMPZ_OPLIST ),
(value, testobj_t, TESTOBJ_OPLIST ),
(data, const char *, ()))
// cmp shall be defined
TUPLE_DEF2(pair3,
(key, string_t, (INIT(string_init), INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear), CMP(string_cmp), HASH(string_hash), EQUAL(string_equal_p))),
(value, my_mpz_t, M_OPEXTEND( MYMPZ_OPLIST, CMP(my_mpz_cmp)) ) )
(value, testobj_t, M_OPEXTEND( TESTOBJ_OPLIST, CMP(testobj_cmp)) ) )
TUPLE_DEF2(pair_str,
(vala, string_t, STRING_OPLIST),
(valb, string_t, STRING_OPLIST))
#define M_OPL_pair_str_t() TUPLE_OPLIST(pair_str, STRING_OPLIST, STRING_OPLIST)
TUPLE_DEF2(single_str, (vala, string_t, STRING_OPLIST))
TUPLE_DEF2(pair2_str,
(str, string_t),
(value, unsigned long))
// Recursive tuple definition.
TUPLE_DEF2(rtuple,
(ituple, pair_str_t),
(name, string_t))
#define M_OPL_rtuple_t() TUPLE_OPLIST(rtuple, M_OPL_pair_str_t(), STRING_OPLIST)
TUPLE_DEF2(rtuple2, (name, string_t), (value, int))
#define M_OPL_rtuple2_t() TUPLE_OPLIST(rtuple2, STRING_OPLIST, M_DEFAULT_OPLIST)
TUPLE_DEF2(rtuple3, (name, string_t), (ituple2, rtuple2_t), (ituple, rtuple_t) )
static void check_swap(void)
{
pair_str_t p1, p2;
@@ -68,6 +90,24 @@ static void check_swap(void)
pair_str_clear(p2);
}
static void check_clean(void)
{
single_str_t p1;
single_str_init (p1);
string_set_str(p1->vala, "Hello");
single_str_clean(p1);
assert(string_equal_str_p (p1->vala, ""));
single_str_clear(p1);
M_LET(r, rtuple_t) {
string_set_str(r->name, "Hello");
rtuple_clean(r);
assert(string_equal_str_p (r->name, ""));
}
}
static void check_io(void)
{
M_LET(s, STRING_OPLIST)
@@ -77,6 +117,11 @@ static void check_io(void)
string_set_str(pair->valb, "World");
pair_str_get_str(s, pair, false);
assert(string_cmp_str(s, "(\"Hello\",\"World\")") == 0);
const char *end;
bool b = pair_str_parse_str(pair2, string_get_cstr(s), &end);
assert (b);
assert (pair_str_equal_p(pair, pair2) == true);
assert(*end == 0);
FILE *f = fopen("a-mtuple.dat", "wt");
if (!f) abort();
@@ -85,56 +130,78 @@ static void check_io(void)
f = fopen("a-mtuple.dat", "rt");
if (!f) abort();
bool b = pair_str_in_str(pair2, f);
b = pair_str_in_str(pair2, f);
assert (b);
fclose(f);
assert (pair_str_equal_p(pair, pair2) == true);
}
}
int main(void)
static void test1(void)
{
pair_t p1, p2;
pair_init (p1);
string_set_str(p1->key, "HELLO");
my_mpz_set_ui(p1->value, 1742);
testobj_set_ui(p1->value, 1742);
pair_init_set (p2, p1);
assert(my_mpz_cmp_ui(p2->value, 1742) == 0);
assert(testobj_cmp_ui(p2->value, 1742) == 0);
assert(string_equal_str_p(p2->key, "HELLO"));
string_set_str(p2->key, "HELLO WORLD");
my_mpz_set_ui(p2->value, 174217);
testobj_set_ui(p2->value, 174217);
pair_set(p1, p1);
pair_set(p1, p2);
assert(my_mpz_cmp_ui(p1->value, 174217) == 0);
assert(testobj_cmp_ui(p1->value, 174217) == 0);
assert(string_equal_str_p(p1->key, "HELLO WORLD"));
pair_clear(p1);
pair_clear(p2);
string_t s;
my_mpz_t z;
testobj_t z;
pair3_t p3, p4;
string_init_set_str(s, "HELLO");
my_mpz_init_set_ui (z, 1442);
testobj_init_set_ui (z, 1442);
pair3_init_set2(p3, s, z);
pair3_init_set2(p4, s, z);
int i = pair3_cmp (p3, p4);
assert (i == 0);
my_mpz_set_ui (z, 1443);
pair3_set2(p4, s, z);
i = pair3_cmp (p3, p4);
assert (i == 0);
testobj_set_ui (z, 1443);
pair3_set_value(p4, z);
i = pair3_cmp (p3, p4);
assert (i < 0);
my_mpz_set_ui (z, 1442);
testobj_set_ui (z, 1442);
string_set_str(s, "HELLN");
pair3_set_key(p4, s);
i = pair3_cmp (p3, p4);
assert (i > 0);
// p3 = HELLO, 1442
// p4 = HELLN, 1443
i = pair3_cmp_order(p3, p3, TUPLE_ORDER(pair3, ASC(value), DSC(key)));
assert (i == 0);
i = pair3_cmp_order(p3, p4, TUPLE_ORDER(pair3, ASC(key), ASC(value)));
assert (i > 0);
i = pair3_cmp_order(p3, p4, TUPLE_ORDER(pair3, ASC(value), ASC(key)));
assert (i < 0);
i = pair3_cmp_order(p3, p4, TUPLE_ORDER(pair3, DSC(key), ASC(value)));
assert (i < 0);
i = pair3_cmp_order(p3, p4, TUPLE_ORDER(pair3, DSC(value), ASC(key)));
assert (i > 0);
pair3_clear(p3);
pair3_clear(p4);
string_clear(s);
my_mpz_clear(z);
testobj_clear(z);
}
int main(void)
{
test1();
check_io();
check_swap();
check_clean();
exit(0);
}
+58 -11
View File
@@ -21,7 +21,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "mympz.h"
#include "test-obj.h"
#include "m-string.h"
#include "m-variant.h"
@@ -33,6 +33,32 @@ VARIANT_DEF2(pair,
(value, float, M_DEFAULT_OPLIST) )
END_COVERAGE
VARIANT_DEF2(flux,
(z, int),
(f, float, M_DEFAULT_OPLIST),
(s, string_t) )
// Minimal oplist definition.
VARIANT_DEF2(fluxmin,
(s, string_t, (INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear)) ))
// Recursive variant definition.
VARIANT_DEF2(pair_str,
(vala, string_t, STRING_OPLIST),
(valb, string_t, STRING_OPLIST))
#define M_OPL_pair_str_t() VARIANT_OPLIST(pair_str, STRING_OPLIST, STRING_OPLIST)
VARIANT_DEF2(rvariant,
(ivariant, pair_str_t),
(name, string_t))
#define M_OPL_rvariant_t() VARIANT_OPLIST(rvariant, M_OPL_pair_str_t(), STRING_OPLIST)
VARIANT_DEF2(rvariant2, (name, string_t), (value, int))
#define M_OPL_rvariant2_t() VARIANT_OPLIST(rvariant2, STRING_OPLIST, M_DEFAULT_OPLIST)
VARIANT_DEF2(rvariant3, (name, string_t), (ivariant2, rvariant2_t), (ivariant, rvariant_t) )
static void test_pair(void)
{
pair_t p;
@@ -134,11 +160,23 @@ static void test_pair(void)
pair_clear(p2);
pair_clear(p);
pair_init_value(p);
assert(pair_value_p(p));
f = pair_get_value(p);
assert (*f == 0.0);
pair_clear(p);
pair_init_set_value(p, 17.0);
assert(pair_value_p(p));
f = pair_get_value(p);
assert (*f == 17.0);
pair_clear(p);
}
VARIANT_DEF2(triple,
(s, string_t, STRING_OPLIST),
(z, my_mpz_t, (INIT(my_mpz_init), INIT_SET(my_mpz_init_set), SET(my_mpz_set), CLEAR(my_mpz_clear) )),
(z, testobj_t, (INIT(testobj_init), INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear) )),
(i, int, M_DEFAULT_OPLIST) )
static void
@@ -148,26 +186,26 @@ test_triple(void)
triple_init(t);
string_t s;
string_init(s);
my_mpz_t z;
my_mpz_init(z);
testobj_t z;
testobj_init(z);
my_mpz_set_ui(z, 2556789045);
testobj_set_ui(z, 2556789045);
string_set_str(s, "FHZKJHFKZUHFKZHFUHZFUHURHYERUYEUIRYEIURYIEYRIU");
assert( triple_type(t) == triple_EMPTY);
triple_set_s(t, s);
assert( triple_type(t) == triple_s);
assert( triple_type(t) == triple_s_value);
triple_set_s(t, s);
assert( triple_type(t) == triple_s);
assert( triple_type(t) == triple_s_value);
assert( string_equal_p (s, *triple_get_s(t)));
triple_set_z(t, z);
assert( triple_type(t) == triple_z);
assert( triple_type(t) == triple_z_value);
triple_set_z(t, z);
assert( triple_type(t) == triple_z);
assert( my_mpz_cmp (z, *triple_get_z(t)) == 0);
assert( triple_type(t) == triple_z_value);
assert( testobj_cmp (z, *triple_get_z(t)) == 0);
my_mpz_clear(z);
testobj_clear(z);
string_clear(s);
triple_clear(t);
}
@@ -194,6 +232,11 @@ test_io(void)
single_get_str(s, x, false);
assert(string_equal_str_p(s, "@EMPTY@@"));
const char *endp;
b = single_parse_str(y, string_get_cstr(s), &endp);
assert(b);
assert(*endp==0);
assert(single_equal_p(x, y));
// Fill in the variant
single_set_s (x, s);
@@ -211,6 +254,10 @@ test_io(void)
single_get_str(s, x, false);
assert(string_equal_str_p(s, "@s@\"@EMPTY@@\"@"));
b = single_parse_str(y, string_get_cstr(s), &endp);
assert(b);
assert(*endp==0);
assert(single_equal_p(x, y));
}
}
+4 -4
View File
@@ -48,9 +48,9 @@ static int fib(int n)
struct fib2_s f;
worker_sync_t b;
worker_start(b);
worker_start(b, w_g);
f.n = n - 2;
worker_spawn (w_g, b, subfunc_1, &f);
worker_spawn (b, subfunc_1, &f);
int y = fib (n-1);
worker_sync(b);
return f.x + y;
@@ -90,8 +90,8 @@ static int fib2(int n)
worker_sync_t b;
int y1, y2;
worker_start(b);
WORKER_SPAWN(w_g, b, (n), { y2 = fib2(n-2); }, (y2));
worker_start(b, w_g);
WORKER_SPAWN(b, (n), { y2 = fib2(n-2); }, (y2));
y1 = fib (n-1);
worker_sync(b);
return y1 + y2;
+149
View File
@@ -0,0 +1,149 @@
#ifndef TESTOBJ_T
#define TESTOBJ_T
#include <stdbool.h>
#include <assert.h>
#include "m-string.h"
/* This is a trivial encapsulation of an opaque structure.
Used for test purpose only.*/
typedef struct testobj_s {
unsigned int n;
unsigned int a;
bool allocated;
unsigned int *ptr;
} testobj_t[1];
static void testobj_init(testobj_t z)
{
z->n = 1;
z->a = 1;
z->ptr = (unsigned int*) calloc(1, sizeof(unsigned int));
if (!z->ptr) abort();
z->allocated = true;
}
static void testobj_clear(testobj_t z)
{
assert (z->allocated);
free(z->ptr);
z->ptr = NULL;
z->allocated = false;
}
static void testobj_init_set(testobj_t d, const testobj_t s)
{
d->n = s->n;
d->a = s->n;
d->ptr = (unsigned int *) calloc (s->n, sizeof(unsigned int));
if (!d->ptr) abort();
memcpy(d->ptr, s->ptr, sizeof(unsigned int) * s->n);
d->allocated = true;
}
static void testobj_set(testobj_t d, const testobj_t s)
{
testobj_clear(d);
testobj_init_set(d, s);
}
static void testobj_set_ui(testobj_t d, unsigned int v)
{
d->n = 1;
d->ptr[0] = v;
}
static void testobj_init_set_ui(testobj_t d, unsigned int v)
{
testobj_init(d);
testobj_set_ui(d, v);
}
static unsigned int testobj_get_ui(const testobj_t z)
{
return z->ptr[0];
}
static void testobj_add(testobj_t d, const testobj_t a, const testobj_t b)
{
d->ptr[0] = a->ptr[0] + b->ptr[0];
}
static void testobj_out_str(FILE *f, const testobj_t z)
{
assert(z->n == 1);
fprintf(f, "%u", z->ptr[0]);
}
static bool testobj_in_str(testobj_t z, FILE *f)
{
z->n = 1;
return fscanf(f, "%u", &z->ptr[0]) == 1;
}
static bool testobj_parse_str(testobj_t z, const char str[], const char **endptr)
{
z->n = 1;
char *end;
z->ptr[0] = strtol(str, &end, 0);
if (endptr) { *endptr = (const char*) end; }
return (uintptr_t) end != (uintptr_t) str;
}
static bool testobj_equal_p(const testobj_t z1, const testobj_t z2)
{
if (z1->n != z2->n) return false;
return memcmp(z1->ptr, z2->ptr, z1->n*sizeof(unsigned int)) == 0;
}
static int testobj_cmp(const testobj_t z1, const testobj_t z2)
{
if (z1->n != z2->n) return z1-> n < z2->n ? -1 : 1;
for(unsigned int i = 0; i < z1->n; i++) {
if (z1->ptr[i] != z2->ptr[i])
return z1->ptr[i] < z2->ptr[i] ? -1 : 1;
}
return 0;
}
static int testobj_cmp_ui(const testobj_t z1, unsigned int z2)
{
if (z1->n != 1) return z1-> n < 1 ? -1 : 1;
return z1->ptr[0] < z2 ? -1 : z1->ptr[0] > z2;
}
static void testobj_str(string_t str, const testobj_t z, bool append)
{
if (append) string_cat_printf (str, "%u", z->ptr[0]);
else string_printf (str, "%u", z->ptr[0]);
}
#define TESTOBJ_OPLIST \
(INIT(testobj_init), \
INIT_SET(testobj_init_set), \
SET(testobj_set), \
CLEAR(testobj_clear), \
TYPE(testobj_t), \
OUT_STR(testobj_out_str), \
IN_STR(testobj_in_str), \
PARSE_STR(testobj_parse_str), \
GET_STR(testobj_str), \
EQUAL(testobj_equal_p), \
)
#define TESTOBJ_CMP_OPLIST \
(INIT(testobj_init), \
INIT_SET(testobj_init_set), \
SET(testobj_set), \
CLEAR(testobj_clear), \
TYPE(testobj_t), \
OUT_STR(testobj_out_str), \
IN_STR(testobj_in_str), \
PARSE_STR(testobj_parse_str), \
GET_STR(testobj_str), \
EQUAL(testobj_equal_p), \
CMP(testobj_cmp) \
)
#endif
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2017-2018, 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 <stdint.h>
#include "m-dict.h"
static inline bool my_oor_equal_p(uint64_t k, unsigned char n)
{
return k == ~(uint64_t) n;
}
static inline void my_oor_set(uint64_t *k, unsigned char n)
{
*k = ~(uint64_t)n;
}
DICT_OA_DEF2(dict,
uint64_t, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(my_oor_equal_p), OOR_SET(my_oor_set M_IPTR)),
uint32_t, M_DEFAULT_OPLIST)
extern void set_at(dict_t d, uint64_t key, uint32_t value);
void set_at(dict_t d, uint64_t key, uint32_t value)
{
dict_set_at(d, key, value);
}
extern uint32_t get(dict_t d, uint64_t key);
uint32_t get(dict_t d, uint64_t key)
{
uint32_t *p = dict_get(d, key);
return p == NULL ? 0: *p;
}
extern void increment(dict_t d, uint64_t key);
void increment(dict_t d, uint64_t key)
{
uint32_t *p = dict_get(d, key);
if (p != NULL) {
(*p) ++;
} else {
dict_set_at(d, key, 1);
}
}
extern void clean(dict_t d);
void clean(dict_t d)
{
dict_clean(d);
}
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2017-2018, 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 "m-string.h"
size_t fsize(const char str[])
{
return stringi_utf8_length(str);
}
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2017-2018, 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 "m-buffer.h"
QUEUE_MPMC_DEF(queue_uint, unsigned int, BUFFER_QUEUE)
queue_uint_t g_buff2;
extern void push(unsigned int r);
void push(unsigned int r)
{
queue_uint_push(g_buff2, r );
}
extern unsigned int pop(void);
unsigned int pop(void)
{
unsigned int r = -1;
queue_uint_pop(&r, g_buff2 );
return r;
}