207 Commits
Author SHA1 Message Date
Patrick Pelissier d75237ba66 Update 2018-03-31 12:05:42 +02:00
Patrick Pelissier 9909877771 Avoid warning with C++ 2018-03-31 12:01:05 +02:00
Patrick Pelissier 64ef1f3aba Fix classic issue with C++ 2018-03-31 11:56:28 +02:00
Patrick Pelissier d670e1a6bb Update 2018-03-31 10:05:24 +02:00
Patrick Pelissier 7082a4dc24 Fix wrong initialization of ATOMIC_VAR_INIT for the emulation layer
(wrong since the simplication of the atomic structure).
2018-03-31 10:04:41 +02:00
Patrick Pelissier e6c9314c91 Reorder the list of other libraries. 2018-03-30 21:39:10 +02:00
Patrick Pelissier 3dccd4484e Add nedtries 2018-03-30 21:35:19 +02:00
Patrick Pelissier 170ed98701 Remove dependency of boost/glib to the pool benchmark 2018-03-29 20:51:42 +02:00
Patrick Pelissier 54fa2c8635 Don't assume boost is always installed on the platform. 2018-03-29 20:12:53 +02:00
Patrick Pelissier bc83fe43e5 Remove dependency on GMP, so that it is easier to run the bench suite. 2018-03-29 20:01:45 +02:00
Patrick Pelissier 18710567f2 Make QT & GLIB optional libraries 2018-03-29 19:19:48 +02:00
Patrick Pelissier 9a98ed5cb6 Add PHONY target. 2018-03-29 19:15:11 +02:00
Patrick Pelissier 35a98fd3b5 Remove unused header file 2018-03-29 19:13:59 +02:00
Patrick Pelissier cd74fdf234 time command doesn't work reliabely in Makefile 2018-03-29 19:13:35 +02:00
Patrick Pelissier 6cccbfc73a Add worker_sync_p function. 2018-03-26 22:13:50 +02:00
Patrick Pelissier e59308a9a3 Update documentation. 2018-03-26 21:55:51 +02:00
Patrick Pelissier 85a3be4ae3 Update documentation 2018-03-26 21:45:06 +02:00
Patrick Pelissier d873693fe7 Update to ignore 'other' directory 2018-03-24 12:47:19 +01:00
Patrick Pelissier 2df967d5c2 add TODO 2018-03-24 08:52:20 +01:00
Patrick Pelissier 20989a7ab5 Add test for bounded string. 2018-03-24 08:42:47 +01:00
Patrick Pelissier 8e114d6fe4 Add bounded string definition so that you can easily use them for a container. 2018-03-24 08:42:15 +01:00
Patrick Pelissier 479ad2d4ba Update doc 2018-03-23 22:07:04 +01:00
Patrick Pelissier d05bb49f5d Add more assertions.
Change prototype of fputs to return the error / success status.
2018-03-23 21:25:55 +01:00
Patrick Pelissier fc9755379d Add ctemplates 2018-03-23 20:10:37 +01:00
Patrick Pelissier a85db0c383 Add libgenerics 2018-03-21 23:13:34 +01:00
Patrick Pelissier d19ec5bf49 Fix format of _size 2018-03-21 20:11:31 +01:00
Patrick Pelissier ba72e4ebbf Remove check in protected contract:
since there are two mutex now, there are data race when we want to check it.
TODO: Properly separate the contract.
2018-03-17 19:54:59 +01:00
Patrick Pelissier 5936e25ce4 Add test 2018-03-17 09:24:26 +01:00
Patrick Pelissier d82dc196e0 Fix datarace (?) if support for pop deferred has been activated
(a rewake of thread may be lost)
2018-03-16 23:55:16 +01:00
Patrick Pelissier c174b368e8 Fix issue with atomic variables needing writable variable even for reading only. 2018-03-16 23:27:08 +01:00
Patrick Pelissier 81e3515f40 Add missing tests 2018-03-16 23:06:15 +01:00
Patrick Pelissier bffec6206b Remove usage of variable array extension in C tests to avoid warning with C++ compilers. 2018-03-16 23:02:28 +01:00
Patrick Pelissier d269c23948 Remove warning with C++.
It'll will increase the size of the type a little bit.
TODO: Check compatibility between code using C def and code using C++ def
2018-03-16 23:00:46 +01:00
Patrick Pelissier f2b2335080 Fix issue with C++ not supporting passing an int constant value to an unsigned atomic type...
I definitely find this disturbing.
2018-03-16 22:59:51 +01:00
Patrick Pelissier 5dded0d9aa Clarify the displayed message 2018-03-16 22:30:59 +01:00
Patrick Pelissier 33142c3a0d Fix build for flathaspmap (needs of C++14 and not C++11). 2018-03-16 09:27:00 +01:00
Patrick Pelissier 06e256f77a Fix build with newer version of library 2018-03-16 09:13:34 +01:00
Patrick Pelissier 3f13cca666 Fix compilation with newer version of library 2018-03-16 09:04:32 +01:00
Patrick Pelissier 73117708e5 Analyze generated code 2018-03-14 23:51:51 +01:00
Patrick Pelissier f88b53dce5 Fix issue 2018-03-14 23:51:43 +01:00
Patrick Pelissier 3e609bab04 Add method pop_until 2018-03-14 23:46:30 +01:00
Patrick Pelissier a6bf530c5f Remove a warning. 2018-03-14 22:19:16 +01:00
Patrick Pelissier 5d003b7678 Generate more functions 2018-03-14 22:18:48 +01:00
Patrick Pelissier a5cbc3f34a Rename method into GET_KEY. Add method SET_KEY 2018-03-13 22:22:26 +01:00
Patrick Pelissier 52e92e1ebf Bench stable sort 2018-03-11 00:36:51 +01:00
Patrick Pelissier 5307b6c097 Add stable sort for array 2018-03-11 00:36:38 +01:00
Patrick Pelissier dd4f4761de Add GET_AT method
:
2018-03-10 19:26:59 +01:00
Patrick Pelissier 96f3533e46 Fix bug for default oplist used by M_A1_OPLIST
o
2018-03-10 18:52:16 +01:00
Patrick Pelissier 774e1720b7 Add M_SWAP_DEFAULT 2018-03-10 18:48:27 +01:00
Patrick Pelissier 83f8eadce9 Fix name of variable without a macro (shadow variable) 2018-03-10 18:09:23 +01:00
Patrick Pelissier f8e75761ef Change SNAPSHOT_SRSW to SNAPSHOT_SPSC to be uniform with queue definition
(Replace Reader / Writer term by Consummer / Producer term)
2018-03-10 17:46:02 +01:00
Patrick Pelissier cbb881df86 Fix overwrite branch which has a data race on number.
Rewrite it to be simpler & faster and without data race.
2018-03-10 10:13:54 +01:00
Patrick Pelissier 103e5304e8 Use of 2 mutex for buffer:
* one for the enqueue
* one for the dequeue
The number of items in the buffer is the only variable which can be accessed
by both at the same time.
This improve the performance of the communication and reduce the possibility
of priority inversion between the producer and the consummer thread.
2018-03-09 21:07:21 +01:00
Patrick Pelissier e152ff0377 Add TODO 2018-03-09 21:07:07 +01:00
Patrick Pelissier 65f39ab22e Optmize the buffer queue:
don't broadcast the condition variable if we know that
 no thread is waiting for it.
 Improve bench test from 700ms to 450ms
2018-03-09 19:15:47 +01:00
Patrick Pelissier df51c6dc64 Add m_cond_broad_cast 2018-03-09 19:15:31 +01:00
Patrick Pelissier b7c86ee01e Fix detection
of GCC
2018-03-06 21:58:41 +01:00
Patrick Pelissier 992bb6a73a Add bench of hash computation library (XXHASH) 2018-03-04 01:16:37 +01:00
Patrick Pelissier 557dd3e0d5 Fix spelling 2018-03-03 18:32:08 +01:00
Patrick Pelissier c8d5b5440f Add documentation for LIST_DUAL_PUSH_DEF 2018-03-03 18:30:01 +01:00
Patrick Pelissier 0900e72070 Add TODO 2018-02-28 21:44:52 +01:00
Patrick Pelissier dcdc64f974 Update graph 2018-02-28 21:34:47 +01:00
Patrick Pelissier 58898adbcd Add target to Generate depend.png 2018-02-28 21:34:31 +01:00
Patrick Pelissier ff2050466b Fix spelling 2018-02-28 21:17:16 +01:00
Patrick Pelissier dd209c05b9 Use new kind of dictionary for bench 2018-02-28 21:07:53 +01:00
Patrick Pelissier 12a4806b85 Add documentation 2018-02-28 21:07:43 +01:00
Patrick Pelissier 82575962ed Add expansion of the new kind of dictionary 2018-02-28 21:07:29 +01:00
Patrick Pelissier 1db2813aa3 Add dictionary with store computed hash, avoiding the need
of recomputation in some cases.
2018-02-28 21:06:58 +01:00
Patrick Pelissier c71613dcfe Don't display warnings about unused variables in release mode. 2018-02-28 21:05:15 +01:00
Patrick Pelissier 762d8a8e74 Update assertion 2018-02-27 22:43:17 +01:00
Patrick Pelissier b7966f6b61 Update assertions 2018-02-27 22:41:20 +01:00
Patrick Pelissier b1443533e0 Update comment 2018-02-27 22:41:11 +01:00
Patrick Pelissier 6f12ac1d19 Update comments & add new assertions 2018-02-27 22:32:03 +01:00
Patrick Pelissier 0295eea145 Rewrite the prototype of intrusive shared object
to be more clear when there is a shared pointer
and when there is not.
2018-02-26 21:38:33 +01:00
Patrick Pelissier 171402f99f Fix bug 2018-02-25 11:52:21 +01:00
Patrick Pelissier 3d57d35536 Update test 2018-02-25 11:52:14 +01:00
Patrick Pelissier bacf2b9eec Add more test for dual push list 2018-02-25 11:43:31 +01:00
Patrick Pelissier fd885bdb19 Rewrite a little bit singly linked list
to be up-to-date with standards of other containers.
2018-02-25 11:24:44 +01:00
Patrick Pelissier a497c07b0b Update test 2018-02-24 21:41:30 +01:00
Patrick Pelissier ffd5f23406 Update due to new generic type 2018-02-24 21:41:16 +01:00
Patrick Pelissier 97e3cc35c2 Add more tests. 2018-02-24 20:26:32 +01:00
Patrick Pelissier 44d8363292 Fix issue with assertion 2018-02-24 20:26:19 +01:00
Patrick Pelissier e540a95ad0 Fix spelling 2018-02-24 15:28:07 +01:00
Patrick Pelissier db63b0d515 Fix code generation analyzis for list
Add dual push list
2018-02-24 15:21:23 +01:00
Patrick Pelissier 7637c2fb58 Update test 2018-02-24 15:16:11 +01:00
Patrick Pelissier 5b40b43435 Add some tests. 2018-02-24 15:13:34 +01:00
Patrick Pelissier 6ec277ec99 Add dual push singly linked list 2018-02-24 15:07:58 +01:00
Patrick Pelissier 1befa63c9b Remove duplicate code. 2018-02-24 15:04:44 +01:00
Patrick Pelissier 3d3e052f23 Add reference to wikipedia data structure in the documentation 2018-02-24 09:03:47 +01:00
Patrick Pelissier aea816dcaf Fix data race 2018-02-24 07:44:16 +01:00
Patrick Pelissier d258fb3eff Fix memory leak 2018-02-23 23:13:10 +01:00
Patrick Pelissier 1463d83b9f Fix memory leak in test 2018-02-23 23:10:26 +01:00
Patrick Pelissier 10c947d9d4 Support of monocore cpu 2018-02-23 22:21:20 +01:00
Patrick Pelissier 2da51ea6e9 Remove constraint on size > 0
as workers can create a queue of size 0
in mono core system.
2018-02-23 22:12:17 +01:00
Patrick Pelissier d930c0a4ad Fix memory leak in test suite 2018-02-23 22:00:15 +01:00
Patrick Pelissier d0e7cc41bf Add more assertions 2018-02-23 20:40:44 +01:00
Patrick Pelissier 8c610adee5 Update README 2018-02-23 20:39:37 +01:00
Patrick Pelissier a1e791d1e9 Add queue SPSC 2018-02-23 20:38:51 +01:00
Patrick Pelissier 264249fb8b Improve queue MPMC contract checking 2018-02-23 20:13:04 +01:00
Patrick Pelissier e2b00d7c73 Split function definitions into separate macro 2018-02-21 22:16:55 +01:00
Patrick Pelissier ff3964e2eb Factorization of the mympz type 2018-02-21 22:06:45 +01:00
Patrick Pelissier 2ed95bfe16 Fix generic issue for deque
(was totaly broken before).
2018-02-21 22:05:51 +01:00
Patrick Pelissier 958936319f Activate test 2018-02-21 21:51:54 +01:00
Patrick Pelissier 39fca33958 Reuse memory node in case of pop from the opposite side
if there is at least one free node in the opposite side.
This reduce the memory consumption ***a lot*** for FIFO queues
usage.
2018-02-21 21:50:40 +01:00
Patrick Pelissier eb4cbe863e Add some TODO 2018-02-20 23:10:47 +01:00
Patrick Pelissier d146ea6a63 Add new test (disabled) 2018-02-20 22:57:58 +01:00
Patrick Pelissier f4b2ba8322 Fix coverage 2018-02-20 22:12:09 +01:00
Patrick Pelissier acb1aa8104 Add new restriction 2018-02-20 22:12:03 +01:00
Patrick Pelissier 03f7a75e54 Add more check 2018-02-20 22:01:26 +01:00
Patrick Pelissier 2dc71cc5fd Fix bug 2018-02-20 22:01:19 +01:00
Patrick Pelissier 4a92419bbe Add tests 2018-02-20 21:55:16 +01:00
Patrick Pelissier 92699501f6 Add more assertions 2018-02-19 23:41:29 +01:00
Patrick Pelissier b49ed97be0 Update comment 2018-02-19 23:38:22 +01:00
Patrick Pelissier aec661edea Add shared ressource container 2018-02-19 23:37:10 +01:00
Patrick Pelissier 675fa2cf85 Add note to document 2018-02-19 23:36:36 +01:00
Patrick Pelissier b442d72ef7 Add forgotten free + check for memory allocation 2018-02-19 23:14:16 +01:00
Patrick Pelissier 2ff197c670 Add function _size 2018-02-19 23:14:09 +01:00
Patrick Pelissier 5c9a610823 Fix data race issue 2018-02-19 22:49:05 +01:00
Patrick Pelissier 8d871256ed Reformat 2018-02-19 22:48:46 +01:00
Patrick Pelissier 3d59fb0d9a Fix a deadlock due to an ABA like bug. 2018-02-19 19:00:24 +01:00
Patrick Pelissier 057d783158 Add comment 2018-02-18 19:19:41 +01:00
Patrick Pelissier ffb8a2a00a Improve test suite
(Test fails randomly)
2018-02-18 19:18:40 +01:00
Patrick Pelissier b32b93340c Improve tests & fix bugs.
Still one bug remain.
2018-02-18 17:01:41 +01:00
Patrick Pelissier 35a3f7c02a Improve test 2018-02-18 09:55:31 +01:00
Patrick Pelissier 6de4c4092f Add MRMW snapshot 2018-02-18 08:27:10 +01:00
Patrick Pelissier c5de5e07d8 Update comment 2018-02-18 08:00:14 +01:00
Patrick Pelissier 0176071011 Add proper test for MRSW snapshot 2018-02-18 07:58:48 +01:00
Patrick Pelissier 3f2a641cdf Add contract 2018-02-17 20:25:40 +01:00
Patrick Pelissier 20be2d8850 Externalized currentWrite 2018-02-17 20:21:53 +01:00
Patrick Pelissier b37cd7dba7 Rewrite / simplify code 2018-02-17 20:08:00 +01:00
Patrick Pelissier e274a49ffd Fix bug as we can't fail spuriously here. 2018-02-17 19:28:09 +01:00
Patrick Pelissier cba37abfae Reword 2018-02-17 19:24:16 +01:00
Patrick Pelissier be198a7040 Add MRSW snapshots. 2018-02-17 19:19:51 +01:00
Patrick Pelissier 29d181c113 Add macro M_CTYPE_FROM_FIELD like M_TYPE_FROM_FIELD
but for const pointer.
2018-02-17 19:19:09 +01:00
Patrick Pelissier 3d5914f389 Fix issue in test 2018-02-17 18:50:03 +01:00
Patrick Pelissier c78c75d89a Add more test 2018-02-17 18:48:52 +01:00
Patrick Pelissier a4753be5ae Add test for int snapshot MRSW 2018-02-17 18:20:25 +01:00
Patrick Pelissier 3bda360196 Add first step of MRSW snapshot 2018-02-17 17:35:18 +01:00
Patrick Pelissier 2b4de98aee Update comment 2018-02-17 17:35:07 +01:00
Patrick Pelissier bbd887fd2c Update comments 2018-02-17 14:21:54 +01:00
Patrick Pelissier 84a5add410 Recursive clean 2018-02-17 14:03:24 +01:00
Patrick Pelissier c999563ecd Fix spelling 2018-02-17 12:02:54 +01:00
Patrick Pelissier 80c7cdbdd2 Rename snapshot_def as snapshot_srsw_def 2018-02-17 12:00:45 +01:00
Patrick Pelissier 9c7b453732 Update doc 2018-02-17 11:56:04 +01:00
Patrick Pelissier 45982c4b01 Improve test suite 2018-02-17 11:06:28 +01:00
Patrick Pelissier 438704be37 Rewrite & fix int queue generator.
Limitation to 4096 max entries.
A classic queue may be way faster (too much sharing for thread) but will use much more memory...
To bench
2018-02-16 21:22:46 +01:00
Patrick Pelissier 1753ddc4d6 Improve bitset_at version by avoiding a redundant variable shift. 2018-02-16 20:42:42 +01:00
Patrick Pelissier 96178194b3 Update size to long long 2018-02-16 18:00:08 +01:00
Patrick Pelissier 57fb2192be Add libdict 2018-02-16 07:40:20 +01:00
Patrick Pelissier 546a78be33 Fix spelling 2018-02-15 22:48:25 +01:00
Patrick Pelissier 29acb67566 Update example of snapshot to a better one. 2018-02-15 22:43:43 +01:00
Patrick Pelissier 0afad9a825 Update comments. 2018-02-15 22:34:36 +01:00
Patrick Pelissier c99b3de902 Fix double minus which transformed into + ! 2018-02-15 22:31:50 +01:00
Patrick Pelissier e8cf1d6b9a Update doc 2018-02-14 21:12:38 +01:00
Patrick Pelissier a9aa1e13ee Add relaxed shared pointer (thread unsafe with non-atomic counter). 2018-02-10 17:31:12 +01:00
Patrick Pelissier f5857c8aab Create an oplist for the counter and use it.
It will allow to use other oplist.
2018-02-10 17:22:51 +01:00
Patrick Pelissier 67856a98af Avoid false sharing for snapshot by aligning properly the
data of the triple buffer to a cache boundary.
2018-02-10 08:29:34 +01:00
Patrick Pelissier c71de15cb0 Update comment 2018-02-10 08:22:37 +01:00
Patrick Pelissier 73f15c1980 Update comment 2018-02-10 08:22:12 +01:00
Patrick Pelissier 646df4f34e Move aligned cache line constant to commun header. 2018-02-10 08:20:37 +01:00
Patrick Pelissier 8489d0df97 Clarify algorithm 2018-02-09 20:56:28 +01:00
Patrick Pelissier 86dfad860e Improve coverage 2018-02-05 22:28:35 +01:00
Patrick Pelissier c97a68029b Improve coverage 2018-02-05 22:18:56 +01:00
Patrick Pelissier 08a4dfbe4c Improve coverage 2018-02-05 22:14:14 +01:00
Patrick Pelissier adcacf3cf9 Improve coverage 2018-02-05 22:04:50 +01:00
Patrick Pelissier 7950b69136 Improve coverage 2018-02-05 21:47:22 +01:00
Patrick Pelissier 5d75416948 Improve coverage 2018-02-05 21:41:28 +01:00
Patrick Pelissier 2e96a00fde Improve coverage. 2018-02-05 21:25:11 +01:00
Patrick Pelissier 1f08bcf0f8 Add clear callback for workers. 2018-01-29 22:08:21 +01:00
Patrick Pelissier a3e2e75021 Use new macro. 2018-01-29 21:59:57 +01:00
Patrick Pelissier 603bdd2941 Add new macro M_DEFAULT_ARGS 2018-01-29 21:59:39 +01:00
Patrick Pelissier 6fb7a4f24b Update doc 2018-01-29 21:21:54 +01:00
Patrick Pelissier 0c2d290835 Add missing copyright notice. 2018-01-29 20:29:54 +01:00
Patrick Pelissier 210e05f7fc Update copyright to 2018 2018-01-29 20:28:30 +01:00
Patrick Pelissier f4b443c33e Finish documenting the string API. 2018-01-27 22:28:48 +01:00
Patrick Pelissier 52ffa09f73 Fix issue 2018-01-24 22:30:12 +01:00
Patrick Pelissier 52bb23bb6f Update doc 2018-01-24 22:28:52 +01:00
Patrick Pelissier 2089af8fd3 Fix broken code due to previous commits. 2018-01-24 22:26:46 +01:00
Patrick Pelissier 778bc4072b Rename parameter 2018-01-24 22:23:56 +01:00
Patrick Pelissier 2b2ebecae7 Improve comments. 2018-01-23 23:03:02 +01:00
Patrick Pelissier 69cbd61915 Document string API. 2018-01-23 22:53:37 +01:00
Patrick Pelissier 4d41774345 Rename STRING_CONTRACT into internal macro STRINGI_CONTRACT 2018-01-23 21:45:45 +01:00
Patrick Pelissier ff6772aaa7 Ignore depend files 2018-01-13 13:55:36 +01:00
Patrick Pelissier bbe9d43532 Move chapter ERRORS below 2018-01-13 00:14:52 +01:00
Patrick Pelissier 6549bea3e0 Fix issue for BSD 2018-01-12 20:11:11 +01:00
Patrick Pelissier 9d727589aa Fix data race reported by thread sanitinizer 2018-01-12 18:58:27 +01:00
Patrick Pelissier aede0547d3 Optimization: replace a division into a conditional move. 2018-01-12 18:56:01 +01:00
Patrick Pelissier 55332d61fd Fix data race for buffer in POP_RELEASE mode. 2018-01-12 18:52:34 +01:00
Patrick Pelissier 83eeb5d6d0 Make the code more robust 2018-01-12 18:48:38 +01:00
Patrick Pelissier 5eaf796aab Remove warnings 2018-01-12 18:46:26 +01:00
Patrick Pelissier d46c40d3fa Don't compute coverage of the float expansion. 2018-01-09 20:05:05 +01:00
Patrick Pelissier 2461afa573 Improve coverage suite. 2018-01-09 20:03:05 +01:00
Patrick Pelissier 6acacf5efe Fix issue for hash computation. 2018-01-09 20:02:53 +01:00
Patrick Pelissier 075a74ea0c Don't expand contract for coverage. 2018-01-09 18:52:18 +01:00
Patrick Pelissier f9ddc43349 Add bench k-nucleotide as per
http://benchmarksgame.alioth.debian.org/u64q/knucleotide.html
2018-01-09 18:44:11 +01:00
Patrick Pelissier 1c9a232a9d Add 'worker_flush' function.
Factorization of the exec function.
2018-01-07 22:15:58 +01:00
Patrick Pelissier 9c727a8d8c Update doc 2018-01-07 21:57:23 +01:00
Patrick Pelissier 7c241c65de Add new lib for smart pointers in Gnu C 2018-01-07 00:09:38 +01:00
Patrick Pelissier 4f3823bfeb Add new function _blocking allowing to use
runtime behavior of the blocking characteristic of the
buffer regardless on how it has been configured.
2018-01-07 00:07:27 +01:00
Patrick Pelissier 3f7b16c736 If the size is constant (!= 0) when defining the buffer
then the array is embedded within the structure rather
than allocated when initialization of the structure
occurs.
2018-01-06 22:57:14 +01:00
Patrick Pelissier 362fbb39d4 Update comments 2018-01-06 21:58:30 +01:00
Patrick Pelissier 38fe24085f Improve comments. 2018-01-05 23:26:27 +01:00
Patrick Pelissier af3d5cb273 Proper semantic 2018-01-05 20:46:28 +01:00
Patrick Pelissier 9200b742c5 Add iterators for priority queue. 2018-01-04 22:09:20 +01:00
Patrick Pelissier f39c8ebaba Fix comment 2018-01-04 22:08:08 +01:00
Patrick Pelissier bbb1831c5f Add missing exit(0) 2017-12-31 11:42:56 +01:00
Patrick Pelissier ecae3d0e1e Update doc 2017-12-31 02:10:18 +01:00
69 changed files with 5595 additions and 966 deletions

No files matched your search

+5
View File
@@ -7,6 +7,8 @@
# Precompiled Headers
*.gch
*.pch
depend
*.depend
# Libraries
*.lib
@@ -31,3 +33,6 @@
# Debug files
*.dSYM/
*.su
# Others
other/
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 2-Clause License
Copyright (c) 2017, Patrick Pelissier
Copyright (c) 2017-2018, Patrick Pelissier
All rights reserved.
Redistribution and use in source and binary forms, with or without
+7 -1
View File
@@ -2,6 +2,8 @@ PREFIX=/usr/local
RM=rm -f
MKDIR=mkdir -p
.PHONY: all test check doc clean distclean depend depend.png install
all:
@echo "Nothing to be done."
@@ -18,7 +20,7 @@ clean:
cd tests && $(MAKE) clean
cd example && $(MAKE) clean
cd bench && $(MAKE) clean
$(RM) -f README.html
$(RM) -f README.html depend.dot
distclean:
cd tests && $(MAKE) distclean
@@ -26,6 +28,10 @@ distclean:
depend:
cd tests && $(MAKE) depend
depend.png:
(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
install:
$(MKDIR) $(DESTDIR)$(PREFIX)/include
cp m-*.h $(DESTDIR)$(PREFIX)/include
+1002 -150
View File
File diff suppressed because it is too large. Load diff
+37 -10
View File
@@ -5,6 +5,8 @@ CPPFLAGS=-I..
N=4
BENCH_DEF=
.PHONY: all container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain
all: container queue mempool string plain
#########################################################################
@@ -39,6 +41,7 @@ bench-mlib:
@./bench-mlib.exe 42
@./bench-mlib.exe 43
@./bench-mlib.exe 50
@./bench-mlib.exe 51
bench-mlib-mempool:
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c -DUSE_MEMPOOL -pthread -o bench-mlib-mempool.exe
@@ -50,6 +53,7 @@ bench-mlib-mempool:
@./bench-mlib-mempool.exe 42
@./bench-mlib-mempool.exe 43
@./bench-mlib-mempool.exe 50
@./bench-mlib-mempool.exe 51
bench-mlib-thread:
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c -DMULTI_THREAD_MEASURE -pthread -o bench-mlib-thread.exe
@@ -66,10 +70,13 @@ bench-stl:
@./bench-stl.exe 42
@./bench-stl.exe 43
@./bench-stl.exe 50
@./bench-stl.exe 51
# QT is supposed to be installed
# QT shall point to the the directory containing the file .pc are stored
bench-qt:
$(CXX) $(CFLAGS) $(CPPFLAGS) -fPIC `pkg-config --libs --cflags Qt5Core` bench-qt.cpp -o bench-qt.exe
@if test -n "$${QT}" ; then $(MAKE) bench-qt0 ; else echo "Nothing to be done for QT." ; fi
bench-qt0:
$(CXX) $(CFLAGS) $(CPPFLAGS) -fPIC `PKG_CONFIG_PATH="$${QT}" pkg-config --libs --cflags Qt5Core` bench-qt.cpp -o bench-qt.exe
@./bench-qt.exe 10
@./bench-qt.exe 20
@./bench-qt.exe 30
@@ -78,9 +85,11 @@ bench-qt:
@./bench-qt.exe 42
@./bench-qt.exe 50
#GLIB is supposed to be installed
# GLIB shall point to the the directory containing the file .pc are stored
bench-glib:
$(CC) $(CFLAGS) $(CPPFLAGS) bench-glib.c -o bench-glib.exe `pkg-config --libs --cflags glib-2.0`
@if test -n "$${GLIB}" ; then $(MAKE) bench-glib0 ; else echo "Nothing to be done for GLIB." ; fi
bench-glib0:
$(CC) $(CFLAGS) $(CPPFLAGS) bench-glib.c -o bench-glib.exe `PKG_CONFIG_PATH="$${GLIB}" pkg-config --libs --cflags glib-2.0`
@./bench-glib.exe 10
@./bench-glib.exe 20
@./bench-glib.exe 30
@@ -164,7 +173,7 @@ bench-flathashmap:
@if test -n "$${FLATHASHMAP}" ; then $(MAKE) bench-flathashmap0 ; else echo "Nothing to be done for FLATHASHMAP." ; fi
bench-flathashmap0:
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${FLATHASHMAP}" bench-flathashmap.cpp -o bench-flathashmap.exe
$(CXX) -std=c++14 $(CFLAGS) $(CPPFLAGS) -I "$${FLATHASHMAP}" bench-flathashmap.cpp -o bench-flathashmap.exe
@./bench-flathashmap.exe 41
@./bench-flathashmap.exe 42
@./bench-flathashmap.exe 43
@@ -222,7 +231,6 @@ bench-libsrt0:
# The library shall be built.
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
@LD_LIBRARY_PATH="$${LIBLFDS}/bin:$${LD_LIBRARY_PATH}" ./bench-liblfds.exe 60
@@ -232,17 +240,33 @@ bench-liblfds0:
# The library shall be built.
bench-concurrentqueue:
@if test -n "$${CONCURRENTQUEUE}" ; then $(MAKE) bench-concurrentqueue0 ; else echo "Nothing to be done for CONCURRENTQUEUE." ; fi
bench-concurrentqueue0:
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${CONCURRENTQUEUE}/" bench-concurrentqueue.cpp -o bench-concurrentqueue.exe -lpthread
@./bench-concurrentqueue.exe 60
# BOOST is assumed to be installed in the system
# XXHASH shall point to the source directory of xxhash
bench-xxhash:
@if test -n "$${XXHASH}" ; then $(MAKE) bench-xxhash0 ; else echo "Nothing to be done for XXHASH." ; fi
bench-xxhash0:
$(CC) $(CFLAGS) $(CPPFLAGS) -I "$${XXHASH}/" bench-xxhash.c "$${XXHASH}/libxxhash.a" -o bench-xxhash.exe
@./bench-xxhash.exe 70
# BOOST shall point to the header location.
bench-boost:
$(CXX) $(CFLAGS) $(CPPFLAGS) bench-boost.cpp -o bench-boost.exe -lpthread
@if test -n "$${BOOST}" ; then $(MAKE) bench-boost0 ; else echo "Nothing to be done for BOOST." ; fi
bench-boost0:
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${BOOST}" bench-boost.cpp -o bench-boost.exe -lpthread
@./bench-boost.exe 60
# NEDTRIES shall point to the header location.
bench-nedtries:
@if test -n "$${NEDTRIES}" ; then $(MAKE) bench-nedtries0 ; else echo "Nothing to be done for NEDTRIES." ; fi
bench-nedtries0:
$(CC) $(CFLAGS) $(CPPFLAGS) -I "$${NEDTRIES}" bench-nedtries.c -o bench-nedtries.exe
@./bench-nedtries.exe 40
@./bench-nedtries.exe 45
############################################################################
bench-plain:
@@ -252,7 +276,9 @@ bench-plain:
############################################################################
bench-mempool:
$(CXX) $(CFLAGS) $(CPPFLAGS) pool.cc `pkg-config --libs --cflags glib-2.0` -lboost_system -o bench-mempool.exe
@if test -n "$${BOOST}" ; then if test -n "$${GLIB}" ; then make bench-mempool0 BENCH_DEF="-DUSE_BOOST -DUSE_GLIB `pkg-config --libs --cflags glib-2.0` -lboost_system" ; else make bench-mempool0 BENCH_DEF="-DUSE_BOOST -lboost_system" ; fi ; else if test -n "$${GLIB}" ; then make bench-mempool0 BENCH_DEF="-DUSE_GLIB `pkg-config --libs --cflags glib-2.0`" ; else make bench-mempool0 ; fi ; fi
bench-mempool0:
$(CXX) $(CFLAGS) $(CPPFLAGS) pool.cc $(BENCH_DEF) -o bench-mempool.exe
@./bench-mempool.exe
############################################################################
@@ -280,6 +306,7 @@ bench-string-exe:
clean:
rm -f *.o bench-*.exe bench-*.s *~ massif.out.*
cd nucleotide && $(MAKE) clean
############################################################################
+9 -8
View File
@@ -5,6 +5,7 @@
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include "dynamic.h"
@@ -29,26 +30,26 @@ static void test_array(size_t n)
s += *(unsigned int*) vector_at(&a1, i) * *(unsigned int*) vector_at(&a2, i);
}
g_result = s;
vector_destruct(&a1);
vector_destruct(&a2);
vector_destruct(&a1, NULL);
vector_destruct(&a2, NULL);
}
/********************************************************************************************/
static size_t hash_func (map *m, void *a)
static size_t hash_func (void *a)
{
return hash_data(a, sizeof (unsigned long));
}
static int equal_func(map *m, void *a, void *b)
static int equal_func(void *a, void *b)
{
const unsigned long *pa = a;
const unsigned long *pb = b;
return *pa == *pb;
}
static void set_func(map *m, void *a, void *b)
static void set_func(void *a, void *b)
{
unsigned long *pa = a;
const unsigned long *pb = b;
@@ -86,20 +87,20 @@ test_dict(unsigned long n)
typedef char char_array_t[256];
static int char_equal (map *m, void *a, void *b)
static int char_equal (void *a, 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;
}
static size_t char_hash(map *m, void *a)
static size_t char_hash(void *a)
{
char_array_t *pa = (char_array_t *)a;
return hash_string(*pa);
}
static void char_set(map *m, void *a, void *b)
static void char_set(void *a, void *b)
{
char_array_t *pa = (char_array_t *)a;
const char_array_t *pb = (const char_array_t *)b;
+15 -2
View File
@@ -177,9 +177,9 @@ static size_t char_hash(const char_array_t a) { return m_core_hash (a, strlen(a)
#define CHAR_OPLIST (INIT(char_init), INIT_SET(char_set), SET(char_set), CLEAR(char_init), HASH(char_hash), EQUAL(char_equal_p))
#ifdef USE_MEMPOOL
DICT_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(CHAR_OPLIST,MEMPOOL(dict_mpool2), MEMPOOL_LINKAGE(static)), char_array_t, CHAR_OPLIST)
#else
DICT_DEF2(dict_char, char_array_t, CHAR_OPLIST, char_array_t, CHAR_OPLIST)
DICT_STOREHASH_DEF2(dict_char, char_array_t, CHAR_OPLIST, char_array_t, CHAR_OPLIST)
#endif
static void
@@ -263,6 +263,17 @@ static void test_sort(size_t n)
}
}
static void test_stable_sort(size_t n)
{
M_LET(a1, ARRAY_OPLIST(array_float)) {
for(size_t i = 0; i < n; i++) {
array_float_push_back(a1, rand_get() );
}
array_float_special_stable_sort(a1);
g_result = *array_float_get(a1, 0);
}
}
/********************************************************************************************/
BUFFER_DEF(buffer_uint, unsigned int, 0, BUFFER_QUEUE|BUFFER_BLOCKING)
@@ -485,6 +496,8 @@ int main(int argc, const char *argv[])
test_function("DictS time", 1000000, test_dict_str);
if (n == 50)
test_function("Sort time", 10000000, test_sort);
if (n == 51)
test_function("Stable Sort time", 10000000, test_stable_sort);
if (n == 60)
test_function("Buffer time", 1000000, test_buffer);
if (n == 61)
+101
View File
@@ -0,0 +1,101 @@
#define NDEBUG
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "nedtrie.h"
#include "common.h"
/********************************************************************************************/
typedef struct foo_s {
NEDTRIE_ENTRY(foo_s) link;
unsigned long key;
unsigned long value;
} foo_t;
typedef struct foo_tree_s foo_tree_t;
NEDTRIE_HEAD(foo_tree_s, foo_s);
static inline size_t fookeyfunct(const foo_t *r)
{
return r->key;
}
NEDTRIE_GENERATE(static, foo_tree_s, foo_s, link, fookeyfunct, NEDTRIE_NOBBLEZEROS(foo_tree_s))
static void
test_dict(unsigned long n)
{
foo_tree_t footree;
NEDTRIE_INIT(&footree);
for (size_t i = 0; i < n; i++) {
unsigned long key = rand_get();
unsigned long val = rand_get();
foo_t * p = malloc(sizeof(foo_t));
if (p == NULL) abort();
p->key = key;
p->value = val;
NEDTRIE_INSERT(foo_tree_s, &footree, p);
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
foo_t key = { .key = rand_get() };
foo_t *p = NEDTRIE_FIND(foo_tree_s, &footree, &key);
if (p)
s += p->value;
}
g_result = s;
foo_t *r, *next;
NEDTRIE_FOREACH_SAFE(r, foo_tree_s, &footree, next) {
// Remove is needed, otherwise it segfault
NEDTRIE_REMOVE(foo_tree_s, &footree, r);
free(r);
}
}
static void
test_dict_noalloc(unsigned long n)
{
foo_tree_t footree;
NEDTRIE_INIT(&footree);
foo_t *tab = malloc(n*sizeof(foo_t));
if (tab == NULL) abort();
for (size_t i = 0; i < n; i++) {
unsigned long key = rand_get();
unsigned long val = rand_get();
tab[i].key = key;
tab[i].value = val;
NEDTRIE_INSERT(foo_tree_s, &footree, &tab[i]);
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
foo_t key = { .key = rand_get() };
foo_t *p = NEDTRIE_FIND(foo_tree_s, &footree, &key);
if (p)
s += p->value;
}
g_result = s;
free(tab);
}
/********************************************************************************************/
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 40)
test_function("Dict time", 1000000, test_dict);
if (n == 45)
test_function("Dict No Alloc time", 1000000, test_dict_noalloc);
exit(0);
}
+1
View File
@@ -1,4 +1,5 @@
#define NDEBUG
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
+12
View File
@@ -208,6 +208,16 @@ static void test_sort(size_t n)
g_result = a1[0];
}
static void test_stable_sort(size_t n)
{
vector<float> a1;
for(size_t i = 0; i < n; i++) {
a1.push_back(rand_get() );
}
stable_sort(a1.begin(), a1.end());
g_result = a1[0];
}
/********************************************************************************************/
int main(int argc, const char *argv[])
@@ -231,5 +241,7 @@ int main(int argc, const char *argv[])
test_function("DictS(m) time", 1000000, test_dict_str2);
if (n == 50)
test_function("Sort time", 10000000, test_sort);
if (n == 51)
test_function("Stable Sort time", 10000000, test_stable_sort);
exit(0);
}
+47
View File
@@ -0,0 +1,47 @@
#define NDEBUG
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "xxhash.h"
#include "common.h"
static unsigned long *g_p;
static void test_hash_prepare(size_t n)
{
g_p = malloc (n * sizeof(unsigned long));
if (g_p == NULL) abort();
for(size_t i = 0; i < n ; i++)
g_p[i] = ((rand_get()*RAND_MAX + rand_get())*RAND_MAX+rand_get())*RAND_MAX + rand_get();
}
static void test_hash_final(void)
{
free(g_p);
}
static void test_hash(size_t n)
{
g_result = XXH64(g_p, sizeof(unsigned long)*n, 0);
}
/********************************************************************************************/
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 70) {
n = (argc > 2) ? atoi(argv[2]) : 100000000;
test_hash_prepare(n);
test_function("XXHASH64 time", n, test_hash);
test_hash_final();
}
exit(0);
}
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - common functions for bench module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* MLIB - TEST module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
+22
View File
@@ -0,0 +1,22 @@
CC=cc -std=c11
CXX=c++ -std=c++11
CFLAGS=-O2 -march=native -Wall
CPPFLAGS=-I../..
all: k-nucleotide
k-nucleotide: k-nucleotide.exe data.txt
./k-nucleotide.exe < data.txt
k-nucleotide.exe: nucleotide.c
$(CC) $(CFLAGS) $(CPPFLAGS) nucleotide.c -o k-nucleotide.exe -lpthread
data.txt: fasta.exe
./fasta.exe 25000000 > data.txt
fasta.exe: fasta.c
$(CC) $(CFLAGS) $(CPPFLAGS) -fopenmp fasta.c -o fasta.exe
clean:
rm -f *.exe *~ *.o data.txt
+344
View File
@@ -0,0 +1,344 @@
// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by Jeremy Zerfas
// rewritten by Аноним Легионов, inspired by fasta Rust #2 program
// use two OpenMP locks instead of one critical section
// decouples IO activity from random number generation
//
// modified by Josh Goldfoot, adding use of a buffer for fasta_repeat
// This controls the width of lines that are output by this program.
#define MAXIMUM_LINE_WIDTH 60
// This program will generate the random nucleotide sequences in parallel which
// are worked on in blocks of lines. The number of lines in those blocks is
// controlled by this setting.
#define LINES_PER_BLOCK 1024
#define CHARACTERS_PER_BLOCK (MAXIMUM_LINE_WIDTH*LINES_PER_BLOCK)
#define THREADS_TO_USE 4
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef _OPENMP
#include <omp.h>
#endif
// intptr_t should be the native integer type on most sane systems.
typedef intptr_t intnative_t;
typedef struct
{
char letter;
float probability;
} nucleotide_info;
// Repeatedly print string_To_Repeat until it has printed
// number_Of_Characters_To_Create. The output is also wrapped to
// MAXIMUM_LINE_WIDTH columns.
static char* make_Sequence_Buffer(const char string_To_Repeat[])
{
const intnative_t string_To_Repeat_Length = strlen(string_To_Repeat);
// JG: Changed to that this writes a sequence to a buffer, which is used
intnative_t number_Of_Characters_To_Create = string_To_Repeat_Length * MAXIMUM_LINE_WIDTH;
char* buffer = (char*) malloc(number_Of_Characters_To_Create +
number_Of_Characters_To_Create / MAXIMUM_LINE_WIDTH + 1);
if (buffer == NULL)
exit(-1);
char* bufferOffset = buffer;
// Create an extended_String_To_Repeat which is a copy of string_To_Repeat
// but extended with another copy of the first MAXIMUM_LINE_WIDTH characters
// of string_To_Repeat appended to the end. Later on this allows us to
// generate a line of output just by doing simple memory copies using an
// appropriate offset into extended_String_To_Repeat.
char extended_String_To_Repeat[string_To_Repeat_Length + MAXIMUM_LINE_WIDTH];
for (intnative_t column = 0; column<string_To_Repeat_Length + MAXIMUM_LINE_WIDTH;
column++)
extended_String_To_Repeat[column] =
string_To_Repeat[column%string_To_Repeat_Length];
intnative_t offset = 0;
char line[MAXIMUM_LINE_WIDTH + 1];
line[MAXIMUM_LINE_WIDTH] = '\n';
for (intnative_t current_Number_Of_Characters_To_Create =
number_Of_Characters_To_Create;
current_Number_Of_Characters_To_Create>0;)
{
// Figure out the length of the line we need to write. If it's less than
// MAXIMUM_LINE_WIDTH then we also need to add a line feed in the right
// spot too.
intnative_t line_Length = MAXIMUM_LINE_WIDTH;
if (current_Number_Of_Characters_To_Create<MAXIMUM_LINE_WIDTH)
{
line_Length = current_Number_Of_Characters_To_Create;
line[line_Length] = '\n';
}
memcpy(line, extended_String_To_Repeat + offset, line_Length);
// Update the offset, reducing it by string_To_Repeat_Length if
// necessary.
offset += line_Length;
if (offset>string_To_Repeat_Length)
offset -= string_To_Repeat_Length;
// "Output" that line to our buffer and update the
// current_Number_Of_Characters_To_Create.
memcpy(bufferOffset, line, line_Length + 1); // JG: used to be fwrite(line, line_Length + 1, 1, stdout);
bufferOffset += line_Length + 1;
current_Number_Of_Characters_To_Create -= line_Length;
}
*bufferOffset = 0;
return buffer;
}
void repeat_And_Wrap_String(const char string_To_Repeat[], intnative_t number_Of_Characters_To_Create)
{
/* JG: fasta_repeat repeats every len(alu) * line-length = 287 * 61 = 17507 characters.
So, calculate this once, then just print that buffer over and over. */
char* sequence = make_Sequence_Buffer(string_To_Repeat);
intnative_t sequenceLen = (intnative_t) strlen(sequence);
intnative_t outputBytes = number_Of_Characters_To_Create + number_Of_Characters_To_Create / 60;
while (outputBytes >= sequenceLen) {
fwrite(sequence, sequenceLen, 1, stdout);
outputBytes -= sequenceLen;
}
if (outputBytes > 0) {
fwrite(sequence, outputBytes, 1, stdout);
printf("\n");
}
free(sequence);
}
// Generate a pseudorandom number from 0 to max using a linear
// congruential generator.
#define IM 139968
#define IA 3877
#define IC 29573
uint32_t seed = 42;
int rng_tid; //Thread ID
int rng_tnum = 1; //Thread number
intnative_t rng_cnt = 0;
#ifdef _OPENMP
omp_lock_t rng_lock;
#define RNG_LOCK_INIT() omp_init_lock(&rng_lock)
#define RNG_LOCK() omp_set_lock(&rng_lock)
#define RNG_FREE() omp_unset_lock(&rng_lock)
#else
#define RNG_LOCK_INIT() do{}while(0)
#define RNG_LOCK() do{}while(0)
#define RNG_FREE() do{}while(0)
#endif
static void rng_init(void)
{
RNG_LOCK_INIT();
rng_tid = 0;
}
static intnative_t rng_gen_blk(uint32_t * buf, intnative_t len, int curr_tid)
{
intnative_t gen_cnt = -1;//Error by default
RNG_LOCK();
if (rng_tid == curr_tid)
{
if (++rng_tid >= rng_tnum)
{
rng_tid = 0;
}
gen_cnt = (len<rng_cnt) ? len : rng_cnt;
rng_cnt -= gen_cnt;
len = gen_cnt;
while (0 != len--)
{
seed = (seed*IA + IC) % IM;
*(buf++) = seed;//This is stupid actually!
}
}
RNG_FREE();
return gen_cnt;
}
int out_tid; //Thread ID
int out_tnum = 1; //Thread number
#ifdef _OPENMP
omp_lock_t out_lock;
#define OUT_LOCK_INIT() omp_init_lock(&out_lock)
#define OUT_LOCK() omp_set_lock(&out_lock)
#define OUT_FREE() omp_unset_lock(&out_lock)
#else
#define OUT_LOCK_INIT() do{}while(0)
#define OUT_LOCK() do{}while(0)
#define OUT_FREE() do{}while(0)
#endif
static void out_init(void)
{
OUT_LOCK_INIT();
rng_tid = 0;
}
static intnative_t out_write(char * buf, intnative_t len, int curr_tid)
{
intnative_t wr_cnt = -1;//Error by default
OUT_LOCK();
if (out_tid == curr_tid)
{
if (++out_tid >= out_tnum)
{
out_tid = 0;
}
wr_cnt = fwrite(buf, len, 1, stdout);
}
OUT_FREE();
return wr_cnt; //-1 - thread error, 0 - IO error, 1 - ОК
}
static void generate_And_Wrap_Pseudorandom_DNA_Sequence(
const nucleotide_info nucl_info[],
const intnative_t nucl_num,
const intnative_t char_num)
{
uint32_t cumul_p[nucl_num];
float cumul_acc = 0.0;
for (intnative_t i = 0; i<nucl_num; i++)
{
cumul_acc += nucl_info[i].probability;
cumul_p[i] = 1ul + (uint32_t)(cumul_acc*(float)IM); //Compensate rounding errors on test file
}
#ifdef _OPENMP
intnative_t tnum = omp_get_num_procs();
if (tnum>THREADS_TO_USE) tnum = THREADS_TO_USE;
omp_set_num_threads(tnum);
rng_tnum = tnum;
out_tnum = tnum;
#endif
rng_tid = 0;
out_tid = 0;
rng_cnt = char_num;
#pragma omp parallel
{
char block[CHARACTERS_PER_BLOCK + LINES_PER_BLOCK];
char * line;
uint32_t rnd[CHARACTERS_PER_BLOCK], r;
intnative_t cnt, col, prid, nid, ncnt;
int cur_tid;
#ifdef _OPENMP
cur_tid = omp_get_thread_num();
#else
cur_tid = 0;
#endif
while (1)
{
do
{
cnt = rng_gen_blk(rnd, CHARACTERS_PER_BLOCK, cur_tid);
} while (-1 == cnt);
if (0 == cnt)
{
break;//Work finished!
}
line = block;
for (col = 0, prid = 0; prid < cnt; prid++)
{
r = rnd[prid];
ncnt = 0;
for (nid = 0; nid < nucl_num; nid++)
{
if (cumul_p[nid] <= r)
{
ncnt++;
}
}
*line++ = nucl_info[ncnt].letter;
if (++col >= MAXIMUM_LINE_WIDTH)
{
col = 0;
*line++ = '\n';
}
}
//Check if we need to end the line
if (0 != col)
{
//Last iteration didn't end the line, so finish the job.
*line++ = '\n';
}
//Print results
do
{
cnt = out_write(block, line - block, cur_tid);
} while (-1 == cnt);
//Check fot IO error
if (0 == cnt)
{
exit(1);
}
}
}
}
int main(int argc, char ** argv)
{
const intnative_t n = atoi(argv[1]);
fputs(">ONE Homo sapiens alu\n", stdout);
const char homo_Sapiens_Alu[] =
"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTC"
"AGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCG"
"TGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGG"
"AGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
repeat_And_Wrap_String(homo_Sapiens_Alu, 2 * n);
rng_init();
out_init();
fputs(">TWO IUB ambiguity codes\n", stdout);
nucleotide_info iub_Nucleotides_Information[] =
{
{ 'a', 0.27 },{ 'c', 0.12 },{ 'g', 0.12 },{ 't', 0.27 },{ 'B', 0.02 },
{ 'D', 0.02 },{ 'H', 0.02 },{ 'K', 0.02 },{ 'M', 0.02 },{ 'N', 0.02 },
{ 'R', 0.02 },{ 'S', 0.02 },{ 'V', 0.02 },{ 'W', 0.02 },{ 'Y', 0.02 }
};
generate_And_Wrap_Pseudorandom_DNA_Sequence(iub_Nucleotides_Information,
sizeof(iub_Nucleotides_Information) / sizeof(nucleotide_info), 3 * n);
fputs(">THREE Homo sapiens frequency\n", stdout);
nucleotide_info homo_Sapien_Nucleotides_Information[] =
{
{ 'a', 0.3029549426680 },{ 'c', 0.1979883004921 },
{ 'g', 0.1975473066391 },{ 't', 0.3015094502008 }
};
generate_And_Wrap_Pseudorandom_DNA_Sequence(homo_Sapien_Nucleotides_Information,
sizeof(homo_Sapien_Nucleotides_Information) / sizeof(nucleotide_info), 5 * n);
return 0;
}
+293
View File
@@ -0,0 +1,293 @@
// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// 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"
// 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)
{
return k == ~(uint64_t) n;
}
static inline void 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
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)
typedef struct {
uint64_t key;
uint32_t value;
} element;
// 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
// need the three least significant bits to differentiate the letters 'A', 'C',
// 'G', and 'T'. Spaces in this array/string will never be used as long as
// 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])
// 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)
{
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;
}
// 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;
// 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];
// 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);
}
}
// 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);
}
// 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)
{
const int oligonucleotide_Length=strlen(oligonucleotide);
assert (2*oligonucleotide_Length <= 64);
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);
}
}
// Generate the key for oligonucleotide.
key=0;
for(int 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;
snprintf(output, MAXIMUM_OUTPUT_LENGTH, "%ju\t%s", count, oligonucleotide);
dict_oligonucleotide_clear(hash_Table);
}
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);
// 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;
// Do the following functions in parallel.
// Define a synchronization block
worker_sync_t block;
worker_start(block);
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
generate_Count_For_Oligonucleotide(polynucleotide,
polynucleotide_Length,
"GGTATTTTAATTTATAGT", output[6]);
}, (/*no output*/));
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
generate_Count_For_Oligonucleotide(polynucleotide,
polynucleotide_Length,
"GGTATTTTAATT", output[5]);
}, (/*no output*/));
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
generate_Count_For_Oligonucleotide(polynucleotide,
polynucleotide_Length,
"GGTATT", output[4]);
}, (/*no output*/));
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
generate_Count_For_Oligonucleotide(polynucleotide,
polynucleotide_Length,
"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]);
worker_sync(block);
// Output the results to stdout.
for(int i=0; i<7; i++)
printf("%s\n", output_Buffer[i]);
free(polynucleotide);
worker_clear(worker);
return 0;
}
+18 -5
View File
@@ -51,9 +51,13 @@
#include <iostream>
#include <string>
#ifdef USE_BOOST
#include <boost/pool/object_pool.hpp>
#endif
#ifdef USE_GLIB
#include <glib.h>
#endif
static const size_t PAGE_SIZE = 4096;
@@ -115,6 +119,8 @@ benchmark(std::string &&desc, std::function<void ()> cb)
* Boost::pool
* ------------------------------------------------------------------------
*/
#ifdef USE_BOOST
template<class T>
void
benchmark_boost_pool()
@@ -166,6 +172,7 @@ benchmark_boost_pool_create_and_destroy()
}
});
}
#endif
/*
* ------------------------------------------------------------------------
@@ -220,6 +227,7 @@ benchmark_mallocfree_free()
* GLib slices
* ------------------------------------------------------------------------
*/
#ifdef USE_GLIB
template<class T>
void
benchmark_glib_slices()
@@ -262,6 +270,7 @@ benchmark_glib_slices_free()
}
});
}
#endif
/*
* ------------------------------------------------------------------------
@@ -798,7 +807,7 @@ benchmark_mempool_small()
mempool_small_init (p);
mempool_small_t *ptr = &p; // C++ lambda !
benchmark(std::move(Small() + "mempool"), [=]() {
benchmark(std::move(Small() + "M*LIB mempool"), [=]() {
for (size_t i = 0; i < N * sizeof(Small) / sizeof(Small); ++i) {
Small *o = mempool_small_alloc(*ptr);
touch_obj(o);
@@ -815,7 +824,7 @@ benchmark_mempool_big()
mempool_big_init (p);
mempool_big_t *ptr = &p; // C++ lambda !
benchmark(std::move(Big() + "mempool"), [=]() {
benchmark(std::move(Big() + "M*LIB mempool"), [=]() {
for (size_t i = 0; i < N * sizeof(Small) / sizeof(Big); ++i) {
Big *o = mempool_big_alloc(*ptr);
touch_obj(o);
@@ -836,7 +845,7 @@ benchmark_mempool_mix_free()
mempool_big_init (b);
mempool_huge_init (h);
benchmark(std::move(std::string("mempool w/ free (Mix)")), [=]() {
benchmark(std::move(std::string("M*LIB mempool w/ free (Mix)")), [=]() {
for (size_t i = 0; i < N; ++i) {
if (__builtin_expect(!(i & 0xfff), 0)) {
Huge *o = mempool_huge_alloc (*ptr_h);
@@ -892,19 +901,23 @@ main()
benchmark_mallocfree_free<Big>();
std::cout << std::endl;
#ifdef USE_GLIB
benchmark_glib_slices<Small>();
benchmark_glib_slices_free<Small>();
benchmark_glib_slices<Big>();
benchmark_glib_slices_free<Big>();
std::cout << std::endl;
#endif
#ifdef USE_BOOST
benchmark_boost_pool<Small>();
benchmark_boost_pool_free<Small>();
benchmark_boost_pool<Big>();
benchmark_boost_pool_free<Big>();
benchmark_boost_pool_create_and_destroy();
std::cout << std::endl;
#endif
benchmark_ngx_pool<Small>();
benchmark_ngx_pool<Big>();
benchmark_ngx_pool_mix_free();
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 150 KiB

+7 -2
View File
@@ -7,7 +7,8 @@ How to make a release?
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:
Run 'make sanitize' in tests folder on a system.
This needs at least GCC 7
@@ -22,7 +23,9 @@ How to make a release?
5) Check that coverage is reasonnable.
Run 'make coverage' and analyze result.
In case of problem, open a problem error.
6) Publish the release
In case of problem, open a problem report.
List of primary systems
=======================
@@ -33,3 +36,5 @@ List of primary systems
* clang 4 on linux/x86-64
* g++ 7 on linux/x86-64
* tcc on linux/x86-64
* gcc 6 on windows/x86-64
+27 -14
View File
@@ -5,11 +5,13 @@
#include "m-mutex.h"
/* Global variable to stop scheduling */
bool continue_threading_g;
atomic_bool continue_threading_g;
/**************************************************************/
/* Define a random big data structure */
/* Define a custom random big data structure
with its constructor and its destructor.
*/
#define BIGDATA_SIZE 1000
#define BIGDATA_NUM 10
@@ -28,6 +30,7 @@ static void bigdata_init(bigdata_t d)
{
memset(d->bigdata, 0, BIGDATA_SIZE);
d->ptr = malloc (BIGDATA_HEIGHT*BIGDATA_WIDTH);
if (!d->ptr) abort();
d->count = count_g++;
printf ("Init image %d\n", d->count);
}
@@ -38,19 +41,25 @@ static void bigdata_clear(bigdata_t d)
free(d->ptr);
}
/* Let's register the oplist of our custom type globally */
#define M_OPL_bigdata_t() (INIT(bigdata_init), CLEAR(bigdata_clear))
/**************************************************************/
/* Perform some random works on this big data */
/* Perform some random works on this custom type */
static void perform_acquisition(bigdata_t p)
{
printf ("Acquiring image %d\n", p->count);
// Let's say that rand is our acquisition function.
for(int i = 0 ; i < BIGDATA_SIZE;i++)
p->bigdata[i] = rand();
for(int i = 0 ; i < BIGDATA_WIDTH*BIGDATA_HEIGHT;i++)
p->ptr[i] = rand();
// Let's stop arbitrary after 20 acquisitions
if (p->count == 20)
continue_threading_g = false;
atomic_store(&continue_threading_g, false);
}
static void perform_computation2(bigdata_t p)
@@ -69,7 +78,7 @@ static void perform_computation3(bigdata_t p)
static void perform_computation4(bigdata_t p)
{
printf ("Computation 4 on image %d\n", p->count);
printf ("Reduction on image %d\n", p->count);
unsigned long s = 0;
for(int i = 0 ; i < BIGDATA_WIDTH*BIGDATA_HEIGHT;i++)
s += p->ptr[i];
@@ -81,11 +90,12 @@ static void perform_computation4(bigdata_t p)
/**************************************************************/
/* Let's define a shared pointer interface around the bigdata structure */
SHARED_PTR_DEF(shared_bigdata, bigdata_t, (INIT(bigdata_init), CLEAR(bigdata_clear)))
SHARED_PTR_DEF(shared_bigdata, bigdata_t)
/* Let's define the communication queue between the thread:
* - size of queue is 10,
* - it is a queue BUFFER_QUEUE,
* - it store shared pointer to our bigdata_t,
* - we change the semantics of _push / _pop into buffer as push a new item and pop it as a move (ideal semantics for shared_ptr interface).
*/
#define MY_QUEUE_SIZE 10
@@ -94,11 +104,11 @@ BUFFER_DEF(buffer_bigdata, shared_bigdata_t, MY_QUEUE_SIZE,
/* Let's build a Thread synchros tree:
*
* Thread1 perform the simulation acquisition of the data.
* Thread2 & Thread3 perform independet computation.
* Thread1 perform the simulated acquisition of the data.
* Thread2 & Thread3 perform independent computation.
* Thread4 finalizes the computation :
*
* Thread1 ---> Thread 2
* Thread1 ---> Thread 2 +
* +-> Thread 3 --> Thread 4
*/
buffer_bigdata_t buf_t1tot2;
@@ -123,7 +133,7 @@ static void clearbuf(void)
static void thread1 (void *arg)
{
(void) arg;
while (continue_threading_g) {
while (atomic_load(&continue_threading_g)) {
shared_bigdata_t ptr;
shared_bigdata_init_new (ptr);
perform_acquisition(*shared_bigdata_ref(ptr));
@@ -135,7 +145,7 @@ static void thread1 (void *arg)
static void thread2 (void *arg)
{
(void) arg;
while (continue_threading_g) {
while (atomic_load(&continue_threading_g)) {
shared_bigdata_t ptr;
buffer_bigdata_pop(&ptr, buf_t1tot2); // NOTE: Pop has been configured to init ptr
perform_computation2(*shared_bigdata_ref(ptr));
@@ -145,7 +155,7 @@ static void thread2 (void *arg)
static void thread3 (void *arg)
{
(void) arg;
while (continue_threading_g) {
while (atomic_load(&continue_threading_g)) {
shared_bigdata_t ptr;
buffer_bigdata_pop(&ptr, buf_t1tot3); // NOTE: Pop has been configured to init ptr
perform_computation3(*shared_bigdata_ref(ptr));
@@ -156,7 +166,7 @@ static void thread3 (void *arg)
static void thread4 (void *arg)
{
(void) arg;
while (continue_threading_g) {
while (atomic_load(&continue_threading_g)) {
shared_bigdata_t ptr;
buffer_bigdata_pop(&ptr, buf_t3tot4); // NOTE: Pop has been configured to init ptr
perform_computation4(*shared_bigdata_ref(ptr));
@@ -164,11 +174,12 @@ static void thread4 (void *arg)
}
}
/**************************************************************/
static void init(void)
{
initbuf();
continue_threading_g = true;
atomic_init(&continue_threading_g, true);
m_thread_create(t1, thread1, NULL);
m_thread_create(t2, thread2, NULL);
m_thread_create(t3, thread3, NULL);
@@ -184,6 +195,8 @@ static void clear(void)
clearbuf();
}
/**************************************************************/
int main(void)
{
init();
+1 -1
View File
@@ -38,7 +38,7 @@ int main(void)
list_string_get_str (tmpstr, grow, false);
// print out
printf("Number of elements = %lu\n", (unsigned long) list_string_size(grow));
printf("Number of elements = %zu\n", list_string_size(grow));
printf("Final string = %s\n", string_get_cstr(tmpstr));
// Let's iterate over each element of the list
+49 -33
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - ALGO module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -28,7 +28,7 @@
#include "m-core.h"
/* Define different kind of algorithms named 'name' over the container
which oplist is 'cont_oplist'
which oplist is 'cont_oplist' as static inline functions.
USAGE:
ALGO_DEF(algogName, containerOplist) */
#define ALGO_DEF(name, cont_oplist) \
@@ -38,7 +38,7 @@
/* Map a function or a macro to all elements of a container.
USAGE:
ALGO_MAP(container, containerOplist, func[, extra arguments of function]) */
ALGO_MAP(container, containerOplist, function[, extra arguments of function]) */
#define ALGO_MAP(container, cont_oplist, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(ALGOI_MAP(container, cont_oplist, __VA_ARGS__), \
@@ -47,7 +47,7 @@
/* Extract a subset of a container to fill in another container.
USAGE:
ALGO_EXTRACT(contDst, contDstOplist, contSrc, contSrcOplist, func
ALGO_EXTRACT(contDst, contDstOplist, contSrc, contSrcOplist, function
[, extra arguments of function]) */
// TODO: without 'func' parameter, extract all.
#define ALGO_EXTRACT(contD, contDop, contS, contSop, ...) \
@@ -81,7 +81,9 @@
#define ALGOI_DEF(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
static inline void M_C(name, _find) (it_t it, container_t l, const type_t data) \
/* TODO: Add a specialization if container is sorted */ \
static inline void \
M_C(name, _find) (it_t it, container_t l, const type_t data) \
{ \
for (M_GET_IT_FIRST cont_oplist (it, l); \
!M_GET_IT_END_P cont_oplist (it) ; \
@@ -91,17 +93,20 @@
} \
} \
\
static inline bool M_C(name, _contains) (container_t l, const type_t data) \
static inline bool \
M_C(name, _contains) (container_t l, const type_t data) \
{ \
it_t it; \
M_C(name,_find)(it, l, data); \
return !M_GET_IT_END_P cont_oplist (it); \
} \
\
/* NOTE: If PREVIOUS & IT_LAST exist, then go backwards */ \
/* For the definition of _find_last, if the methods \
PREVIOUS & IT_LAST are defined, then search backwards */ \
M_IF(M_AND(M_TEST_METHOD_P(PREVIOUS, cont_oplist), M_TEST_METHOD_P(IT_LAST, cont_oplist))) \
( \
static inline void M_C(name, _find_last) (it_t it, container_t l, const type_t data) \
static inline void \
M_C(name, _find_last) (it_t it, container_t l, const type_t data) \
{ \
for (M_GET_IT_LAST cont_oplist (it, l); \
!M_GET_IT_END_P cont_oplist (it) ; \
@@ -111,7 +116,8 @@
} \
} \
, \
static inline void M_C(name, _find_last) (it_t it, container_t l, const type_t data) \
static inline void \
M_C(name, _find_last) (it_t it, container_t l, const type_t data) \
{ \
M_GET_IT_END cont_oplist (it, l); \
it_t it2; \
@@ -124,7 +130,8 @@
} \
) /* End of alternative of _find_last */ \
\
static inline size_t M_C(name, _count) (container_t l, const type_t data) \
static inline size_t \
M_C(name, _count) (container_t l, const type_t data) \
{ \
it_t it; \
size_t count = 0; \
@@ -137,43 +144,43 @@
return count; \
} \
\
static inline void M_C(name, _map) (container_t l, \
void (*f)(type_t const) ) \
static inline void \
M_C(name, _map) (container_t l, void (*f)(type_t const) ) \
{ \
for M_EACH(item, l, cont_oplist) { \
f(*item); \
} \
} \
} \
\
static inline void M_C(name, _reduce) (type_t *dest, \
container_t l, \
void (*f)(type_t *, type_t const) ) \
static inline void \
M_C(name, _reduce) (type_t *dest, container_t l, void (*f)(type_t *, type_t const) ) \
{ \
bool initDone = false; \
for M_EACH(item, l, cont_oplist) { \
if (initDone) \
if (initDone) { \
f(dest, *item); \
else { \
} else { \
M_GET_SET type_oplist (*dest, *item); \
initDone = true; \
} \
} \
} \
} \
\
static inline void M_C(name, _map_reduce) (type_t *dest, \
container_t l, \
void (*r)(type_t*, type_t const), \
void (*m)(type_t*, type_t const) ) \
static inline \
void M_C(name, _map_reduce) (type_t *dest, \
container_t l, \
void (*redFunc)(type_t*, type_t const), \
void (*mapFunc)(type_t*, type_t const) ) \
{ \
bool initDone = false; \
type_t tmp; \
M_GET_INIT type_oplist (tmp); \
for M_EACH(item, l, cont_oplist) { \
if (initDone) { \
m(&tmp, *item); \
r(dest, tmp); \
mapFunc(&tmp, *item); \
redFunc(dest, tmp); \
} else { \
m(dest, *item); \
mapFunc(dest, *item); \
initDone = true; \
} \
} \
@@ -181,7 +188,8 @@
} \
\
M_IF_METHOD(CMP, type_oplist)( \
static inline type_t *M_C(name, _min) (const container_t l) \
static inline type_t * \
M_C(name, _min) (const container_t l) \
{ \
type_t *min = NULL; \
for M_EACH(cref, l, cont_oplist) { \
@@ -192,7 +200,8 @@
return min; \
} \
\
static inline type_t *M_C(name, _max) (const container_t l) \
static inline type_t * \
M_C(name, _max) (const container_t l) \
{ \
type_t *max = NULL; \
for M_EACH(cref, l, cont_oplist) { \
@@ -203,8 +212,9 @@
return max; \
} \
\
static inline void M_C(name, _minmax) (type_t **min_p, type_t **max_p, \
const container_t l) \
static inline void \
M_C(name, _minmax) (type_t **min_p, type_t **max_p, \
const container_t l) \
{ \
type_t *min = NULL; \
type_t *max = NULL; \
@@ -220,7 +230,8 @@
*max_p = max; \
} \
\
static inline bool M_C(name, _sort_p)(const container_t l) \
static inline bool \
M_C(name, _sort_p)(const container_t l) \
{ \
it_t it1; \
it_t it2; \
@@ -240,7 +251,8 @@
} \
\
M_IF_METHOD(IT_REMOVE, cont_oplist)( \
static inline void M_C(name, _uniq)(container_t l) \
static inline void \
M_C(name, _uniq)(container_t l) \
{ \
it_t it1; \
it_t it2; \
@@ -261,6 +273,7 @@
} \
,) \
\
\
/* Sort can be generated from 3 algorithms: */ \
/* - a specialized version defined by the container */ \
/* - an insertion sort (need 'previous' method) */ \
@@ -417,6 +430,8 @@
{ \
it_t itSrc; \
it_t itDst; \
assert(M_C(name, _sort_p)(dst)); \
assert(M_C(name, _sort_p)(src)); \
M_GET_IT_FIRST cont_oplist (itSrc, src); \
M_GET_IT_FIRST cont_oplist (itDst, dst); \
while (!M_GET_IT_END_P cont_oplist (itSrc) \
@@ -451,6 +466,8 @@
{ \
it_t itSrc; \
it_t itDst; \
assert(M_C(name, _sort_p)(dst)); \
assert(M_C(name, _sort_p)(src)); \
M_GET_IT_FIRST cont_oplist (itSrc, src); \
M_GET_IT_FIRST cont_oplist (itDst, dst); \
/* TODO: Not optimized at all for array ! O(n^2) */ \
@@ -476,7 +493,6 @@
, /* NO IT_REMOVE */ ), /* NO CMP */) \
//TODO: const_iterator missing...
//TODO: Algorithm missing
// nth_element ( http://softwareengineering.stackexchange.com/questions/284767/kth-selection-routine-floyd-algorithm-489 )
//, average, find_if, count_if, ...
+102 -4
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - dynamic ARRAY module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -378,6 +378,15 @@
ARRAYI_CONTRACT(v); \
} \
\
static inline void \
M_C(name, _pop_until)(array_t v, array_it_t pos) \
{ \
ARRAYI_CONTRACT(v); \
assert (v == pos->array); \
M_ASSUME (pos->index <= v->size); \
M_C(name, _resize)(v, pos->index); \
} \
\
static inline bool \
M_C(name, _empty_p)(const array_t v) \
{ \
@@ -622,14 +631,103 @@
func_void = (int (*)(const void*, const void*))func_type; \
qsort (l->ptr, l->size, sizeof(type), func_void); \
} \
,) /* IF CMP oplist */ \
\
M_IF_METHOD(SWAP, oplist)( \
static inline void \
M_C(name, _special_stable_sort_noalloc) (type tab[], size_t size, type tmp[]) \
{ \
size_t th = 4; \
M_IF_DEBUG(type *org_tab = tab;) \
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) \
th += th; \
\
/* Pass 1: insertion sort (stable) */ \
for(size_t k = 0 ; k < size; ) { \
size_t max = size - k < 2*th ? size - k : th; \
M_ASSUME(max >= th); \
for(size_t i = 1; i < max; i++) { \
size_t j = i; \
while (j > 0 && M_GET_CMP oplist (tab[k+j-1], tab[k+j]) > 0) { \
M_GET_SWAP oplist (tab[k+j-1], tab[k+j]); \
j = j - 1; \
} \
} \
k += max; \
} \
\
/* N Pass of merge */ \
while (th < size) { \
type *dest = tmp; \
/* Pass n: Merge */ \
for(size_t k = 0 ; k < size; ) { \
type *el1 = &tab[k]; \
type *el2 = &tab[k+th]; \
size_t n1 = th; \
size_t n2 = size-k <= 3*th ? size-k-th : th; \
assert (size-k > th); \
assert (0 < n1 && n1 <= size); \
assert (0 < n2 && n2 <= size); \
k += n1+n2; \
for (;;) { \
if (M_GET_CMP oplist (*el1, *el2) <= 0) { \
M_GET_SET oplist (*dest, *el1); \
dest++; \
el1++; \
if (-- n1 == 0) { \
if (n2 > 0) { \
memcpy (dest, el2, n2 * sizeof (type)); \
dest += n2; \
} \
break; \
} \
} else { \
M_GET_SET oplist (*dest, *el2); \
dest++; \
el2++; \
if (-- n2 == 0) { \
if (n1 > 0) { \
memcpy (dest, el1, n1 * sizeof (type)); \
dest += n1; \
} \
break; \
} \
} \
} \
} \
/* Swap t & tab */ \
M_SWAP(type *, tab, tmp); \
/* Increase th for next pass */ \
th += th; \
} \
assert (org_tab == tab); \
} \
\
static inline void \
M_C(name, _special_stable_sort)(array_t l) \
{ \
if (M_UNLIKELY (l->size < 2)) \
return; \
type *temp = M_GET_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); \
} \
,) /* IF SWAP method */ \
\
,) /* IF CMP oplist */ \
\
M_IF_METHOD(GET_STR, oplist)( \
static inline void \
M_C(name, _get_str)(string_t str, array_t array, \
bool append) \
{ \
STRING_CONTRACT(str); \
STRINGI_CONTRACT(str); \
ARRAYI_CONTRACT(array); \
(append ? string_cat_str : string_set_str) (str, "["); \
array_it_t it; \
@@ -642,7 +740,7 @@
string_push_back (str, M_GET_SEPARATOR oplist); \
} \
string_push_back (str, ']'); \
STRING_CONTRACT(str); \
STRINGI_CONTRACT(str); \
} \
, /* no GET_STR */ ) \
\
+2 -2
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Thin stdatomic wrapper for C++ compatibility
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -201,7 +201,7 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
#define atomic_fetch_and(ptr, val) atomic_fetch_op(ptr, val, &=)
#define atomic_exchange(ptr, val) atomic_fetch_op(ptr, val, =)
#define ATOMIC_VAR_INIT(val) { val, 0, 0, 0, M_MUTEXI_INIT_VALUE }
#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)
+6 -6
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - BITSET module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -145,11 +145,11 @@ bitset_set_at(bitset_t v, size_t i, bool x)
{
BITSETI_CONTRACT(v);
assert (i < v->size && v->ptr != NULL);
size_t offset = i / BITSET_LIMB_BIT;
size_t index = i % BITSET_LIMB_BIT;
// This is a branchless version as x can only be 0 or 1.
v->ptr[offset] &= ~(((bitset_limb)1)<<index);
v->ptr[offset] |= ((bitset_limb)x)<<index;
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;
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (-(bitset_limb)x));
BITSETI_CONTRACT (v);
}
+304 -84
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Fixed size BUFFER & STACK interface
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -50,14 +50,14 @@ typedef enum {
BUFFER_DEFERRED_POP = 64
} buffer_policy_e;
/* Define a buffer.
/* Define a lock based buffer.
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_C(name,_t))))
/* Define a queue for Many Producer Many Consummer
/* 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.
*/
@@ -66,19 +66,18 @@ typedef enum {
((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t)), \
(name, type, __VA_ARGS__, M_C(name,_t))))
/* Define a wait-free queue for Single Producer Single Consummer
Much faster than queue of BUFFER_DEF in heavy communication scenario
Size of created queue can only a power of 2.
*/
#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_C(name,_t))))
/********************************** INTERNAL ************************************/
/* Define the exclusion size so that 2 atomic variables can be in
separate cache line. This prevent false sharing to occur within the
CPU cache. */
#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
# define BUFFERI_ALIGN_FOR_CACHELINE_EXCLUSION 128
#else
# define BUFFERI_ALIGN_FOR_CACHELINE_EXCLUSION 64
#endif
#define BUFFERI_IF_CTE_SIZE(m_size) M_IF(M_BOOL(m_size))
#define BUFFERI_SIZE(m_size) BUFFERI_IF_CTE_SIZE(m_size) (m_size, v->size)
@@ -92,8 +91,6 @@ typedef enum {
#define BUFFERI_PROTECTED_CONTRACT(buffer, size) do { \
assert (atomic_load(&buffer->number[0]) <= BUFFERI_SIZE(size)); \
assert (buffer->idx_prod <= BUFFERI_SIZE(size)); \
assert (buffer->idx_cons <= BUFFERI_SIZE(size)); \
} while (0)
#define BUFFERI_DEF(arg) BUFFERI_DEF2 arg
@@ -101,35 +98,38 @@ typedef enum {
#define BUFFERI_DEF2(name, type, m_size, policy, oplist, buffer_t) \
\
typedef struct M_C(name, _s) { \
m_mutex_t mutex; \
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; \
atomic_ulong number[1 + BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)]; \
type *data; \
BUFFERI_IF_CTE_SIZE(m_size)(type data[m_size], type *data); \
} buffer_t[1]; \
\
static inline void \
M_C(name, _init)(buffer_t v, size_t size) \
{ \
assert( size > 0); \
BUFFERI_IF_CTE_SIZE(m_size)(assert(size == m_size), v->size = size); \
v->idx_prod = v->idx_cons = v->overwrite = 0; \
atomic_init (&v->number[0], 0UL); \
if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
atomic_init (&v->number[1], 0UL); \
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
m_mutex_init(v->mutex); \
m_mutex_init(v->mutexPush); \
m_mutex_init(v->mutexPop); \
m_cond_init(v->there_is_data); \
m_cond_init(v->there_is_room_for_data); \
} else \
assert(BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING)); \
v->data = M_GET_REALLOC oplist (type, NULL, BUFFERI_SIZE(m_size)); \
if (v->data == NULL) { \
M_MEMORY_FULL (BUFFERI_SIZE(m_size)*sizeof(type)); \
return; \
} \
BUFFERI_IF_CTE_SIZE(m_size)( , \
v->data = M_GET_REALLOC oplist (type, NULL, BUFFERI_SIZE(m_size)); \
if (v->data == NULL) { \
M_MEMORY_FULL (BUFFERI_SIZE(m_size)*sizeof(type)); \
return; \
} \
) \
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]); \
@@ -167,11 +167,14 @@ M_C(name, _init)(buffer_t v, size_t size) \
{ \
BUFFERI_CONTRACT(v,m_size); \
M_C(name, _int_clear_obj)(v); \
M_GET_FREE oplist (v->data); \
v->data = NULL; \
BUFFERI_IF_CTE_SIZE(m_size)( , \
M_GET_FREE oplist (v->data); \
v->data = NULL; \
) \
v->overwrite = 0; \
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
m_mutex_clear(v->mutex); \
m_mutex_clear(v->mutexPush); \
m_mutex_clear(v->mutexPop); \
m_cond_clear(v->there_is_data); \
m_cond_clear(v->there_is_room_for_data); \
} \
@@ -181,8 +184,10 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_C(name, _clean)(buffer_t v) \
{ \
BUFFERI_CONTRACT(v,m_size); \
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) \
m_mutex_lock(v->mutex); \
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)) \
M_C(name, _int_clear_obj)(v); \
@@ -191,8 +196,9 @@ M_C(name, _init)(buffer_t v, size_t size) \
if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
atomic_store(&v->number[1], 0UL); \
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
m_cond_signal(v->there_is_room_for_data); \
m_mutex_unlock(v->mutex); \
m_cond_broadcast(v->there_is_room_for_data); \
m_mutex_unlock(v->mutexPop); \
m_mutex_unlock(v->mutexPush); \
} \
BUFFERI_CONTRACT(v,m_size); \
} \
@@ -201,6 +207,10 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_C(name, _empty_p)(buffer_t v) \
{ \
BUFFERI_CONTRACT(v,m_size); \
/* If the buffer has been configured with deferred pop \
we considered the queue as empty when the number of \
deferred pop has reached 0, not the number of items in the \
buffer is 0. */ \
if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
return atomic_load (&v->number[1]) == 0; \
else \
@@ -222,63 +232,80 @@ M_C(name, _init)(buffer_t v, size_t size) \
} \
\
static inline bool \
M_C(name, _push)(buffer_t v, type const data) \
M_C(name, _push_blocking)(buffer_t v, type const data, bool blocking) \
{ \
BUFFERI_CONTRACT(v,m_size); \
\
/* BUFFER lock */ \
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
m_mutex_lock(v->mutex); \
m_mutex_lock(v->mutexPush); \
while (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \
&& M_C(name, _full_p)(v)) { \
if (BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING_PUSH)) { \
m_mutex_unlock(v->mutex); \
if (!blocking) { \
m_mutex_unlock(v->mutexPush); \
return false; \
} \
m_cond_wait(v->there_is_room_for_data, v->mutex); \
m_cond_wait(v->there_is_room_for_data, v->mutexPush); \
} \
} else if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \
&& M_C(name, _full_p)(v)) \
return false; \
BUFFERI_PROTECTED_CONTRACT(v, m_size); \
\
size_t previousSize, idx = v->idx_prod; \
/* INDEX computation if we have to overwrite the last element */ \
if (M_UNLIKELY (BUFFERI_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \
&& atomic_load (&v->number[0]) == BUFFERI_SIZE(m_size) )) { \
&& M_C(name, _full_p)(v))) { \
v->overwrite++; \
/* Let's clear the last element to overwrite it */ \
/* Let's overwrite the last element */ \
/* Compute the index of the last push element */ \
idx--; \
if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \
v->idx_prod = (v->idx_prod - 1) % BUFFERI_SIZE(m_size); \
idx = (idx == -1U) ? BUFFERI_SIZE(m_size)-1 : idx; \
} \
/* Update data in the buffer */ \
M_GET_SET oplist (v->data[idx], data); \
previousSize = BUFFERI_SIZE(m_size); \
\
} else { \
\
/* 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); \
} else { \
(v->idx_prod) --; \
M_GET_INIT_SET oplist(v->data[idx], data); \
} \
atomic_store (&v->number[0], atomic_load(&v->number[0]) - 1); \
if (BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) \
atomic_store (&v->number[1], atomic_load(&v->number[1]) - 1); \
if (BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
M_GET_CLEAR oplist(v->data[v->idx_prod]); \
\
/* Increment production INDEX of the buffer */ \
idx++; \
if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \
idx = (idx == BUFFERI_SIZE(m_size)) ? 0 : idx; \
} \
v->idx_prod = idx; \
\
/* number[] is the only variable which can be modified by both \
the consummer thread which has the pop lock and the producer \
thread which has the push lock. As such, it has to be handled \
like an atomic variable. */ \
/* Increment number of elements of the buffer */ \
previousSize = atomic_fetch_add (&v->number[0], 1UL); \
if (BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \
previousSize = atomic_fetch_add (&v->number[1], 1UL); \
} \
} \
\
/* PUSH data */ \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
M_GET_SET oplist (v->data[v->idx_prod], data); \
} else { \
M_GET_INIT_SET oplist(v->data[v->idx_prod], data); \
} \
if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \
v->idx_prod = (v->idx_prod +1) % BUFFERI_SIZE(m_size); \
} else { \
(v->idx_prod) ++; \
} \
atomic_store (&v->number[0], atomic_load(&v->number[0]) + 1); \
if (BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) \
atomic_store (&v->number[1], atomic_load(&v->number[1]) + 1); \
\
/* BUFFER unlock */ \
/* BUFFER unlock */ \
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
m_cond_signal(v->there_is_data); \
m_mutex_unlock(v->mutex); \
m_mutex_unlock(v->mutexPush); \
/* If the number of items in the buffer was 0, some consummer \
may be waiting. Signal to them the availibility of the data \
We cannot only signal one thread. */ \
if (previousSize == 0) { \
m_mutex_lock(v->mutexPop); \
m_cond_broadcast(v->there_is_data); \
m_mutex_unlock(v->mutexPop); \
} \
} \
\
BUFFERI_CONTRACT(v,m_size); \
@@ -286,34 +313,36 @@ M_C(name, _init)(buffer_t v, size_t size) \
} \
\
static inline bool \
M_C(name, _pop)(type *data, buffer_t v) \
M_C(name, _pop_blocking)(type *data, buffer_t v, bool blocking) \
{ \
BUFFERI_CONTRACT(v,m_size); \
assert (data != NULL); \
\
/* BUFFER lock */ \
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
m_mutex_lock(v->mutex); \
m_mutex_lock(v->mutexPop); \
while (M_C(name, _empty_p)(v)) { \
if (BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING_POP)) { \
m_mutex_unlock(v->mutex); \
if (!blocking) { \
m_mutex_unlock(v->mutexPop); \
return false; \
} \
m_cond_wait(v->there_is_data, v->mutex); \
m_cond_wait(v->there_is_data, v->mutexPop); \
} \
} else if (M_C(name, _empty_p)(v)) \
return false; \
BUFFERI_PROTECTED_CONTRACT(v, m_size); \
\
/* POP data */ \
/* POP data from the buffer and update INDEX */ \
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]); \
} else { \
M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_cons]); \
} \
v->idx_cons = (v->idx_cons +1) % BUFFERI_SIZE(m_size); \
v->idx_cons = (v->idx_cons == BUFFERI_SIZE(m_size)-1) ? 0 : (v->idx_cons + 1); \
} else { \
/* 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]); \
@@ -321,20 +350,52 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_prod]); \
} \
} \
if (!BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) \
atomic_store (&v->number[0], atomic_load(&v->number[0]) - 1); \
else \
atomic_store (&v->number[1], atomic_load(&v->number[1]) - 1); \
\
/* number[] is the only variable which can be modified by both \
the consummer thread which has the pop lock and the producer \
thread which has the push lock. As such, it has to be handled \
like an atomic variable. */ \
/* Decrement number of elements in the buffer */ \
size_t previousSize; \
if (!BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \
previousSize = atomic_fetch_sub (&v->number[0], 1UL); \
} else { \
atomic_fetch_sub (&v->number[1], 1UL); \
} \
\
/* BUFFER unlock */ \
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
m_cond_signal(v->there_is_room_for_data); \
m_mutex_unlock(v->mutex); \
m_mutex_unlock(v->mutexPop); \
/* If the number of items in the buffer was the max, some producer \
may be waiting. Signal to them the availibility of the free room \
We cannot only signal one thread. */ \
if ((!BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) \
&& previousSize == BUFFERI_SIZE(m_size)) { \
m_mutex_lock(v->mutexPush); \
m_cond_broadcast(v->there_is_room_for_data); \
m_mutex_unlock(v->mutexPush); \
} \
} \
\
BUFFERI_CONTRACT(v,m_size); \
return true; \
} \
\
\
static inline bool \
M_C(name, _push)(buffer_t v, type const data) \
{ \
return M_C(name, _push_blocking)(v, data, \
!BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING_PUSH)); \
} \
\
static inline bool \
M_C(name, _pop)(type *data, buffer_t v) \
{ \
return M_C(name, _pop_blocking)(data, v, \
!BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING_POP)); \
} \
\
static inline size_t \
M_C(name, _overwrite)(const buffer_t v) \
{ \
@@ -351,8 +412,15 @@ M_C(name, _init)(buffer_t v, size_t size) \
static inline void \
M_C(name, _pop_release)(buffer_t v) \
{ \
if (BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) \
atomic_store (&v->number[0], atomic_load(&v->number[0]) - 1); \
/* Decrement the effective number of elements in the buffer */ \
if (BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \
size_t previousSize = atomic_fetch_sub (&v->number[0], 1UL); \
if (previousSize == BUFFERI_SIZE(m_size)) { \
m_mutex_lock(v->mutexPush); \
m_cond_broadcast(v->there_is_room_for_data); \
m_mutex_unlock(v->mutexPush); \
} \
} \
} \
@@ -369,12 +437,20 @@ M_C(name, _init)(buffer_t v, size_t size) \
*/
#define QUEUEI_MPMC_DEF(arg) QUEUEI_MPMC_DEF2 arg
#define QUEUEI_MPMC_CONTRACT(v) do { \
#ifdef NDEBUG
# define QUEUEI_MPMC_CONTRACT(v) /* nothing */
#else
# define QUEUEI_MPMC_CONTRACT(v) do { \
assert (v != 0); \
assert (v->Tab != NULL); \
/* ProdIdx >= ConsoIdx, but due to atomic constraints, we can't check it reliabely */ \
unsigned long long _r = atomic_load(&v->ConsoIdx); \
unsigned long long _w = atomic_load(&v->ProdIdx); \
assert (_r <= _w); \
_r = atomic_load(&v->ConsoIdx); \
assert (_r > _w || _w-_r <= v->size); \
assert (M_POWEROF2_P(v->size)); \
} while (0)
#endif
#define QUEUEI_MPMC_DEF2(name, type, policy, oplist, buffer_t) \
\
@@ -385,14 +461,14 @@ M_C(name, _init)(buffer_t v, size_t size) \
typedef struct M_C(name, _el_s) { \
atomic_ullong seq; /* Can only increase. */ \
type x; \
char align[BUFFERI_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(atomic_ullong)+sizeof(type) ? BUFFERI_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(atomic_ullong)-sizeof(type) : 1]; \
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(atomic_ullong)+sizeof(type) ? M_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(atomic_ullong)-sizeof(type) : 1]; \
} M_C(name, _el_t); \
\
typedef struct M_C(name, _s) { \
atomic_ullong ProdIdx; /* Can only increase */ \
char align1[BUFFERI_ALIGN_FOR_CACHELINE_EXCLUSION]; \
char align1[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
atomic_ullong ConsoIdx; /* can only increase */ \
char align2[BUFFERI_ALIGN_FOR_CACHELINE_EXCLUSION]; \
char align2[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
M_C(name, _el_t) *Tab; \
unsigned int size; \
} buffer_t[1]; \
@@ -426,6 +502,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
M_C(name, _pop)(type *ptr, buffer_t table) \
{ \
QUEUEI_MPMC_CONTRACT(table); \
assert (ptr != NULL); \
unsigned long long iC = atomic_load(&table->ConsoIdx); \
const unsigned int i = (iC & (table->size -1)); \
const unsigned long long seq = atomic_load(&table->Tab[i].seq); \
@@ -512,19 +589,162 @@ M_C(name, _init)(buffer_t v, size_t size) \
static inline bool \
M_C(name, _empty_p)(buffer_t v) \
{ \
QUEUEI_MPMC_CONTRACT(v); \
return M_C(name, _size) (v) == 0; \
} \
\
static inline bool \
M_C(name, _full_p)(buffer_t v) \
{ \
QUEUEI_MPMC_CONTRACT(v); \
return M_C(name, _size)(v) == v->size; \
} \
/* Definition of a a QUEUE for Single Produccer / Single Consummer
for high bandwidth scenario:
* wait-free,
* quite fast
* no blocking calls.
* only queue (no stack)
* size of queue is always a power of 2
* no overwriting.
*/
#define QUEUEI_SPSC_DEF(arg) QUEUEI_SPSC_DEF2 arg
#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); \
_r = atomic_load(&table->consoIdx); \
assert (_r > _w || _w-_r <= table->size); \
assert (M_POWEROF2_P(table->size)); \
} while (0)
#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; \
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; \
} 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) \
return false; \
size_t i = w & (table->size -1); \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
M_GET_SET oplist (table->Tab[i].x, x); \
} else { \
M_GET_INIT_SET oplist (table->Tab[i].x, x); \
} \
atomic_store(&table->prodIdx, w+1); \
QUEUEI_SPSC_CONTRACT(table); \
return true; \
} \
\
static inline bool \
M_C(name, _pop)(type *ptr, buffer_t table) \
{ \
QUEUEI_SPSC_CONTRACT(table); \
assert (ptr != NULL); \
unsigned long long w = atomic_load(&table->prodIdx); \
unsigned long long r = atomic_load(&table->consoIdx); \
if (w-r == 0) \
return false; \
size_t i = r & (table->size -1); \
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
M_GET_SET oplist (*ptr , table->Tab[i].x); \
} else { \
M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \
} \
atomic_store(&table->consoIdx, r+1); \
QUEUEI_SPSC_CONTRACT(table); \
return true; \
} \
\
static inline size_t \
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); \
return w-r; \
} \
\
static inline bool \
M_C(name, _empty_p)(buffer_t v) \
{ \
return M_C(name, _size) (v) == 0; \
} \
\
static inline bool \
M_C(name, _full_p)(buffer_t v) \
{ \
return M_C(name, _size)(v) == v->size; \
} \
\
static inline void \
M_C(name, _init)(buffer_t buffer, size_t size) \
{ \
assert (buffer != NULL); \
assert( M_POWEROF2_P(size)); \
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); \
buffer->size = size; \
buffer->Tab = M_GET_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); \
} \
} \
QUEUEI_SPSC_CONTRACT(buffer); \
} \
\
static inline void \
M_C(name, _clear)(buffer_t buffer) \
{ \
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); \
} \
} else { \
unsigned long long iP = atomic_load(&buffer->prodIdx); \
unsigned int i = iP & (buffer->size -1); \
unsigned long long iC = atomic_load(&buffer->consoIdx); \
unsigned int j = iC & (buffer->size -1); \
while (i != j) { \
M_GET_CLEAR oplist(buffer->Tab[j].x); \
j++; \
if (j >= buffer->size) \
j = 0; \
} \
} \
M_GET_FREE oplist (buffer->Tab); \
buffer->Tab = NULL; /* safer */ \
} \
\
// NOTE: SET & INIT_SET are deliberatly missing. TBC if it the right way.
// NOTE: There is no oplist defined for this container.
+46 -13
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Extended Pre-processing macros module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -42,7 +42,7 @@
#if !defined(NDEBUG)
# define M_ASSUME(x) assert(x)
#elif defined(__GNUC__) \
&& (__GNUC__ * 100 + __GNUC_MINOR__) >= 480
&& (__GNUC__ * 100 + __GNUC_MINOR__) >= 408
# define M_ASSUME(x) \
(! __builtin_constant_p (!!(x) || !(x)) || (x) ? \
(void) 0 : __builtin_unreachable())
@@ -62,6 +62,14 @@
# define M_UNLIKELY(cond) (cond)
#endif
/* Define the exclusion size so that 2 atomic variables can be in
separate cache line. This prevents false sharing to occur within the
CPU cache. */
#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
# define M_ALIGN_FOR_CACHELINE_EXCLUSION 128
#else
# define M_ALIGN_FOR_CACHELINE_EXCLUSION 64
#endif
/***************************************************************/
/****************** Preprocessing Times Macro ******************/
@@ -967,6 +975,19 @@
#define M_IF_DEFAULT1(value, ...) \
__VA_ARGS__ M_IF_NARGS_EQ1(__VA_ARGS__)(M_DEFERRED_COMMA value, )
/* Helper macro to redefine a function with a default values:
Give the number of expected arguments, the value list of the
default argument, and the arguments.
It will complete the arguments with the value of the default
argument to complete up to 'expected' arguments.
Example:
#define f(...) f(M_DEFAULT_ARGS(4, (0, 1, NULL), __VA_ARGS__))
*/
#define M_DEFAULT_ARGS2(expected, value, ...) \
__VA_ARGS__ M_IF(M_NOTEQUAL(M_NARGS(__VA_ARGS__), expected))(M_DEFERRED_COMMA, ) \
M_ID M_INVERT(M_KEEP(M_SUB(expected, M_NARGS(__VA_ARGS__)), M_ID M_INVERT value))
#define M_DEFAULT_ARGS_EVAL(...) __VA_ARGS__
#define M_DEFAULT_ARGS( ...) M_DEFAULT_ARGS_EVAL(M_DEFAULT_ARGS2(__VA_ARGS__))
/* NOTEQUAL(val1,val2) with val from [0 to 30[
Return 1 or 0 if val1=val2
@@ -1142,9 +1163,9 @@
/* Swap two types */
#define M_SWAP(type, x, y) do { \
type tmp = (x); \
(x) = (y); \
(y) = tmp; \
type _tmp = (x); \
(x) = (y); \
(y) = _tmp; \
} while (0)
/* Check if 'n' is assignable to an object of type 'type'.
@@ -1181,6 +1202,8 @@
#define M_TYPE_FROM_FIELD(type, ptr, field_type, field) \
((type *)(void*)( (char *)M_ASSIGN_CAST(field_type*, (ptr)) - offsetof(type, field) ))
#define M_CTYPE_FROM_FIELD(type, ptr, field_type, field) \
((const type *)(const void*)( (const char *)M_ASSIGN_CAST(const field_type*, (ptr)) - offsetof(const type, field) ))
/************************************************************/
@@ -1427,6 +1450,8 @@ m_core_hash (const void *str, size_t length)
#define M_SUBTYPE_SUBTYPE(a) ,a,
#define M_OPLIST_OPLIST(a) ,a,
#define M_SORT_SORT(a) ,a,
#define M_GET_KEY_GET_KEY(a) ,a,
#define M_SET_KEY_SET_KEY(a) ,a,
#define M_UPDATE_UPDATE(a) ,a,
#define M_IT_TYPE_IT_TYPE(a) ,a,
#define M_IT_FIRST_IT_FIRST(a) ,a,
@@ -1490,6 +1515,8 @@ m_core_hash (const void *str, size_t length)
#define M_GET_SUBTYPE(...) M_GET_METHOD(SUBTYPE, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_OPLIST(...) M_GET_METHOD(OPLIST, (), __VA_ARGS__)
#define M_GET_SORT(...) M_GET_METHOD(SORT, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_GET_KEY(...) M_GET_METHOD(GET_KEY, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_SET_KEY(...) M_GET_METHOD(SET_KEY, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_IT_TYPE(...) M_GET_METHOD(IT_TYPE, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_IT_FIRST(...) M_GET_METHOD(IT_FIRST, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_IT_LAST(...) M_GET_METHOD(IT_LAST, M_NO_DEFAULT, __VA_ARGS__)
@@ -1549,22 +1576,28 @@ m_core_hash (const void *str, size_t length)
#define M_MEMSET_DEFAULT(a) (memset(&(a), 0, sizeof (a)))
#define M_MEMCMP1_DEFAULT(a,b) (memcmp(&(a), &(b), sizeof (a)) == 0)
#define M_MEMCMP2_DEFAULT(a,b) (memcmp(&(a), &(b), sizeof (a)))
#define M_SWAP_DEFAULT(el1, el2) do { \
char _tmp[sizeof (el1)]; \
memcpy(&_tmp, &(el1), sizeof (el1)); \
memcpy(&(el1), &(el2), sizeof (el1)); \
memcpy(&(el2), &_tmp, sizeof (el1)); \
} while (0)
/* NOTE: Theses operators are to be used with the '[1]' tricks
if the variable is defined as a parameter of a function
(sizeof (a) is not portable). */
#define M_MOVE_A1_DEFAULT(a,b) (M_MEMCPY_A1_DEFAULT(a, b), M_MEMSET_A1_DEFAULT(b))
#define M_MEMCPY_A1_DEFAULT(a,b) (memcpy(&(a), &(b), sizeof (a[0])))
#define M_MEMSET_A1_DEFAULT(a) (memset(&(a), 0, sizeof (a[0])))
#define M_MEMCMP1_A1_DEFAULT(a,b) (memcmp(&(a), &(b), sizeof (a[0])) == 0)
#define M_MEMCMP2_A1_DEFAULT(a,b) (memcmp(&(a), &(b), sizeof (a[0])))
#define M_HASH_A1_DEFAULT(a) (m_core_hash((const void*) &(a), sizeof (a[0])) )
#define M_MEMCPY_A1_DEFAULT(a,b) (memcpy(&(a[0]), &(b[0]), sizeof (a[0])))
#define M_MEMSET_A1_DEFAULT(a) (memset(&(a[0]), 0, sizeof (a[0])))
#define M_MEMCMP1_A1_DEFAULT(a,b) (memcmp(&(a[0]), &(b[0]), sizeof (a[0])) == 0)
#define M_MEMCMP2_A1_DEFAULT(a,b) (memcmp(&(a[0]), &(b[0]), sizeof (a[0])))
#define M_HASH_A1_DEFAULT(a) (m_core_hash((const void*) &(a[0]), sizeof (a[0])) )
/* Default oplist for plain structure */
#define M_POD_OPLIST \
(INIT(M_MEMSET_DEFAULT), INIT_SET(M_MEMCPY_DEFAULT), SET(M_MEMCPY_DEFAULT), \
CLEAR(M_NOTHING_DEFAULT), EQUAL(M_MEMCMP1_DEFAULT), CMP(M_MEMCMP2_DEFAULT), \
HASH(M_HASH_DEFAULT))
HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT))
/* Default oplist for a structure defined with an array of size 1 */
#define M_A1_OPLIST \
@@ -1577,7 +1610,7 @@ m_core_hash (const void *str, size_t length)
(INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \
CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \
INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \
HASH(M_HASH_DEFAULT) )
HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT) )
#define M_CLASSIC_OPLIST(name) ( \
INIT(M_C(name, _init)), \
@@ -1688,7 +1721,7 @@ m_core_hash (const void *str, size_t length)
/* Check if a a symbol composed of M_OPL_##a() is defined as an oplist, and returns it
otherwise return M_DEFAULT_OPLIST.
In short, if a global oplist is defined for the argument, it returns it
otherwise it returns the argument.
otherwise it returns the default oplist.
Global oplist is limited to typedef types.
*/
#define M_GLOBAL_OPLIST_OR_DEF(a) \
+69 -38
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - DEQUE module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -46,6 +46,14 @@
#define DEQUEUI_DEFAULT_SIZE 8
/* C++ doesn't support flexible array within a structure.
Let's define at least one element. */
#ifdef __cplusplus
# define DEQUEI_MIN_ARRAY_SIZE 1
#else
# define DEQUEI_MIN_ARRAY_SIZE
#endif
#define DEQUEI_CONTRACT(d) do { \
assert ((d) != NULL); \
assert ((d)->default_size >= DEQUEUI_DEFAULT_SIZE); \
@@ -66,7 +74,7 @@
typedef struct M_C(name, _node_s) { \
ILIST_INTERFACE(M_C(name, _node_list), struct M_C(name, _node_s)); \
size_t size; \
type data[]; \
type data[DEQUEI_MIN_ARRAY_SIZE]; \
} node_t; \
\
ILIST_DEF(M_C(name, _node_list), node_t, (DEL(M_GET_FREE oplist)) ) \
@@ -92,23 +100,25 @@
\
typedef type M_C(name, _type_t); \
\
static inline deque_node_t* \
static inline M_C(name, _node_t)* \
M_C(name, _int_new_node)(deque_t d) \
{ \
const size_t def = d->default_size; \
if (M_UNLIKELY (def >SIZE_MAX / sizeof (type) - sizeof(deque_node_t))) { \
M_MEMORY_FULL(sizeof(deque_node_t)+def * sizeof(type)); \
size_t def = d->default_size; \
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; \
} \
deque_node_t*n = (deque_node_t*) (void*) \
M_C(name, _node_t)*n = (M_C(name, _node_t)*) (void*) \
M_GET_REALLOC oplist (char, NULL, \
sizeof(deque_node_t)+def * sizeof(type) ); \
sizeof(M_C(name, _node_t)) + def * sizeof(type) ); \
if (n==NULL) { \
M_MEMORY_FULL(sizeof(deque_node_t)+def * sizeof(type)); \
M_MEMORY_FULL(sizeof(M_C(name, _node_t))+def * sizeof(type)); \
return NULL; \
} \
n->size = def; \
deque_node_list_init_field(n); \
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); \
return n; \
} \
@@ -119,9 +129,9 @@
M_C(name, _node_list_init)(d->list); \
d->default_size = DEQUEUI_DEFAULT_SIZE; \
d->count = 0; \
deque_node_t *n = M_C(name, _int_new_node)(d); \
M_C(name, _node_t) *n = M_C(name, _int_new_node)(d); \
if (n == NULL) return; \
deque_node_list_push_back(d->list, n); \
M_C(name, _node_list_push_back)(d->list, n); \
d->front->node = n; \
d->front->index = DEQUEUI_DEFAULT_SIZE/2; \
d->back->node = n; \
@@ -134,11 +144,11 @@
{ \
DEQUEI_CONTRACT(d); \
M_C(name, _node_list_it_t) it; \
deque_node_t *min_node = NULL; \
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) ){ \
deque_node_t *n = M_C(name, _node_list_ref)(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(size_t i = min; i < max; i++) { \
@@ -172,7 +182,7 @@
M_C(name, _push_back_raw)(deque_t d) \
{ \
DEQUEI_CONTRACT(d); \
deque_node_t *n = d->back->node; \
M_C(name, _node_t) *n = d->back->node; \
size_t index = d->back->index; \
if (M_UNLIKELY (n->size <= index)) { \
n = M_C(name, _node_list_next_obj)(d->list, n); \
@@ -215,7 +225,7 @@
M_C(name, _push_front_raw)(deque_t d) \
{ \
DEQUEI_CONTRACT(d); \
deque_node_t *n = d->front->node; \
M_C(name, _node_t) *n = d->front->node; \
size_t index = d->front->index; \
index --; \
/* If overflow */ \
@@ -260,11 +270,20 @@
{ \
DEQUEI_CONTRACT(d); \
assert(d->count > 0); \
deque_node_t *n = d->back->node; \
M_C(name, _node_t) *n = d->back->node; \
size_t index = d->back->index; \
index --; \
if (M_UNLIKELY (n->size <= index)) { \
n = deque_node_list_previous_obj(d->list, n); \
/* If there is a next node, \
pop the back node and push it back to the front. This \
reduce the used memory if the deque is used as a FIFO queue.*/ \
M_C(name, _node_t) *next = M_C(name, _node_list_next_obj)(d->list, n); \
if (next != NULL) { \
next = M_C(name, _node_list_pop_back)(d->list); \
assert (next != n); \
M_C(name, _node_list_push_front)(d->list, next); \
} \
n = M_C(name, _node_list_previous_obj)(d->list, n); \
assert (n != NULL); \
d->back->node = n; \
index = n->size-1; \
@@ -286,10 +305,19 @@
{ \
DEQUEI_CONTRACT(d); \
assert(d->count > 0); \
deque_node_t *n = d->front->node; \
M_C(name, _node_t) *n = d->front->node; \
size_t index = d->front->index; \
if (M_UNLIKELY (n->size <= index)) { \
n = deque_node_list_next_obj(d->list, n); \
/* If there is a previous node, \
pop the front node and push it back to the back. This \
reduce the used memory if the deque is used as a FIFO queue.*/ \
M_C(name,_node_t) *prev = M_C(name, _node_list_previous_obj)(d->list, n); \
if (prev != NULL) { \
prev = M_C(name, _node_list_pop_front)(d->list); \
assert (prev != n); \
M_C(name, _node_list_push_back)(d->list, prev); \
} \
n = M_C(name, _node_list_next_obj)(d->list, n); \
assert (n != NULL); \
d->front->node = n; \
index = 0; \
@@ -312,9 +340,9 @@
DEQUEI_CONTRACT(d); \
assert (d->count > 0); \
size_t i = d->back->index; \
deque_node_t *n = d->back->node; \
M_C(name, _node_t) *n = d->back->node; \
if (M_UNLIKELY (i == 0)) { \
n = deque_node_list_previous_obj(d->list, n); \
n = M_C(name, _node_list_previous_obj)(d->list, n); \
assert (n != NULL); \
i = n->size; \
} \
@@ -327,9 +355,9 @@
DEQUEI_CONTRACT(d); \
assert (d->count > 0); \
size_t i = d->front->index; \
deque_node_t *n = d->front->node; \
M_C(name, _node_t) *n = d->front->node; \
if (M_UNLIKELY (n->size <= i)) { \
n = deque_node_list_next_obj(d->list, n); \
n = M_C(name, _node_list_next_obj)(d->list, n); \
assert (n != NULL); \
i = 0; \
} \
@@ -369,7 +397,7 @@
it->index = d->back->index - 1; \
it->deque = d; \
if (M_UNLIKELY (it->index >= it->node->size)) { \
it->node = deque_node_list_previous_obj(d->list, it->node); \
it->node = M_C(name, _node_list_previous_obj)(d->list, it->node); \
assert (it->node != NULL); \
it->index = it->node->size-1; \
} \
@@ -409,10 +437,10 @@
M_C(name, _next)(it_t it) \
{ \
assert (it != NULL); \
deque_node_t *n = it->node; \
M_C(name, _node_t) *n = it->node; \
it->index ++; \
if (M_UNLIKELY (it->index >= n->size)) { \
n = deque_node_list_next_obj(it->deque->list, n); \
n = M_C(name, _node_list_next_obj)(it->deque->list, n); \
if (M_UNLIKELY (n == NULL)) { \
/* Point to 'end' (can't undo it) */ \
it->node = it->deque->back->node; \
@@ -428,10 +456,10 @@
M_C(name, _previous)(it_t it) \
{ \
assert (it != NULL); \
deque_node_t *n = it->node; \
M_C(name, _node_t) *n = it->node; \
it->index --; \
if (M_UNLIKELY (it->index >= n->size)) { \
n = deque_node_list_previous_obj(it->deque->list, n); \
n = M_C(name, _node_list_previous_obj)(it->deque->list, n); \
if (M_UNLIKELY (n == NULL)) { \
/* Point to 'end' (can't undo it) */ \
it->node = it->deque->back->node; \
@@ -487,10 +515,10 @@
M_C(name, _node_list_init)(d->list); \
d->default_size = DEQUEUI_DEFAULT_SIZE + src->count; \
d->count = src->count; \
deque_node_t *n = M_C(name, _int_new_node)(d); \
M_C(name, _node_t) *n = M_C(name, _int_new_node)(d); \
if (n == NULL) return; \
d->default_size /= 2; \
deque_node_list_push_back(d->list, n); \
M_C(name, _node_list_push_back)(d->list, n); \
d->front->node = n; \
d->front->index = DEQUEUI_DEFAULT_SIZE/2; \
d->back->node = n; \
@@ -541,7 +569,7 @@
{ \
DEQUEI_CONTRACT(d); \
DEQUEI_CONTRACT(e); \
deque_node_list_swap (d->list, e->list); \
M_C(name, _node_list_swap) (d->list, e->list); \
M_SWAP(node_t *, d->front->node, e->front->node); \
M_SWAP(node_t *, d->back->node, e->back->node); \
M_SWAP(size_t, d->front->index, e->front->index); \
@@ -564,7 +592,7 @@
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) ){ \
deque_node_t *n = M_C(name, _node_list_ref)(it); \
M_C(name, _node_t) *n = M_C(name, _node_list_ref)(it); \
if (index0 + key < count + n->size) { \
return &n->data[index0 + key - count]; \
} \
@@ -645,7 +673,7 @@
static inline void \
M_C(name, _get_str)(string_t str, deque_t deque, bool append) \
{ \
STRING_CONTRACT(str); \
STRINGI_CONTRACT(str); \
DEQUEI_CONTRACT(deque); \
(append ? string_cat_str : string_set_str) (str, "["); \
it_t it; \
@@ -658,7 +686,7 @@
string_push_back (str, M_GET_SEPARATOR oplist); \
} \
string_push_back (str, ']'); \
STRING_CONTRACT(str); \
STRINGI_CONTRACT(str); \
} \
, /* no GET_STR */ ) \
\
@@ -669,10 +697,13 @@
DEQUEI_CONTRACT(deque); \
assert (file != NULL); \
fputc ('[', file); \
for (size_t i = 0; i < deque->size; i++) { \
const type *item = M_C(name, _cget)(deque, i); \
it_t it; \
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); \
if (i != deque->size-1) \
if (!M_C(name, _last_p)(it)) \
fputc (M_GET_SEPARATOR oplist, file); \
} \
fputc (']', file); \
+46 -15
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - DICTIONARY Module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -49,9 +49,32 @@
ARRAY_DEF(M_C(name, _array_list_pair), M_C(name, _list_pair_t), \
LIST_OPLIST(M_C(name, _list_pair), TUPLE_OPLIST(M_C(name, _pair), key_oplist, value_oplist))) \
\
DICTI_FUNC_DEF2(name, key_type, key_oplist, value_type, value_oplist, 0, M_C(name, _t), M_C(name, _it_t))
DICTI_FUNC_DEF2(name, key_type, key_oplist, value_type, value_oplist, 0, 0, M_C(name, _t), M_C(name, _it_t))
/* Define a dictionary with the key key_type to the value value_type.
which stores the computed hash value (avoiding the need of recomputing it).
USAGE: DICT_STOREHASH_DEF2(name, key_type, key_oplist, value_type, value_oplist)
*/
#define DICT_STOREHASH_DEF2(name, key_type, key_oplist, value_type, value_oplist) \
\
TUPLE_DEF2(M_C(name, _pair), (hash, size_t, M_DEFAULT_OPLIST), (key, key_type, key_oplist), (value, value_type, value_oplist)) \
\
M_IF_METHOD(MEMPOOL, key_oplist) \
( \
LIST_DEF(M_C(name, _list_pair), M_C(name, _pair_t), \
M_OPEXTEND(TUPLE_OPLIST(M_C(name, _pair), key_oplist, value_oplist), \
MEMPOOL(M_GET_MEMPOOL key_oplist), MEMPOOL_LINKAGE(M_GET_MEMPOOL_LINKAGE key_oplist))) \
, \
LIST_DEF(M_C(name, _list_pair), M_C(name, _pair_t), \
TUPLE_OPLIST(M_C(name, _pair), M_DEFAULT_OPLIST, key_oplist, value_oplist)) \
) \
\
ARRAY_DEF(M_C(name, _array_list_pair), M_C(name, _list_pair_t), \
LIST_OPLIST(M_C(name, _list_pair), TUPLE_OPLIST(M_C(name, _pair), M_DEFAULT_OPLIST, key_oplist, value_oplist))) \
\
DICTI_FUNC_DEF2(name, key_type, key_oplist, value_type, value_oplist, 0, 1, M_C(name, _t), M_C(name, _it_t))
/* Define the oplist of a dictionnary.
USAGE: DICT_OPLIST(name[, oplist of the key type, oplist of the value type]) */
#define DICT_OPLIST(...) \
@@ -82,7 +105,7 @@
DICTI_FUNC_DEF2(name, key_type, key_oplist, key_type, \
(INIT(M_EMPTY_DEFAULT), INIT_SET(M_EMPTY_DEFAULT), SET(M_EMPTY_DEFAULT), CLEAR(M_EMPTY_DEFAULT), \
EQUAL(M_EMPTY_DEFAULT), GET_STR(M_EMPTY_DEFAULT), OUT_STR(M_EMPTY_DEFAULT), IN_STR(M_TRUE_DEFAULT)), \
1, M_C(name, _t), M_C(name, _it_t))
1, 0, M_C(name, _t), M_C(name, _it_t))
/* Define the oplist of a dictionnary.
@@ -105,7 +128,7 @@
/********************************** INTERNAL ************************************/
/* Define a chained dictionnary */
#define DICTI_FUNC_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, dict_t, dict_it_t) \
#define DICTI_FUNC_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, isStoreHash, dict_t, dict_it_t) \
\
typedef struct M_C(name, _s) { \
size_t used, lower_limit, upper_limit; \
@@ -218,14 +241,15 @@
{ \
DICTI_CONTRACT(name, map); \
size_t hash = M_GET_HASH key_oplist (key); \
hash = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \
size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \
const M_C(name, _list_pair_t) *list_ptr = \
M_C(name, _array_list_pair_cget)(map->table, hash); \
M_C(name, _array_list_pair_cget)(map->table, i); \
M_C(name, _list_pair_it_t) it; \
for(M_C(name, _list_pair_it)(it, *list_ptr); \
!M_C(name, _list_pair_end_p)(it); \
M_C(name, _list_pair_next)(it)) { \
M_C(name, _pair_t) *ref = M_C(name, _list_pair_ref)(it); \
M_IF(isStoreHash)(if ((*ref)->hash != hash) { continue; }, ) \
if (M_GET_EQUAL key_oplist ((*ref)->key, key)) \
return &(*ref)->M_IF(isSet)(key, value); \
} \
@@ -253,7 +277,7 @@
M_C(name, _list_pair_it)(it, *list); \
while (!M_C(name, _list_pair_end_p)(it)) { \
M_C(name, _pair_ptr) pair = *M_C(name, _list_pair_ref)(it); \
size_t hash = M_GET_HASH key_oplist (pair->key); \
size_t hash = M_IF(isStoreHash)(pair->hash, M_GET_HASH key_oplist (pair->key)); \
if ((hash & (new_size-1)) >= old_size) { \
assert( (hash & (new_size-1)) == (i + old_size)); \
M_C(name, _list_pair_t) *new_list = \
@@ -300,21 +324,24 @@
DICTI_CONTRACT(name, map); \
\
size_t hash = M_GET_HASH key_oplist(key); \
hash = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \
size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \
M_C(name, _list_pair_t) *list_ptr = \
M_C(name, _array_list_pair_get)(map->table, hash); \
M_C(name, _array_list_pair_get)(map->table, i); \
M_C(name, _list_pair_it_t) it; \
for(M_C(name, _list_pair_it)(it, *list_ptr); \
!M_C(name, _list_pair_end_p)(it); \
M_C(name, _list_pair_next)(it)) { \
M_C(name, _pair_ptr) ref = *M_C(name, _list_pair_ref)(it); \
M_IF(isStoreHash)(if (ref->hash != hash) continue;, ) \
if (M_GET_EQUAL key_oplist(ref->key, key)) { \
M_GET_SET value_oplist(ref->value, value); \
return; \
} \
} \
M_C(name, _pair_init_set2)(*M_C(name, _list_pair_push_raw)(*list_ptr), \
key M_IF(isSet)(, M_DEFERRED_COMMA value)); \
M_IF(isStoreHash)(hash M_DEFERRED_COMMA,) \
key \
M_IF(isSet)(, M_DEFERRED_COMMA value)); \
map->used ++; \
if (M_UNLIKELY (map->used > map->upper_limit) ) \
M_C(name,_int_resize_up)(map); \
@@ -328,14 +355,15 @@
\
bool ret = false; \
size_t hash = M_GET_HASH key_oplist(key); \
hash = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \
size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \
M_C(name, _list_pair_t) *list_ptr = \
M_C(name, _array_list_pair_get)(map->table, hash); \
M_C(name, _array_list_pair_get)(map->table, i); \
M_C(name, _list_pair_it_t) it; \
for(M_C(name, _list_pair_it)(it, *list_ptr); \
!M_C(name, _list_pair_end_p)(it); \
M_C(name, _list_pair_next)(it)) { \
M_C(name, _pair_ptr) ref = *M_C(name, _list_pair_ref)(it); \
M_IF(isStoreHash)(if (ref->hash != hash) continue;, ) \
if (M_GET_EQUAL key_oplist(ref->key, key)) { \
M_C(name, _list_pair_remove)(*list_ptr, it); \
map->used --; \
@@ -469,14 +497,14 @@
static inline void \
M_C(name, _get_str)(string_t str, dict_t dict, const bool append) \
{ \
STRING_CONTRACT (str); \
STRINGI_CONTRACT (str); \
DICTI_CONTRACT(name, dict); \
(append ? string_cat_str : string_set_str) (str, "{"); \
dict_it_t it; \
for (M_C(name, _it)(it, dict) ; \
!M_C(name, _end_p)(it); \
M_C(name, _next)(it)){ \
const struct M_C(name, _pair_s) *item = \
const struct M_C(name, _pair_s) *item = \
M_C(name, _cref)(it); \
M_GET_GET_STR key_oplist (str, item->key, true); \
string_push_back (str, ':'); \
@@ -485,7 +513,7 @@
string_push_back (str, ','); \
} \
string_push_back (str, '}'); \
STRING_CONTRACT(str); \
STRINGI_CONTRACT(str); \
} \
, /* no GET_STR */ ) \
\
@@ -583,7 +611,10 @@
#define DICTI_INITIAL_SIZE 16
#define DICTI_CONTRACT(name, map) do { \
assert(map != NULL); \
assert(map->used <= map->upper_limit); \
assert(map->upper_limit >= DICTI_UPPER_BOUND(DICTI_INITIAL_SIZE)); \
assert(map->used >= map->lower_limit); \
assert(M_POWEROF2_P(M_C(name, _array_list_pair_size)(map->table))); \
} while (0)
+128 -44
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - GENINT module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -31,43 +31,72 @@
/* GENINT is a container of integers with the following properties:
- it stores integer from [0..N) (N is fixed).
- an integer can have only one occurence in the container
(makeing the container a kind of permutation of [0..N) )
- you can atomically push in / pop out integer from this container.
- an integer can have only one occurrence in the container.
- you can atomically push in / pop out integer from this container
provided that they were not already in the container.
- there are no order (like FIFO or stack)
This can be used to map integers to index of ressources in a table.
This can be used to map integers to index of resources in a table.
At most we can support N = GENINT_LIMBSIZE * GENINT_LIMBSIZE >= 4096
due to the master trick. For the typical usage of this container
(mapping hardware or software limited resources), this should be
enough.
*/
typedef unsigned long genint_limb_t;
// TO DO: We may want a specialization with constant N value.
// Define the limb size
typedef unsigned long long genint_limb_t;
typedef struct genint_s {
size_t n;
atomic_ulong *data;
unsigned int n; // size of the container
unsigned int max; // number of allocated limb - 1
genint_limb_t mask0; // mask of the last limb
genint_limb_t mask_master; // mask of master
atomic_ullong master; // master bitfield (which informs if a limb is full or not)
atomic_ullong *data; // the bitfield which informs if an integer
} genint_t[1];
#define GENINT_LIMBSIZE (sizeof(genint_limb_t) * CHAR_BIT)
#define GENINT_CONTRACT(s) do { \
assert (s != NULL); \
assert (s->n > 0); \
assert (s->data != NULL); \
#define GENINT_CONTRACT(s) do { \
assert (s != NULL); \
assert (s->n > 0 && s->n <= GENINT_LIMBSIZE * GENINT_LIMBSIZE); \
assert ((s->max+1) * GENINT_LIMBSIZE >= s->n); \
assert (s->data != NULL); \
} while (0)
#define GENINT_ONE ((genint_limb_t)1)
#define GENINT_ONE ((genint_limb_t)1)
#define GENINT_ABA_CPT 32
#define GENINT_ABA_CPT_T uint32_t
#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)))
#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)
{
assert (s != NULL && n > 0);
assert (s != NULL && n > 0 && n <= GENINT_LIMBSIZE * (GENINT_LIMBSIZE - GENINT_ABA_CPT));
const size_t alloc = (n + GENINT_LIMBSIZE - 1) / GENINT_LIMBSIZE;
atomic_ulong *ptr = M_MEMORY_REALLOC (atomic_ulong, NULL, alloc);
s->n = n;
s->data = ptr;
const size_t index = n % GENINT_LIMBSIZE;
atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, alloc);
if (M_UNLIKELY (ptr == NULL)) {
M_MEMORY_FULL(alloc);
return;
}
s->n = n;
s->data = ptr;
s->max = alloc-1;
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++)
atomic_init(&s->data[i], 0UL);
atomic_init(&s->data[i], (genint_limb_t)0);
GENINT_CONTRACT(s);
}
@@ -78,47 +107,102 @@ static inline void genint_clear(genint_t s)
s->data = NULL;
}
static inline size_t genint_size(genint_t s)
{
GENINT_CONTRACT(s);
return s->n;
}
// Typical case: one CAS per pop.
static inline size_t genint_pop(genint_t s)
{
GENINT_CONTRACT(s);
const size_t max = (s->n + GENINT_LIMBSIZE - 1) / GENINT_LIMBSIZE;
const size_t index = s->n % GENINT_LIMBSIZE;
const genint_limb_t mask0 = (index == 0) ? -GENINT_ONE : (GENINT_ONE<<index)-1;
// O(n) approach, but with a really low constant factor
for(size_t i = 0; i < max; i++)
{
const size_t mask = (i+1 == max) ? mask0 : -GENINT_ONE;
unsigned int bit;
genint_limb_t next, org = atomic_load(&s->data[i]);
do {
if (org == mask)
goto next_element;
// At least one bit is free in the limb
bit = GENINT_LIMBSIZE - m_core_clz(org);
assert ((org & (GENINT_ONE<<bit)) == 0);
// Set & reserve the integer as being used.
next = org | (GENINT_ONE << bit);
} while (!atomic_compare_exchange_weak (&s->data[i], &org, next));
// Return the new number
GENINT_CONTRACT(s);
return i * GENINT_LIMBSIZE + bit;
next_element: (void)1;
// First read master to see which limb is not full.
genint_limb_t master = atomic_load(&s->master);
// While master is not full
while ((master >> GENINT_ABA_CPT) != s->mask_master) {
// Let's get the index i of the first not full limb according to master.
unsigned int i = m_core_clz(~master);
// 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;
unsigned int bit;
// Let's load this limb,
genint_limb_t next, org = atomic_load(&s->data[i]);
do {
// If it is now full, we have been preempted by another.
if (M_UNLIKELY (org == mask))
goto next_element;
// At least one bit is free in the limb. Find one.
bit = GENINT_LIMBSIZE - 1 - m_core_clz(~org);
assert ((org & (GENINT_ONE<<bit)) == 0);
assert (i * GENINT_LIMBSIZE + GENINT_LIMBSIZE - 1 - bit < s->n);
// Set the integer as being used.
next = org | (GENINT_ONE << bit);
// Try to reserve the integer
} while (!atomic_compare_exchange_weak (&s->data[i], &org, next));
// We have reserved the integer.
// If the limb is now full, try to update master
if (M_UNLIKELY(next == mask)) {
while (true) {
genint_limb_t newMaster;
if (next == mask) {
newMaster = GENINT_MASTER_SET(master, i);
} else {
newMaster = GENINT_MASTER_RESET(master, i);
}
if (atomic_compare_exchange_weak (&s->master, &master, newMaster))
break;
// Fail to update. Reload limb to check if it is still full.
next = atomic_load(&s->data[i]);
}
}
// Return the new number
GENINT_CONTRACT(s);
return i * GENINT_LIMBSIZE + GENINT_LIMBSIZE - 1 - bit;
next_element:
// Reload master
master = atomic_load(&s->master);
}
GENINT_CONTRACT(s);
return -(size_t)1; // No more ressource available
return -(size_t)1; // No more resource available
}
// Typical usage: one CAS per push
static inline void genint_push(genint_t s, size_t n)
{
GENINT_CONTRACT(s);
assert (n < s->n);
size_t i = n / GENINT_LIMBSIZE;
size_t bit = n % GENINT_LIMBSIZE;
const size_t i = n / GENINT_LIMBSIZE;
const size_t 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]);
do {
assert ((org & (GENINT_ONE<<bit)) != 0);
assert ((org & (GENINT_ONE << bit)) != 0);
// Reset it
next = org & (~(GENINT_ONE << bit));
// Try to unreserve it.
} while (!atomic_compare_exchange_weak (&s->data[i], &org, next));
// if the limb was marked as full by master
genint_limb_t mask = s->mask0;
mask = (i == s->max) ? mask : -GENINT_ONE;
if (M_UNLIKELY (next != mask)) {
// Let's compute the mask of this limb representing the limb as being full
// Let's try to update master to say that this limb is not full
while (true) {
genint_limb_t newMaster;
if (next == mask) {
newMaster = GENINT_MASTER_SET(master, i);
} else {
newMaster = GENINT_MASTER_RESET(master, i);
}
if (atomic_compare_exchange_weak (&s->master, &master, newMaster))
break;
// Fail to update. Reload limb to check if it is still full.
next = atomic_load(&s->data[i]);
}
}
GENINT_CONTRACT(s);
}
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Intrusive List module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
+10 -10
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - INTRUSIVE SHARED PTR Module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -75,7 +75,7 @@
typedef type *M_C(name,_t); \
typedef type M_C(name, _type_t); \
\
static inline type * \
static inline M_C(name,_t) \
M_C(name, _init)(type *ptr) \
{ \
if (M_LIKELY (ptr != NULL)) \
@@ -83,8 +83,8 @@
return ptr; \
} \
\
static inline type * \
M_C(name, _init_set)(type *shared) \
static inline M_C(name,_t) \
M_C(name, _init_set)(M_C(name,_t) shared) \
{ \
if (M_LIKELY (shared != NULL)) { \
int n = atomic_fetch_add(&(shared->M_C(name, _cpt)), 1); \
@@ -94,14 +94,14 @@
} \
\
static inline void \
M_C(name, _init_set2)(type ** ptr, type *shared) \
M_C(name, _init_set2)(M_C(name,_t) *ptr, M_C(name,_t) shared) \
{ \
assert (ptr != NULL); \
*ptr = M_C(name, _init_set)(shared); \
} \
\
static inline type * \
M_C(name, _init_new)(void) \
static inline M_C(name,_t) \
M_C(name, _init_new)(void) \
{ \
type *ptr = M_GET_NEW oplist (type); \
if (ptr == NULL) { \
@@ -114,7 +114,7 @@
} \
\
static inline void \
M_C(name, _clear)(type *shared) \
M_C(name, _clear)(M_C(name,_t) shared) \
{ \
if (shared != NULL) { \
if (atomic_fetch_sub(&(shared->M_C(name, _cpt)), 1) == 1) { \
@@ -125,14 +125,14 @@
} \
\
static inline void \
M_C(name, _clean)(type **shared) \
M_C(name, _clean)(M_C(name,_t) *shared) \
{ \
M_C(name, _clear)(*shared); \
*shared = NULL; \
} \
\
static inline void \
M_C(name, _set)(type ** ptr, type *shared) \
M_C(name, _set)(M_C(name,_t) *ptr, M_C(name,_t)shared) \
{ \
assert (ptr != NULL); \
if (M_LIKELY (*ptr != shared)) { \
+577 -91
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - LIST module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -27,13 +27,20 @@
#include "m-core.h"
/* Define a list of a given type.
/* Define a singly linked list of a given type.
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_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_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(...) \
@@ -84,21 +91,8 @@
#define LISTI_DEF(arg) LISTI_DEF2 arg
#define LISTI_DEF2(name, type, oplist, list_t, list_it_t) \
\
typedef struct M_C(name, _s) { \
struct M_C(name, _s) *next; \
type data; \
} *list_t[1]; \
\
typedef type M_C(name, _type_t); \
\
typedef struct M_C(name, _it_s) { \
struct M_C(name, _s) *previous; \
list_t l; \
} list_it_t[1]; \
\
/* Define alloc functions. If MEMPOOL, we need to define it */ \
/* Define allocation functions. If MEMPOOL, we need to define it */
#define LISTI_MEMPOOL_DEF(name, type, oplist, list_t, list_it_t) \
M_IF_METHOD(MEMPOOL, oplist)( \
\
MEMPOOL_DEF(M_C(name, _mempool), struct M_C(name, _s)) \
@@ -118,24 +112,43 @@
static inline void M_C(name,_int_del)(struct M_C(name, _s) *ptr) { \
M_GET_DEL oplist (ptr); \
} \
) \
\
LISTI_DEF3(name, type, oplist, list_t, list_it_t) \
) \
#define LISTI_DEF2(name, type, oplist, list_t, list_it_t) \
\
typedef struct M_C(name, _s) { \
struct M_C(name, _s) *next; \
type data; \
} *list_t[1]; \
\
typedef type M_C(name, _type_t); \
\
typedef struct M_C(name, _it_s) { \
struct M_C(name, _s) *previous; \
struct M_C(name, _s) *current; \
} list_it_t[1]; \
\
LISTI_MEMPOOL_DEF(name, type, oplist, list_t, list_it_t) \
LISTI_DEF3(name, type, oplist, list_t, list_it_t) \
LISTI_ITBASE_DEF(name, type, oplist, list_t, list_it_t)
#define LISTI_CONTRACT(v) do { \
assert (v != NULL); \
} while (0)
#define LISTI_DEF3(name, type, oplist, list_t, list_it_t) \
\
static inline void \
M_C(name, _init)(list_t v) \
{ \
assert( v != NULL); \
assert (v != NULL); \
*v = NULL; \
} \
\
static inline void \
M_C(name, _clean)(list_t v) \
{ \
assert (v != NULL); \
LISTI_CONTRACT(v); \
struct M_C(name, _s) *it = *v; \
*v = NULL; \
while (it != NULL) { \
@@ -144,6 +157,7 @@
M_C(name,_int_del)(it); \
it = next; \
} \
LISTI_CONTRACT(v); \
} \
\
static inline void \
@@ -155,14 +169,15 @@
static inline const type * \
M_C(name, _back)(const list_t v) \
{ \
assert(v != NULL && *v != NULL); \
LISTI_CONTRACT(v); \
assert(*v != NULL); \
return M_CONST_CAST(type, &((*v)->data)); \
} \
\
static inline type * \
M_C(name, _push_raw)(list_t v) \
{ \
assert (v != NULL); \
LISTI_CONTRACT(v); \
struct M_C(name, _s) *next; \
next = M_C(name, _int_new)(); \
if (M_UNLIKELY (next == NULL)) { \
@@ -172,6 +187,7 @@
type *ret = &next->data; \
next->next = *v; \
*v = next; \
LISTI_CONTRACT(v); \
return ret; \
} \
\
@@ -197,7 +213,8 @@
static inline void \
M_C(name, _pop_back)(type *data, list_t v) \
{ \
assert(v != NULL && *v != NULL); \
LISTI_CONTRACT(v); \
assert(*v != NULL); \
if (data != NULL) { \
M_GET_SET oplist(*data, (*v)->data); \
} \
@@ -205,96 +222,102 @@
struct M_C(name, _s) *tofree = *v; \
*v = (*v)->next; \
M_C(name,_int_del)(tofree); \
LISTI_CONTRACT(v); \
} \
\
static inline bool \
M_C(name, _empty_p)(const list_t v) \
{ \
assert (v!= NULL); \
LISTI_CONTRACT(v); \
return *v == NULL; \
} \
\
static inline void \
M_C(name, _swap)(list_t l, list_t v) \
{ \
assert (v != NULL && l != NULL); \
LISTI_CONTRACT(l); \
LISTI_CONTRACT(v); \
struct M_C(name, _s) *tmp = *l; \
*l = *v; \
*v = tmp; \
LISTI_CONTRACT(l); \
LISTI_CONTRACT(v); \
} \
\
static inline void \
M_C(name, _it)(list_it_t l, const list_t v) \
M_C(name, _it)(list_it_t it, const list_t v) \
{ \
assert (v != NULL && l[0].l != NULL); \
l[0].l[0] = *v; \
l[0].previous = NULL; \
LISTI_CONTRACT(v); \
assert (it != NULL); \
it->current = *v; \
it->previous = NULL; \
} \
\
static inline void \
M_C(name, _it_set)(list_it_t it1, const list_it_t it2) \
{ \
assert (it1 != NULL && it2 != NULL); \
it1[0].l[0] = it2[0].l[0]; \
it1[0].previous = it2[0].previous; \
it1->current = it2->current; \
it1->previous = it2->previous; \
} \
\
static inline void \
M_C(name, _it_end)(list_it_t it1, const list_t v) \
{ \
assert (it1 != NULL && v != NULL); \
LISTI_CONTRACT(v); \
assert (it1 != NULL); \
(void)v; /* unused */ \
it1[0].l[0] = NULL; \
it1[0].previous = NULL; \
it1->current = NULL; \
it1->previous = NULL; \
} \
\
static inline bool \
M_C(name, _end_p)(const list_it_t v) \
M_C(name, _end_p)(const list_it_t it) \
{ \
assert (v!= NULL); \
return v[0].l[0] == NULL; \
assert (it != NULL); \
return it->current == NULL; \
} \
\
static inline bool \
M_C(name, _last_p)(const list_it_t v) \
M_C(name, _last_p)(const list_it_t it) \
{ \
assert (v!= NULL); \
return v[0].l[0] == NULL || v[0].l[0]->next == NULL; \
assert (it != NULL); \
return it->current == NULL || it->current->next == NULL; \
} \
\
static inline void \
M_C(name, _next)(list_it_t tail) \
M_C(name, _next)(list_it_t it) \
{ \
assert(tail != NULL && tail[0].l[0] != NULL); \
tail[0].previous = tail[0].l[0]; \
tail[0].l[0] = tail[0].l[0]->next; \
assert(it != NULL && it->current != NULL); \
it->previous = it->current; \
it->current = it->current->next; \
} \
\
static inline bool \
M_C(name, _it_equal_p)(const list_it_t it1, const list_it_t it2) \
{ \
assert(it1 != NULL && it2 != NULL); \
return it1[0].l[0] == it2[0].l[0]; \
return it1->current == it2->current; \
} \
\
static inline type * \
M_C(name, _ref)(const list_it_t v) \
M_C(name, _ref)(const list_it_t it) \
{ \
assert(v != NULL && v[0].l[0] != NULL); \
return &(v[0].l[0]->data); \
assert(it != NULL && it->current != NULL); \
return &(it->current->data); \
} \
\
static inline const type * \
M_C(name, _cref)(const list_it_t v) \
M_C(name, _cref)(const list_it_t it) \
{ \
assert(v != NULL && v[0].l[0] != NULL); \
return M_CONST_CAST(type, &(v[0].l[0]->data)); \
assert(it != NULL && it->current != NULL); \
return M_CONST_CAST(type, &(it->current->data)); \
} \
\
static inline size_t \
M_C(name, _size)(const list_t list) \
{ \
assert (list != NULL); \
LISTI_CONTRACT(list); \
size_t size = 0; \
struct M_C(name, _s) *it = *list; \
while (it != NULL) { \
@@ -305,22 +328,22 @@
} \
\
static inline bool \
M_C(name, _sublist_p)(const list_t list, \
const list_it_t sublist) \
M_C(name, _sublist_p)(const list_t list, const list_it_t itsub) \
{ \
assert (list != NULL && sublist != NULL); \
LISTI_CONTRACT(list); \
assert (itsub != NULL); \
struct M_C(name, _s) *it = *list; \
while (it != NULL) { \
if (it == sublist[0].l[0]) return true; \
if (it == itsub->current) return true; \
it = it->next; \
} \
return (sublist[0].l[0] == NULL); \
return (itsub->current == NULL); \
} \
\
static inline type * \
M_C(name, _get)(const list_t list, size_t i) \
{ \
assert (list != NULL); \
LISTI_CONTRACT(list); \
struct M_C(name, _s) *it = *list; \
/* FIXME: How to avoid the double iteration over the list? */ \
size_t len = M_C(name,_size)(list); \
@@ -341,50 +364,53 @@
} \
\
static inline void \
M_C(name, _insert)(list_t list, \
list_it_t insertion_point, \
M_C(name, _insert)(list_t list, list_it_t insertion_point, \
type const x) \
{ \
assert (list != NULL && insertion_point != NULL); \
LISTI_CONTRACT(list); \
assert (insertion_point != NULL); \
assert(M_C(name, _sublist_p)(list, insertion_point)); \
struct M_C(name, _s) *next; \
next = M_C(name, _int_new)(); \
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
if (M_UNLIKELY (next == NULL)) { \
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
return; \
} \
M_GET_INIT_SET oplist(next->data, x); \
if (M_UNLIKELY (insertion_point[0].l[0] == NULL)) { \
struct M_C(name, _s) *current = insertion_point->current; \
if (M_UNLIKELY (current == NULL)) { \
next->next = *list; \
*list = next; \
} else { \
next->next = insertion_point[0].l[0]->next; \
insertion_point[0].l[0]->next = next; \
next->next = current->next; \
current->next = next; \
} \
LISTI_CONTRACT(list); \
} \
\
static inline void \
M_C(name, _remove)(list_t list, \
list_it_t removing_point) \
M_C(name, _remove)(list_t list, list_it_t removing_point) \
{ \
assert (list != NULL && removing_point != NULL); \
assert(removing_point[0].l[0] != NULL); \
LISTI_CONTRACT(list); \
assert (removing_point != NULL); \
assert (removing_point->current != NULL); \
assert(M_C(name, _sublist_p)(list, removing_point)); \
struct M_C(name, _s) *next = removing_point[0].l[0]->next; \
struct M_C(name, _s) *next = removing_point->current->next; \
if (M_UNLIKELY (removing_point->previous == NULL)) { \
*list = next; \
} else { \
removing_point->previous->next = next; \
} \
M_GET_CLEAR oplist(removing_point[0].l[0]->data); \
M_C(name,_int_del) (removing_point[0].l[0]); \
removing_point[0].l[0] = next; \
M_GET_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) \
{ \
assert (list != NULL && org != NULL); \
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; \
@@ -396,6 +422,7 @@
*update_list = next; \
if (M_UNLIKELY (next == NULL)) { \
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
/* FIXME: Partialy initialized list. What to do? */ \
return; \
} \
update_list = &next->next; \
@@ -408,7 +435,6 @@
static inline void \
M_C(name, _init_set)(list_t list, const list_t org) \
{ \
assert (list != NULL && org != NULL && list != org); \
M_C(name, _init)(list); \
M_C(name, _set)(list, org); \
} \
@@ -416,36 +442,38 @@
static inline void \
M_C(name, _init_move)(list_t list, list_t org) \
{ \
assert (list != NULL && org != NULL && list != org); \
LISTI_CONTRACT(org); \
assert (list != NULL && list != org); \
*list = *org; \
*org = NULL; \
*org = NULL; /* safer */ \
} \
\
static inline void \
M_C(name, _move)(list_t list, list_t org) \
{ \
assert (list != NULL && org != NULL && list != org); \
assert (list != org); \
M_C(name, _clear)(list); \
M_C(name, _init_move)(list, org); \
} \
\
\
static inline void \
M_C(name, _splice_back)(list_t nv, list_t ov, list_it_t it) \
{ \
assert (nv != NULL && ov != NULL && it != NULL && nv != ov); \
assert(it[0].l[0] != NULL); \
assert(M_C(name, _sublist_p)(ov, it)); \
LISTI_CONTRACT(nv); \
LISTI_CONTRACT(ov); \
assert (it != NULL && nv != ov); \
assert (it->current != NULL); \
assert (M_C(name, _sublist_p)(ov, it)); \
/* Remove it from ov */ \
struct M_C(name, _s) *next = it[0].l[0]->next; \
struct M_C(name, _s) *current = it[0].l[0]; \
struct M_C(name, _s) *current = it->current; \
struct M_C(name, _s) *next = current->next; \
if (it->previous == NULL) { \
*ov = next; \
} else { \
it->previous->next = next; \
} \
/* Update it to next element */ \
it[0].l[0] = next; \
it->current = next; \
/* Move current in nv */ \
current->next = *nv; \
*nv = current; \
@@ -454,7 +482,9 @@
static inline void \
M_C(name, _splice)(list_t list1, list_t list2) \
{ \
assert (list1 != NULL && list2 != NULL && list1 != list2); \
LISTI_CONTRACT(list1); \
LISTI_CONTRACT(list2); \
assert (list1 != list2); \
struct M_C(name, _s) **update_list = list1; \
struct M_C(name, _s) *it = *list1; \
while (it != NULL) { \
@@ -468,7 +498,7 @@
static inline void \
M_C(name, _reverse)(list_t list) \
{ \
assert (list != NULL); \
LISTI_CONTRACT(list); \
struct M_C(name, _s) *previous = NULL, *it = *list, *next; \
while (it != NULL) { \
next = it->next; \
@@ -478,7 +508,8 @@
} \
*list = previous; \
} \
\
#define LISTI_ITBASE_DEF(name, type, oplist, list_t, list_it_t) \
M_IF_METHOD(GET_STR, oplist)( \
static inline void \
M_C(name, _get_str)(string_t str, const list_t list, \
@@ -586,5 +617,460 @@
} \
, /* no hash */ ) \
/* Dual Push singly linked list.
Support Push Back / Push Front / Pop back in O(1).
Doesn't support Pop front.
This is done by keeping a pointer to both back & front
*/
#define LISTI_DUAL_PUSH_DEF(arg) LISTI_DUAL_PUSH_DEF2 arg
#define LISTI_DUAL_PUSH_DEF2(name, type, oplist, list_t, list_it_t) \
\
struct M_C(name, _s) { \
struct M_C(name, _s) *next; \
type data; \
}; \
\
typedef struct { \
struct M_C(name, _s) *front; \
struct M_C(name, _s) *back; \
} list_t[1]; \
\
typedef type M_C(name, _type_t); \
\
typedef struct M_C(name, _it_s) { \
struct M_C(name, _s) *previous; \
struct M_C(name, _s) *current; \
} list_it_t[1]; \
\
LISTI_MEMPOOL_DEF(name, type, oplist, list_t, list_it_t) \
LISTI_DUAL_PUSH_DEF3(name, type, oplist, list_t, list_it_t) \
LISTI_ITBASE_DEF(name, type, oplist, list_t, list_it_t)
#define LISTI_DUAL_PUSH_CONTRACT(l) do { \
assert (l != NULL); \
assert ( (l->back == NULL && l->front == NULL) \
|| (l->back != NULL && l->front != NULL)); \
} while (0)
#define LISTI_DUAL_PUSH_DEF3(name, type, oplist, list_t, list_it_t) \
\
static inline void \
M_C(name, _init)(list_t v) \
{ \
assert( v != NULL); \
v->front = NULL; \
v->back = NULL; \
LISTI_DUAL_PUSH_CONTRACT(v); \
} \
\
static inline void \
M_C(name, _clean)(list_t v) \
{ \
LISTI_DUAL_PUSH_CONTRACT(v); \
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_C(name,_int_del)(it); \
it = next; \
} \
v->front = NULL; \
v->back = NULL; \
LISTI_DUAL_PUSH_CONTRACT(v); \
} \
\
static inline void \
M_C(name, _clear)(list_t v) \
{ \
M_C(name, _clean)(v); \
} \
\
static inline const type * \
M_C(name, _back)(const list_t v) \
{ \
LISTI_DUAL_PUSH_CONTRACT(v); \
assert (v->back != NULL); \
return M_CONST_CAST(type, &(v->back->data)); \
} \
\
static inline type * \
M_C(name, _push_back_raw)(list_t v) \
{ \
LISTI_DUAL_PUSH_CONTRACT(v); \
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
if (M_UNLIKELY (next == NULL)) { \
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
return NULL; \
} \
type *ret = &next->data; \
next->next = v->back; \
v->back = next; \
/* Update front too if the list was empty */ \
/* This C code shall generate branchless code */ \
struct M_C(name, _s) *front = v->front; \
front = (front == NULL) ? next : front; \
v->front = front; \
LISTI_DUAL_PUSH_CONTRACT(v); \
return ret; \
} \
\
static inline void \
M_C(name, _push_back)(list_t v, type const x) \
{ \
type *data = M_C(name, _push_back_raw)(v); \
if (M_UNLIKELY (data == NULL)) \
return; \
M_GET_INIT_SET oplist(*data, x); \
} \
\
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); \
return data; \
} \
\
static inline void \
M_C(name, _pop_back)(type *data, list_t v) \
{ \
LISTI_DUAL_PUSH_CONTRACT(v); \
assert (v->back != NULL); \
struct M_C(name, _s) *tofree = v->back; \
if (data != NULL) { \
M_GET_SET oplist(*data, 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 */ \
/* 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 const type * \
M_C(name, _front)(list_t v) \
{ \
LISTI_DUAL_PUSH_CONTRACT(v); \
assert (v->front != NULL); \
return M_CONST_CAST(type, &(v->front->data)); \
} \
\
static inline type * \
M_C(name, _push_front_raw)(list_t v) \
{ \
LISTI_DUAL_PUSH_CONTRACT(v); \
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
if (M_UNLIKELY (next == NULL)) { \
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
return NULL; \
} \
type *ret = &next->data; \
next->next = NULL; \
if (M_LIKELY(v->front != NULL)) { \
v->front->next = next; \
} else { \
/* Update back too as the list was empty */ \
v->back = next; \
} \
v->front = next; \
LISTI_DUAL_PUSH_CONTRACT(v); \
return ret; \
} \
\
static inline void \
M_C(name, _push_front)(list_t v, type const x) \
{ \
type *data = M_C(name, _push_front_raw)(v); \
if (M_UNLIKELY (data == NULL)) \
return; \
M_GET_INIT_SET oplist(*data, x); \
} \
\
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); \
return data; \
} \
\
static inline bool \
M_C(name, _empty_p)(const list_t v) \
{ \
LISTI_DUAL_PUSH_CONTRACT(v); \
return v->back == NULL; \
} \
\
static inline void \
M_C(name, _swap)(list_t l, list_t v) \
{ \
LISTI_DUAL_PUSH_CONTRACT(l); \
LISTI_DUAL_PUSH_CONTRACT(v); \
M_SWAP(struct M_C(name, _s) *, l->front, v->front); \
M_SWAP(struct M_C(name, _s) *, l->back, v->back); \
} \
\
static inline void \
M_C(name, _it)(list_it_t it, const list_t v) \
{ \
LISTI_DUAL_PUSH_CONTRACT(v); \
assert (it != NULL); \
it->current = v->back; \
it->previous = NULL; \
} \
\
static inline void \
M_C(name, _it_set)(list_it_t it1, const list_it_t it2) \
{ \
assert (it1 != NULL && it2 != NULL); \
it1->current = it2->current; \
it1->previous = it2->previous; \
} \
\
static inline void \
M_C(name, _it_end)(list_it_t it1, const list_t v) \
{ \
assert (it1 != NULL); \
LISTI_DUAL_PUSH_CONTRACT(v); \
(void)v; /* unused */ \
it1->current = NULL; \
it1->previous = NULL; \
} \
\
static inline bool \
M_C(name, _end_p)(const list_it_t it) \
{ \
assert (it != NULL); \
return it->current == NULL; \
} \
\
static inline bool \
M_C(name, _last_p)(const list_it_t it) \
{ \
assert (it != NULL); \
return it->current == NULL || it->current->next == NULL; \
} \
\
static inline void \
M_C(name, _next)(list_it_t it) \
{ \
assert(it != NULL && it->current != NULL); \
it->previous = it->current; \
it->current = it->current->next; \
} \
\
static inline bool \
M_C(name, _it_equal_p)(const list_it_t it1, const list_it_t it2) \
{ \
assert(it1 != NULL && it2 != NULL); \
return it1->current == it2->current; \
} \
\
static inline type * \
M_C(name, _ref)(const list_it_t it) \
{ \
assert(it != NULL && it->current != NULL); \
return &(it->current->data); \
} \
\
static inline const type * \
M_C(name, _cref)(const list_it_t it) \
{ \
assert(it != NULL && it->current != NULL); \
return M_CONST_CAST(type, &(it->current->data)); \
} \
\
static inline size_t \
M_C(name, _size)(const list_t v) \
{ \
LISTI_DUAL_PUSH_CONTRACT(v); \
size_t size = 0; \
struct M_C(name, _s) *it = v->back; \
while (it != NULL) { \
size ++; \
it = it->next; \
} \
return size; \
} \
\
static inline void \
M_C(name, _insert)(list_t list, list_it_t insertion_point, \
type const x) \
{ \
LISTI_DUAL_PUSH_CONTRACT(list); \
assert (insertion_point != NULL); \
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
if (M_UNLIKELY (next == NULL)) { \
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
return; \
} \
M_GET_INIT_SET oplist(next->data, x); \
if (M_UNLIKELY (insertion_point->current == NULL)) { \
next->next = list->back; \
list->back = next; \
/* update front if list is empty */ \
struct M_C(name, _s) *front = list->front; \
front = (front == NULL) ? next : front; \
list->front = front; \
} else { \
next->next = insertion_point->current->next; \
insertion_point->current->next = next; \
/* update front if current == front */ \
struct M_C(name, _s) *front = list->front; \
front = (front == insertion_point->current) ? next : front; \
list->front = front; \
} \
} \
\
static inline void \
M_C(name, _remove)(list_t list, list_it_t removing_point) \
{ \
LISTI_DUAL_PUSH_CONTRACT(list); \
assert (removing_point != NULL); \
assert(removing_point->current != NULL); \
struct M_C(name, _s) *next = removing_point->current->next; \
struct M_C(name, _s) *previous = removing_point->previous; \
if (M_UNLIKELY (previous == NULL)) { \
list->back = next; \
} else { \
previous->next = next; \
} \
/* Update front */ \
struct M_C(name, _s) *front = list->front; \
front = (next == NULL) ? previous : front; \
list->front = front; \
/* Remove node */ \
M_GET_CLEAR oplist(removing_point->current->data); \
M_C(name,_int_del) (removing_point->current); \
removing_point->current = next; \
} \
\
static inline void \
M_C(name, _set)(list_t list, const list_t org) \
{ \
LISTI_DUAL_PUSH_CONTRACT(list); \
LISTI_DUAL_PUSH_CONTRACT(org); \
struct M_C(name, _s) *next = NULL; \
struct M_C(name, _s) *it_org; \
struct M_C(name, _s) **update_list; \
if (M_UNLIKELY (list == org)) return; \
M_C(name, _clean)(list); \
update_list = &list->back; \
it_org = org->back; \
while (it_org != NULL) { \
next = M_C(name, _int_new)(); \
*update_list = next; \
if (M_UNLIKELY (next == NULL)) { \
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
return; \
} \
update_list = &next->next; \
M_GET_INIT_SET oplist(next->data, it_org->data); \
it_org = it_org->next; \
} \
list->front = next; \
*update_list = NULL; \
} \
\
static inline void \
M_C(name, _init_set)(list_t list, const list_t org) \
{ \
assert (list != org); \
M_C(name, _init)(list); \
M_C(name, _set)(list, org); \
} \
\
static inline void \
M_C(name, _init_move)(list_t list, list_t org) \
{ \
assert (list != org); \
list->back = org->back; \
list->front = org->front; \
org->back = NULL; \
org->front = NULL; \
} \
\
static inline void \
M_C(name, _move)(list_t list, list_t org) \
{ \
M_C(name, _clear)(list); \
M_C(name, _init_move)(list, org); \
} \
\
static inline void \
M_C(name, _splice_back)(list_t list1, list_t list2, list_it_t it) \
{ \
LISTI_DUAL_PUSH_CONTRACT(list1); \
LISTI_DUAL_PUSH_CONTRACT(list2); \
assert (list1 != list2); \
assert(it->current != NULL); \
/* First remove 'it' from list2 */ \
struct M_C(name, _s) *current = it->current; \
struct M_C(name, _s) *next = current->next; \
if (it->previous == NULL) { \
list2->back = next; \
} else { \
it->previous->next = next; \
} \
/* Update front */ \
struct M_C(name, _s) *front = list2->front; \
front = (next == NULL) ? it->previous : front; \
list2->front = front; \
/* Update it to next element */ \
it->current = next; \
/* Move current in nv */ \
current->next = list1->back; \
list1->back = current; \
/* Update front too if the list was empty */ \
/* This C code shall generate branchless code */ \
front = list1->front; \
front = (front == NULL) ? current : front; \
list1->front = front; \
} \
\
static inline void \
M_C(name, _splice)(list_t list1, list_t list2) \
{ \
LISTI_DUAL_PUSH_CONTRACT(list1); \
LISTI_DUAL_PUSH_CONTRACT(list2); \
assert (list1 != list2); \
if (M_LIKELY (list1->front != NULL)) { \
list1->front->next = list2->back; \
list1->front = list2->front; \
} else { \
/* list1 is empty */ \
list1->back = list2->back; \
list1->front = list2->front; \
} \
list2->back = NULL; \
list2->front = NULL; \
LISTI_DUAL_PUSH_CONTRACT(list1); \
LISTI_DUAL_PUSH_CONTRACT(list2); \
} \
\
static inline void \
M_C(name, _reverse)(list_t list) \
{ \
LISTI_DUAL_PUSH_CONTRACT(list); \
list->front = list->back; \
struct M_C(name, _s) *previous = NULL, *it = list->back, *next; \
while (it != NULL) { \
next = it->next; \
it->next = previous; \
previous = it; \
it = next; \
} \
list->back = previous; \
LISTI_DUAL_PUSH_CONTRACT(list); \
} \
#endif
+2 -2
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - MEMPOOL module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -29,7 +29,7 @@
/* Fast Fixed Size thread unsafe allocator.
USAGE:
MEMPOOL_DEF(uint, unsigned int)
MEMPOOL_DEF(memppol_uint, unsigned int)
...
memppol_uint_t m;
mempool_uint_init(m);
+23 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Thin Mutex & Thread wrapper
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -77,6 +77,16 @@ 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);
}
static inline void m_cond_broadcast(m_cond_t c)
{
cnd_broadcast(c);
}
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
{
cnd_wait(c, m);
@@ -153,6 +163,8 @@ static inline void m_mutexi_lazy_lock (m_mutex_t m)
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);
@@ -169,6 +181,11 @@ static inline void m_cond_signal(m_cond_t c)
PulseEvent(*c);
}
static inline void m_cond_broadcast(m_cond_t c)
{
PulseEvent(*c);
}
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
{
DWORD dwWaitResult = SignalObjectAndWait(*m, *c, INFINITE,FALSE);
@@ -245,6 +262,11 @@ static inline void m_cond_signal(m_cond_t c)
pthread_cond_signal(c);
}
static inline void m_cond_broadcast(m_cond_t c)
{
pthread_cond_broadcast(c);
}
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
{
pthread_cond_wait(c, m);
+67 -4
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - dynamic priority queue module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -34,8 +34,8 @@
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) ), \
(name, __VA_ARGS__, M_C(name,_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.
USAGE: PRIOQUEUE_OPLIST(name[, oplist of the type]) */
@@ -66,7 +66,7 @@
,OPLIST(oplist) \
)
#define PRIOQUEUEI_DEF2(name, type, oplist, prioqueue_t) \
#define PRIOQUEUEI_DEF2(name, type, oplist, prioqueue_t, it_t) \
ARRAY_DEF(M_C(name, _array), type, oplist) \
\
typedef type M_C(name, _type_t); \
@@ -75,6 +75,8 @@
M_C(name, _array_t) array; \
} prioqueue_t[1]; \
\
typedef M_C(name, _array_it_t) it_t; \
\
static inline void \
M_C(name, _init)(prioqueue_t p) \
{ \
@@ -205,6 +207,67 @@
i = child; \
} \
} \
\
static inline void \
M_C(name, _it)(it_t it, const prioqueue_t v) \
{ \
M_C(name, _array_it)(it, v->array); \
} \
\
static inline void \
M_C(name, _it_last)(it_t it, const prioqueue_t v) \
{ \
M_C(name, _array_it_last)(it, v->array); \
} \
\
static inline void \
M_C(name, _it_end)(it_t it, const prioqueue_t v) \
{ \
M_C(name, _array_it_end)(it, v->array); \
} \
\
static inline void \
M_C(name, _it_set)(it_t it, const it_t org) \
{ \
M_C(name, _array_it_set)(it, org); \
} \
\
static inline bool \
M_C(name, _end_p)(const it_t it) \
{ \
return M_C(name, _array_end_p)(it); \
} \
\
static inline bool \
M_C(name, _last_p)(const it_t it) \
{ \
return M_C(name, _array_last_p)(it); \
} \
\
static inline bool \
M_C(name, _it_equal_p)(const it_t it1, \
const it_t it2) \
{ \
return M_C(name, _array_it_equal_p)(it1, it2); \
} \
\
static inline void \
M_C(name, _next)(it_t it) \
{ \
M_C(name, _array_next)(it); \
} \
\
static inline void \
M_C(name, _previous)(it_t it) \
{ \
M_C(name, _array_previous)(it); \
} \
\
static inline const type * \
M_C(name, _cref)(const it_t it) \
{ \
return M_C(name, _array_cref)(it); \
} \
#endif
+2 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - RED BLACK TREE module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -892,6 +892,7 @@ typedef enum {
while (!M_C(name, _end_p)(it1)) { \
const type *ref1 = M_C(name, _cref)(it1); \
M_HASH_UP(hash, M_GET_HASH oplist (*ref1)); \
M_C(name, _next)(it1); \
} \
return M_HASH_FINAL (hash); \
} \
+199 -37
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - SHARED PTR Module
* M*LIB - SHARED Module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -27,6 +27,7 @@
#include "m-core.h"
#include "m-atomic.h"
#include "m-genint.h"
/* Define the oplist of a shared pointer.
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
@@ -36,11 +37,28 @@
_OPLIST(__VA_ARGS__ )))
/* Define shared pointer and its function.
USAGE: SHARED_PTR_DEF(name[, oplist]) */
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__) ), \
(name, __VA_ARGS__ )))
((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__ , SHAREDI_INTEGER_OPLIST)))
/* Define shared resource and its function.
This is a bounded pool of resource shared by multiple owners.
USAGE: SHARED_RESOURCE_DEF(name, type, [, oplist]) */
#define SHARED_RESOURCE_DEF(name, ...) \
SHAREDI_RESOURCE_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
(name, __VA_ARGS__)))
/********************************** INTERNAL ************************************/
@@ -64,11 +82,34 @@
// deferred
#define SHAREDI_PTR_DEF(arg) SHAREDI_PTR_DEF2 arg
#define SHAREDI_PTR_DEF2(name, type, oplist) \
// OPLIST to handle a counter of atomic type
#define SHAREDI_ATOMIC_OPLIST (TYPE(atomic_int), \
INIT_SET(atomic_init), \
ADD(atomic_fetch_add), \
SUB(atomic_fetch_sub), \
IT_CREF(atomic_load))
// OPLIST to handle a counter of non-atomic type with its helper functions.
#define SHAREDI_INTEGER_OPLIST (TYPE(int), \
INIT_SET(sharedi_integer_init_set), \
ADD(sharedi_integer_add), \
SUB(sharedi_integer_sub), \
IT_CREF(sharedi_integer_cref))
static inline void sharedi_integer_init_set(int *p, int val) { *p = val; }
static inline int sharedi_integer_add(int *p, int val) { int r = *p; *p += val; return r; }
static inline int sharedi_integer_sub(int *p, int val) { int r = *p; *p -= val; return r; }
static inline int sharedi_integer_cref(int *p) { return *p; }
#define SHAREDI_CONTRACT(shared, cpt_oplist) do { \
assert(shared != NULL); \
assert(*shared == NULL || M_GET_IT_CREF cpt_oplist ( &(*shared)->cpt) >= 1); \
} while (0)
#define SHAREDI_PTR_DEF2(name, type, oplist, cpt_oplist) \
\
typedef struct M_C(name, _s){ \
type *data; /* Pointer to the data */ \
atomic_int cpt; /* Counter of how many points to the data */ \
type *data; /* Pointer to the data */ \
M_GET_TYPE cpt_oplist cpt; /* Counter of how many points to the data */ \
bool combineAlloc; /* Does the data and the ptr share the slot? */ \
} *M_C(name, _t)[1]; \
\
@@ -99,10 +140,10 @@
return; \
} \
ptr->data = data; \
atomic_init (&ptr->cpt, 1); \
M_GET_INIT_SET cpt_oplist (&ptr->cpt, 1); \
ptr->combineAlloc = false; \
*shared = ptr; \
SHAREDI_CONTRACT(shared); \
SHAREDI_CONTRACT(shared, cpt_oplist); \
} \
\
static inline void \
@@ -119,16 +160,16 @@
type *data = &p->data; \
M_GET_INIT oplist(*data); \
ptr->data = data; \
atomic_init (&ptr->cpt, 1); \
M_GET_INIT_SET cpt_oplist (&ptr->cpt, 1); \
ptr->combineAlloc = true; \
*shared = ptr; \
SHAREDI_CONTRACT(shared); \
SHAREDI_CONTRACT(shared, cpt_oplist); \
} \
\
static inline bool \
M_C(name, _NULL_p)(const M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(shared); \
SHAREDI_CONTRACT(shared, cpt_oplist); \
return *shared == NULL; \
} \
\
@@ -136,22 +177,22 @@
M_C(name, _init_set)(M_C(name, _t) dest, \
const M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(shared); \
SHAREDI_CONTRACT(shared, cpt_oplist); \
assert (dest != shared); \
*dest = *shared; \
if (*dest != NULL) { \
int n = atomic_fetch_add(&((*dest)->cpt), 1); \
int n = M_GET_ADD cpt_oplist ( &((*dest)->cpt), 1); \
(void) n; /* unused return value */ \
} \
SHAREDI_CONTRACT(dest); \
SHAREDI_CONTRACT(dest, cpt_oplist); \
} \
\
static inline void \
M_C(name, _clear)(M_C(name, _t) dest) \
{ \
SHAREDI_CONTRACT(dest); \
SHAREDI_CONTRACT(dest, cpt_oplist); \
if (*dest != NULL) { \
if (atomic_fetch_sub(&((*dest)->cpt), 1) == 1) { \
if (M_GET_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 \
@@ -164,7 +205,7 @@
} \
*dest = NULL; \
} \
SHAREDI_CONTRACT(dest); \
SHAREDI_CONTRACT(dest, cpt_oplist); \
} \
\
static inline void \
@@ -178,8 +219,8 @@
M_C(name, _set)(M_C(name, _t) dest, \
const M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(dest); \
SHAREDI_CONTRACT(shared); \
SHAREDI_CONTRACT(dest, cpt_oplist); \
SHAREDI_CONTRACT(shared, cpt_oplist); \
M_C(name, _clear)(dest); \
M_C(name, _init_set)(dest, shared); \
} \
@@ -188,19 +229,19 @@
M_C(name, _init_move)(M_C(name, _t) dest, \
M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(shared); \
SHAREDI_CONTRACT(shared, cpt_oplist); \
assert (dest != NULL && dest != shared); \
*dest = *shared; \
*shared = NULL; \
SHAREDI_CONTRACT(dest); \
SHAREDI_CONTRACT(dest, cpt_oplist); \
} \
\
static inline void \
M_C(name, _move)(M_C(name, _t) dest, \
M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(dest); \
SHAREDI_CONTRACT(shared); \
SHAREDI_CONTRACT(dest, cpt_oplist); \
SHAREDI_CONTRACT(shared, cpt_oplist); \
assert (dest != shared); \
M_C(name, _clear)(dest); \
M_C(name, _init_move)(dest, shared); \
@@ -210,26 +251,26 @@
M_C(name, _swap)(M_C(name, _t) p1, \
M_C(name, _t) p2) \
{ \
SHAREDI_CONTRACT(p1); \
SHAREDI_CONTRACT(p2); \
SHAREDI_CONTRACT(p1, cpt_oplist); \
SHAREDI_CONTRACT(p2, cpt_oplist); \
M_SWAP (struct M_C(name, _s)*, *p1, *p2); \
SHAREDI_CONTRACT(p1); \
SHAREDI_CONTRACT(p2); \
SHAREDI_CONTRACT(p1, cpt_oplist); \
SHAREDI_CONTRACT(p2, cpt_oplist); \
} \
\
static inline bool \
M_C(name, _equal_p)(const M_C(name, _t) p1, \
const M_C(name, _t) p2) \
{ \
SHAREDI_CONTRACT(p1); \
SHAREDI_CONTRACT(p2); \
SHAREDI_CONTRACT(p1, cpt_oplist); \
SHAREDI_CONTRACT(p2, cpt_oplist); \
return *p1 == *p2; \
} \
\
static inline const type * \
M_C(name, _cref)(const M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(shared); \
SHAREDI_CONTRACT(shared, cpt_oplist); \
assert(*shared != NULL); \
type *data = (*shared)->data; \
assert (data != NULL); \
@@ -239,18 +280,139 @@
static inline type * \
M_C(name, _ref)(M_C(name, _t) shared) \
{ \
SHAREDI_CONTRACT(shared); \
SHAREDI_CONTRACT(shared, cpt_oplist); \
assert(*shared != NULL); \
type *data = (*shared)->data; \
assert (data != NULL); \
return data; \
} \
/********************************** INTERNAL ************************************/
/********************************** SHARED RESOURCE ************************************/
#define SHAREDI_CONTRACT(shared) do { \
assert(shared != NULL); \
assert(*shared == NULL || atomic_load (&(*shared)->cpt) >= 1); \
#define SHAREDI_RESOURCE_CONTRACT(s) do { \
assert (s != NULL); \
assert (s->buffer != NULL); \
} while (0)
// deferred
#define SHAREDI_RESOURCE_DEF(arg) SHAREDI_RESOURCE_DEF2 arg
#define SHAREDI_RESOURCE_DEF2(name, type, oplist) \
\
/* Create an aligned type to avoid false sharing between threads */ \
typedef struct M_C(name, _atype_s) { \
atomic_uint cpt; \
type x; \
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(type) +sizeof(atomic_uint) ? M_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(type) -sizeof(atomic_uint) : 1]; \
} M_C(name, _atype_t); \
\
typedef struct M_C(name, _s) { \
genint_t core; \
M_C(name, _atype_t) *buffer; \
} M_C(name, _t)[1]; \
\
typedef struct M_C(name, _it_s) { \
unsigned int idx; \
struct M_C(name, _s) *ref; \
} M_C(name, _it_t)[1]; \
\
static inline void \
M_C(name, _init)(M_C(name, _t) s, size_t n) \
{ \
assert(s != NULL); \
assert (n > 0); \
s->buffer = M_GET_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); \
} \
genint_init(s->core, n); \
SHAREDI_RESOURCE_CONTRACT(s); \
} \
\
static inline void \
M_C(name, _clear)(M_C(name, _t) s) \
{ \
SHAREDI_RESOURCE_CONTRACT(s); \
size_t n = genint_size(s->core); \
for(size_t i = 0; i < n; i++) { \
M_GET_CLEAR oplist (s->buffer[i].x); \
} \
M_GET_FREE oplist (s->buffer); \
s->buffer = NULL; \
genint_clear(s->core); \
} \
\
static inline void \
M_C(name, _it)(M_C(name, _it_t) it, M_C(name, _t) s) \
{ \
SHAREDI_RESOURCE_CONTRACT(s); \
assert (it != NULL); \
unsigned int idx = genint_pop(s->core); \
it->idx = idx; \
it->ref = s; \
if (M_LIKELY (idx != -1U)) { \
assert(atomic_load(&s->buffer[idx].cpt) == 0); \
atomic_store(&s->buffer[idx].cpt, 1U); \
} \
} \
\
static inline bool \
M_C(name, _end_p)(M_C(name, _it_t) it) \
{ \
assert (it != NULL); \
return it->idx == -1U; \
} \
\
static inline type * \
M_C(name, _ref)(M_C(name, _it_t) it) \
{ \
assert (it != NULL && it->ref != NULL && it->idx != -1U); \
SHAREDI_RESOURCE_CONTRACT(it->ref); \
return &it->ref->buffer[it->idx].x; \
} \
\
static inline const type * \
M_C(name, _cref)(M_C(name, _it_t) it) \
{ \
assert (it != NULL && it->ref != NULL && it->idx != -1U); \
SHAREDI_RESOURCE_CONTRACT(it->ref); \
return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \
} \
\
static inline void \
M_C(name, _end)(M_C(name, _it_t) it, M_C(name, _t) s) \
{ \
SHAREDI_RESOURCE_CONTRACT(s); \
assert (it != NULL); \
assert (it->ref == s); \
unsigned int idx = it->idx; \
if (M_LIKELY (idx != -1U)) { \
unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \
if (c == 1) { \
genint_push(it->ref->core, idx); \
} \
it->idx = -1U; \
} \
} \
\
static inline void \
M_C(name, _it_set)(M_C(name, _it_t) itd, M_C(name, _it_t) its) \
{ \
assert (itd != NULL && its != NULL); \
SHAREDI_RESOURCE_CONTRACT(its->ref); \
itd->ref = its->ref; \
unsigned int idx = its->idx; \
itd->idx = idx; \
if (M_LIKELY (idx != -1U)) { \
unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \
assert (c >= 1); \
} \
} \
#endif
+460 -83
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - SNAPSHOT Module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -27,13 +27,31 @@
#include "m-atomic.h"
#include "m-core.h"
#include "m-genint.h"
/* Define a snapshot and it function
USAGE: SNAPSHOT_DEF(name, type[, oplist]) */
#define SNAPSHOT_DEF(name, ...) \
SNAPSHOTI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
(name, __VA_ARGS__ )))
// For compatibility with previous version
#define SNAPSHOT_DEF SNAPSHOT_SPSC_DEF
/* Define a SRSW snapshot and it function
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__) ), \
(name, __VA_ARGS__ )))
/* Define a SPMC snapshot and it function
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__ )))
/* Define a MPMC snapshot and it function
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__ )))
/* Define the oplist of a snapshot.
USAGE: SNAPSHOT_OPLIST(name[, oplist]) */
@@ -61,47 +79,55 @@
,M_IF_METHOD(MOVE, oplist)(MOVE(M_C(name, _move)),) \
)
/******************************** INTERNAL SRSW **********************************/
/* Flag defining the atomic state of a snapshot:
* - r: Index of the read buffer Range [0..2]
* - w: Index of the write buffer Range [0..2]
* - 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_FLAG(r, w, f, b) \
#define SNAPSHOTI_SRSW_FLAG(r, w, f, b) \
((unsigned char)( ( (r) << 4) | ((w) << 2) | ((f)) | ((b) << 6)))
#define SNAPSHOTI_R(flags) \
#define SNAPSHOTI_SRSW_R(flags) \
(((flags) >> 4) & 0x03u)
#define SNAPSHOTI_W(flags) \
#define SNAPSHOTI_SRSW_W(flags) \
(((flags) >> 2) & 0x03u)
#define SNAPSHOTI_F(flags) \
#define SNAPSHOTI_SRSW_F(flags) \
(((flags) >> 0) & 0x03u)
#define SNAPSHOTI_B(flags) \
#define SNAPSHOTI_SRSW_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_FLAGS_CONTRACT(flags) \
assert(SNAPSHOTI_R(flags) != SNAPSHOTI_W(flags) \
&& SNAPSHOTI_R(flags) != SNAPSHOTI_F(flags) \
&& SNAPSHOTI_W(flags) != SNAPSHOTI_F(flags))
#define SNAPSHOTI_CONTRACT(snap) do { \
#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 { \
assert((snap) != NULL); \
unsigned char f = atomic_load (&(snap)->flags); \
SNAPSHOTI_FLAGS_CONTRACT(f); \
SNAPSHOTI_SRSW_FLAGS_CONTRACT(f); \
} while (0)
//defered
#define SNAPSHOTI_DEF(arg) SNAPSHOTI_DEF2 arg
// Defered evaluation (TBC if it really helps).
#define SNAPSHOTI_SRSW_DEF(arg) SNAPSHOTI_SRSW_DEF2 arg
// This is basically an atomic triple buffer between a produced thread
// and a consummer thread.
// TODO: Analyse generalisation to N produced threads and M consummer threads
#define SNAPSHOTI_MAX_BUFFER 3
// 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_DEF2(name, type, oplist) \
\
#define SNAPSHOTI_SRSW_DEF2(name, type, oplist) \
\
/* Create an aligned type to avoid false sharing between threads */ \
typedef struct M_C(name, _aligned_type_s) { \
type x; \
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(type) ? M_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(type) : 1]; \
} M_C(name, _aligned_type_t); \
\
typedef struct M_C(name, _s) { \
type data[SNAPSHOTI_MAX_BUFFER]; \
M_C(name, _aligned_type_t) data[SNAPSHOTI_SRSW_MAX_BUFFER]; \
atomic_uchar flags; \
} M_C(name, _t)[1]; \
\
@@ -110,137 +136,488 @@
static inline void M_C(name, _init)(M_C(name, _t) snap) \
{ \
assert(snap != NULL); \
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
M_GET_INIT oplist(snap->data[i]); \
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
M_GET_INIT oplist(snap->data[i].x); \
} \
atomic_init (&snap->flags, SNAPSHOTI_FLAG(0, 1, 2, 0)); \
SNAPSHOTI_CONTRACT(snap); \
atomic_init (&snap->flags, SNAPSHOTI_SRSW_FLAG(0, 1, 2, 0)); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
} \
\
\
static inline void M_C(name, _clear)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_CONTRACT(snap); \
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
M_GET_CLEAR oplist(snap->data[i]); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
M_GET_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_CONTRACT(org); \
SNAPSHOTI_SRSW_CONTRACT(org); \
assert(snap != NULL && snap != org); \
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
M_GET_INIT_SET oplist(snap->data[i], org->data[i]); \
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
M_GET_INIT_SET oplist(snap->data[i].x, org->data[i].x); \
} \
atomic_init (&snap->flags, atomic_load(&org->flags)); \
SNAPSHOTI_CONTRACT(snap); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
} \
\
\
static inline void M_C(name, _set)(M_C(name, _t) snap, \
M_C(name, _t) org) \
{ \
SNAPSHOTI_CONTRACT(snap); \
SNAPSHOTI_CONTRACT(org); \
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
M_GET_SET oplist(snap->data[i], org->data[i]); \
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); \
} \
atomic_init (&snap->flags, atomic_load(&org->flags)); \
SNAPSHOTI_CONTRACT(snap); \
SNAPSHOTI_SRSW_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_CONTRACT(org); \
SNAPSHOTI_SRSW_CONTRACT(org); \
assert(snap != NULL && snap != org); \
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
M_GET_INIT_MOVE oplist(snap->data[i], org->data[i]); \
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
M_GET_INIT_MOVE oplist(snap->data[i].x, org->data[i].x); \
} \
atomic_store (&snap->flags, atomic_load(&org->flags)); \
atomic_store (&org->flags, SNAPSHOTI_FLAG(0,0,0,0) ); \
SNAPSHOTI_CONTRACT(snap); \
atomic_store (&org->flags, SNAPSHOTI_SRSW_FLAG(0,0,0,0) ); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
} \
,) /* IF_METHOD (INIT_MOVE) */ \
\
\
M_IF_METHOD(MOVE, oplist)( \
static inline void M_C(name, _move)(M_C(name, _t) snap, \
M_C(name, _t) org) \
{ \
SNAPSHOTI_CONTRACT(snap); \
SNAPSHOTI_CONTRACT(org); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
SNAPSHOTI_SRSW_CONTRACT(org); \
assert(snap != org); \
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
M_GET_MOVE oplist(snap->data[i], org->data[i]); \
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
M_GET_MOVE oplist(snap->data[i].x, org->data[i].x); \
} \
atomic_store (&snap->flags, atomic_load(&org->flags)); \
atomic_store (&org->flags, SNAPSHOTI_FLAG(0,0,0,0) ); \
SNAPSHOTI_CONTRACT(snap); \
atomic_store (&org->flags, SNAPSHOTI_SRSW_FLAG(0,0,0,0) ); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
} \
,) /* IF_METHOD (MOVE) */ \
\
\
\
static inline type *M_C(name, _write)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_CONTRACT(snap); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
/* Atomic CAS operation */ \
do { \
/* Swap F and W buffer, setting exchange flag */ \
nextFlags = SNAPSHOTI_FLAG(SNAPSHOTI_R(origFlags), \
SNAPSHOTI_F(origFlags), \
SNAPSHOTI_W(origFlags), 1); \
/* FIXME: Is exponential backoff really needed ? */ \
nextFlags = SNAPSHOTI_SRSW_FLAG(SNAPSHOTI_SRSW_R(origFlags), \
SNAPSHOTI_SRSW_F(origFlags), \
SNAPSHOTI_SRSW_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_W(nextFlags)]; \
return &snap->data[SNAPSHOTI_SRSW_W(nextFlags)].x; \
} \
\
\
static inline const type *M_C(name, _read)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_CONTRACT(snap); \
SNAPSHOTI_SRSW_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_B(origFlags)) { \
if (!SNAPSHOTI_SRSW_B(origFlags)) { \
nextFlags = origFlags; \
break; \
} \
/* Swap R and F buffer, clearing exchange flag */ \
nextFlags = SNAPSHOTI_FLAG(SNAPSHOTI_F(origFlags), \
SNAPSHOTI_W(origFlags), \
SNAPSHOTI_R(origFlags), 0); \
/* FIXME: Is exponential backoff really needed ? */ \
nextFlags = SNAPSHOTI_SRSW_FLAG(SNAPSHOTI_SRSW_F(origFlags), \
SNAPSHOTI_SRSW_W(origFlags), \
SNAPSHOTI_SRSW_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_R(nextFlags)]); \
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SRSW_R(nextFlags)].x); \
} \
\
\
static inline bool M_C(name, _updated_p)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_CONTRACT(snap); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
unsigned char flags = atomic_load (&snap->flags); \
return SNAPSHOTI_B(flags); \
return SNAPSHOTI_SRSW_B(flags); \
} \
\
static inline type *M_C(name, _get_write_buffer)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_CONTRACT(snap); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
unsigned char flags = atomic_load(&snap->flags); \
return &snap->data[SNAPSHOTI_W(flags)]; \
return &snap->data[SNAPSHOTI_SRSW_W(flags)].x; \
} \
\
\
static inline const type *M_C(name, _get_read_buffer)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_CONTRACT(snap); \
SNAPSHOTI_SRSW_CONTRACT(snap); \
unsigned char flags = atomic_load(&snap->flags); \
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_R(flags)]); \
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SRSW_R(flags)].x); \
} \
// FIXME: Method SWAP ?
/******************************** INTERNAL SPMC **********************************/
#define SNAPSHOTI_SPMC_INT_FLAG(w, n) ( ((w) << 1) | (n) )
#define SNAPSHOTI_SPMC_INT_FLAG_W(f) ((f) >> 1)
#define SNAPSHOTI_SPMC_INT_FLAG_N(f) ((f) & 1)
// 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)
// structure to handle SPMC snapshot but return a unique index in a buffer array.
typedef struct snapshot_mrsw_int_s {
atomic_uint lastNext;
unsigned int currentWrite;
size_t n;
atomic_uint *cptTab;
genint_t freeList;
} snapshot_mrsw_int_t[1];
// can't check currentWrite due to potential data race on it
#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)) \
<= s->n + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
assert (s->cptTab != NULL); \
} while (0)
static inline void snapshot_mrsw_int_init(snapshot_mrsw_int_t s, size_t n)
{
assert (s != NULL);
assert (n >= 1 && n <= SNAPSHOTI_SPMC_MAX_READER);
s->n = n;
n += SNAPSHOTI_SPMC_EXTRA_BUFFER;
atomic_uint *ptr = M_MEMORY_REALLOC (atomic_uint, NULL, n);
if (M_UNLIKELY (ptr == NULL)) {
M_MEMORY_FULL(sizeof (atomic_uint) * n);
return;
}
s->cptTab = ptr;
for(size_t i = 0; i < n; i++)
atomic_init(&s->cptTab[i], 0U);
genint_init (s->freeList, n);
// Get a free buffer and set it as available for readers
unsigned int w = genint_pop(s->freeList);
assert (w != -1U);
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);
atomic_store(&s->cptTab[s->currentWrite], 1U);
SNAPSHOTI_SPMC_INT_CONTRACT(s);
}
static inline void snapshot_mrsw_int_clear(snapshot_mrsw_int_t s)
{
SNAPSHOTI_SPMC_INT_CONTRACT(s);
M_MEMORY_FREE (s->cptTab);
genint_clear(s->freeList);
s->cptTab = NULL;
s->n = 0;
}
static inline unsigned int snapshot_mrsw_int_get_write_idx(snapshot_mrsw_int_t s)
{
SNAPSHOTI_SPMC_INT_CONTRACT(s);
return s->currentWrite;
}
static inline unsigned int snapshot_mrsw_int_write_idx(snapshot_mrsw_int_t s, unsigned int idx)
{
SNAPSHOTI_SPMC_INT_CONTRACT(s);
unsigned int newNext, previous = atomic_load(&s->lastNext);
do {
newNext = SNAPSHOTI_SPMC_INT_FLAG(idx, true);
} while (!atomic_compare_exchange_weak(&s->lastNext, &previous, newNext));
if (SNAPSHOTI_SPMC_INT_FLAG_N(previous)) {
// Reuse previous buffer as it was not used by any reader
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
// Some other read threads may already have try to reserve this index
// So atomic_load(&s->cptTab[idx]) can be greater than 1.
// However they will fail to ack it in lastNext, and remove their reservation later
} else {
// Free the write index
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
unsigned int c = atomic_fetch_sub(&s->cptTab[idx], 1U);
assert (c != 0 && c <= s->n + 1);
// Get a new buffer.
if (c != 1) {
// If someone else keeps a ref on the buffer, we can't reuse it
// get another free one.
idx = genint_pop(s->freeList);
// TODO: sometimes fails...
assert(idx != -1U);
}
assert (idx < s->n + SNAPSHOTI_SPMC_EXTRA_BUFFER);
assert (atomic_load(&s->cptTab[idx]) == 0);
atomic_store(&s->cptTab[idx], 1U);
}
SNAPSHOTI_SPMC_INT_CONTRACT(s);
return idx;
}
static inline unsigned int snapshot_mrsw_int_write(snapshot_mrsw_int_t s)
{
s->currentWrite = snapshot_mrsw_int_write_idx(s, s->currentWrite);
SNAPSHOTI_SPMC_INT_CONTRACT(s);
return s->currentWrite;
}
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 < s->n + SNAPSHOTI_SPMC_EXTRA_BUFFER);
assert (atomic_load(&s->cptTab[idx]) == 0);
atomic_store(&s->cptTab[idx], 1U);
SNAPSHOTI_SPMC_INT_CONTRACT(s);
return idx;
}
static inline void snapshot_mrsw_int_write_end(snapshot_mrsw_int_t s, unsigned int idx)
{
SNAPSHOTI_SPMC_INT_CONTRACT(s);
unsigned int newNext, previous = atomic_load(&s->lastNext);
do {
newNext = SNAPSHOTI_SPMC_INT_FLAG(idx, true);
} while (!atomic_compare_exchange_weak(&s->lastNext, &previous, newNext));
// Free the previous write buffer
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
unsigned int c = atomic_fetch_sub(&s->cptTab[idx], 1U);
assert (c != 0 && c <= s->n + 1);
if (c == 1) {
genint_push(s->freeList, idx);
}
SNAPSHOTI_SPMC_INT_CONTRACT(s);
}
static inline unsigned int snapshot_mrsw_int_read_start(snapshot_mrsw_int_t s)
{
SNAPSHOTI_SPMC_INT_CONTRACT(s);
unsigned int idx, previous;
reload:
// Load the last published index + Next flag
previous = atomic_load(&s->lastNext);
while (true) {
// Get the last published index
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
// Load the number of threads using this index
unsigned int c = atomic_load(&s->cptTab[idx]);
assert (c <= s->n + 1);
// Reserve the index if it still being reserved by someone else
if (M_UNLIKELY (c == 0
|| !atomic_compare_exchange_strong(&s->cptTab[idx], &c, c+1)))
goto reload;
// Try to ack it
unsigned int newNext = SNAPSHOTI_SPMC_INT_FLAG(idx, false);
reforce:
if (M_LIKELY (atomic_compare_exchange_strong(&s->lastNext, &previous, newNext)))
break;
// We have been preempted by another thread
if (idx == SNAPSHOTI_SPMC_INT_FLAG_W(previous)) {
// This is still ok if the index has not changed
// We can get previous to true again if the writer has recycled the index,
// while we reserved it, and the reader get prempted until its CAS.
if (M_UNLIKELY (SNAPSHOTI_SPMC_INT_FLAG_N(previous) == true)) goto reforce;
break;
}
// Free the reserved index as we failed it to ack it
c = atomic_fetch_sub(&s->cptTab[idx], 1U);
assert (c != 0 && c <= s->n+1);
if (c == 1) {
genint_push(s->freeList, idx);
}
}
SNAPSHOTI_SPMC_INT_CONTRACT(s);
return idx;
}
static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned int idx)
{
SNAPSHOTI_SPMC_INT_CONTRACT(s);
assert (idx < s->n + SNAPSHOTI_SPMC_EXTRA_BUFFER);
// Decrement reference counter of the buffer
unsigned int c = atomic_fetch_sub(&s->cptTab[idx], 1U);
assert (c != 0 && c <= s->n+1);
if (c == 1) {
// Buffer no longer used by any reader thread.
// Push back index in free list
genint_push(s->freeList, idx);
}
SNAPSHOTI_SPMC_INT_CONTRACT(s);
}
#define SNAPSHOTI_SPMC_CONTRACT(snap) do { \
assert (snap != NULL); \
assert (snap->data != NULL); \
} while (0)
// Defered evaluation (TBC if it really helps).
#define SNAPSHOTI_SPMC_DEF(arg) SNAPSHOTI_SPMC_DEF2 arg
#define SNAPSHOTI_SPMC_DEF2(name, type, oplist) \
\
/* Create an aligned type to avoid false sharing between threads */ \
typedef struct M_C(name, _aligned_type_s) { \
type x; \
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(type) ? M_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(type) : 1]; \
} M_C(name, _aligned_type_t); \
\
typedef struct M_C(name, _s) { \
M_C(name, _aligned_type_t) *data; \
snapshot_mrsw_int_t core; \
} M_C(name, _t)[1]; \
\
typedef type M_C(name, _type_t); \
\
static inline void M_C(name, _init)(M_C(name, _t) snap, size_t nReader) \
{ \
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); \
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); \
} \
snapshot_mrsw_int_init(snap->core, nReader); \
SNAPSHOTI_SPMC_CONTRACT(snap); \
} \
\
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); \
} \
M_GET_FREE oplist (snap->data); \
snapshot_mrsw_int_clear(snap->core); \
} \
\
static inline type *M_C(name, _write)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_SPMC_CONTRACT(snap); \
const unsigned int idx = snapshot_mrsw_int_write(snap->core); \
return &snap->data[idx].x; \
} \
\
static inline const type *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) \
{ \
SNAPSHOTI_SPMC_CONTRACT(snap); \
assert (old != NULL); \
const M_C(name, _aligned_type_t) *oldx; \
oldx = M_CTYPE_FROM_FIELD(M_C(name, _aligned_type_t), old, type, x); \
assert (oldx >= snap->data); \
assert (oldx < snap->data + snap->core->n+SNAPSHOTI_SPMC_EXTRA_BUFFER); \
const unsigned int idx = oldx - snap->data; \
snapshot_mrsw_int_read_end(snap->core, idx); \
} \
\
static inline type *M_C(name, _get_write_buffer)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_SPMC_CONTRACT(snap); \
const unsigned int idx = snapshot_mrsw_int_get_write_idx(snap->core); \
return &snap->data[idx].x; \
} \
\
//TODO: _set_, _init_set
/******************************** INTERNAL MPMC **********************************/
// MPMC is built upon SPMC
// Defered evaluation (TBC if it really helps).
#define SNAPSHOTI_MPMC_DEF(arg) SNAPSHOTI_MPMC_DEF2 arg
#define SNAPSHOTI_MPMC_DEF2(name, type, oplist) \
\
SNAPSHOTI_SPMC_DEF((M_C(name, _mrsw), type, oplist)) \
\
typedef struct M_C(name, _s) { \
M_C(name, _mrsw_t) core; \
} M_C(name, _t)[1]; \
\
typedef type M_C(name, _type_t); \
\
static inline void M_C(name, _init)(M_C(name, _t) snap, size_t nReader, size_t nWriter) \
{ \
M_C(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \
unsigned int idx = snap->core->core->currentWrite; \
snap->core->core->currentWrite = -1; \
snapshot_mrsw_int_write_end(snap->core->core, idx); \
} \
\
static inline void M_C(name, _clear)(M_C(name, _t) snap) \
{ \
M_C(name, _mrsw_clear)(snap->core); \
} \
\
static inline type *M_C(name, _write_start)(M_C(name, _t) snap) \
{ \
SNAPSHOTI_SPMC_CONTRACT(snap->core); \
const unsigned int idx = snapshot_mrsw_int_write_start(snap->core->core); \
return &snap->core->data[idx].x; \
} \
\
static inline void M_C(name, _write_end)(M_C(name, _t) snap, type *old) \
{ \
SNAPSHOTI_SPMC_CONTRACT(snap->core); \
const M_C(name, _mrsw_aligned_type_t) *oldx; \
oldx = M_CTYPE_FROM_FIELD(M_C(name, _mrsw_aligned_type_t), old, type, x); \
assert (oldx >= snap->core->data); \
assert (oldx < snap->core->data + snap->core->core->n + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
const unsigned int idx = oldx - snap->core->data; \
snapshot_mrsw_int_write_end(snap->core->core, idx); \
} \
\
static inline const type *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) \
{ \
M_C(name, _mrsw_read_end)(snap->core, old); \
} \
\
//TODO: _set_, _init_set
#endif
+333 -95
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Dynamic Size String Module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -43,7 +43,7 @@
// 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.
#define STRING_CONTRACT(v) do { \
#define STRINGI_CONTRACT(v) do { \
M_ASSUME (v != NULL); \
M_ASSUME (v->ptr != NULL || (v->size == 0 && v->alloc == 0)); \
STRINGI_ASSUME (v->ptr == NULL || v->size == strlen(v->ptr)); \
@@ -52,7 +52,13 @@
} while (0)
/********************************** EXTERNAL ************************************/
/****************************** EXTERNAL *******************************/
/***********************************************************************/
/* */
/* DYNAMIC STRING */
/* */
/***********************************************************************/
/* Index returned in case of error */
#define STRING_FAILURE ((size_t)-1)
@@ -72,13 +78,13 @@ string_init(string_t v)
{
v->size = v->alloc = 0;
v->ptr = NULL;
STRING_CONTRACT(v);
STRINGI_CONTRACT(v);
}
static inline void
string_clear(string_t v)
{
STRING_CONTRACT(v);
STRINGI_CONTRACT(v);
M_MEMORY_FREE(v->ptr);
v->size = v->alloc = 0;
v->ptr = NULL;
@@ -91,7 +97,7 @@ static inline void stringi_clear2(string_t *v) { string_clear(*v); }
static inline char *
string_clear_get_str(string_t v)
{
STRING_CONTRACT(v);
STRINGI_CONTRACT(v);
char *p = v->ptr;
v->size = v->alloc = 0;
v->ptr = NULL;
@@ -101,31 +107,31 @@ string_clear_get_str(string_t v)
static inline void
string_clean(string_t v)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
v->size = 0;
if (M_LIKELY (v->ptr))
v->ptr[0] = 0;
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
}
static inline size_t
string_size(const string_t v)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
return v->size;
}
static inline size_t
string_capacity(const string_t v)
{
STRING_CONTRACT(v);
STRINGI_CONTRACT(v);
return v->alloc;
}
static inline char
string_get_char(const string_t v, size_t index)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
M_ASSUME( v->ptr != NULL && index < v->size);
return v->ptr[index];
}
@@ -133,10 +139,11 @@ string_get_char(const string_t v, size_t index)
static inline bool
string_empty_p(const string_t v)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
return v->size == 0;
}
// Size includes the final null char
static inline void
stringi_fit2size (string_t v, size_t size)
{
@@ -163,7 +170,7 @@ stringi_fit2size (string_t v, size_t size)
static inline void
string_reserve(string_t v, size_t alloc)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
/* NOTE: Reserve below needed size, perform a shrink to fit */
if (v->size + 1 > alloc) {
alloc = v->size+1;
@@ -183,25 +190,25 @@ string_reserve(string_t v, size_t alloc)
v->ptr = ptr; // Can be != ptr if v->ptr was NULL before.
v->alloc = alloc;
}
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
}
static inline void
string_set_str(string_t v, const char str[])
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
M_ASSUME(str != NULL);
size_t size = strlen(str);
stringi_fit2size(v, size+1);
memcpy(v->ptr, str, size+1);
v->size = size;
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
}
static inline void
string_set_strn(string_t v, const char str[], size_t n)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
M_ASSUME(str != NULL);
size_t len = strlen(str);
size_t size = M_MIN (len, n);
@@ -209,21 +216,21 @@ string_set_strn(string_t v, const char str[], size_t n)
memcpy(v->ptr, str, size);
v->ptr[size] = 0;
v->size = size;
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
}
static inline const char*
string_get_cstr(const string_t v)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
return M_UNLIKELY (v->ptr == NULL) ? "" : v->ptr;
}
static inline void
string_set (string_t v1, const string_t v2)
{
STRING_CONTRACT (v1);
STRING_CONTRACT (v2);
STRINGI_CONTRACT (v1);
STRINGI_CONTRACT (v2);
if (M_LIKELY (v1 != v2)) {
size_t size = v2->size;
stringi_fit2size(v1, size+1);
@@ -235,14 +242,14 @@ string_set (string_t v1, const string_t v2)
}
v1->size = size;
}
STRING_CONTRACT (v1);
STRINGI_CONTRACT (v1);
}
static inline void
string_set_n(string_t v, const string_t ref, size_t offset, size_t length)
{
STRING_CONTRACT (v);
STRING_CONTRACT (ref);
STRINGI_CONTRACT (v);
STRINGI_CONTRACT (ref);
assert (offset <= ref->size);
assert (v != ref); // Not supported yet
if (M_UNLIKELY (ref->size == 0)) {
@@ -273,7 +280,7 @@ string_init_set_str(string_t v1, const char str[])
static inline void
string_init_move(string_t v1, string_t v2)
{
STRING_CONTRACT (v2);
STRINGI_CONTRACT (v2);
v1->size = v2->size;
v1->alloc = v2->alloc;
v1->ptr = v2->ptr;
@@ -281,19 +288,19 @@ string_init_move(string_t v1, string_t v2)
v2->size = 0;
v2->alloc = 0;
v2->ptr = NULL;
STRING_CONTRACT (v1);
STRINGI_CONTRACT (v1);
}
static inline void
string_swap(string_t v1, string_t v2)
{
STRING_CONTRACT (v1);
STRING_CONTRACT (v2);
STRINGI_CONTRACT (v1);
STRINGI_CONTRACT (v2);
M_SWAP (size_t, v1->size, v2->size);
M_SWAP (size_t, v1->alloc, v2->alloc);
M_SWAP (char *, v1->ptr, v2->ptr);
STRING_CONTRACT (v1);
STRING_CONTRACT (v2);
STRINGI_CONTRACT (v1);
STRINGI_CONTRACT (v2);
}
static inline void
@@ -306,30 +313,30 @@ string_move(string_t v1, string_t v2)
static inline void
string_push_back (string_t v, char c)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
stringi_fit2size(v, v->size+2);
v->ptr[v->size++] = c;
v->ptr[v->size] = 0;
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
}
static inline void
string_cat_str(string_t v, const char str[])
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
M_ASSUME (str != NULL);
const size_t size = strlen(str);
stringi_fit2size(v, v->size + size + 1);
memcpy(&v->ptr[v->size], str, size + 1);
v->size += size;
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
}
static inline void
string_cat(string_t v, const string_t v2)
{
STRING_CONTRACT (v2);
STRING_CONTRACT (v);
STRINGI_CONTRACT (v2);
STRINGI_CONTRACT (v);
const size_t size = v2->size;
if (M_LIKELY (size > 0)) {
stringi_fit2size(v, v->size + size + 1);
@@ -338,13 +345,13 @@ string_cat(string_t v, const string_t v2)
v->size += size;
v->ptr[v->size] = 0;
}
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
}
static inline int
string_cmp_str(const string_t v1, const char str[])
{
STRING_CONTRACT (v1);
STRINGI_CONTRACT (v1);
M_ASSUME (str != NULL);
return strcmp(string_get_cstr(v1), str);
}
@@ -352,15 +359,15 @@ string_cmp_str(const string_t v1, const char str[])
static inline int
string_cmp(const string_t v1, const string_t v2)
{
STRING_CONTRACT (v1);
STRING_CONTRACT (v2);
STRINGI_CONTRACT (v1);
STRINGI_CONTRACT (v2);
return strcmp(string_get_cstr(v1), string_get_cstr(v2));
}
static inline bool
string_equal_str_p(const string_t v1, const char str[])
{
STRING_CONTRACT(v1);
STRINGI_CONTRACT(v1);
M_ASSUME (str != NULL);
return string_cmp_str(v1, str) == 0;
}
@@ -368,8 +375,8 @@ string_equal_str_p(const string_t v1, const char str[])
static inline bool
string_equal_p(const string_t v1, const string_t v2)
{
STRING_CONTRACT(v1);
STRING_CONTRACT(v2);
STRINGI_CONTRACT(v1);
STRINGI_CONTRACT(v2);
return v1->size == v2->size && string_cmp(v1, v2) == 0;
}
@@ -377,7 +384,7 @@ string_equal_p(const string_t v1, const string_t v2)
static inline int
string_cmpi_str(const string_t v1, const char p2[])
{
STRING_CONTRACT (v1);
STRINGI_CONTRACT (v1);
M_ASSUME (p2 != NULL);
// strcasecmp is POSIX
const char *p1 = string_get_cstr(v1);
@@ -399,7 +406,7 @@ string_cmpi(const string_t v1, const string_t v2)
static inline size_t
string_search_char (const string_t v, char c, size_t start)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
assert (start <= v->size);
const char *p = M_ASSIGN_CAST(const char*,
strchr(string_get_cstr(v)+start, c));
@@ -409,7 +416,7 @@ string_search_char (const string_t v, char c, size_t start)
static inline size_t
string_search_rchar (const string_t v, char c, size_t start)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
assert (start <= v->size);
// NOTE: Can implement it in a faster way than the libc function
// by scanning backward from the bottom of the string (which is
@@ -422,7 +429,7 @@ string_search_rchar (const string_t v, char c, size_t start)
static inline size_t
string_search_str (const string_t v, const char str[], size_t start)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
assert (start <= v->size);
M_ASSUME (str != NULL);
const char *p = M_ASSIGN_CAST(const char*,
@@ -433,7 +440,7 @@ string_search_str (const string_t v, const char str[], size_t start)
static inline size_t
string_search (const string_t v1, const string_t v2, size_t start)
{
STRING_CONTRACT (v2);
STRINGI_CONTRACT (v2);
assert (start <= v1->size);
return string_search_str(v1, string_get_cstr(v2), start);
}
@@ -441,7 +448,7 @@ string_search (const string_t v1, const string_t v2, size_t start)
static inline size_t
string_search_pbrk(const string_t v1, const char first_of[], size_t start)
{
STRING_CONTRACT (v1);
STRINGI_CONTRACT (v1);
assert (start <= v1->size);
M_ASSUME (first_of != NULL);
const char *p = M_ASSIGN_CAST(const char*,
@@ -452,63 +459,63 @@ string_search_pbrk(const string_t v1, const char first_of[], size_t start)
static inline int
string_strcoll_str(const string_t v, const char str[])
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
return strcoll(string_get_cstr(v), str);
}
static inline int
string_strcoll (const string_t v1, const string_t v2)
{
STRING_CONTRACT (v2);
STRINGI_CONTRACT (v2);
return string_strcoll_str(v1, string_get_cstr(v2));
}
static inline size_t
string_spn(const string_t v1, const char accept[])
{
STRING_CONTRACT (v1);
STRINGI_CONTRACT (v1);
M_ASSUME (accept != NULL);
return strspn(string_get_cstr(v1), accept);
}
static inline size_t
string_cspn(const string_t v1, const char accept[])
string_cspn(const string_t v1, const char reject[])
{
STRING_CONTRACT (v1);
M_ASSUME (accept != NULL);
return strcspn(string_get_cstr(v1), accept);
STRINGI_CONTRACT (v1);
M_ASSUME (reject != NULL);
return strcspn(string_get_cstr(v1), reject);
}
static inline void
string_left(string_t v, size_t index)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
if (index >= v->size)
return;
M_ASSUME (v->ptr != NULL);
v->ptr[index] = 0;
v->size = index;
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
}
// Note: this is an index, not the size to keep from the right !
static inline void
string_right(string_t v, size_t index)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
if (index >= v->size) {
if (v->ptr != NULL) {
v->ptr[0] = 0;
v->size = 0;
}
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
return;
}
M_ASSUME (v->ptr != NULL);
size_t s2 = v->size - index;
memmove (&v->ptr[0], &v->ptr[index], s2+1);
v->size = s2;
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
}
static inline void
@@ -521,7 +528,7 @@ string_mid (string_t v, size_t index, size_t size)
static inline size_t
string_replace_str (string_t v, const char str1[], const char str2[], size_t start)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
M_ASSUME (str1 != NULL && str2 != NULL);
size_t i = string_search_str(v, str1, start);
if (i != STRING_FAILURE) {
@@ -532,7 +539,7 @@ string_replace_str (string_t v, const char str1[], const char str2[], size_t sta
memmove(&v->ptr[i+str2_l], &v->ptr[i+str1_l], v->size - i - str1_l + 1);
memcpy (&v->ptr[i], str2, str2_l);
v->size += str2_l - str1_l;
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
}
return i;
}
@@ -540,16 +547,16 @@ string_replace_str (string_t v, const char str1[], const char str2[], size_t sta
static inline size_t
string_replace (string_t v, const string_t v1, const string_t v2, size_t start)
{
STRING_CONTRACT (v);
STRING_CONTRACT (v1);
STRING_CONTRACT (v2);
STRINGI_CONTRACT (v);
STRINGI_CONTRACT (v1);
STRINGI_CONTRACT (v2);
return string_replace_str(v, string_get_cstr(v1), string_get_cstr(v2), start);
}
static inline void
string_replace_at (string_t v, size_t pos, size_t len, const char str2[])
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
M_ASSUME (pos+len < v->size && str2 != NULL);
const size_t str1_l = len;
const size_t str2_l = strlen(str2);
@@ -558,13 +565,13 @@ string_replace_at (string_t v, size_t pos, size_t len, const char str2[])
memmove(&v->ptr[pos+str2_l], &v->ptr[pos+str1_l], v->size - pos - str1_l + 1);
memcpy (&v->ptr[pos], str2, str2_l);
v->size += str2_l - str1_l;
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
}
static inline int
string_printf (string_t v, const char format[], ...)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
M_ASSUME (format != NULL);
va_list args;
int size;
@@ -583,14 +590,14 @@ string_printf (string_t v, const char format[], ...)
v->size = (size_t) size;
}
va_end (args);
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
return size;
}
static inline int
string_cat_printf (string_t v, const char format[], ...)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
M_ASSUME (format != NULL);
va_list args;
int size;
@@ -608,14 +615,15 @@ string_cat_printf (string_t v, const char format[], ...)
v->size += (size_t) size;
}
va_end (args);
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
return size;
}
static inline bool
string_fgets(string_t v, FILE *f, string_fgets_t arg)
{
STRING_CONTRACT(v);
STRINGI_CONTRACT(v);
assert (f != NULL);
stringi_fit2size (v, 100);
M_ASSUME(v->ptr != NULL);
v->size = 0;
@@ -624,13 +632,13 @@ string_fgets(string_t v, FILE *f, string_fgets_t arg)
while (fgets(&v->ptr[v->size], v->alloc - v->size, f) != NULL) {
retcode = true; /* Something has been read */
v->size += strlen(&v->ptr[v->size]);
STRING_CONTRACT(v);
STRINGI_CONTRACT(v);
if (arg != STRING_READ_FILE && v->ptr[v->size-1] == '\n') {
if (arg == STRING_READ_PURE_LINE) {
v->size --;
v->ptr[v->size] = 0; /* Remove EOL */
}
STRING_CONTRACT(v);
STRINGI_CONTRACT(v);
return retcode; /* Normal terminaison */
} else if (v->ptr[v->size-1] != '\n' && !feof(f)) {
/* The string buffer is not big enough:
@@ -638,7 +646,7 @@ string_fgets(string_t v, FILE *f, string_fgets_t arg)
stringi_fit2size (v, v->alloc + v->alloc/2);
}
}
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
return retcode; /* Abnormal terminaison */
}
@@ -647,7 +655,8 @@ string_fget_word (string_t v, const char separator[], FILE *f)
{
char buffer[128];
char c = 0;
STRING_CONTRACT(v);
STRINGI_CONTRACT(v);
assert (f != NULL);
assert (1+20+2+strlen(separator)+3 < sizeof buffer);
stringi_fit2size (v, 10);
v->size = 0;
@@ -666,7 +675,7 @@ string_fget_word (string_t v, const char separator[], FILE *f)
&& fscanf(f, buffer, &v->ptr[v->size], &c) == 2) {
retcode = true;
v->size += strlen(&v->ptr[v->size]);
STRING_CONTRACT(v);
STRINGI_CONTRACT(v);
if (strchr(separator, c) != NULL)
return retcode;
/* Next char is not a separator: continue parsing */
@@ -678,17 +687,18 @@ string_fget_word (string_t v, const char separator[], FILE *f)
return retcode;
}
static inline void
static inline bool
string_fputs(FILE *f, const string_t v)
{
STRING_CONTRACT (v);
fputs(string_get_cstr(v), f);
STRINGI_CONTRACT (v);
assert (f != NULL);
return fputs(string_get_cstr(v), f) >= 0;
}
static inline bool
string_start_with_str_p(const string_t v, const char str[])
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
M_ASSUME (str != NULL);
const char *v_str = string_get_cstr(v);
while (*str){
@@ -703,21 +713,21 @@ string_start_with_str_p(const string_t v, const char str[])
static inline bool
string_start_with_string_p(const string_t v, const string_t v2)
{
STRING_CONTRACT (v2);
STRINGI_CONTRACT (v2);
return string_start_with_str_p (v, string_get_cstr(v2));
}
static inline size_t
string_hash(const string_t v)
{
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
return m_core_hash(v->ptr, v->size);
}
static inline void
string_strim(string_t v)
{
STRING_CONTRACT (v);
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'))
@@ -734,7 +744,7 @@ string_strim(string_t v)
memmove (v->ptr, b, size);
v->ptr[size] = 0;
v->size = size;
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
}
/* I/O */
@@ -743,8 +753,8 @@ string_get_str(string_t v, const string_t v2, bool append)
{
/* Output: "string" with quote around
Replace " by \" within the string */
STRING_CONTRACT(v2);
STRING_CONTRACT(v);
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;
@@ -762,7 +772,7 @@ string_get_str(string_t v, const string_t v2, bool append)
v->ptr[v->size ++] = '"';
v->ptr[v->size] = 0;
M_ASSUME (v->size <= targetSize);
STRING_CONTRACT (v);
STRINGI_CONTRACT (v);
}
static inline void
@@ -770,7 +780,7 @@ string_out_str(FILE *f, const string_t v)
{
/* Output: "string" with quote around
Replace " by \" within the string */
STRING_CONTRACT(v);
STRINGI_CONTRACT(v);
M_ASSUME (f != NULL);
fputc('"', f);
for(size_t i = 0 ; i < v->size; i++) {
@@ -786,7 +796,7 @@ string_out_str(FILE *f, const string_t v)
static inline bool
string_in_str(string_t v, FILE *f)
{
STRING_CONTRACT(v);
STRINGI_CONTRACT(v);
M_ASSUME (f != NULL);
int c = fgetc(f);
if (c != '"') return false;
@@ -929,7 +939,7 @@ typedef struct {
static inline void
string_it(string_it_t it, const string_t str)
{
STRING_CONTRACT(str);
STRINGI_CONTRACT(str);
assert(it != NULL);
it->ptr = str->ptr;
it->next_ptr = str->ptr;
@@ -972,7 +982,7 @@ string_get_cref (const string_it_t it)
static inline void
string_push_u (string_t str, string_unicode_t u)
{
STRING_CONTRACT(str);
STRINGI_CONTRACT(str);
char buffer[4+1];
stringi_utf8_encode(buffer, u);
string_cat_str(str, buffer);
@@ -982,7 +992,7 @@ string_push_u (string_t str, string_unicode_t u)
static inline size_t
string_length_u(string_t str)
{
STRING_CONTRACT(str);
STRINGI_CONTRACT(str);
return stringi_utf8_length(string_get_cstr(str));
}
@@ -990,7 +1000,7 @@ string_length_u(string_t str)
static inline bool
string_utf8_p(string_t str)
{
STRING_CONTRACT(str);
STRINGI_CONTRACT(str);
return stringi_utf8_valid_str_p(string_get_cstr(str));
}
@@ -1158,4 +1168,232 @@ namespace m_string {
#endif
/***********************************************************************/
/* */
/* BOUNDED STRING, aka char[N+1] */
/* */
/***********************************************************************/
#define BOUNDED_STRING_DEF(name, size) \
\
typedef struct M_C(name, _s) { \
char s[size+1]; \
} M_C(name,_t)[1]; \
\
static inline void \
M_C(name, _init)(M_C(name,_t) s) \
{ \
assert(s != NULL); \
s->s[0] = 0; \
} \
\
static inline void \
M_C(name, _clear)(M_C(name,_t) s) \
{ \
assert(s != NULL); \
/* nothing to do */ \
} \
\
static inline void \
M_C(name, _clean)(M_C(name,_t) s) \
{ \
assert(s != NULL); \
s->s[0] = 0; \
} \
\
static inline size_t \
M_C(name, _size)(const M_C(name,_t) s) \
{ \
assert(s != NULL); \
return strlen(s->s); \
} \
\
static inline size_t \
M_C(name, _capacity)(const M_C(name,_t) s) \
{ \
assert(s != NULL); \
(void)s; /* unused */ \
return size+1; \
} \
\
static inline char \
M_C(name, _get_char)(const M_C(name,_t) s, size_t index) \
{ \
assert(s != NULL); \
assert(index < size); \
return s->s[index]; \
} \
\
static inline bool \
M_C(name, _empty_p)(const M_C(name,_t) s) \
{ \
assert(s != NULL); \
return s->s[0] == 0; \
} \
\
static inline void \
M_C(name, _set_str)(M_C(name,_t) s, const char str[]) \
{ \
assert (s != NULL && str != NULL); \
strncpy(s->s, str, size+1); \
s->s[size] = 0; \
} \
\
static inline void \
M_C(name, _set_strn)(M_C(name,_t) s, const char str[], size_t n) \
{ \
assert (s != NULL && str != NULL); \
size_t len = M_MIN(size, n); \
strncpy(s->s, str, len+1); \
s->s[len] = 0; \
} \
\
static inline const char * \
M_C(name, _get_cstr)(const M_C(name,_t) s) \
{ \
assert (s != NULL); \
return s->s; \
} \
\
static inline void \
M_C(name, _set)(M_C(name,_t) s, const M_C(name,_t) str) \
{ \
assert (s != NULL && str != NULL); \
M_C(name, _set_str)(s, str->s); \
} \
\
static inline void \
M_C(name, _set_n)(M_C(name,_t) s, const M_C(name,_t) str, \
size_t offset, size_t length) \
{ \
assert (s != NULL && str != NULL); \
assert (offset <= size); \
M_C(name, _set_strn)(s, str->s+offset, length); \
} \
\
static inline void \
M_C(name, _init_set)(M_C(name,_t) s, const M_C(name,_t) str) \
{ \
M_C(name,_init)(s); \
M_C(name,_set)(s, str); \
} \
\
static inline void \
M_C(name, _init_set_str)(M_C(name,_t) s, const char str[]) \
{ \
M_C(name,_init)(s); \
M_C(name,_set_str)(s, str); \
} \
\
static inline void \
M_C(name, _cat_str)(M_C(name,_t) s, const char str[]) \
{ \
assert (s != NULL && str != NULL); \
assert (strlen(s->s) <= size); \
strncat(s->s, str, size-strlen(s->s)); \
} \
\
static inline void \
M_C(name, _cat)(M_C(name,_t) s, const M_C(name,_t) str) \
{ \
M_C(name, _cat_str)(s, str->s); \
} \
\
static inline int \
M_C(name, _cmp_str)(const M_C(name,_t) s, const char str[]) \
{ \
assert (s != NULL && str != NULL); \
return strcmp(s->s, str); \
} \
\
static inline int \
M_C(name, _cmp)(const M_C(name,_t) s, const M_C(name,_t) str) \
{ \
assert (s != NULL && str != NULL); \
return strcmp(s->s, str->s); \
} \
\
static inline int \
M_C(name, _equal_str_p)(const M_C(name,_t) s, const char str[]) \
{ \
assert (s != NULL && str != NULL); \
return strcmp(s->s, str) == 0; \
} \
\
static inline int \
M_C(name, _equal_p)(const M_C(name,_t) s, const M_C(name,_t) str) \
{ \
assert (s != NULL && str != NULL); \
return strcmp(s->s, str->s) == 0; \
} \
\
static inline int \
M_C(name, _printf)(M_C(name,_t) s, const char format[], ...) \
{ \
assert (s != NULL && format != NULL); \
va_list args; \
int ret; \
va_start (args, format); \
ret = vsnprintf (s->s, size+1, format, args); \
va_end (args); \
return ret; \
} \
\
static inline int \
M_C(name, _cat_printf)(M_C(name,_t) s, const char format[], ...) \
{ \
assert (s != NULL && format != NULL); \
va_list args; \
int ret; \
va_start (args, format); \
size_t length = strlen(s->s); \
assert(length <= size); \
ret = vsnprintf (&s->s[length], size+1-length, format, args); \
va_end (args); \
return ret; \
} \
\
static inline bool \
M_C(name, _fgets)(M_C(name,_t)s, FILE *f, string_fgets_t arg) \
{ \
assert (s != NULL && f != NULL); \
assert (arg != STRING_READ_FILE); \
char *ret = fgets(s->s, size+1, f); \
s->s[size] = 0; \
if (ret != NULL && arg == STRING_READ_PURE_LINE) { \
size_t length = strlen(s->s); \
if (length > 0 && s->s[length-1] == '\n') \
s->s[length-1] = 0; \
} \
return ret != NULL; \
} \
\
static inline bool \
M_C(name, _fputs)(FILE *f, const M_C(name,_t) s) \
{ \
assert(f != NULL && s != NULL); \
return fputs(s->s, f) >= 0; \
} \
\
static inline size_t \
M_C(name, _hash)(const M_C(name,_t) s) \
{ \
assert (s != NULL); \
/* Cannot use m_core_hash: not aligned on an int */ \
M_HASH_DECL(hash); \
const char *str = s->s; \
while (*str) M_HASH_UP(hash, *str++); \
return M_HASH_FINAL(hash); \
} \
/* Define the OPLIST of a BOUNDED_STRING */
#define BOUNDED_STRING_OPLIST(name) \
(INIT(M_C(name,_init)), INIT_SET(M_C(name,_init_set)), \
SET(M_C(name,_set)), CLEAR(M_C(name,_clear)), HASH(M_C(name,_hash)), \
EQUAL(M_C(name,_equal_p)), CMP(M_C(name,_cmp)), TYPE(M_C(name,_t)), \
)
#endif
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - VARIANT module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
+64 -24
View File
@@ -1,7 +1,7 @@
/*
* M*LIB / WORKER - Extra worker interface
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -128,6 +128,9 @@ typedef struct worker_s {
/* The global reset function */
void (*resetFunc_g)(void);
/* The global clear function */
void (*clearFunc_g)(void);
} worker_t[1];
/* Return the number of CPU of the system */
@@ -145,7 +148,7 @@ workeri_get_cpu_count(void)
nm[0] = CTL_HW;
nm[1] = HW_NCPU;
sysctl(nm, 2, &count, &len, NULL, 0);
return MAX(1, count);
return M_MAX(1, count);
#elif defined (_SC_NPROCESSORS_ONLN)
return sysconf(_SC_NPROCESSORS_ONLN);
#else
@@ -153,6 +156,29 @@ workeri_get_cpu_count(void)
#endif
}
/* Execute a work order */
static inline void
workeri_exec(worker_order_t *w)
{
assert (w!= NULL && w->block != NULL);
//printf ("Starting thread with data %p\n", w->data);
#if WORKER_USE_CLANG_BLOCK
//printf ("Running %s f=%p b=%p\n", (w->func == NULL) ? "Blocks" : "Function", w->func, w->blockFunc);
if (w->func == NULL)
w->blockFunc(w->data);
else
#endif
#if WORKER_USE_CPP_FUNCTION
//printf ("Running %s f=%p b=%p\n", (w->function == NULL) ? "Lambda" : "Function", w->func, w->blockFunc);
if (w->function)
w->function(w->data);
else
#endif
w->func(w->data);
atomic_fetch_add (&w->block->num_terminated_spawn, 1);
}
/* The worker thread */
static inline void
workeri_thread(void *arg)
@@ -164,24 +190,12 @@ workeri_thread(void *arg)
g->resetFunc_g();
//printf ("Waiting for data (queue: %lu / %lu)\n", worker_queue_size(g->queue_g), worker_queue_capacity(g->queue_g));
worker_queue_pop(&w, g->queue_g);
if (w.block == NULL) return;
//printf ("Starting thread with data %p\n", w.data);
#if WORKER_USE_CLANG_BLOCK
//printf ("Running %s f=%p b=%p\n", (w.func == NULL) ? "Blocks" : "Function", w.func, w.blockFunc);
if (w.func == NULL)
w.blockFunc(w.data);
else
#endif
#if WORKER_USE_CPP_FUNCTION
//printf ("Running %s f=%p b=%p\n", (w.function == NULL) ? "Lambda" : "Function", w.func, w.blockFunc);
if (w.function)
w.function(w.data);
else
#endif
w.func(w.data);
if (w.block == NULL) break;
workeri_exec(&w);
worker_queue_pop_release(g->queue_g);
atomic_fetch_add (&w.block->num_terminated_spawn, 1);
}
if (g->clearFunc_g != NULL)
g->clearFunc_g();
}
/* Initialization of the worker module
@@ -189,9 +203,10 @@ workeri_thread(void *arg)
@numWorker: number of worker to create
@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))
worker_init(worker_t g, unsigned int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
{
if (numWorker == 0)
numWorker = workeri_get_cpu_count()-1;
@@ -202,10 +217,13 @@ worker_init(worker_t g, unsigned int numWorker, unsigned int extraQueue, void (*
M_ASSERT_INIT (g->worker != NULL);
g->numWorker_g = numWorker;
g->resetFunc_g = resetFunc;
g->clearFunc_g = clearFunc;
for(size_t i = 0; i < numWorker; i++) {
m_thread_create(g->worker[i].id, workeri_thread, M_ASSIGN_CAST(void*, g));
}
}
// Define function with default values.
#define worker_init(...) worker_init(M_DEFAULT_ARGS(5, (0, 0, NULL, NULL), __VA_ARGS__))
/* Clear of the worker module */
static inline void
@@ -213,7 +231,10 @@ worker_clear(worker_t g)
{
for(unsigned int i = 0; i < g->numWorker_g; i++) {
worker_order_t w = WORKER_EMPTY_ORDER;
worker_queue_push (g->queue_g, w);
// Normaly all worker threads shall be waiting at this
// stage, so all push won't block as the queue is empty.
// But for robustness, let's wait.
worker_queue_push_blocking (g->queue_g, w, true);
}
for(unsigned int i = 0; i < g->numWorker_g; i++) {
@@ -288,17 +309,36 @@ worker_spawn_function(worker_t g, worker_sync_t block, std::function<void(void *
}
#endif
/* Test if all work orders are finished */
static inline bool
worker_sync_p(worker_sync_t block)
{
/* If the number of spawns is greated than the number
of terminated spawns, some spawns are still working.
So wait for terminaison */
return (atomic_load(&block->num_spawn) == atomic_load (&block->num_terminated_spawn));
}
/* Wait for all work orders to be finished */
static inline void
worker_sync(worker_sync_t block)
{
//printf ("Waiting for thread terminasion.\n");
/* If the number of spawns is greated than the number
of terminated spawns, some spawns are still working.
So wait for terminaison */
while (atomic_load(&block->num_spawn) != atomic_load (&block->num_terminated_spawn));
while (!worker_sync_p(block)) ;
}
/* Flush any work order in the queue if some remains.*/
static inline void
worker_flush(worker_t g)
{
worker_order_t w;
while (worker_queue_pop_blocking (&w, g->queue_g, false) == true) {
workeri_exec(&w);
worker_queue_pop_release(g->queue_g);
}
}
/* Return the number of workers */
static inline size_t
worker_count(worker_t g)
+1 -2
View File
@@ -1,10 +1,9 @@
#NOTE: Neither GMP not pthread is not a real dependency. It is only used for the test suite.
CC=cc -std=c99
WCFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -ftrapv
XCFLAGS=
CFLAGS=$(WCFLAGS) $(XCFLAGS)
CPPFLAGS=-I..
LDFLAGS=-pthread -lgmp
LDFLAGS=-pthread
RM=rm -f
all:
+11 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -49,17 +49,26 @@
#undef M_UNLIKELY
#undef M_MEMORY_FULL
#undef M_SWAP
#undef STRING_CONTRACT
#undef STRINGI_CONTRACT
#undef ARRAYI_CONTRACT
#undef LIST_CONTRACT
#undef DICTI_CONTRACT
#undef DICTI_OA_CONTRACT
#undef SHAREDI_CONTRACT
#undef SHAREDI_RESSOURCE_CONTRACT
#undef BUFFERI_CONTRACT
#undef BUFFERI_PROTECTED_CONTRACT
#undef ILISTI_CONTRACT
#undef DEQUEI_CONTRACT
#undef QUEUEI_MPMC_CONTRACT
#undef RBTREEI_CONTRACT_NODE
#undef RBTREEI_CONTRACT
#undef LISTI_CONTRACT
#undef LISTI_DUAL_PUSH_CONTRACT
#undef NDEBUG
#undef atomic_init
#undef atomic_load
#undef atomic_store
#else
/* For normal builds, empty macros which does nothing */
#define START_COVERAGE
+105
View File
@@ -0,0 +1,105 @@
#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
+30
View File
@@ -1,3 +1,25 @@
/*
* 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-list.h"
#include "m-array.h"
#include "m-string.h"
@@ -163,6 +185,14 @@ static void test_array(void)
assert (array_int_size(l) == 0);
assert( algo_array_sort_p(l) == true);
for(int i = -14025; i < 324035; i+=17)
array_int_push_back(l, i);
for(int i = -14025; i < 324035; i+=7)
array_int_push_back(l, i);
assert( algo_array_sort_p(l) == false);
array_int_special_stable_sort(l);
assert( algo_array_sort_p(l) == true);
array_int_clear(l);
ALGO_INIT_VA(l, ARRAY_OPLIST(array_int), 1, 2, 3, 4, 5);
+23 -39
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -21,41 +21,13 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <gmp.h>
#include "mympz.h"
#include "m-array.h"
static void my_mpz_out_str(FILE *f, const mpz_t z)
{
mpz_out_str (f, 10, z);
}
static bool my_mpz_in_str(mpz_t z, FILE *f)
{
return mpz_inp_str (z, f, 10) > 0;
}
static bool my_mpz_equal_p(const mpz_t z1, const mpz_t z2)
{
return mpz_cmp (z1, z2) == 0;
}
#include "m-string.h"
static void my_mpz_str(string_t str, const mpz_t z, bool append)
{
char *s = mpz_get_str(NULL, 10, z);
assert (s != NULL);
if (append) string_cat_str (str, s);
else string_set_str (str, s);
free(s);
}
#include "coverage.h"
START_COVERAGE
ARRAY_DEF(array_uint, unsigned int)
ARRAY_DEF(array_mpz, mpz_t,
(INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), \
OUT_STR(my_mpz_out_str), IN_STR(my_mpz_in_str), EQUAL(my_mpz_equal_p), \
GET_STR(my_mpz_str) ))
ARRAY_DEF(array_mpz, my_mpz_t, MYMPZ_OPLIST)
END_COVERAGE
#define ARRAY_UINT_OPLIST ARRAY_OPLIST(array_uint)
@@ -86,6 +58,10 @@ static void test_uint(void)
}
assert( s == 100 * 99 /2);
array_uint_pop_at(&s, v, 49);
assert (s == 49);
array_uint_push_at(v, 49, 49);
array_uint_pop_at (NULL, v, 0);
assert(array_uint_size(v) == 99);
s= 0;
@@ -125,9 +101,17 @@ static void test_uint(void)
assert(array_uint_size(v) == 1000);
assert(*array_uint_cget(v, 999) == 0);
array_uint_t v2;
array_uint_t v2, v3;
array_uint_init_set(v2,v);
array_uint_init(v3);
array_uint_push_back(v3, 459320);
array_uint_set(v3, v);
assert (array_uint_equal_p(v3, v));
array_uint_push_back(v3, 459320);
array_uint_set(v3, v);
assert (array_uint_equal_p(v3, v));
array_uint_clear(v);
array_uint_clear(v3);
assert(array_uint_size(v2) == 1000);
assert(*array_uint_cget(v2, 999) == 0);
array_uint_push_at (v2, 0, 1742);
@@ -170,11 +154,11 @@ static void test_uint(void)
static void test_mpz(void)
{
array_mpz_t array1, array2;
mpz_t z;
my_mpz_t z;
array_mpz_init (array1);
array_mpz_init (array2);
mpz_init (z);
my_mpz_init (z);
// Test empty
FILE *f = fopen ("a-marray.dat", "wt");
@@ -191,7 +175,7 @@ static void test_mpz(void)
// Test non empty
for(int n = 0; n < 1000; n++) {
mpz_set_ui (z, n);
my_mpz_set_ui (z, n);
array_mpz_push_back (array1, z);
}
@@ -212,18 +196,18 @@ static void test_mpz(void)
M_LET(str, STRING_OPLIST) {
array_mpz_get_str(str, array1, false);
assert (string_cmp_str (str, "[]") == 0);
mpz_set_ui (z, 17);
my_mpz_set_ui (z, 17);
array_mpz_push_back (array1, z);
array_mpz_get_str(str, array1, false);
assert (string_cmp_str (str, "[17]") == 0);
mpz_set_ui (z, 42);
my_mpz_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);
// NOTE: Not the same order than list...
}
mpz_clear (z);
my_mpz_clear (z);
array_mpz_clear(array2);
array_mpz_clear(array1);
}
+41 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -105,6 +105,17 @@ static void test1(void)
assert (b == false);
assert (bitset_size(set) == 196);
bitset_set_str(set, "[1010101010101010101000000000000000000000000000000000000000000000000000001111]");
bitset_push_at(set, 23, true);
bitset_t set3;
bitset_init(set3);
bitset_set_str(set3, "[10101010101010101010000100000000000000000000000000000000000000000000000001111]");
assert(bitset_equal_p(set, set3));
bitset_push_at(set, 25, true);
bitset_set_str(set3, "[101010101010101010100001010000000000000000000000000000000000000000000000001111]");
assert(bitset_equal_p(set, set3));
bitset_clear(set3);
bitset_clean(set);
for(int i = 0; i < 200; i++)
bitset_push_back(set, (i*17547854547UL)&1) ;
@@ -144,6 +155,15 @@ static void test1(void)
assert (bitset_get(set2, 2) == false);
assert (bitset_get(set2, 75) == true);
bitset_set_at (set2, 3, false);
bitset_set_at (set2, 76, true);
bitset_flip_at (set2, 2);
bitset_flip_at (set2, 75);
assert (bitset_get(set2, 2) == true);
assert (bitset_get(set2, 3) == false);
assert (bitset_get(set2, 75) == false);
assert (bitset_get(set2, 76) == true);
bitset_set(set, set2);
bitset_set_at(set, 199, !bitset_get(set, 199));
assert(!bitset_equal_p(set, set2));
@@ -182,6 +202,20 @@ static void test1(void)
bitset_clear(set2);
}
static void test2(void)
{
M_LET(set1, bitset_t) {
bitset_t set2;
bitset_push_back(set1, true);
bitset_init_move(set2, set1);
bool b;
bitset_pop_back(&b, set2);
assert(b);
bitset_init(set1);
bitset_move(set1, set2);
}
}
static void test_str(void)
{
bitset_t set1, set2;
@@ -253,15 +287,15 @@ static void test_logic(void)
bitset_set_str(s2, "[11100000000000000000010000000000000000000000000000000000000000000]");
assert(bitset_equal_p(s1, s2));
bitset_set_str(s1, "[1010000000000000000001111111111110]");
bitset_set_str(s2, "[1100000000000000000111111111111111]");
bitset_set_str(s1, "[10100000000000000000011111111111100000000000000000000000000000000]");
bitset_set_str(s2, "[110000000000000000011111111111111100000000000000000000000000000000]");
bitset_xor (s1, s2);
bitset_set_str(s2, "[0110000000000000000110000000000001]");
bitset_set_str(s2, "[01100000000000000001100000000000010000000000000000000000000000000]");
assert(bitset_equal_p(s1, s2));
bitset_set_str(s1, "[1010000000000000000000000000000000000]");
bitset_set_str(s1, "[1010000000000000000000000000000000000000000000000000000000000000001]");
bitset_not (s1);
bitset_set_str(s2, "[0101111111111111111111111111111111111]");
bitset_set_str(s2, "[0101111111111111111111111111111111111111111111111111111111111111110]");
assert(bitset_equal_p(s1, s2));
}
@@ -277,6 +311,7 @@ static void test_let(void)
int main(void)
{
test1();
test2();
test_str();
test_logic();
test_let();
+6 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -27,6 +27,7 @@ START_COVERAGE
// Define a fixed queue of unsigned int
BUFFER_DEF(buffer_uint, unsigned int, 10, BUFFER_QUEUE|BUFFER_BLOCKING)
QUEUE_MPMC_DEF(queue_uint, unsigned int, BUFFER_QUEUE)
QUEUE_SPSC_DEF(squeue_uint, unsigned int, BUFFER_QUEUE)
END_COVERAGE
// Define a variable stack of float
@@ -97,11 +98,14 @@ static void test_global(void)
assert (!buffer_uint_empty_p(g_buff));
assert (buffer_uint_full_p(g_buff));
assert (buffer_uint_size(g_buff) == 10);
assert (buffer_uint_push_blocking(g_buff, 15, false) == false);
buffer_uint_clean(g_buff);
assert (buffer_uint_empty_p(g_buff));
assert (!buffer_uint_full_p(g_buff));
assert (buffer_uint_size(g_buff) == 0);
unsigned int s;
assert (buffer_uint_pop_blocking(&s, g_buff, false) == false);
assert (buffer_uint_overwrite(g_buff) == 0);
+4 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -23,7 +23,7 @@
#include <stdbool.h>
#include <assert.h>
#include <gmp.h>
#include "mympz.h"
#include "m-core.h"
@@ -158,8 +158,8 @@ static void test_map(void)
static void test_let(void)
{
M_LET(z, M_CLASSIC_OPLIST(mpz)) {
mpz_add(z,z,z);
M_LET(z, M_CLASSIC_OPLIST(my_mpz)) {
my_mpz_add(z,z,z);
}
}
+30 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -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 "mympz.h"
#include "m-string.h"
#include "m-deque.h"
@@ -31,6 +31,7 @@
START_COVERAGE
DEQUE_DEF(deque, int)
END_COVERAGE
DEQUE_DEF(deque_mpz, my_mpz_t, MYMPZ_OPLIST)
#define OPL DEQUE_OPLIST(deque)
@@ -42,19 +43,21 @@ static void test_ti1(int n)
for(int i =0; i < n ;i++) {
deque_push_back(d, i);
assert(*deque_back(d) == i);
deque_push_front(d, i);
assert(*deque_front(d) == i);
}
assert (*deque_back(d) == n-1);
assert (*deque_front(d) == n-1);
assert (!deque_empty_p(d));
assert (deque_size(d) == (size_t)2*n);
int s = 0;
for(int i =0; i < 2*n ;i++) {
int z;
if ((i % 3) == 0)
if ((i % 3) == 0) {
deque_pop_front(&z, d);
else
assert (z > *deque_front(d) );
} else {
deque_pop_back(&z, d);
}
s += z;
}
assert (s == n*(n-1) );
@@ -138,6 +141,8 @@ static void test_it(void)
deque_previous(it);
assert (deque_end_p(it) || !deque_last_p(it));
}
deque_previous(it);
assert (deque_end_p(it));
deque_it_end(it, d);
assert (deque_end_p(it));
assert (deque_last_p(it));
@@ -201,6 +206,23 @@ static void test_set(void)
}
}
// This test showed a very bad behavior in the memory allocator
// deque will continously allocate a new space whereas at most only
// one item is in the container!
// This is still quite slow.
static void test_advance(void)
{
deque_t d;
int j;
deque_init(d);
for(int i = 0; i < 100000000; i ++) {
deque_push_back(d, i);
deque_pop_front(&j, d);
assert (i == j);
}
deque_clear(d);
}
int main(void)
{
test1();
@@ -210,4 +232,6 @@ int main(void)
test_ti1(10000);
test_it();
test_set();
test_advance();
exit(0);
}
+2 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -42,6 +42,7 @@ 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)
END_COVERAGE
DICT_STOREHASH_DEF2(dict_str2, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
DICT_SET_DEF2(dict_setstr, string_t, STRING_OPLIST)
/* Helper structure */
+91 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -21,8 +21,13 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "m-mutex.h"
#include "m-atomic.h"
#include "m-genint.h"
#define MAX_N 256
static void test(size_t n)
{
genint_t s;
@@ -46,9 +51,91 @@ static void test(size_t n)
genint_clear(s);
}
int main(void)
/*******************************************************/
genint_t global;
atomic_bool tab_g[MAX_N];
static void conso(void *p)
{
for(size_t n = 1; n < 256; n++) {
test(n);
size_t n = *(size_t*)p;
for(int i = 0; i < 100000; i++) {
unsigned int tab[4];
for(int j= 0; j < 4; j++) {
tab[j] = genint_pop(global);
if (tab[j] != -1U) {
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) {
assert (tab[j] < n);
assert (atomic_load(&tab_g[tab[j]]) == true);
atomic_store(&tab_g[tab[j]], false);
genint_push(global, tab[j]);
}
}
}
}
static void test2(size_t n)
{
m_thread_t idx[4];
genint_init(global, n);
for(int i = 0; i < MAX_N; i++)
atomic_init(&tab_g[i], false);
for(int i = 0; i < 4; i++) {
m_thread_create (idx[i], conso, (void*)&n);
}
for(int i = 0; i < 4;i++) {
m_thread_join(idx[i]);
}
genint_clear(global);
}
// In this test, the dimension of the global and the number of threads
// match: we cannot have a failure.
static void conso2(void *p)
{
size_t n = *(size_t*)p;
for(int i = 0; i < 1000000; i++) {
unsigned int j = genint_pop(global);
assert (j != -1U);
assert (j < n);
genint_push(global, j);
}
}
static void test3(size_t n)
{
m_thread_t idx[MAX_N];
assert (n <= MAX_N);
genint_init(global, n);
for(size_t i = 0; i < n; i++) {
m_thread_create (idx[i], conso2, (void*)&n);
}
for(size_t i = 0; i < n;i++) {
m_thread_join(idx[i]);
}
genint_clear(global);
}
int main(void)
{
for(size_t n = 1; n < MAX_N; n++) {
test(n);
}
for(size_t n = 1; n < MAX_N; n+=17) {
test2(n);
}
for(size_t n = 2; n < 6; n++) {
test3(n);
}
exit(0);
}
+10 -1
View File
@@ -1,7 +1,7 @@
/*
* MLIB - TEST module
*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -99,6 +99,15 @@ static void test(void)
assert(false);
}
ilist_tname_push_back (list, &x3);
assert (ilist_tname_size (list) == 1);
ilist_tname_push_front (list, &x1);
assert (ilist_tname_size (list) == 2);
ilist_tname_push_after (&x1, &x2);
assert (ilist_tname_size (list) == 3);
assert (ilist_tname_front (list)->n == 1);
assert (ilist_tname_back (list)->n == 3);
ilist_tname_clear(list);
}
+293 -43
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -21,40 +21,17 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <gmp.h> // For testing purpose only.
#include "mympz.h"
#include "m-string.h"
#include "m-list.h"
static void my_mpz_out_str(FILE *f, const mpz_t z)
{
mpz_out_str (f, 10, z);
}
static bool my_mpz_in_str(mpz_t z, FILE *f)
{
return mpz_inp_str (z, f, 10) > 0;
}
static bool my_mpz_equal_p(const mpz_t z1, const mpz_t z2)
{
return mpz_cmp (z1, z2) == 0;
}
static void my_mpz_str(string_t str, const mpz_t z, bool append)
{
char *s = mpz_get_str(NULL, 10, z);
if (append) string_cat_str (str, s);
else string_set_str (str, s);
free(s);
}
#include "coverage.h"
START_COVERAGE
LIST_DEF(list_uint, unsigned int)
LIST_DEF(list_mpz, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), \
OUT_STR(my_mpz_out_str), IN_STR(my_mpz_in_str), EQUAL(my_mpz_equal_p), \
GET_STR(my_mpz_str)))
LIST_DEF(list_mpz, my_mpz_t, MYMPZ_OPLIST)
LIST_DUAL_PUSH_DEF(list2_double, double)
END_COVERAGE
LIST_DUAL_PUSH_DEF(list2_mpz, my_mpz_t, MYMPZ_OPLIST)
#define LIST_UINT_OPLIST LIST_OPLIST(list_uint)
static void test_uint(void)
@@ -211,36 +188,36 @@ static void test_uint(void)
static void test_mpz(void)
{
list_mpz_t v;
mpz_t z, x, s;
my_mpz_t z, x, s;
mpz_init (z);
mpz_init (x);
mpz_init (s);
my_mpz_init (z);
my_mpz_init (x);
my_mpz_init (s);
list_mpz_init(v);
assert (list_mpz_empty_p(v) == true);
mpz_set_ui (z, 2);
my_mpz_set_ui (z, 2);
list_mpz_push_back(v, z);
assert (list_mpz_empty_p(v) == false);
list_mpz_pop_back(&x, v);
assert( mpz_cmp (x, z) == 0);
assert( my_mpz_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 ++) {
mpz_set_ui (z, i);
my_mpz_set_ui (z, i);
list_mpz_push_back(v, z);
}
assert (list_mpz_size(v) == 1000);
list_mpz_it_t u;
mpz_set_ui (s, 0);
my_mpz_set_ui (s, 0);
for(list_mpz_it(u, v); !list_mpz_end_p(u); list_mpz_next(u)) {
mpz_add (s, s, *list_mpz_cref(u));
my_mpz_add (s, s, *list_mpz_cref(u));
}
assert (mpz_get_ui(s) == 1000*999/2);
assert (my_mpz_get_ui(s) == 1000*999/2);
FILE *f = fopen ("a-mlist.dat", "wt");
if (!f) abort();
@@ -260,11 +237,11 @@ static void test_mpz(void)
M_LET(str, STRING_OPLIST) {
list_mpz_get_str(str, v, false);
assert (string_cmp_str (str, "[]") == 0);
mpz_set_ui (z, 17);
my_mpz_set_ui (z, 17);
list_mpz_push_back (v, z);
list_mpz_get_str(str, v, false);
assert (string_cmp_str (str, "[17]") == 0);
mpz_set_ui (z, 42);
my_mpz_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);
@@ -272,14 +249,287 @@ static void test_mpz(void)
list_mpz_clear(v);
mpz_clear (z);
mpz_clear (x);
mpz_clear (s);
my_mpz_clear (z);
my_mpz_clear (x);
my_mpz_clear (s);
}
static void test_dual_push1(void)
{
list2_double_t list;
double d;
list2_double_init(list);
assert(list2_double_empty_p(list));
assert(list2_double_size(list) == 0);
list2_double_push_back(list, 2.0);
assert(!list2_double_empty_p(list));
assert (*list2_double_back(list) == 2.0);
assert (*list2_double_front(list) == 2.0);
list2_double_pop_back(&d, list);
assert (d == 2.0);
assert(list2_double_empty_p(list));
assert(list2_double_size(list) == 0);
list2_double_push_front(list, 3.0);
assert (*list2_double_back(list) == 3.0);
assert (*list2_double_front(list) == 3.0);
assert(!list2_double_empty_p(list));
list2_double_pop_back(&d, list);
assert (d == 3.0);
assert(list2_double_empty_p(list));
assert(list2_double_size(list) == 0);
list2_double_push_back(list, 2.0);
list2_double_push_back(list, 3.0);
list2_double_push_front(list, 1.0);
list2_double_push_front(list, 0.0);
assert (*list2_double_back(list) == 3.0);
assert (*list2_double_front(list) == 0.0);
list2_double_pop_back(&d, list);
assert (d == 3.0);
list2_double_pop_back(&d, list);
assert (d == 2.0);
list2_double_pop_back(&d, list);
assert (d == 1.0);
list2_double_pop_back(&d, list);
assert (d == 0.0);
assert(list2_double_empty_p(list));
list2_double_push_back_new(list);
list2_double_pop_back(&d, list);
assert (d == 0.0);
list2_double_push_front_new(list);
list2_double_pop_back(&d, list);
assert (d == 0.0);
list2_double_push_back_new(list);
list2_double_pop_back(NULL, list);
assert(list2_double_empty_p(list));
list2_double_push_front_new(list);
list2_double_pop_back(NULL, list);
assert(list2_double_empty_p(list));
for(double e = 0.0; e < 1024.0; e += 1.0) {
if (e < 1000.0)
list2_double_push_front(list, e);
if (e >= 24.0 && e < 1000.0) {
assert (list2_double_size (list) == 25);
}
if (e >= 24.0) {
list2_double_pop_back(&d, list);
assert (d + 24.0 == e);
}
}
list2_double_push_back(list, 15);
list2_double_t list2;
list2_double_init(list2);
assert(list2_double_empty_p(list2));
assert(!list2_double_empty_p(list));
list2_double_swap(list, list2);
assert(!list2_double_empty_p(list2));
assert(list2_double_empty_p(list));
list2_double_clear(list2);
for(double e = 0.0; e < 1024.0; e += 1.0) {
list2_double_push_back(list, e);
}
list2_double_init_set (list2, list);
assert(list2_double_equal_p(list, list2));
list2_double_reverse(list2);
for(double e = 0.0; e < 1024.0 ; e += 1.0) {
list2_double_pop_back(&d, list2);
assert (d == e);
}
assert(list2_double_empty_p(list2));
list2_double_splice(list2, list);
assert(list2_double_size(list2) == 1024);
assert(list2_double_size(list) == 0);
list2_double_set(list, list2);
assert(list2_double_size(list) == 1024);
list2_double_splice(list2, list);
assert(list2_double_size(list2) == 2048);
assert(list2_double_size(list) == 0);
list2_double_move(list, list2);
list2_double_clear(list);
}
static void test_dual_it1(void)
{
list2_double_t list;
list2_double_it_t it, it2;
double d;
list2_double_init(list);
list2_double_it(it, list);
assert(list2_double_end_p(it));
list2_double_it_end(it, list);
assert(list2_double_end_p(it));
for(double e = 0.0; e < 1024.0 ; e += 1.0)
list2_double_push_front(list, e);
list2_double_it(it, list);
assert(!list2_double_end_p(it));
list2_double_it_set (it2, it);
assert(list2_double_it_equal_p(it2, it));
list2_double_it_end(it, list);
assert(!list2_double_it_equal_p(it2, it));
assert(list2_double_end_p(it));
assert(!list2_double_end_p(it2));
assert(*list2_double_ref(it2) == 0.0);
d = 0.0;
for(list2_double_it(it, list) ;
!list2_double_end_p(it) ;
list2_double_next(it) ) {
double e = *list2_double_cref(it);
assert(e == d);
if (list2_double_last_p(it))
assert (d == 1023.0);
d += 1.0;
}
assert (d == 1024.0);
// Insert in last
list2_double_it_end(it, list);
list2_double_insert(list, it, -1.0);
d = -1.0;
for(list2_double_it(it, list) ;
!list2_double_end_p(it) ;
list2_double_next(it) ) {
double e = *list2_double_cref(it);
assert(e == d);
if (list2_double_last_p(it))
list2_double_it_set(it2, it);
d += 1.0;
}
assert (d == 1024.0);
assert(*list2_double_back(list) == -1.0);
assert(*list2_double_front(list) == 1023.0);
// Insert in front
list2_double_insert(list, it2, 1024.0);
d = -1.0;
for(list2_double_it(it, list) ;
!list2_double_end_p(it) ;
list2_double_next(it) ) {
double e = *list2_double_cref(it);
assert(e == d);
d += 1.0;
}
assert (d == 1025.0);
assert(*list2_double_back(list) == -1.0);
assert(*list2_double_front(list) == 1024.0);
// Insert in between
list2_double_it(it, list) ;
list2_double_insert(list, it, -0.5);
d = -1.0;
for(list2_double_it(it, list) ;
!list2_double_end_p(it) ;
list2_double_next(it) ) {
double e = *list2_double_cref(it);
assert(e == d);
d += (d < 0.0) ? 0.5 : 1.0;
}
assert (d == 1025.0);
assert(*list2_double_back(list) == -1.0);
assert(*list2_double_front(list) == 1024.0);
// Remove in between
list2_double_it(it, list) ;
list2_double_next(it);
assert (*list2_double_cref(it) == -0.5);
list2_double_remove(list, it);
d = -1.0;
for(list2_double_it(it, list) ;
!list2_double_end_p(it) ;
list2_double_next(it) ) {
double e = *list2_double_cref(it);
assert(e == d);
if (list2_double_last_p(it))
list2_double_it_set(it2, it);
d += 1.0;
}
assert (d == 1025.0);
assert(*list2_double_back(list) == -1.0);
assert(*list2_double_front(list) == 1024.0);
// Remove front
list2_double_remove(list, it2);
d = -1.0;
for(list2_double_it(it, list) ;
!list2_double_end_p(it) ;
list2_double_next(it) ) {
double e = *list2_double_cref(it);
assert(e == d);
d += 1.0;
}
assert (d == 1024.0);
assert(*list2_double_back(list) == -1.0);
assert(*list2_double_front(list) == 1023.0);
// Remove back
list2_double_it(it, list);
list2_double_remove(list, it);
d = 0.0;
for(list2_double_it(it, list) ;
!list2_double_end_p(it) ;
list2_double_next(it) ) {
double e = *list2_double_cref(it);
assert(e == d);
d += 1.0;
}
assert (d == 1024.0);
assert(*list2_double_back(list) == 0.0);
assert(*list2_double_front(list) == 1023.0);
list2_double_t list2;
list2_double_init_set(list2, list);
// Splice back the back of list
list2_double_it(it, list);
list2_double_splice_back(list2, list, it);
assert(*list2_double_back(list) == 1.0);
assert(*list2_double_cref(it) == 1.0);
list2_double_it(it2, list2);
assert(*list2_double_cref(it2) == 0.0);
list2_double_next(it2);
assert(*list2_double_cref(it2) == 0.0);
list2_double_next(it2);
assert(*list2_double_cref(it2) == 1.0);
// Splice back an element of list
list2_double_next(it);
list2_double_splice_back(list2, list, it);
assert(*list2_double_back(list) == 1.0);
assert(*list2_double_cref(it) == 3.0);
list2_double_it(it2, list2);
assert(*list2_double_cref(it2) == 2.0);
list2_double_next(it2);
assert(*list2_double_cref(it2) == 0.0);
list2_double_next(it2);
assert(*list2_double_cref(it2) == 0.0);
list2_double_next(it2);
assert(*list2_double_cref(it2) == 1.0);
list2_double_clear(list2);
list2_double_clear(list);
}
int main(void)
{
test_uint();
test_mpz();
test_dual_push1();
test_dual_it1();
exit(0);
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
+2 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -99,4 +99,5 @@ int main(void)
{
test1();
test2();
exit(0);
}
+78 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -43,21 +43,57 @@ 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_float, float)
END_COVERAGE
RBTREE_DEF(rbtree_float, float)
#define UINT_OPLIST RBTREE_OPLIST(rbtree_uint)
#define FLOAT_OP RBTREE_OPLIST(rbtree_float)
static void test_uint(void)
{
rbtree_uint_t tree, tree2;
rbtree_uint_t tree, tree2, tree3;
rbtree_uint_init(tree);
assert (rbtree_uint_empty_p(tree));
rbtree_uint_init_set(tree2, tree);
assert (rbtree_uint_empty_p(tree2));
rbtree_uint_clear(tree);
rbtree_uint_push(tree, 10);
rbtree_uint_push(tree, 5);
rbtree_uint_push(tree, 17);
rbtree_uint_push(tree, 3);
rbtree_uint_push(tree, 11);
assert(rbtree_uint_size(tree) == 5);
assert(rbtree_uint_empty_p(tree) == false);
const unsigned int tab[] = {3, 5, 10, 11, 17};
int k = 0;
for M_EACH(item, tree, UINT_OPLIST) {
assert (tab[k] == *item);
k ++;
}
assert (k == 5);
rbtree_uint_it_t it, it2;
for (rbtree_uint_it_last(it, tree) ; !rbtree_uint_end_p(it) ; rbtree_uint_previous(it)) {
k--;
rbtree_uint_it_set(it2, it);
assert(rbtree_uint_it_equal_p(it2, it));
assert (tab[k] == *rbtree_uint_cref(it2) );
}
rbtree_uint_it_end(it, tree);
assert (rbtree_uint_end_p(it));
assert(!rbtree_uint_it_equal_p(it2, it));
assert( k == 0);
assert (rbtree_uint_hash(tree) != 0);
rbtree_uint_init(tree3);
rbtree_uint_push(tree3, 5);
rbtree_uint_move(tree3, tree);
rbtree_uint_clear(tree3);
rbtree_uint_init_move(tree, tree2);
rbtree_uint_init_move(tree2, tree);
assert (rbtree_uint_empty_p(tree2));
const unsigned int max = 1001;
for(unsigned int num = 1; num < max; num++) {
rbtree_uint_init(tree);
@@ -65,6 +101,11 @@ static void test_uint(void)
rbtree_uint_push(tree, i);
assert(rbtree_uint_size(tree) == num);
assert(rbtree_uint_empty_p(tree) == false);
if (num > 10) {
rbtree_uint_push(tree, 10);
assert(rbtree_uint_size(tree) == num);
assert(rbtree_uint_empty_p(tree) == false);
}
unsigned int count = 0;
for M_EACH(item, tree, UINT_OPLIST) {
assert (count == *item);
@@ -72,11 +113,16 @@ static void test_uint(void)
}
assert (*rbtree_uint_min(tree) == 0);
assert (*rbtree_uint_max(tree) == num-1);
assert (*rbtree_uint_cmin(tree) == 0);
assert (*rbtree_uint_cmax(tree) == num-1);
assert (count == num);
rbtree_uint_set(tree2, tree);
unsigned int *ptr = rbtree_uint_get(tree2, num/2);
assert (ptr != NULL);
assert (*ptr == num/2);
const unsigned int *cptr = rbtree_uint_cget(tree2, num/2);
assert (cptr != NULL);
assert (*cptr == num/2);
rbtree_uint_clear(tree);
bool b = rbtree_uint_pop(NULL, tree2, num+1);
@@ -92,7 +138,7 @@ static void test_uint(void)
assert(b);
ptr = rbtree_uint_get(tree2, i);
assert (ptr == NULL);
}
}
}
rbtree_uint_init (tree);
@@ -110,6 +156,32 @@ static void test_uint(void)
rbtree_uint_clear(tree2);
}
static void test_uint_permut(void)
{
const unsigned int max = 1001;
unsigned int tab[1001];
for(unsigned int num = 1; num < max; num++) {
rbtree_uint_t tree;
rbtree_uint_init(tree);
for(unsigned int i = 0; i < num; i++)
tab[i] = i;
for(unsigned int i = 0; i < 2 * num; i++) {
int j = rand() % num;
int k = rand() % num;
M_SWAP(unsigned int, tab[j], tab[k]);
}
for(unsigned int i = 0; i < num; i++)
rbtree_uint_push(tree, tab[i]);
unsigned int k = 0;
for M_EACH(item, tree, UINT_OPLIST) {
assert (k == *item);
k++;
}
rbtree_uint_clear(tree);
}
}
static void test_float(void)
{
M_LET(tree, FLOAT_OP) {
@@ -172,6 +244,7 @@ static void test_io(void)
int main(void)
{
test_uint();
test_uint_permut();
test_float();
test_io();
exit(0);
+55 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -20,16 +20,18 @@
* (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>
#include <assert.h>
#include "mympz.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))
END_COVERAGE
SHARED_PTR_DEF(shared_mpz, mpz_t, M_CLASSIC_OPLIST(mpz))
SHARED_PTR_DEF(shared_mpz, my_mpz_t, M_CLASSIC_OPLIST(my_mpz))
SHARED_PTR_RELAXED_DEF(shared_relaxed_int, int)
static int f(const shared_int_t p)
{
@@ -128,9 +130,59 @@ static void test2(void)
shared_int_clear(p1);
}
#define MAX_RESSOURCE 10
static void test_ressource(int n)
{
shared_ressource_t ressource;
shared_ressource_it_t it[MAX_RESSOURCE];
shared_ressource_it_t copy[MAX_RESSOURCE];
shared_ressource_it_t onemore;
shared_ressource_init (ressource, 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]);
assert (z != NULL);
my_mpz_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]);
assert (z != NULL);
assert (my_mpz_cmp_ui(*z, i) == 0);
}
shared_ressource_it (onemore, ressource);
assert (shared_ressource_end_p(onemore));
for(int i = 0; i < n ; i++) {
shared_ressource_end (it[i], ressource);
}
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]);
assert (z != NULL);
shared_ressource_end (copy[i], ressource);
assert (shared_ressource_end_p(copy[i]));
shared_ressource_it (onemore, ressource);
assert (!shared_ressource_end_p(onemore));
shared_ressource_end (onemore, ressource);
shared_ressource_end (copy[i], ressource);
}
shared_ressource_clear(ressource);
}
int main(void)
{
test1();
test2();
for(int i = 1; i < MAX_RESSOURCE; i++)
test_ressource(i);
exit(0);
}
+213 -21
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -26,11 +26,34 @@
#include "m-mutex.h"
#include "coverage.h"
// Long Structure with a simple CRC to check for proper passing
typedef struct {
unsigned int n;
unsigned long long spare1;
unsigned int c;
unsigned long long spare2;
unsigned int p;
} data_t;
static void data_crc(data_t *p) { p->p = -p->n; p->c = ~p->n; }
static void data_init(data_t *p) { p->n = 0; p->spare1 = 0; p->spare2 = 0; data_crc(p); }
static void data_valid_p(const data_t *p) { assert (p->n == -p->p && p->n == ~p->c); }
static void data_clear(data_t *p) { (void) p;}
static void data_set(data_t *p, data_t o) { p->n = o.n; data_crc(p); }
#define DATA_OPLIST \
(INIT(data_init M_IPTR), INIT_SET(data_set M_IPTR), SET(data_set M_IPTR), CLEAR(data_clear M_IPTR))
START_COVERAGE
SNAPSHOT_DEF(snapshot_uint, unsigned int)
SNAPSHOT_DEF(snapshot_mpz, mpz_t,
(INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear)))
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_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 )
static void test_uint(void)
{
@@ -75,21 +98,6 @@ static void test_uint(void)
assert (*snapshot_uint_read(t) == 3);
}
typedef struct {
unsigned int n;
unsigned int c;
unsigned int p;
} data_t;
static void data_crc(data_t *p) { p->p = -p->n; p->c = ~p->n; }
static void data_init(data_t *p) { p->n = 0; data_crc(p); }
static void data_clear(data_t *p) { (void) p;}
static void data_set(data_t *p, data_t o) { p->p = o.p; data_crc(p); }
SNAPSHOT_DEF(snapshot_data, data_t,
(INIT(data_init M_IPTR), INIT_SET(data_set M_IPTR), SET(data_set M_IPTR), CLEAR(data_clear M_IPTR))
)
snapshot_data_t g_buff;
static void conso(void *arg)
@@ -97,8 +105,7 @@ static void conso(void *arg)
assert (arg == NULL);
while (true) {
const data_t *p = snapshot_data_read(g_buff);
assert (p->n == -p->p);
assert (p->n == ~p->c);
data_valid_p(p);
if (p->n == 0)
return;
}
@@ -140,10 +147,195 @@ static void test_global(void)
snapshot_data_clear(g_buff);
}
static void test_mrsw_int1(void)
{
snapshot_mrsw_int_t idx;
snapshot_mrsw_int_init(idx, 1);
assert (snapshot_mrsw_int_get_write_idx(idx) == 1);
assert (snapshot_mrsw_int_write(idx) == 0);
assert (snapshot_mrsw_int_write(idx) == 1);
assert (snapshot_mrsw_int_write(idx) == 0);
assert (snapshot_mrsw_int_write(idx) == 1);
assert (snapshot_mrsw_int_read_start(idx) == 0);
snapshot_mrsw_int_read_end(idx, 0);
assert (snapshot_mrsw_int_read_start(idx) == 0);
snapshot_mrsw_int_read_end(idx, 0);
assert (snapshot_mrsw_int_write(idx) == 0);
assert (snapshot_mrsw_int_read_start(idx) == 1);
assert (snapshot_mrsw_int_write(idx) == 2);
assert (snapshot_mrsw_int_write(idx) == 0);
assert (snapshot_mrsw_int_write(idx) == 2);
snapshot_mrsw_int_read_end(idx, 1);
assert (snapshot_mrsw_int_read_start(idx) == 0);
assert (snapshot_mrsw_int_write(idx) == 1);
snapshot_mrsw_int_clear(idx);
}
static void test_mrsw_int2(void)
{
snapshot_mrsw_int_t idx;
snapshot_mrsw_int_init(idx, 2);
assert (snapshot_mrsw_int_get_write_idx(idx) == 1);
assert (snapshot_mrsw_int_write(idx) == 0);
assert (snapshot_mrsw_int_write(idx) == 1);
assert (snapshot_mrsw_int_write(idx) == 0);
assert (snapshot_mrsw_int_write(idx) == 1);
assert (snapshot_mrsw_int_read_start(idx) == 0);
snapshot_mrsw_int_read_end(idx, 0);
assert (snapshot_mrsw_int_read_start(idx) == 0);
snapshot_mrsw_int_read_end(idx, 0);
assert (snapshot_mrsw_int_write(idx) == 0);
assert (snapshot_mrsw_int_read_start(idx) == 1);
assert (snapshot_mrsw_int_write(idx) == 2);
assert (snapshot_mrsw_int_write(idx) == 0);
assert (snapshot_mrsw_int_write(idx) == 2);
assert (snapshot_mrsw_int_read_start(idx) == 0);
assert (snapshot_mrsw_int_write(idx) == 3);
snapshot_mrsw_int_read_end(idx, 1);
assert (snapshot_mrsw_int_read_start(idx) == 2);
assert (snapshot_mrsw_int_write(idx) == 1);
snapshot_mrsw_int_read_end(idx, 0);
snapshot_mrsw_int_clear(idx);
}
snapshot_mrsw_data_t global_mrsw;
static void conso2(void *arg)
{
assert (arg == NULL);
while (true) {
const data_t *p = snapshot_mrsw_data_read_start(global_mrsw);
assert (p != NULL);
data_valid_p(p);
if (p->n == 0)
return;
snapshot_mrsw_data_read_end(global_mrsw, p);
}
}
static void prod2(void *arg)
{
assert (arg == NULL);
data_t *p = snapshot_mrsw_data_get_write_buffer(global_mrsw);
for(unsigned int i = 1; i < 200000;i++) {
assert (p != NULL);
p->n = i * i;
data_crc(p);
p = snapshot_mrsw_data_write(global_mrsw);
}
p->n = 0;
data_crc(p);
p = snapshot_mrsw_data_write(global_mrsw);
assert (p != NULL);
}
#define MAX_WRITER 8
#define MAX_READER 8
static void test_mrsw_global(int reader)
{
m_thread_t idx_w;
m_thread_t idx[MAX_READER];
snapshot_mrsw_data_init(global_mrsw, reader);
data_t *p = snapshot_mrsw_data_write(global_mrsw);
assert (p != NULL);
p->n = 42;
data_crc(p);
p = snapshot_mrsw_data_write(global_mrsw);
assert (p != NULL);
for(int i = 0 ; i < reader; i++)
m_thread_create (idx[i], conso2, NULL);
m_thread_create (idx_w, prod2, NULL);
m_thread_join(idx_w);
for(int i = 0 ; i < reader; i++)
m_thread_join(idx[i]);
snapshot_mrsw_data_clear(global_mrsw);
}
snapshot_mrmw_data_t global_mrmw;
static void conso3(void *arg)
{
assert (arg == NULL);
while (true) {
const data_t *p = snapshot_mrmw_data_read_start(global_mrmw);
assert (p != NULL);
data_valid_p(p);
if (p->n == 0)
return;
snapshot_mrmw_data_read_end(global_mrmw, p);
}
}
static void prod3(void *arg)
{
assert (arg == NULL);
for(unsigned int i = 1; i < 20000000;i++) {
data_t *p = snapshot_mrmw_data_write_start(global_mrmw);
assert (p != NULL);
p->n = i * i;
data_crc(p);
snapshot_mrmw_data_write_end(global_mrmw, p);
}
data_t *p = snapshot_mrmw_data_write_start(global_mrmw);
p->n = 0;
data_crc(p);
snapshot_mrmw_data_write_end(global_mrmw, p);
}
static void test_mrmw_global(int reader, int writer)
{
m_thread_t idx_w[MAX_WRITER];
m_thread_t idx[MAX_READER];
snapshot_mrmw_data_init(global_mrmw, reader, writer);
data_t *p = snapshot_mrmw_data_write_start(global_mrmw);
assert (p != NULL);
p->n = 42;
data_crc(p);
snapshot_mrmw_data_write_end(global_mrmw, p);
for(int i = 0 ; i < reader; i++)
m_thread_create (idx[i], conso3, NULL);
for(int i = 0 ; i < writer; i++)
m_thread_create (idx_w[i], prod3, NULL);
for(int i = 0 ; i < writer; i++)
m_thread_join(idx_w[i]);
for(int i = 0 ; i < reader; i++)
m_thread_join(idx[i]);
snapshot_mrmw_data_clear(global_mrmw);
}
int main(void)
{
test_uint();
test_global();
test_mrsw_int1();
test_mrsw_int2();
test_mrsw_global(1);
test_mrsw_global(2);
test_mrsw_global(4);
test_mrsw_global(MAX_READER);
test_mrmw_global(1, 1);
test_mrmw_global(MAX_READER/4, MAX_WRITER/4);
exit(0);
}
+64 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -24,11 +24,14 @@
#define STRING_WITHIN_TEST
#include "m-string.h"
BOUNDED_STRING_DEF(string16, 16)
static void test1(void)
{
M_LET(s1, s2, string_t) {
string_set_str(s1, "Success!");
string_set(s2, s1);
assert(string_equal_p(s1, s2));
}
}
@@ -111,7 +114,7 @@ static void test_utf8_it(void)
string_clear(s);
}
int main(void)
static void test0(void)
{
string_t s1;
string_t s2;
@@ -147,6 +150,9 @@ int main(void)
assert (strcmp(string_get_cstr(s1), "Hello beautiful world!") == 0);
string_clean(s1);
string_set_n (s2, s1, 0, 5);
assert(string_empty_p(s2));
string_set_str(s1, "Hello");
string_cat_str(s1, ", world!");
assert (string_size(s1) == 13);
@@ -418,8 +424,64 @@ int main(void)
string_clear (s1);
string_clear (s2);
}
static void test_bounded1(void)
{
string16_t s, d;
string16_init(s);
assert (string16_empty_p(s));
assert (string16_size(s) == 0);
assert (string16_capacity(s) == 17);
string16_set_str(s, "Hello");
assert (!string16_empty_p(s));
assert (string16_size(s) == 5);
assert (string16_equal_str_p(s, "Hello"));
assert (string16_cmp_str(s, "Hello") == 0);
assert (string16_get_char(s, 1) == 'e');
assert (strcmp(string16_get_cstr(s), "Hello") == 0);
string16_clean(s);
assert (string16_empty_p(s));
assert (string16_size(s) == 0);
string16_set_str(s, "Hello, world! How do you do?");
assert (!string16_empty_p(s));
assert (string16_size(s) == 16);
assert (string16_equal_str_p(s, "Hello, world! Ho"));
string16_set_strn(s, "Hello, world! How do you do?", 17);
assert (!string16_empty_p(s));
assert (string16_size(s) == 16);
assert (string16_equal_str_p(s, "Hello, world! Ho"));
string16_set_strn(s, "Hello, world! How do you do?", 15);
assert (!string16_empty_p(s));
assert (string16_size(s) == 15);
assert (string16_equal_str_p(s, "Hello, world! H"));
string16_cat_str(s, "ow do you do?");
assert (string16_size(s) == 16);
assert (!string16_equal_str_p(s, "Hello, world! H"));
assert (string16_equal_str_p(s, "Hello, world! Ho"));
string16_printf(s, "HeH:%d", 16);
assert (string16_size(s) == 6);
assert (string16_equal_str_p(s, "HeH:16"));
string16_cat_printf(s, " GeG:%d/%d FRE:%d", 17, 42, 13);
assert (string16_size(s) == 16);
assert (string16_equal_str_p(s, "HeH:16 GeG:17/42"));
assert (string16_hash(s) != 0);
string16_set_strn(s, "Hello, world! How do you do?", 15);
string16_init_set(d, s);
string16_clean(s);
assert (string16_equal_str_p(d, "Hello, world! H"));
string16_clear(d);
string16_clear(s);
}
int main(void)
{
test0();
test1();
test_utf8_basic();
test_utf8_it();
test_bounded1();
exit(0);
}
+15 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -21,28 +21,28 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <gmp.h>
#include "mympz.h"
#include "m-string.h"
#include "m-tuple.h"
#include "coverage.h"
START_COVERAGE
TUPLE_DEF2(pair,
(key, string_t, (INIT(string_init), INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear))),
(value, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear) )))
(value, my_mpz_t, MYMPZ_OPLIST) )
END_COVERAGE
// 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, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear) )),
(value, my_mpz_t, MYMPZ_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, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), CMP(mpz_cmp) )))
(value, my_mpz_t, M_OPEXTEND( MYMPZ_OPLIST, CMP(my_mpz_cmp)) ) )
TUPLE_DEF2(pair_str,
(vala, string_t, STRING_OPLIST),
@@ -98,33 +98,33 @@ int main(void)
pair_init (p1);
string_set_str(p1->key, "HELLO");
mpz_set_str(p1->value, "1742", 10);
my_mpz_set_ui(p1->value, 1742);
pair_init_set (p2, p1);
assert(mpz_cmp_ui(p2->value, 1742) == 0);
assert(my_mpz_cmp_ui(p2->value, 1742) == 0);
assert(string_equal_str_p(p2->key, "HELLO"));
string_set_str(p2->key, "HELLO WORLD");
mpz_set_str(p2->value, "174217", 10);
my_mpz_set_ui(p2->value, 174217);
pair_set(p1, p1);
pair_set(p1, p2);
assert(mpz_cmp_ui(p1->value, 174217) == 0);
assert(my_mpz_cmp_ui(p1->value, 174217) == 0);
assert(string_equal_str_p(p1->key, "HELLO WORLD"));
pair_clear(p1);
pair_clear(p2);
string_t s;
mpz_t z;
my_mpz_t z;
pair3_t p3, p4;
string_init_set_str(s, "HELLO");
mpz_init_set_ui (z, 1442);
my_mpz_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);
mpz_set_ui (z, 1443);
my_mpz_set_ui (z, 1443);
pair3_set_value(p4, z);
i = pair3_cmp (p3, p4);
assert (i < 0);
mpz_set_ui (z, 1442);
my_mpz_set_ui (z, 1442);
string_set_str(s, "HELLN");
pair3_set_key(p4, s);
i = pair3_cmp (p3, p4);
@@ -132,7 +132,7 @@ int main(void)
pair3_clear(p3);
pair3_clear(p4);
string_clear(s);
mpz_clear(z);
my_mpz_clear(z);
check_io();
check_swap();
+9 -9
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -21,9 +21,9 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <gmp.h>
#include "mympz.h"
#include "m-string.h"
#include "m-variant.h"
#include "coverage.h"
@@ -138,7 +138,7 @@ static void test_pair(void)
VARIANT_DEF2(triple,
(s, string_t, STRING_OPLIST),
(z, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear) )),
(z, my_mpz_t, (INIT(my_mpz_init), INIT_SET(my_mpz_init_set), SET(my_mpz_set), CLEAR(my_mpz_clear) )),
(i, int, M_DEFAULT_OPLIST) )
static void
@@ -148,10 +148,10 @@ test_triple(void)
triple_init(t);
string_t s;
string_init(s);
mpz_t z;
mpz_init(z);
my_mpz_t z;
my_mpz_init(z);
mpz_set_str(z, "125567890456789345784567812345678", 10);
my_mpz_set_ui(z, 2556789045);
string_set_str(s, "FHZKJHFKZUHFKZHFUHZFUHURHYERUYEUIRYEIURYIEYRIU");
assert( triple_type(t) == triple_EMPTY);
@@ -165,9 +165,9 @@ test_triple(void)
assert( triple_type(t) == triple_z);
triple_set_z(t, z);
assert( triple_type(t) == triple_z);
assert( mpz_cmp (z, *triple_get_z(t)) == 0);
assert( my_mpz_cmp (z, *triple_get_z(t)) == 0);
mpz_clear(z);
my_mpz_clear(z);
string_clear(s);
triple_clear(t);
}
+17 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -30,10 +30,10 @@ static int fib(int n);
struct fib2_s {
int x, n;
};
volatile bool resetFunc_called;
atomic_bool resetFunc_called = ATOMIC_VAR_INIT(false);
static void resetFunc(void)
{
resetFunc_called = true;
atomic_store(&resetFunc_called, true);
}
static void subfunc_1 (void *data) {
@@ -58,12 +58,22 @@ static int fib(int n)
static void test1(void)
{
resetFunc_called = false;
atomic_store(&resetFunc_called, false);
worker_init(w_g, 0, 0, resetFunc);
int result = fib(39);
assert (result == 63245986);
worker_clear(w_g);
assert (resetFunc_called == true);
assert (atomic_load(&resetFunc_called) == true || workeri_get_cpu_count() == 1);
}
static void test1bis(void)
{
atomic_store(&resetFunc_called, false);
worker_init(w_g, 0, 0, NULL, resetFunc);
int result = fib(4);
assert (result == 3);
worker_clear(w_g);
assert (atomic_load(&resetFunc_called) == true || workeri_get_cpu_count() == 1);
}
#if defined(__GNUC__) && (!defined(__clang__) || WORKER_USE_CLANG_BLOCK || WORKER_USE_CPP_FUNCTION)
@@ -103,5 +113,7 @@ static void test2(void) {}
int main(void)
{
test1();
test1bis();
test2();
exit(0);
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
+25 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -28,6 +28,9 @@ ARRAY_DEF(array_uint, unsigned int)
unsigned int add_two(const array_uint_t tab, size_t i, size_t j);
void size_to_exactly(array_uint_t tab, size_t n);
void push_back (array_uint_t tab, unsigned int n);
void unpop(array_uint_t tab);
void unpop_if(array_uint_t tab, unsigned int x);
void construct(void *p);
unsigned int add_two(const array_uint_t tab, size_t i, size_t j)
{
@@ -44,3 +47,24 @@ void push_back (array_uint_t tab, unsigned int n)
{
array_uint_push_back(tab, n);
}
void unpop(array_uint_t tab)
{
array_uint_pop_back(NULL, tab);
}
void unpop_if(array_uint_t tab, unsigned int x)
{
if (x == *array_uint_back(tab))
array_uint_pop_back(NULL, tab);
}
array_uint_t global;
extern void f(void *p);
void construct(void *p)
{
array_uint_it_t mark;
array_uint_it_end(mark, global);
f(p);
array_uint_pop_until(global, mark);
}
+24 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Patrick Pelissier
* 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:
@@ -24,7 +24,8 @@
#include "m-list.h"
#include "m-i-list.h"
LIST_DEF(dbl, double)
LIST_DEF(list_dbl, double)
LIST_DUAL_PUSH_DEF(list_dbl2, double)
void f_push_back(list_dbl_t list);
double f_iterator(list_dbl_t list);
@@ -36,19 +37,37 @@ void f_push_back(list_dbl_t list)
double f_iterator(list_dbl_t list)
{
list_it_dbl_t it;
list_dbl_it_t it;
double s = 0.0;
for(list_dbl_it(it, list); !list_dbl_end_p(it); list_dbl_next(it))
s += *list_dbl_cref(it);
return s;
}
void f2_push_back(list_dbl2_t list);
double f2_iterator(list_dbl2_t list);
void f2_push_back(list_dbl2_t list)
{
list_dbl2_push_back(list, 2.0);
}
double f2_iterator(list_dbl2_t list)
{
list_dbl2_it_t it;
double s = 0.0;
for(list_dbl2_it(it, list); !list_dbl2_end_p(it); list_dbl2_next(it))
s += *list_dbl2_cref(it);
return s;
}
struct itest {
int n;
ILIST_INTERFACE (list, struct itest);
ILIST_INTERFACE (ilist_list, struct itest);
};
ILIST_DEF(list, struct itest)
ILIST_DEF(ilist_list, struct itest)
extern void f_init(ilist_list_t l);
void f_init(ilist_list_t l)