179 Commits
Author SHA1 Message Date
Patrick Pelissier e694d83cc4 V0.4.0 2020-05-27 21:50:03 +02:00
Patrick Pelissier 19fc150763 Discard warning with clang++ 2020-05-27 21:41:31 +02:00
Patrick Pelissier 3784f653d9 Fix warning with CLANG 2020-05-27 21:41:11 +02:00
Patrick Pelissier eb40cff6a1 Improve checkall target to stop on warning 2020-05-27 21:09:07 +02:00
Patrick Pelissier b7f84236d3 * Update comments
* Micro optimization
2020-05-25 21:41:16 +02:00
Patrick Pelissier 65e3f1049b * Update comments.
* Fix position of const for some prototypes.
2020-05-25 00:23:12 +02:00
Patrick Pelissier cc45b9c1fe Fix issue in test suite. 2020-05-24 20:39:20 +02:00
Patrick Pelissier 9340c2e55c Fix memory leak for _parse_str in case of error. 2020-05-24 19:50:32 +02:00
Patrick Pelissier 9710e014f2 Reindent function 2020-05-24 19:19:19 +02:00
Patrick Pelissier 7761fb6bf1 Add contract for tuple & variant. 2020-05-24 19:08:18 +02:00
Patrick Pelissier 2f4df5f67c Fix potential read before init in test. 2020-05-24 19:07:29 +02:00
Patrick Pelissier b841f81416 Fix package name for MS Windows
The filesystem doesn't support '*'
2020-05-24 18:14:25 +02:00
Patrick Pelissier 72fd53ab44 Update comments 2020-05-24 12:01:56 +02:00
Patrick Pelissier 8335bc525b Add comments 2020-05-23 16:09:18 +02:00
Patrick Pelissier 9e5d14ce36 Factorization & add tests 2020-05-21 13:10:50 +02:00
Patrick Pelissier 3bafede8b7 * Make the test more pertinent 2020-05-21 12:32:33 +02:00
Patrick Pelissier 3f2904ab0d * Add comment 2020-05-21 12:32:20 +02:00
Patrick Pelissier 933b495ed1 * Optimization for M_LET for a string_t in case of constant non formatted string
* Support for string_t in M_LET for string_t in C11 mode.
* Adding associate test
2020-05-21 12:19:17 +02:00
Patrick Pelissier 77813adc00 Add example of formatted C string for string in M_LET 2020-05-21 11:55:35 +02:00
Patrick Pelissier ce2adea6c0 Update documentation 2020-05-21 09:54:08 +02:00
Patrick Pelissier 3ecdfff8f0 Remove more cleanly generated configuration file. 2020-05-21 00:54:24 +02:00
Patrick Pelissier a103ceb850 Add new example of array of string. 2020-05-21 00:36:35 +02:00
Patrick Pelissier 9f24b89487 Add debug flag for example 2020-05-21 00:36:13 +02:00
Patrick Pelissier 8be06cadb3 Add comments on description. 2020-05-20 23:21:27 +02:00
Patrick Pelissier c488d979cf Ignore Visual Code directory if any. 2020-05-20 23:05:28 +02:00
Patrick Pelissier f4c24f07af Update comment description of macros and functions 2020-05-20 22:36:36 +02:00
Patrick Pelissier 3d2ce63d63 Fix performance issue in benchmarks 2020-05-19 23:21:00 +02:00
Patrick Pelissier 0ac2c62ffe Port to new API 2020-05-19 22:57:08 +02:00
Patrick Pelissier 6001781e68 Cleanup namespace, add comments, and remove dead code 2020-05-17 21:39:24 +02:00
Patrick Pelissier d90cb7caf3 Update doc 2020-05-17 12:11:10 +02:00
Patrick Pelissier 88a4835025 Fix issue when defining algorithm with same prefix than container 2020-05-17 12:11:04 +02:00
Patrick Pelissier 75ae7a06e5 Add missing tests 2020-05-17 11:53:43 +02:00
Patrick Pelissier 3885cb29a2 Add control of type and oplists 2020-05-17 11:53:27 +02:00
Patrick Pelissier bf3ffd1766 Add test cases for new control 2020-05-17 11:10:06 +02:00
Patrick Pelissier d884d257bb Export TYPE operator in oplist 2020-05-17 10:53:17 +02:00
Patrick Pelissier a87cac84dd Move up control so that it is the first error reported by the compiler. 2020-05-17 10:52:54 +02:00
Patrick Pelissier d1ae26f0fd * Add control than the type and the oplist are compatible 2020-05-17 10:27:30 +02:00
Patrick Pelissier 9c58e73c37 * Add M_CHECK_COMPATIBLE
* Fix issue in oplist
2020-05-17 10:26:40 +02:00
Patrick Pelissier 024b62a7a7 Add instance for M_CHECK_COMPATIBLE to be able to check multiple types within one container. 2020-05-17 10:26:08 +02:00
Patrick Pelissier c59731775e * Provide alternative for M_STATIC_ASSERT in GNUC + C11 with improved error messages
* Add internal macro M_CHECK_COMPATIBLE_OPLIST to check if a type and an oplist could match.
2020-05-17 09:36:50 +02:00
Patrick Pelissier 4668476c6a Fix issue with old version of ICC 2020-05-16 14:47:30 +02:00
Patrick Pelissier 743959ebde Fix micro performance issue 2020-05-16 14:09:49 +02:00
Patrick Pelissier dd27fa7e72 Add coverage for Function Object 2020-05-16 10:24:29 +02:00
Patrick Pelissier f2025f83d3 Fix help usage 2020-05-16 09:41:05 +02:00
Patrick Pelissier 8c06b43b2b Update tests for new controls 2020-05-15 21:46:18 +02:00
Patrick Pelissier 3cde7a1731 Add protection for use of oplist within a container oplist 2020-05-15 21:46:03 +02:00
Patrick Pelissier e9db1d28b8 Try to work around to print the oplist 2020-05-15 21:45:21 +02:00
Patrick Pelissier adffaf0e87 Fix illegal usage of oplist for function object 2020-05-15 21:45:02 +02:00
Patrick Pelissier 49a2e600c4 Add control of sub-oplist when creating a new oplist of a container
Add test case of this new control
Fix some corner bugs in some containers evolving their own oplists.
2020-05-15 21:19:39 +02:00
Patrick Pelissier 0bedcba32b Rewrite M_STATIC_ASSERT to include an error code and message
Add more control on the default expanded macros to check if arguments are compatible
2020-05-15 14:51:20 +02:00
Patrick Pelissier c531f805b0 Define _reduce only if SET method is properly set 2020-05-15 14:31:47 +02:00
Patrick Pelissier da0ab5ea98 Update failure tests as per latest checks 2020-05-11 20:55:16 +02:00
Patrick Pelissier 6774afd751 Add checks of missing oplist in the last _DEF macros 2020-05-11 20:54:50 +02:00
Patrick Pelissier 6d489136e7 Update help 2020-05-10 22:18:19 +02:00
Patrick Pelissier 4ea6dbc7fa Update makefile as per latest version of library 2020-05-10 20:21:03 +02:00
Patrick Pelissier defc58f6a3 Update bench code to latest version of the library. 2020-05-10 20:20:37 +02:00
Patrick Pelissier 006d0d16a5 Fix error 2020-05-10 20:20:03 +02:00
Patrick Pelissier b8af8bb344 Redisable MSVC testing with new version of compiler 2020-05-10 12:40:37 +02:00
Patrick Pelissier e249be1142 Reenable MSVC testing with new version of compiler 2020-05-10 12:38:36 +02:00
Patrick Pelissier 05fde6c3cf Display MSVC compiler full version 2020-05-10 12:06:31 +02:00
Patrick Pelissier aaa1d7dc4b Update description of test 2020-05-10 11:20:16 +02:00
Patrick Pelissier 8c479b2e5a Update tests 2020-05-10 11:17:25 +02:00
Patrick Pelissier 45d2a529b5 Add more validation of oplists before expanding data 2020-05-10 11:16:46 +02:00
Patrick Pelissier 7d17223332 Update comments 2020-05-10 11:15:56 +02:00
Patrick Pelissier 12bc65b6a8 Fix spelling 2020-05-10 11:15:28 +02:00
Patrick Pelissier a849d5c031 Make check-failure tests parallel 2020-05-09 21:39:01 +02:00
Patrick Pelissier f195b09657 Add more tests 2020-05-09 21:38:48 +02:00
Patrick Pelissier 439177ec71 Add protection against wrong oplist in more headers 2020-05-09 21:38:32 +02:00
Patrick Pelissier aadd4f11b1 Update tests as per new checks 2020-05-09 17:16:11 +02:00
Patrick Pelissier 113fdbf388 Add more controls on proper presence of oplist for _DEF macros 2020-05-09 17:16:00 +02:00
Patrick Pelissier 648406a99a Update tests as per new checks 2020-05-09 16:11:11 +02:00
Patrick Pelissier 055e74d350 Add more check for valid oplists before expanding further 2020-05-09 16:10:56 +02:00
Patrick Pelissier ac3d7568f2 Update test 2020-05-09 11:20:05 +02:00
Patrick Pelissier 6c222b9ad7 Raise proper failure if M_let is used without an oplist
Raise proper failure if a TYPE operator is used in an oplist that doesn't export it.
2020-05-09 11:15:44 +02:00
Patrick Pelissier 4426a60904 Add test for testing expected failures 2020-05-09 10:56:31 +02:00
Patrick Pelissier 34f70a031f Use M_STATIC_FAILURE to stop expanding methods in case of detected failure 2020-05-09 10:56:05 +02:00
Patrick Pelissier 79f2f396b9 Add macro M_STATIC_FAILURE to abort expansion in case of error 2020-05-09 10:55:25 +02:00
Patrick Pelissier 88143f7d52 Update ignore file 2020-05-09 10:54:30 +02:00
Patrick Pelissier c1261dd0f2 Fix doc 2020-05-08 21:47:19 +02:00
Patrick Pelissier 8f7a60ea73 Add documentation for function object 2020-05-08 21:43:35 +02:00
Patrick Pelissier 4758bbd6cc Add more tests 2020-05-08 21:23:48 +02:00
Patrick Pelissier 3f66325c19 Add new example for function object, json & algorithms 2020-05-08 17:50:07 +02:00
Patrick Pelissier 6f10d7deb9 Add synonym of serialisater with specialized oplists to be used in RAII 2020-05-08 17:49:44 +02:00
Patrick Pelissier 919900c90a Update documentation 2020-05-08 17:48:56 +02:00
Patrick Pelissier e6daaf429c Add some tests for function objects 2020-05-08 11:37:38 +02:00
Patrick Pelissier 1200f30695 * Add more Function Object support in algorithm
* Fix bug of selection sort
2020-05-08 11:35:22 +02:00
Patrick Pelissier fca1120990 No longer export IT_REF for map containers (See API changes) 2020-05-08 11:33:28 +02:00
Patrick Pelissier 3735704c95 Update new API change 2020-05-08 11:30:57 +02:00
Patrick Pelissier 8c0c1b3102 Update documentation of reduce if the container is empty 2020-05-08 11:30:38 +02:00
Patrick Pelissier db192993f1 Reduce constraint as the dictionnary iteration is not modifiable 2020-05-08 00:27:15 +02:00
Patrick Pelissier 4f44b3f60b Add CMP callback 2020-05-07 22:13:36 +02:00
Patrick Pelissier b196fcc3c0 Rename _cmp_cb_t into _eq_cb_t 2020-05-07 22:10:53 +02:00
Patrick Pelissier 395f1af19e Implement more function object algorithm 2020-05-07 22:09:07 +02:00
Patrick Pelissier d8f761e889 Update Makefile for dist 2020-05-05 23:44:27 +02:00
Patrick Pelissier 563ffb4275 Add first support for function object for certain algos (WIP) 2020-05-05 23:34:34 +02:00
Patrick Pelissier 9ba2de4b70 Add macro M_IF_FUNCOBJ to handle conditional expression if the function object is defined 2020-05-05 23:34:12 +02:00
Patrick Pelissier 0ac6a53fe9 Define callback types 2020-05-05 22:57:19 +02:00
Patrick Pelissier 4431e9f9ae Factorization / Split of the definition of the algorithm 2020-05-05 22:40:03 +02:00
Patrick Pelissier 48526ff5c7 Simplify logic due to fix of M_PARENTHESIS_P 2020-05-04 00:33:00 +02:00
Patrick Pelissier 4ee453025c Add comments 2020-05-04 00:32:40 +02:00
Patrick Pelissier 1e7b543c0f Fix issue with oplists with 3 arguments and fix warnings 2020-05-04 00:30:14 +02:00
Patrick Pelissier 8c2b4f8cf9 Add test cases for function object 2020-05-04 00:29:42 +02:00
Patrick Pelissier 13cadfa470 Update description of the list of headers 2020-05-03 18:00:46 +02:00
Patrick Pelissier deb595372b Add first version of Function Object 2020-05-03 17:49:02 +02:00
Patrick Pelissier 01fd5d929e * Fix M_RET_ARG so that it accepts also a list of the exact number of arguments (instead of one more) * Add more keywords for pattern recognation 2020-05-03 13:13:45 +02:00
Patrick Pelissier 2d60bd2c1b Fix a bug in M_PARENTHESIS_P 2020-05-02 10:19:31 +02:00
Patrick Pelissier 9655b13203 Add more corner cases for M_PARENTHESIS_P 2020-05-02 10:18:52 +02:00
Patrick Pelissier 6b97a7436d Add basic tests for dispathing init_with based on their number of args 2020-05-02 10:06:30 +02:00
Patrick Pelissier 1c792dd0a4 Add option for init_with to dispatch to different methods in function of the number of args 2020-05-02 10:06:08 +02:00
Patrick Pelissier dcbd9f496f Document NAME operator 2020-05-02 09:56:23 +02:00
Patrick Pelissier 9804120cde * Add simple test for registration of int global operator 2020-05-02 09:56:11 +02:00
Patrick Pelissier a9b06718f0 * Add simple test for NAME operator 2020-05-02 09:55:28 +02:00
Patrick Pelissier 963d819e22 * Add NAME operator. * Register default oplist for char,short,int,long,float,double 2020-05-02 09:55:10 +02:00
Patrick Pelissier 28847af43f Update constraints on MOVE & INIT_MOVE operators 2020-04-27 23:12:06 +02:00
Patrick Pelissier 130fa36970 Update iterator constraint 2020-04-27 22:55:53 +02:00
Patrick Pelissier ab99035291 Add another example 2020-04-20 23:50:05 +02:00
Patrick Pelissier 6de43d8a45 Add doc for ALGO_REDUCE with different type 2020-04-20 23:49:48 +02:00
Patrick Pelissier 7b46891622 Add test for ALGO_REDUCE with different type 2020-04-20 23:49:35 +02:00
Patrick Pelissier a0a32d8c6c ALGO_REDUCE accept dest with different type than the container 2020-04-20 23:49:16 +02:00
Patrick Pelissier 1ffd07dc6e Update format 2020-04-11 00:25:40 +02:00
Patrick Pelissier cb49cd7100 * Fix integer overflow in test of mul reduction 2020-04-10 08:35:44 +02:00
Patrick Pelissier 923b340a80 * Update documentation 2020-04-10 08:29:55 +02:00
Patrick Pelissier 5b8750ee2a * Add support for product in ALGO_REDUCE 2020-04-10 08:28:16 +02:00
Patrick Pelissier d438d089fb Add note on the provided oplists 2020-04-10 08:19:59 +02:00
Patrick Pelissier 843ddac3dd Proper prefix internal variables of macros by '_' 2020-04-01 23:40:41 +02:00
Patrick Pelissier c5238e0a4c Add new example for algorithm 2020-04-01 23:40:16 +02:00
Patrick Pelissier f99ee8aa40 Update documentation 2020-04-01 23:28:07 +02:00
Patrick Pelissier 18c7d0e11a Add test for SET_KEY only containers for ALGO_EXTRACT 2020-04-01 23:27:38 +02:00
Patrick Pelissier 4e67823593 Add support for SET_KEY only containers for ALGO_EXTRACT 2020-04-01 23:27:20 +02:00
Patrick Pelissier e7fcefb391 * Dict supports INIT_WITH method too. 2020-03-29 00:49:36 +01:00
Patrick Pelissier be06426783 Add documentation for ALGO_TRANSFORM 2020-03-28 17:41:29 +01:00
Patrick Pelissier e558e83be3 Add test case for ALGO_TRANSFORM 2020-03-28 17:41:16 +01:00
Patrick Pelissier d77a235b2a Add macro ALGO_TRANSFORM 2020-03-28 17:41:04 +01:00
Patrick Pelissier 3add6bb5bf Improve test suite 2020-03-28 17:17:43 +01:00
Patrick Pelissier 4367daaa00 Add documentation for _transform method. 2020-03-28 13:34:17 +01:00
Patrick Pelissier 4d46b3d126 Add basic test cases for _transform method. 2020-03-28 13:34:02 +01:00
Patrick Pelissier 548cd84a7f Add _transform method for algorithm. 2020-03-28 13:33:43 +01:00
Patrick Pelissier d87ffaa572 Improve documentation. 2020-03-28 13:07:35 +01:00
Patrick Pelissier 370cdb4e45 Add another example. 2020-03-28 13:05:15 +01:00
Patrick Pelissier 068d023917 Factorize in m-core.h the pattern recognication. 2020-03-28 11:36:51 +01:00
Patrick Pelissier 86b6ad54d5 Rename filln, filla, fillan into fill_n, fill_a, fill_an (same name as C++) 2020-03-28 11:10:02 +01:00
Patrick Pelissier bdf999a9fc Disable fully VC++ build as the build is fully broken due to regression in version 16.5 vs 16.4 2020-03-26 22:34:51 +01:00
Patrick Pelissier 39f8b6828b Try workaround against regression with new VisualC++ 2020-03-26 22:03:11 +01:00
Patrick Pelissier 11f84ab34b Document new algorithms 2020-03-26 21:49:04 +01:00
Patrick Pelissier c3a5306266 Add function _fill, _filln, _filla, _fillan as algorithms 2020-03-26 21:48:46 +01:00
Patrick Pelissier 1fe9e4c14c Export ADD / MUL / DIV / SUB for basic C types. 2020-03-26 21:44:19 +01:00
Patrick Pelissier e69203dc50 Remove exported PUSH / POP methods as they don't follow stricly the prototypes of such functions. 2020-03-26 21:43:44 +01:00
Patrick Pelissier 342954f272 Fix introduced build error for Mingw 2020-03-25 11:56:38 +01:00
Patrick Pelissier 741d6b8828 Test string + algorithm 2020-03-25 11:44:35 +01:00
Patrick Pelissier f1f41ef320 * Add missing iterator functions * Export iterators in oplist so that it is usable in algorithm 2020-03-25 11:43:55 +01:00
Patrick Pelissier 785792d1f4 Allow build of examples in C11 mode 2020-03-25 11:17:06 +01:00
Patrick Pelissier 9affe3106c Add example of ALGO_FOR_EACH and ALGO_REDUCE 2020-03-25 11:16:19 +01:00
Patrick Pelissier eb9fd14e2c Fix documentation. 2020-03-25 10:19:43 +01:00
Patrick Pelissier c281a2c339 Update CI script to include VC++ 2020-03-02 18:09:53 +01:00
Patrick Pelissier cb109eb479 Add proper progression for special script 2020-03-02 14:35:49 +01:00
Patrick Pelissier 3c6d194974 Add script to launch the test suite with VC++ 2020-03-02 14:25:42 +01:00
Patrick Pelissier 653a0d9734 Fix build issue for systems where double==long double 2020-03-02 14:23:59 +01:00
Patrick Pelissier a5fbd8405c Avoid C99 construct incompatible with strict C++ compiler 2020-02-24 22:27:43 +01:00
Patrick Pelissier 70994d4f60 Update doc 2020-02-16 11:06:43 +01:00
Patrick Pelissier f15203afb2 Comment a little bit more the examples 2020-02-10 06:47:24 +01:00
Patrick Pelissier 0a0d707afd Document bitset 2020-02-08 23:39:30 +01:00
Patrick Pelissier e206c3fe48 Document SPSC buffer 2020-01-23 23:18:33 +01:00
Patrick Pelissier 7f5704d321 Document MPMC buffer 2020-01-09 22:52:02 +01:00
Patrick Pelissier 4f7b0b9455 Happy new year 2020 2020-01-04 15:41:06 +01:00
Patrick Pelissier f5f16015df In quiet mode, if the result of the bench is not assumed to be reliable, display -1 instead of the result. 2020-01-04 15:12:59 +01:00
Patrick Pelissier 935325e0cb Add bench of emilib 2020-01-04 15:06:24 +01:00
Patrick Pelissier 7b9530ac58 Fix name of bench 2020-01-04 15:05:12 +01:00
Patrick Pelissier a9fc259420 ALGO_EXTRACT func argument is now optional 2019-12-30 14:31:21 +01:00
Patrick Pelissier 6f603b52df Update comments 2019-12-30 14:11:41 +01:00
Patrick Pelissier aeb2a47952 Add comments to example 2019-12-30 13:44:03 +01:00
Patrick Pelissier ca7cea3fe3 Use of linear probing and the same hash function as other libraries 2019-12-30 00:12:05 +01:00
Patrick Pelissier f14aca8808 Port to new UDB2 protocol 2019-12-29 23:51:30 +01:00
Patrick Pelissier f1e5e9d9db Simplify code to use get_at method with its get & create semantic 2019-12-29 23:45:17 +01:00
Patrick Pelissier cecba9777a Update documentation on buffer/queues 2019-12-27 16:42:54 +01:00
Patrick Pelissier 4352267034 Update deprecated API 2019-12-27 16:42:00 +01:00
Patrick Pelissier 0c3730d9a3 Migrate version to 0.3.1 2019-12-27 16:41:42 +01:00
Patrick Pelissier 5111b0c726 Deprecated some buffer options since the _blocking functions are much more usefull 2019-12-27 16:39:42 +01:00
Patrick Pelissier 8ecd3f1592 Add best_within and variance 2019-12-23 23:05:48 +01:00
Patrick Pelissier 0a6f8851c9 Update list of bench to launch automatically 2019-12-20 21:37:51 +01:00
99 changed files with 5628 additions and 1398 deletions

No files matched your search

+14 -3
View File
@@ -26,9 +26,20 @@ jobs:
- uses: actions/checkout@v1
- name: Install MINGW
run: choco install mingw --no-progress
- name: make
shell: bash
run: mingw32-make CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1"
- name: make check
shell: bash
run: mingw32-make CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
build_windows_visual:
strategy:
matrix:
platform: [windows-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v1
- name: make check
shell: cmd
working-directory: ./tests
run: Make-check-cl.bat
+2
View File
@@ -38,3 +38,5 @@ depend
other/
a*.dat
config
fail*.log
.vscode
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 2-Clause License
Copyright (c) 2017-2019, Patrick Pelissier
Copyright (c) 2017-2020, Patrick Pelissier
All rights reserved.
Redistribution and use in source and binary forms, with or without
+4 -4
View File
@@ -10,15 +10,15 @@ PREFIX=/usr/local
DESTDIR=
# Package name & version.
PACKAGE=m*lib-$(VERSION)
VERSION=0.3.0
PACKAGE=m_lib-$(VERSION)
VERSION=0.4.0
# Define the contain of the distribution tarball
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tuple.h m-variant.h m-worker.h
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tuple.h m-variant.h m-worker.h
DOC1=LICENSE README.md
DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/depend.png doc/DEV.md doc/ISSUES.org doc/oplist.odp doc/oplist.png
EXAMPLE=example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-json01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-rbtree01.c example/ex-section.c example/Makefile
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.c tests/test-mcmempool.c tests/test-mconcurrent.c tests/test-mcore.c tests/test-mdeque.c tests/test-mdict.c tests/test-mgenint.c tests/test-milist.c tests/test-mlist.c tests/test-mmempool.c tests/test-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.c tests/test-mshared.c tests/test-msnapshot.c tests/test-mstring.c tests/test-mtuple.c tests/test-mvariant.c tests/test-mworker.c tests/tgen-bitset.c tests/tgen-marray.c tests/tgen-mdict.c tests/tgen-mlist.c tests/tgen-mstring.c tests/tgen-openmp.c tests/tgen-queue.c tests/tgen-shared.c tests/wip-mregister.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.c tests/test-mcmempool.c tests/test-mconcurrent.c tests/test-mcore.c tests/test-mdeque.c tests/test-mdict.c tests/test-mfuncobj.c tests/test-mgenint.c tests/test-milist.c tests/test-mlist.c tests/test-mmempool.c tests/test-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.c tests/test-mshared.c tests/test-msnapshot.c tests/test-mstring.c tests/test-mtuple.c tests/test-mvariant.c tests/test-mworker.c tests/tgen-bitset.c tests/tgen-marray.c tests/tgen-mdict.c tests/tgen-mlist.c tests/tgen-mstring.c tests/tgen-openmp.c tests/tgen-queue.c tests/tgen-shared.c tests/wip-mregister.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt
.PHONY: all test check doc clean distclean depend install uninstall dist
+732 -136
View File
File diff suppressed because it is too large. Load diff
+20 -17
View File
@@ -7,7 +7,7 @@ N=4
BENCH_DEF=
RM=rm -rf
.PHONY: all pgo container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain
.PHONY: all pgo container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain
all: container queue mempool string plain
@@ -17,7 +17,7 @@ pgo:
#########################################################################
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-hopscotchmap
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-densehashmap bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-uthash bench-qlibc bench-libsrt bench-nedtries bench-rigtorp-hashmap
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost
@@ -160,12 +160,12 @@ bench-densehashmap0:
@./bench-densehashmap.exe 42
@./bench-densehashmap.exe 43
# COLLECTIONC shall point to the directory where the 'src' directory is.
# COLLECTIONC shall point to the directory where it is installed
bench-collectionc:
@if test -n "$${COLLECTIONC}" ; then $(MAKE) bench-collectionc0 ; else echo "Nothing to be done for COLLECTIONC." ; fi
bench-collectionc0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${COLLECTIONC}/include" -L "$${COLLECTIONC}" -static bench-collectionc.c common.c -lcollectc -o bench-collectionc.exe
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${COLLECTIONC}/include/collectc" bench-collectionc.c common.c "$${COLLECTIONC}/lib/libcollectc.a" -o bench-collectionc.exe
@./bench-collectionc.exe 10
@./bench-collectionc.exe 20
@./bench-collectionc.exe 30
@@ -196,6 +196,17 @@ bench-flathashmap0:
@./bench-flathashmap.exe 46
@./bench-flathashmap.exe 43
# EMILIB shall point to the directory where the headers are
bench-emilib:
@if test -n "$${EMILIB}" ; then $(MAKE) bench-emilib0 ; else echo "Nothing to be done for EMILIB." ; fi
bench-emilib0:
$(CXX) -std=c++14 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${EMILIB}" bench-emilib.cpp common.c -o bench-emilib.exe
@./bench-emilib.exe 41
@./bench-emilib.exe 42
@./bench-emilib.exe 46
@./bench-emilib.exe 43
# HOPSCOTCHMAP shall point to the directory where the source are
bench-hopscotchmap:
@if test -n "$${HOPSCOTCHMAP}" ; then $(MAKE) bench-hopscotchmap0 ; else echo "Nothing to be done for HOPSCOTCHMAP." ; fi
@@ -214,9 +225,8 @@ bench-uthash0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${UTHASH}" bench-uthash.c common.c -o bench-uthash.exe
@./bench-uthash.exe 10
@./bench-uthash.exe 20
@./bench-uthash.exe 40
@./bench-uthash.exe 41
@./bench-uthash.exe 42
@./bench-uthash.exe 43
@./bench-uthash.exe 50
# QLIBC shall point to the directory where the library is installed.
@@ -228,21 +238,14 @@ bench-qlibc0:
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 10
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 20
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 30
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 42
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 41
# LIBSRT shall point to the directory where the source are
# The library shall be built.
# LIBSRT shall point to the directory where it is installed
bench-libsrt:
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-libsrt0 ; else echo "Nothing to be done for LIBSRT." ; fi
bench-libsrt0:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/src" bench-libsrt.c common.c -o bench-libsrt.exe $${LIBSRT}/libsrt.a
@./bench-libsrt.exe 10
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/include/libsrt" bench-libsrt.c common.c -o bench-libsrt.exe $${LIBSRT}/lib/libsrt.a
@./bench-libsrt.exe 20
@./bench-libsrt.exe 41
@./bench-libsrt.exe 42
@./bench-libsrt.exe 43
@./bench-libsrt.exe 50
@@ -320,12 +323,12 @@ bench-maxdict:
############################################################################
# BSTRLIB shall point to the BSTRLIB sources
# LIBSRT shall point to the LIBSRT sources
# LIBSRT shall point to the LIBSRT install directory
bench-string:
@if test -n "$${BSTRLIB}" ; then $(MAKE) bench-string-step1 BENCH_DEF="-DBENCH_CAN_USE_BSTRLIB -I ${BSTRLIB} $${BSTRLIB}/obj/bstrlib.o $${BSTRLIB}/obj/bstraux.o $${BSTRLIB}/obj/bstrwrap.o" ; else $(MAKE) bench-string-step1 ; fi
bench-string-step1:
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/src $${LIBSRT}/libsrt.a" ; else $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF)"; fi
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/include/libsrt $${LIBSRT}/lib/libsrt.a" ; else $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF)"; fi
#NOTE: Need to build by hand sds.o since it is not build by default and sds.c is not compatible with C++
bench-string-step2:
+138
View File
@@ -0,0 +1,138 @@
#define NDEBUG
#include <vector>
#include <list>
#include <iterator>
#include <map>
#include <set>
#include <unordered_map>
#include <algorithm>
#include <string>
#include <sstream>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "emilib/hash_map.hpp"
using namespace emilib;
using namespace std;
#include "common.h"
/********************************************************************************************/
static void
test_dict2(size_t n)
{
HashMap<unsigned long, unsigned long> dict;
for (size_t i = 0; i < n; i++) {
dict[rand_get()] = rand_get();
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
HashMap<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
if (it != dict.end())
s += it->second;
}
g_result = s;
}
static void
test_dict2_linear(size_t n)
{
HashMap<unsigned long, unsigned long> dict;
for (size_t i = 0; i < n; i++) {
dict[i] = rand_get();
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
HashMap<unsigned long, unsigned long>::iterator it = dict.find(i);
if (it != dict.end())
s += it->second;
}
g_result = s;
}
/********************************************************************************************/
struct char_array_s {
char a[256];
char_array_s () { a[0] = 0 ; }
char_array_s ( const char_array_s & other) { strcpy(a, other.a); }
bool operator==(const char_array_s &other) const { return strcmp(a, other.a) == 0; }
};
namespace std {
template <> struct hash<char_array_s> {
std::size_t operator()(const char_array_s &k) const {
size_t hash = 0;
const char *s = k.a;
while (*s) hash = hash * 31421 + (*s++) + 6927;
return hash;
};
};
}
static void
test_dict_big(size_t n)
{
HashMap<char_array_s, char_array_s> dict;
for (size_t i = 0; i < n; i++) {
char_array_s s1, s2;
sprintf(s1.a, "%u", rand_get());
sprintf(s2.a, "%u", rand_get());
dict[s1] = s2;
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
char_array_s s1;
sprintf(s1.a, "%u", rand_get());
HashMap<char_array_s, char_array_s>::iterator it = dict.find(s1);
if (it != dict.end())
s ++;
}
g_result = s;
}
/********************************************************************************************/
static void
test_dict_str(size_t n)
{
HashMap<string, string> dict;
for (size_t i = 0; i < n; i++) {
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
dict[s1] = s2;
}
rand_init();
unsigned int s = 0;
for (size_t i = 0; i < n; i++) {
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
HashMap<string, string>::iterator it = dict.find(s1);
if (it != dict.end())
s ++;
}
g_result = s;
}
/********************************************************************************************/
const config_func_t table[] = {
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
{ 42,"dict", 1000000, 0, test_dict2, 0},
{ 43, "DictStr", 1000000, 0, test_dict_str, 0},
{ 46, "DictLinear", 1000000, 0, test_dict2_linear, 0}
};
int main(int argc, const char *argv[])
{
test("EMILIB", numberof(table), table, argc, argv);
exit(0);
}
+1 -1
View File
@@ -134,6 +134,6 @@ const config_func_t table[] = {
int main(int argc, const char *argv[])
{
test("DENSE-HASPMAP", numberof(table), table, argc, argv);
test("FLAT-HASPMAP", numberof(table), table, argc, argv);
exit(0);
}
+3
View File
@@ -7,6 +7,9 @@
#include <stdint.h>
#include <unistd.h>
// Needed due to compilation error in pool.h
#include <pthread.h>
#include "dynamic.h"
#include "common.h"
+3 -13
View File
@@ -14,8 +14,8 @@
static void test_array(size_t n)
{
sv_t *a1 = sv_alloc ( sizeof (unsigned int), 16, NULL);
sv_t *a2 = sv_alloc ( sizeof (unsigned int), 16, NULL);
srt_vector *a1 = sv_alloc ( sizeof (unsigned int), 16, NULL);
srt_vector *a2 = sv_alloc ( sizeof (unsigned int), 16, NULL);
for(size_t i = 0; i < n; i++) {
unsigned int value = rand_get();
@@ -48,7 +48,7 @@ static int cmp_float (const void *a, const void *b)
static void test_sort(size_t n)
{
sv_t *a1 = sv_alloc(sizeof(float), 16, cmp_float);
srt_vector *a1 = sv_alloc(sizeof(float), 16, cmp_float);
for(size_t i = 0; i < n; i++) {
unsigned int value = rand_get();
sv_push(&a1, &value );
@@ -72,13 +72,3 @@ int main(int argc, const char *argv[])
exit(0);
}
int main(int argc, const char *argv[])
{
int n = (argc > 1) ? atoi(argv[1]) : 0;
if (n == 20)
test_function("Array", 100000000, test_array);
if (n == 50)
test_function("Sort", 10000000, test_sort);
exit(0);
}
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - String Bench
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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 -2
View File
@@ -1,4 +1,5 @@
#define NDEBUG
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
@@ -202,9 +203,8 @@ static void test_sort(size_t n)
const config_func_t table[] = {
{ 10, "List", 10000000, 0, test_list, 0},
{ 20, "Array", 100000000, 0, test_array, 0},
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
{ 40, "dict", 1000000, 0, test_dict, 0},
{ 41, "dictBig", 1000000, 0, test_dict_big, 0}
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
{ 50, "sort", 10000000, 0, test_sort, 0}
};
+123 -15
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - common functions for bench module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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,6 +26,9 @@
#include <string.h>
#include "common.h"
// Maximum supported value for repeat argument
#define MAX_REPEAT 10000
// The global result
unsigned long g_result;
@@ -46,8 +49,9 @@ void compiler_barrier(void *p)
struct parse_opt_s {
int test_function;
double from, to, step, grow;
double within;
unsigned repeat;
bool graph, best, average, quiet;
bool graph, best, best_within, average, quiet;
};
static void
@@ -62,9 +66,11 @@ parse_config(struct parse_opt_s *opt, int argc, const char *argv[])
opt->grow = 1.1;
opt->graph = false;
opt->best = false;
opt->best_within = false;
opt->average = false;
opt->quiet = false;
opt->repeat = 1;
opt->within = .05;
for(int i = 1; i < argc ; i++)
{
@@ -88,14 +94,23 @@ parse_config(struct parse_opt_s *opt, int argc, const char *argv[])
} else if (strcmp(argv[i], "--repeat") == 0) {
i++;
opt->repeat = strtol(argv[i], &end, 10);
opt->repeat = (opt->repeat > MAX_REPEAT) ? MAX_REPEAT : opt->repeat;
} else if (strcmp(argv[i], "--graph") == 0) {
opt->graph = true;
} else if (strcmp(argv[i], "--best") == 0) {
opt->best = true;
opt->average = false;
opt->best_within = false;
} else if (strcmp(argv[i], "--best-within") == 0) {
opt->best_within = true;
opt->best = false;
opt->average = false;
i++;
opt->within = strtod(argv[i], &end) / 100.0;
} else if (strcmp(argv[i], "--average") == 0) {
opt->average = true;
opt->best = false;
opt->best_within = false;
} else if (strcmp(argv[i], "--quiet") == 0) {
opt->quiet = true;
} else {
@@ -131,14 +146,78 @@ select_config(int func, size_t n, const config_func_t functions[])
for(size_t i = 0; i < n;i++) {
fprintf(stderr, " %d: %s\n", functions[i].num, functions[i].funcname);
}
fprintf(stderr, "USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--best|--average] [--quiet|--graph]\n");
fprintf(stderr,
"USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--grapĥ]\n"
"[--repeat number] [--best|--average|--best-within] [--quiet]\n");
exit(-1);
}
// Utility function for qsort
static int cmp_double(const void *pa, const void *pb)
{
const double *a = (const double *) pa, *b = (const double *)pb;
return (*a < *b) ? -1 : *a > *b;
}
/* Get the longest sequence of values within 'f'% */
static int
get_sequence(int i, int n, double tab[], double f)
{
int j;
for(j = i + 1; j < n; j++) {
if (tab[j] > f * tab[i])
break;
}
return j-i;
}
/* Return the minimum of the longest sequence of values with 'f'% */
static double
get_best_within(int n, double tab[], double f)
{
qsort(tab, n, sizeof(double), cmp_double);
int best_i = 0;
int best_seq = get_sequence(0, n, tab, f);
for(int i = 1; i < n && (n-i) > best_seq ; i++) {
int seq = get_sequence(i, n, tab, f);
if (seq > best_seq) {
best_i = i;
best_seq = seq;
}
}
return tab[best_i];
}
// Integer sqrt function (to avoid depending on libm)
static unsigned integer_sqrt(unsigned n)
{
// Find greatest shift.
int shift = 2;
unsigned nShifted = n >> shift;
// We check for nShifted being n, since some implementations
// perform shift operations modulo the word size.
while (nShifted != 0 && nShifted != n){
shift += 2;
nShifted = n >> shift;
}
shift -= 2;
// Find digits of result.
unsigned result = 0;
while (shift >= 0) {
result = result << 1;
unsigned candidateResult = result + 1;
if (candidateResult*candidateResult <= n >> shift) {
result = candidateResult;
}
shift -= 2;
}
return result;
}
void
test(const char library[], size_t n, const config_func_t functions[], int argc, const char *argv[])
{
// options
// Init & parse arguments
// NUMBER
// --from NUMBER --to NUMBER --step NUMBER --grow NUMBER
// --graph --best --average --quiet
@@ -146,8 +225,10 @@ test(const char library[], size_t n, const config_func_t functions[], int argc,
struct parse_opt_s arg;
parse_config(&arg, argc, argv);
int i = select_config(arg.test_function, n, functions);
double from = arg.from == 0 ? functions[i].default_n : arg.from;
double to = arg.from == 0 ? functions[i].default_n : arg.to;
double from = (arg.from == 0) ? functions[i].default_n : arg.from;
double to = (arg.to == 0) ? functions[i].default_n : arg.to;
// Open plot file if needed
FILE *graph_file = NULL;
if (arg.graph) {
char filename[100];
@@ -159,32 +240,59 @@ test(const char library[], size_t n, const config_func_t functions[], int argc,
}
fprintf(graph_file, "# plotting %s-%d : %s\n# N T", library, arg.test_function, functions[i].funcname);
}
// Do the bench
for(double n = from; n <= to ; n = (arg.grow == 0 ? n + arg.step : n * arg.grow))
for(double n = from; n <= to ; n = ((arg.grow == 0) ? n + arg.step : n * arg.grow))
{
double best = (1.0/0.0);
double avg = 0.0;
double variance = 0.0;
static double measure[MAX_REPEAT];
double ba = 0.0;
if (functions[i].init != NULL)
functions[i].init(n);
// Measure the time of the test_function
for(unsigned r = 0; r < arg.repeat; r++) {
double t0 = test_function(arg.graph|arg.best|arg.average|arg.quiet ? NULL : functions[i].funcname, (size_t) n, functions[i].func);
best = t0 < best ? t0 : best;
double t0 = test_function( (arg.graph|arg.best|arg.average|arg.quiet) ? NULL : functions[i].funcname, (size_t) n, functions[i].func);
best = (t0 < best) ? t0 : best;
avg += t0;
variance += t0 * t0;
measure[r] = t0;
}
// Closure of the tests
if (functions[i].clear != NULL)
functions[i].clear();
avg /= arg.repeat;
// Finish computing the different times
if (arg.repeat > 1) {
avg /= arg.repeat;
variance = (variance - arg.repeat * avg * avg) / (arg.repeat - 1);
ba = get_best_within(arg.repeat, measure, 1. + arg.within);
}
// The average value shall be around best_within (and greater)
// otherwise the result doesn't seem reliable.
bool reliable = (ba <= avg && ba * (1.0+arg.within/2) + 0.5 > avg);
// Print the result
if (arg.graph) {
fprintf(graph_file, "%f %f\n", n, arg.average ? avg : best);
fprintf(graph_file, "%f %f\n", n, arg.average ? avg : arg.best ? best : ba);
} else if (arg.quiet) {
printf("%lu\n", (unsigned long)(arg.average ? avg : best));
printf("%ld\n", (long)(arg.average ? avg : arg.best ? best : reliable ? ba : -1));
} else if (arg.repeat > 1) {
if (arg.average == false)
if (arg.average == false && arg.best_within == false)
printf ("%20.20s time %lu ms for n = %lu *** BEST ***\n", functions[i].funcname, (unsigned long) best, (unsigned long) n);
if (arg.best == false)
printf ("%20.20s time %lu ms for n = %lu *** AVERAGE ***\n", functions[i].funcname, (unsigned long) avg, (unsigned long) n);
if (arg.best == false && arg.best_within == false)
printf ("%20.20s time %lu ms +/- %u ms for n = %lu *** AVERAGE ***\n", functions[i].funcname, (unsigned long) avg, 2*integer_sqrt(variance), (unsigned long) n);
if (arg.best == false && arg.average == false)
printf ("%20.20s time %lu ms for n = %lu *** BEST within %d%% *** %s\n", functions[i].funcname, (unsigned long) ba, (unsigned long) n, (int)(100*arg.within), reliable ? "" : "(unreliable result)");
}
}
// Close the FILE if needed
if (arg.graph) {
fclose(graph_file);
printf("File plot-%s-%d.dat generated.\n"
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - common functions for bench module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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 -7
View File
@@ -1,8 +1,3 @@
#ifndef NDEBUG
#define NDEBUG
#endif
#undef NDEBUG
#include <string.h>
#include "benchmark.h"
@@ -48,7 +43,7 @@ int test_int(int N, const unsigned *data)
if (dict_int_get (h, data[i]) == NULL) {
dict_int_set_at (h, data[i], i);
} else {
dict_int_remove(h, data[i]);
dict_int_erase(h, data[i]);
}
}
ret = (int)dict_int_size(h);
@@ -64,7 +59,7 @@ int test_str(int N, char * const *data)
if (dict_str_get (h, data[i]) == NULL) {
dict_str_set_at (h, data[i], i);
} else {
dict_str_remove(h, data[i]);
dict_str_erase(h, data[i]);
}
}
ret = (int)dict_str_size(h);
+4 -4
View File
@@ -4,10 +4,10 @@
#include "m-dict.h"
#include "m-mempool.h"
DICT_DEF2(dict_int,
DICT_STOREHASH_DEF2(dict_int,
int, M_OPEXTEND(M_DEFAULT_OPLIST, MEMPOOL(mpool_int), MEMPOOL_LINKAGE(static)),
int, M_DEFAULT_OPLIST)
DICT_DEF2(dict_str,
DICT_STOREHASH_DEF2(dict_str,
const char *, M_OPEXTEND (M_CSTR_OPLIST, MEMPOOL(mpool_str), MEMPOOL_LINKAGE(static)),
int, M_DEFAULT_OPLIST)
@@ -20,7 +20,7 @@ int test_int(int N, const unsigned *data)
if (dict_int_get (h, data[i]) == NULL) {
dict_int_set_at (h, data[i], i);
} else {
dict_int_remove(h, data[i]);
dict_int_erase(h, data[i]);
}
}
ret = (int)dict_int_size(h);
@@ -38,7 +38,7 @@ int test_str(int N, char * const *data)
if (dict_str_get (h, data[i]) == NULL) {
dict_str_set_at (h, data[i], i);
} else {
dict_str_remove(h, data[i]);
dict_str_erase(h, data[i]);
}
}
ret = (int)dict_str_size(h);
+8 -5
View File
@@ -1,4 +1,5 @@
#include "../common.c"
#define DICTI_OA_PROBING(s) 1
#include "m-dict.h"
static inline bool oor_equal_p(unsigned int k, unsigned char n)
@@ -11,10 +12,10 @@ static inline void oor_set(unsigned int *k, unsigned char n)
}
DICT_OA_DEF2(dict_oa_uint,
unsigned int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
unsigned int, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(hash_fn), OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
unsigned int, M_DEFAULT_OPLIST)
void test_int(uint32_t n, uint32_t x0)
uint32_t test_int(uint32_t n, uint32_t x0)
{
uint32_t i, x, z = 0;
dict_oa_uint_t h;
@@ -22,10 +23,12 @@ void test_int(uint32_t n, uint32_t x0)
for (i = 0, x = x0; i < n; ++i) {
x = hash32(x);
unsigned int key = get_key(n, x);
unsigned int *ptr = dict_oa_uint_get(h, key);
if (ptr) { (*ptr)++; z+= *ptr; }
else { dict_oa_uint_set_at(h, key, 1); z+=1; }
unsigned int *ptr = dict_oa_uint_get_at(h, key);
(*ptr)++;
z += *ptr;
}
fprintf(stderr, "# unique keys: %d; checksum: %u\n", (int) dict_oa_uint_size(h), z);
z = dict_oa_uint_size(h);
dict_oa_uint_clear(h);
return z;
}
+7 -1
View File
@@ -38,4 +38,10 @@ V0.2.*: * worker_start takes a 'worker_t' as an additional parameter
V0.3.*: * Remove B+TREE _remove method as it has been deprecated (use _erase instead)
* Remove DICT _remove method as it has been deprecated (use _erase instead)
* Make _it_to_p method of B+TREE / RB-TREE as deprecated (uses _it_until_p instead ).
* Deprecated buffer options BUFFER_BLOCKING* and BUFFER_UNBLOCKING*
as the _push_blocking and _pop_blocking functions can do the same and are more versatil.
* Iteration over the items of a dictionnary/tree returns const iterators for access through
OPLIST (impact: algorithm & M_EACH) as the IT_REF operator is no longer exported.
The _it_ref method is still defined and can be used, so you can still modify the values
but it won't be automatically used anymore (as the keys CANNOT be modified).
(Previously it generates incorrect algorithm when used with m-dict).
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 103 KiB

BIN
View File
Binary file not shown.
+3 -2
View File
@@ -1,5 +1,5 @@
CC=cc -std=c99
CFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function
CFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -g
GMP_DIR=
CPPFLAGS=-I..
LDFLAGS=-pthread
@@ -12,11 +12,12 @@ RM=rm -f
all: config
$(MAKE) `ls ex-*.c|sed -e 's/\.c/\.exe/g'`
if test "$(CC)" = "cc -std=c99" ; then $(MAKE) `ls ex11-*.c|sed -e 's/\.c/\.exe/g'` CC="cc -std=c11" ; fi
config:
printf "#include <gmp.h>\nint main(void){mpz_t z; mpz_init(z); return 0;}\n" > config-test.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp config-test.c -o config-test.exe 2> /dev/null && echo "-DHAVE_GMP=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0" > config
$(RM) config-test.*
$(RM) config-test.c config-test.exe
clean:
$(RM) *.exe *.s *~ *.o ./a.dat config
+53
View File
@@ -0,0 +1,53 @@
#include <stdio.h>
#include "m-array.h"
#include "m-algo.h"
/* Define a dynamic array of int */
ARRAY_DEF(vector_int, int)
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
ALGO_DEF(vector_int, vector_int_t)
/* Define a dynamic array of bool */
ARRAY_DEF(vector_bool, bool)
#define M_OPL_vector_bool_t() ARRAY_OPLIST(vector_bool)
ALGO_DEF(vector_bool, vector_bool_t)
static bool id(bool x) { return x ; }
int main(void)
{
M_LET(myvector, tmp, vector_int_t) {
vector_int_fill_n(myvector, 3, 20);
vector_int_fill_n(tmp, 3, 33);
vector_int_splice(myvector, tmp);
vector_int_fill_n(tmp, 2, 10);
vector_int_splice(myvector, tmp);
printf("myvector contains:");
// In C11, the for loop can be simplified as :
// ALGO_FOR_EACH(myvector, vector_int_t, M_PRINT, " ");
for M_EACH(it, myvector, vector_int_t) {
printf(" %d", *it);
}
printf("\n");
}
M_LET(myvector, tmp, vector_bool_t) {
vector_bool_fill_n(myvector, 3, false);
vector_bool_fill_n(tmp, 3, true);
vector_bool_splice(myvector, tmp);
vector_bool_fill_n(tmp, 2, false);
vector_bool_splice(myvector, tmp);
printf("myvector contains:");
// In C11, the for loop can be simplified as :
// ALGO_FOR_EACH(myvector, vector_bool_t, M_PRINT, " ");
for M_EACH(it, myvector, vector_bool_t) {
printf(" %d", (int)*it);
}
printf("\n");
printf ("ALL: %d ANY: %d NONE: %d\n",
vector_bool_all_of_p(myvector, id),
vector_bool_any_of_p(myvector, id),
vector_bool_none_of_p(myvector, id) );
}
return 0;
}
+31
View File
@@ -0,0 +1,31 @@
#include "m-dict.h"
#include "m-array.h"
#include "m-algo.h"
#include "m-string.h"
DICT_DEF2(dict, string_t, int)
#define M_OPL_dict_t() DICT_OPLIST(dict, STRING_OPLIST, M_DEFAULT_OPLIST)
ARRAY_DEF(vector_int, int)
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
#define start_with(pattern, item) \
string_start_with_str_p((item).key, (pattern))
#define get_value(out, item) ((out) = (item).value)
int main(void)
{
int s;
M_LET(keys, vector_int_t)
M_LET( (m, (STRING_CTE("foo"), 1), (STRING_CTE("bar"), 42), (STRING_CTE("bluez"), 7), (STRING_CTE("stop"), 789) ), tmp, dict_t) {
/* Extract all elements of 'm' that starts with 'b' */
ALGO_EXTRACT(tmp, dict_t, m, dict_t, start_with, "b");
/* Extract the values of theses elements */
ALGO_TRANSFORM(keys, vector_int_t, tmp, dict_t, get_value);
/* Sum theses values */
ALGO_REDUCE(s, keys, vector_int_t, sum);
printf("Sum of elements starting with 'b' is: %d\n", s);
}
return 0;
}
+27
View File
@@ -0,0 +1,27 @@
#include "m-algo.h"
#include "m-array.h"
#include "m-string.h"
ARRAY_DEF(vector_int, int)
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
#define str_ui(s, i) string_printf(s, "%d", i)
#define str_cat(s1, s2) (string_cat_str(s1, "-"), string_cat(s1, s2))
int main(void)
{
M_LET(s, string_t)
M_LET( (v, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), vector_int_t) {
int sum, product;
ALGO_REDUCE(sum, v, vector_int_t, add);
ALGO_REDUCE(product, v, vector_int_t, mul);
/* Example of reduction with a transformation of the type from int to string_t */
ALGO_REDUCE( (s, string_t), v, vector_int_t, str_cat, str_ui);
printf ("sum: %d\n"
"product: %d\n"
"dash str: %s\n", sum, product, string_get_cstr(s));
}
return 0;
}
+42 -4
View File
@@ -4,12 +4,14 @@
/* This example show how to use complex structure with array
embedding another library */
/* This is a trivial library */
/* This is a typical trivial library with its interface */
typedef struct lib_ext_struct {
int id;
// Other data
// Other data may be added
} lib_ext_struct;
/* Method to create a duplicate of the object.
The new object is heap allocated */
static lib_ext_struct *lib_ext_struct_Duplicate(const lib_ext_struct *obj)
{
lib_ext_struct *p = malloc(sizeof(lib_ext_struct));
@@ -18,6 +20,7 @@ static lib_ext_struct *lib_ext_struct_Duplicate(const lib_ext_struct *obj)
return p;
}
/* Method to delete any object */
static void lib_ext_struct_Delete(lib_ext_struct *obj)
{
free(obj);
@@ -30,6 +33,11 @@ typedef struct {
lib_ext_struct* properties;
} data_node;
/* This method shall initialize the object data_node to
the init state.
It takes as first argument the object to initialize,
and since it takes by reference through a pointer,
it is compatible with 'API_2' convention for oplist */
static void data_node_init(data_node *obj)
{
obj->id = 0;
@@ -37,6 +45,12 @@ static void data_node_init(data_node *obj)
obj->properties = NULL;
}
/* This method shall initialize the object data_node to
the same state as the 'src' object (creating a copy, a duplicate) .
It takes as first argument the object to initialize,
and as second argument the source object.
It takes both object by reference through pointers,
as such it is compatible with 'API_6' convention for oplist */
static void data_node_init_set(data_node *obj, const data_node *src)
{
obj->id = src->id;
@@ -47,6 +61,13 @@ static void data_node_init_set(data_node *obj, const data_node *src)
obj->properties = NULL;
}
/* This method shall set the object data_node to
the same state as the 'src' object (creating a copy, a duplicate) .
THe object was already initialized.
It takes as first argument the object to initialize,
and as second argument the source object.
It takes both object by reference through pointers,
as such it is compatible with 'API_6' convention for oplist */
static void data_node_set(data_node *obj, const data_node *src)
{
obj->id = src->id;
@@ -59,6 +80,11 @@ static void data_node_set(data_node *obj, const data_node *src)
obj->properties = NULL;
}
/* This method shall clear the object data_node to
the cleared state (aka it shall free any resource).
It takes as first argument the object to initialize,
and since it takes by reference through a pointer,
it is compatible with 'API_2' convention for oplist */
static void data_node_clear(data_node *obj)
{
string_clear(obj->type);
@@ -66,13 +92,25 @@ static void data_node_clear(data_node *obj)
lib_ext_struct_Delete(obj->properties);
}
/* Create a dynamic array of 'data_node' named array_data_node_t
and gives the minimum oplist allowing M*LIB to handle
properly the object 'data_node' with the API convention
to respect for calling the methods.
*/
ARRAY_DEF(/* the array prefix */ array_data_node,
/* the object type */ data_node,
/* the object oplist */ (INIT(API_2(data_node_init)),
SET(API_6(data_node_set)),
INIT_SET(API_6(data_node_init_set)),
CLEAR(API_2(data_node_clear))))
ARRAY_DEF(array_data_node, data_node, (INIT(API_2(data_node_init)),SET(API_6(data_node_set)),INIT_SET(API_6(data_node_init_set)),CLEAR(API_2(data_node_clear))))
/* Define a global array with the created type */
array_data_node_t global_array;
int main(void)
{
/* Call the created method */
array_data_node_init(global_array);
/* Do stuff... */
array_data_node_clear(global_array);
}
+2 -2
View File
@@ -52,11 +52,11 @@ int main(void)
// Dictionary iterator are pair (key,value)
if (my_integer_n_p(p->value)) {
printf ("It is a long long, value = %lld\n",
*my_integer_get_n(p->value));
*my_integer_cget_n(p->value));
}
if (my_integer_z_p(p->value)) {
printf ("It is a mpz_t, value =");
mpz_out_str(stdout, 10, *my_integer_get_z(p->value));
mpz_out_str(stdout, 10, *my_integer_cget_z(p->value));
printf("\n");
}
}
+31
View File
@@ -0,0 +1,31 @@
#include <stdio.h>
#include "m-array.h"
#include "m-string.h"
// Let's create an array of string_t and register it globaly
ARRAY_DEF(vector_string, string_t)
#define M_OPL_vector_string_t() ARRAY_OPLIST(vector_string, STRING_OPLIST)
int main(void)
{
// Let's define a new string named str
M_LET(str, string_t)
// Let's define msg as a vector_array_t
M_LET( (msg, STRING_CTE("Hello"), STRING_CTE("C"), STRING_CTE("World!"), STRING_CTE("Let's"), STRING_CTE("discover"), STRING_CTE("M*LIB!")), vector_string_t) {
// Iterate over all words of the array msg
for M_EACH(word, msg, vector_string_t) {
// Cat the current word into the target string
string_cat(str, *word);
// Also add a space character
string_push_back(str, ' ');
}
// Let's define another string and set it to a formatted value.
M_LET( (count, "\nTo display this it uses \"vector\" of %zu strings!", vector_string_size(msg)), string_t) {
string_cat(str, count);
}
// Print the result
printf("%s\n", string_get_cstr(str) );
}
return 0;
}
+10 -8
View File
@@ -4,6 +4,15 @@
#include "m-rbtree.h"
// Let's define one utility function.
void *xmalloc(size_t n);
void *xmalloc(size_t n)
{
void *p = malloc (n);
if (!p) abort();
return p;
}
// Let's define a new type.
typedef struct {
int key;
@@ -12,7 +21,7 @@ typedef struct {
#define SIZE 256
void *xmalloc(size_t n);
// Let's define the prototypes of the methods of this new type.
void my_type_init(my_type_t x);
void my_type_clear(my_type_t x);
void my_type_init_set(my_type_t x, const my_type_t y);
@@ -24,13 +33,6 @@ void my_type_out_str(FILE *f, const my_type_t x);
bool my_type_in_str(my_type_t x, FILE *f);
void my_type_rand(my_type_t x);
void *xmalloc(size_t n)
{
void *p = malloc (n);
if (!p) abort();
return p;
}
// Let's define its constructor
void my_type_init(my_type_t x)
{
+37
View File
@@ -0,0 +1,37 @@
/* Based on https://en.cppreference.com/w/cpp/algorithm/for_each
Need to be built in C11 mode */
#include <stdio.h>
#include "m-array.h"
#include "m-algo.h"
/* Define a dynamic array of int */
ARRAY_DEF(vector_int, int)
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
/* Define operator increment on int */
#define INC(n) (n)++
int main(void)
{
M_LET( (nums, 3, 4, 2, 8, 15, 267), vector_int_t) {
// Print the array before
printf ("before:");
ALGO_FOR_EACH(nums, vector_int_t, M_PRINT, " ");
printf ("\n");
// Increment each element of the array
ALGO_FOR_EACH(nums, vector_int_t, INC);
// Print the array after
printf ("after: ");
ALGO_FOR_EACH(nums, vector_int_t, M_PRINT, " ");
printf ("\n");
// Sum the elements of the array
int sum = 0;
ALGO_REDUCE(sum, nums, vector_int_t, add);
M_PRINT("sum = ", sum, "\n");
}
return 0;
}
+77
View File
@@ -0,0 +1,77 @@
#include "m-tuple.h"
#include "m-array.h"
#include "m-algo.h"
#include "m-funcobj.h"
#include "m-serial-json.h"
#include "m-string.h"
/* Define the employee */
TUPLE_DEF2(employee,
(name, string_t),
(age, int),
(idnum, int))
#define M_OPL_employee_t() TUPLE_OPLIST(employee, STRING_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
/* Define an array of employee and some algorithms on it */
ARRAY_DEF(vector_employee, employee_t)
#define M_OPL_vector_employee_t() ARRAY_OPLIST(vector_employee, M_OPL_employee_t())
ALGO_DEF(vector_employee, vector_employee_t)
/* Define the function object to select the sort order */
FUNC_OBJ_INS_DEF(compare_by,
vector_employee_cmp_obj,
(a, b), {
if (string_equal_str_p(self->sort_field, "name"))
return string_cmp(a->name, b->name);
else if (string_equal_str_p(self->sort_field, "age"))
return a->age < b->age ? -1 : a->age > b->age;
else
return a->idnum < b->idnum ? -1 : a->idnum > b->idnum;
},
(sort_field, string_t) )
#define M_OPL_compare_by_t() FUNC_OBJ_INS_OPLIST(compare_by, STRING_OPLIST)
// Let's read an array of person from the given JSON file
static void read(vector_employee_t base, const char filename[])
{
m_serial_return_code_t ret;
// Open the file
FILE *f = fopen(filename, "rt");
if (!f) {
fprintf(stderr, "ERROR: Cannot open file '%s'.\n", filename);
exit(2);
}
// Initialize the JSON serializer with this file
M_LET( (in,f), m_serial_json_read_t)
ret = vector_employee_in_serial(base, in);
// Let's handle errors
if (ret != M_SERIAL_OK_DONE) {
fprintf(stderr, "ERROR: Cannot read JSON data from file '%s'.\nParsing stops at:\n", filename);
while (!feof(f)) { fputc(fgetc(f), stdout); }
fclose(f);
exit(2);
}
fclose(f);
}
int main(void)
{
M_LET(emps, vector_employee_t) {
/* Code to populate database from JSON */
read(emps, "ex11-algo02.json");
// Sort the database by employee ID number
M_LET( (cmp, STRING_CTE("idnum")), compare_by_t )
vector_employee_sort_fo(emps, compare_by_as_interface(cmp));
printf("Employees sorted by idnum are: ");
vector_employee_out_str(stdout, emps);
M_LET( (cmp, STRING_CTE("name")), compare_by_t )
vector_employee_sort_fo(emps, compare_by_as_interface(cmp));
printf("\nEmployees sorted by name are: ");
vector_employee_out_str(stdout, emps);
printf("\n");
}
return 0;
}
+9
View File
@@ -0,0 +1,9 @@
[
{ "name": "John Doe", "age": 32, "idnum": 14528},
{ "name": "Clint Smith", "age": 31, "idnum": 14529},
{ "name": "Linda Cameron", "age": 20, "idnum": 14527},
{ "name": "Cameron Carrey", "age": 25, "idnum": 14526},
{ "name": "Marty Brown", "age": 26, "idnum": 14525},
{ "name": "Donald Cow", "age": 45, "idnum": 14520}
]
+629 -378
View File
File diff suppressed because it is too large. Load diff
+31 -10
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - dynamic ARRAY module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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,6 +34,7 @@
((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 dynamic array given its name and its oplist.
If no oplist is given it is assumed to be M_DEFAULT_OPLIST
USAGE: ARRAY_OPLIST(name[, oplist of the type]) */
@@ -52,10 +53,18 @@
so that all arguments are evaluated before further expansion */
#define ARRAYI_OPLIST_P1(arg) ARRAYI_OPLIST_P2 arg
/* Validation of the given oplist */
#define ARRAYI_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(ARRAYI_OPLIST_P3, ARRAYI_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define ARRAYI_OPLIST_FAILURE(name, oplist) \
M_LIB_ERROR(ARGUMENT_OF_ARRAY_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
/* OPLIST definition of a dynamic array */
/* FIXME: Do we want to export some methods as they are slow and
are not fit to be used for building other methods (like _it_remove)? */
#define ARRAYI_OPLIST_P2(name, oplist) \
#define ARRAYI_OPLIST_P3(name, oplist) \
(INIT(M_C(name, _init)) \
,INIT_SET(M_C(name, _init_set)) \
,INIT_WITH(API_1(M_INIT_VAI)) \
@@ -121,6 +130,14 @@
so that all arguments are evaluated before further expansion */
#define ARRAYI_DEF_P1(arg) ARRAYI_DEF_P2 arg
/* Validate the oplist before going further */
#define ARRAYI_DEF_P2(name, type, oplist, array_t, it_t) \
M_IF_OPLIST(oplist)(ARRAYI_DEF_P3, ARRAYI_DEF_FAILURE)(name, type, oplist, array_t, it_t)
/* Stop processing with a compilation failure */
#define ARRAYI_DEF_FAILURE(name, type, oplist, array_t, it_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ARRAY_DEF): the given argument is not a valid oplist: " #oplist)
/* Internal definition:
- name: prefix to be used
- type: type of the elements of the array
@@ -128,7 +145,7 @@
- array_t: alias for M_C(name, _t) [ type of the array ]
- it_t: alias for M_C(name, _it_t) [ iterator of the array ]
*/
#define ARRAYI_DEF_P2(name, type, oplist, array_t, it_t) \
#define ARRAYI_DEF_P3(name, type, oplist, array_t, it_t) \
\
typedef struct M_C(name, _s) { \
size_t size; /* Number of elements in the array */ \
@@ -145,6 +162,8 @@
const struct M_C(name, _s) *array; /* Reference of the array */ \
} it_t[1]; \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void \
M_C(name, _init)(array_t v) \
{ \
@@ -272,6 +291,7 @@
type *ret = &v->ptr[v->size]; \
v->size++; \
ARRAYI_CONTRACT(v); \
M_ASSUME(ret != NULL); \
return ret; \
} \
\
@@ -279,8 +299,8 @@
M_C(name, _push_back)(array_t v, type const x) \
{ \
type *data = M_C(name, _push_raw)(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_CALL_INIT_SET(oplist, *data, x); \
} \
\
@@ -860,7 +880,7 @@
{ \
ARRAYI_CONTRACT(array); \
assert (str != NULL); \
M_C(name,_clean)(array); \
M_C(name,_clean)(array); \
bool success = false; \
int c = *str++; \
if (M_UNLIKELY (c != '[')) goto exit; \
@@ -873,12 +893,13 @@
do { \
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
do { c = *str++; } while (isspace(c)); \
if (b == false || c == 0) { goto exit; } \
M_C(name, _push_back)(array, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_CALL_CLEAR(oplist, item); \
if (b == false || c == 0) { goto exit_clear; } \
M_C(name, _push_back)(array, item); \
} while (c == M_GET_SEPARATOR oplist); \
ARRAYI_CONTRACT(array); \
success = (c == ']'); \
exit_clear: \
M_CALL_CLEAR(oplist, item); \
exit: \
if (endp) *endp = str; \
return success; \
+40 -11
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Thin stdatomic wrapper for C++ compatibility
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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,11 +99,17 @@ using std::memory_order_seq_cst;
#define _Atomic(T) std::atomic< T >
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
|| ( defined(__GNUC__) && !defined(__clang__) && !defined(__cplusplus) && (__GNUC__*100 + __GNUC_MINOR__) >= 409) \
|| (defined(__clang__) && __clang_major__ >= 4)
|| ( defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__cplusplus) && (__GNUC__*100 + __GNUC_MINOR__) >= 409) \
|| (defined(__clang__) && __clang_major__ >= 4) \
|| (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1800)
/* CLANG 3.5 has issues with GCC's stdatomic.h
and doesn't provide its own stdatomic.h */
/* C11 has mandatory working stdatomic
STDATOMIC doesn't work with C++ except for clang
GCC < 4.9 doesn't provide a compliant stdatomic.h
CLANG 3.5 has issues with GCC's stdatomic.h
and doesn't provide its own stdatomic.h
ICC < 18 doesn't provide a compliant stdatomic.h
*/
#include <stdatomic.h>
/* MSYS2 has a conflict between cdefs.h which defines a _Atomic macro (if not C11)
@@ -129,11 +135,13 @@ using std::memory_order_seq_cst;
*/
#include "m-mutex.h"
/* The structure is quite large:
/* _Atomic qualifier for a type (emulation).
The structure is quite large:
_val : value of the atomic type,
_zero : zero value of the atomic type (constant),
_previous: temporary value used within the mutex lock,
_lock : the mutex lock.
Support up to sizeof (long long) type.
*/
#define _Atomic(T) \
struct { \
@@ -143,7 +151,8 @@ using std::memory_order_seq_cst;
m_mutex_t _lock; \
}
/* Even if memory order is defined, only the strongest constraint is used */
/* Define the supported memory order.
Even if memory order is defined, only the strongest constraint is used */
typedef enum {
memory_order_relaxed,
memory_order_consume,
@@ -187,25 +196,26 @@ typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
#if (defined (INTMAX_C) && defined (UINTMAX_C) && !defined(__cplusplus)) || \
defined (_STDINT_H) || defined (_STDINT_H_) || defined (_STDINT) || \
defined (_SYS_STDINT_H_)
/* Define additional atomic types */
typedef _Atomic(intmax_t) atomic_intmax_t;
typedef _Atomic(uintmax_t) atomic_uintmax_t;
#endif
/* Unlock the mutex and return the given value */
/* (INTERNAL) Unlock the mutex and return the given value */
static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
{
m_mutex_unlock (*lock);
return val;
}
/* This is the heart of the wrapper:
/* (INTERNAL) This is the heart of the wrapper:
lock the atomic value, read it and returns the value.
In order to avoid any compiler extension, we need to transform the
atomic type into 'long long' then convert it back to its value.
This is because _previous can't be read after the lock, and we can't
generate temporary variable within a macro.
The trick is computing _val - _zero within the lock, then
returns retvalue + _zero after the lock.
returns retvalue + _zero after the release of the lock.
*/
#define atomic_fetch_op(ptr, val, op) \
(m_mutex_lock((ptr)->_lock), \
@@ -213,33 +223,51 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
(ptr)->_val op (val), \
atomic_fetch_unlock(&(ptr)->_lock, (ptr)->_previous-(ptr)->_zero)+(ptr)->_zero)
/* Perform an atomic add (EMULATION) */
#define atomic_fetch_add(ptr, val) atomic_fetch_op(ptr, val, +=)
/* Perform an atomic sub (EMULATION) */
#define atomic_fetch_sub(ptr, val) atomic_fetch_op(ptr, val, -=)
/* Perform an atomic or (EMULATION) */
#define atomic_fetch_or(ptr, val) atomic_fetch_op(ptr, val, |=)
/* Perform an atomic xor (EMULATION) */
#define atomic_fetch_xor(ptr, val) atomic_fetch_op(ptr, val, ^=)
/* Perform an atomic and (EMULATION) */
#define atomic_fetch_and(ptr, val) atomic_fetch_op(ptr, val, &=)
/* Perform an atomic exchange (EMULATION) */
#define atomic_exchange(ptr, val) atomic_fetch_op(ptr, val, =)
/* Initialize an atomic GLOBAL variable */
#define ATOMIC_VAR_INIT(val) { val, 0, 0, M_MUTEXI_INIT_VALUE }
/* Initialize an atomic variable */
#define atomic_init(ptr, val) \
(m_mutex_init((ptr)->_lock), (ptr)->_val = val, (ptr)->_zero = 0)
/* (INTERNAL) Load an atomic variable within a lock
(needed for variable greater than CPU atomic size) */
#define atomic_load_lock(ptr) \
(m_mutex_lock((ptr)->_lock), \
(ptr)->_previous = (ptr)->_val, \
atomic_fetch_unlock(&(ptr)->_lock, (ptr)->_previous-(ptr)->_zero)+(ptr)->_zero)
/* (INTERNAL) Store an atomic variable within a lock
(needed for variable greater than CPU atomic size) */
#define atomic_store_lock(ptr, val) \
(m_mutex_lock((ptr)->_lock), \
(ptr)->_val = (val), \
m_mutex_unlock((ptr)->_lock))
/* Atomic load of a variable (EMULATION)
If the atomic type size is not greater than the CPU atomic size,
we can perform a direct read of the variable (much faster) */
#define atomic_load(ptr) \
( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE \
? (ptr)->_val \
: atomic_load_lock(ptr))
/* Atomic store of a variable (EMULATION)
If the atomic type size is not greater than the CPU atomic size,
we can perform a direct write of the variable (much faster) */
#define atomic_store(ptr, val) do { \
if ( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE) { \
(ptr)->_val = (val); \
@@ -249,6 +277,7 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
} \
} while (0)
/* Perform a CAS (Compare and swap) operation (EMULATION) */
#define atomic_compare_exchange_strong(ptr, exp, val) \
(m_mutex_lock((ptr)->_lock), \
atomic_fetch_unlock(&(ptr)->_lock, \
@@ -273,7 +302,7 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
#define atomic_compare_exchange_weak_explicit(ptr, exp, val, mem1, mem2) atomic_compare_exchange_strong(ptr, exp, val)
#define atomic_compare_exchange_weak(ptr, exp, val) atomic_compare_exchange_strong(ptr, exp, val)
/* TODO: Missing atomic_flag. Problem: it needs to be lock free! */
/* TODO: Missing atomic_flag. Problem: it is supposed to be lock free! */
#endif
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - BITSET module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
+243 -164
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - B+TREE module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
@@ -78,53 +78,19 @@
USAGE: BPTREE_OPLIST(name [, oplist_of_the_type]) */
#define BPTREE_OPLIST(...) \
BPTREEI_KEY_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLISTR ), \
(__VA_ARGS__ )))
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
(__VA_ARGS__ )))
/* Define the oplist of a rbtree of type (from BPTREE_DEF2).
USAGE: BPTREE_OPLIST2(name, key_oplist, value_oplist) */
#define BPTREE_OPLIST2(name, key_oplist, value_oplist) \
(INIT(M_C(name, _init)), \
INIT_SET(M_C(name, _init_set)), \
SET(M_C(name, _set)), \
CLEAR(M_C(name, _clear)), \
INIT_MOVE(M_C(name, _init_move)), \
MOVE(M_C(name, _move)), \
SWAP(M_C(name, _swap)), \
TYPE(M_C(name,_t)), \
SUBTYPE(M_C(name, _type_t)), \
TEST_EMPTY(M_C(name,_empty_p)), \
IT_TYPE(M_C(name, _it_t)), \
IT_FIRST(M_C(name,_it)), \
IT_SET(M_C(name,_it_set)), \
IT_END(M_C(name,_it_end)), \
IT_END_P(M_C(name,_end_p)), \
IT_EQUAL_P(M_C(name,_it_equal_p)), \
IT_NEXT(M_C(name,_next)), \
IT_REF(M_C(name,_ref)), \
IT_CREF(M_C(name,_cref)), \
CLEAN(M_C(name,_clean)), \
GET_MIN(M_C(name,_min)), \
GET_MAX(M_C(name,_max)), \
KEY_TYPE(M_C(name, _key_type_t)), \
VALUE_TYPE(M_C(name, _value_type_t)), \
SET_KEY(M_C(name, _set_at)), \
GET_KEY(M_C(name, _get)), \
ERASE_KEY(M_C(name, _erase)), \
KEY_OPLIST(key_oplist), \
VALUE_OPLIST(value_oplist), \
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)(GET_STR(M_C(name, _get_str)),), \
M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)(PARSE_STR(M_C(name, _parse_str)),), \
M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)(OUT_STR(M_C(name, _out_str)),), \
M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)(IN_STR(M_C(name, _in_str)),), \
M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)(OUT_SERIAL(M_C(name, _out_serial)),), \
M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)(IN_SERIAL(M_C(name, _in_serial)),), \
M_IF_METHOD_BOTH(EQUAL, key_oplist, value_oplist)(EQUAL(M_C(name, _equal_p)),), \
M_IF_METHOD_BOTH(HASH, key_oplist, value_oplist)(HASH(M_C(name, _hash)),) \
,M_IF_METHOD(NEW, key_oplist)(NEW(M_GET_NEW oplist),) \
,M_IF_METHOD(REALLOC, key_oplist)(REALLOC(M_GET_REALLOC oplist),) \
,M_IF_METHOD(DEL, key_oplist)(DEL(M_GET_DEL oplist),) \
)
USAGE: BPTREE_OPLIST2(name[, key_oplist, value_oplist])
NOTE: IT_REF is not exported so that the contained appears as not modifiable
by algorithm.
*/
#define BPTREE_OPLIST2(...) \
BPTREEI_OPLIST2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST ), \
(__VA_ARGS__ )))
@@ -134,8 +100,16 @@
so that all arguments are evaluated before further expansion */
#define BPTREEI_KEY_OPLIST_P1(arg) BPTREEI_KEY_OPLIST_P2 arg
/* Validation of the given oplists */
#define BPTREEI_KEY_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(BPTREEI_KEY_OPLIST_P3, BPTREEI_KEY_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define BPTREEI_KEY_OPLIST_FAILURE(name, oplist) \
M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
/* OPLIST definition of a b+tree */
#define BPTREEI_KEY_OPLIST_P2(name, oplist) \
#define BPTREEI_KEY_OPLIST_P3(name, oplist) \
(INIT(M_C(name, _init)), \
INIT_SET(M_C(name, _init_set)), \
SET(M_C(name, _set)), \
@@ -171,7 +145,64 @@
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
)
/* Internal contract of a B+TREE node */
/* Deferred evaluation */
#define BPTREEI_OPLIST2_P1(arg) BPTREEI_OPLIST2_P2 arg
/* Validation of the given oplists */
#define BPTREEI_OPLIST2_P2(name, key_oplist, value_oplist) \
M_IF_OPLIST(key_oplist)(BPTREEI_OPLIST2_P3, BPTREEI_OPLIST2_FAILURE)(name, key_oplist, value_oplist)
#define BPTREEI_OPLIST2_P3(name, key_oplist, value_oplist) \
M_IF_OPLIST(value_oplist)(BPTREEI_OPLIST2_P4, BPTREEI_OPLIST2_FAILURE)(name, key_oplist, value_oplist)
/* Prepare a clean compilation failure */
#define BPTREEI_OPLIST2_FAILURE(name, key_oplist, value_oplist) \
M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, key_oplist, value_oplist)
#define BPTREEI_OPLIST2_P4(name, key_oplist, value_oplist) \
(INIT(M_C(name, _init)), \
INIT_SET(M_C(name, _init_set)), \
SET(M_C(name, _set)), \
CLEAR(M_C(name, _clear)), \
INIT_MOVE(M_C(name, _init_move)), \
MOVE(M_C(name, _move)), \
SWAP(M_C(name, _swap)), \
TYPE(M_C(name,_t)), \
SUBTYPE(M_C(name, _type_t)), \
TEST_EMPTY(M_C(name,_empty_p)), \
IT_TYPE(M_C(name, _it_t)), \
IT_FIRST(M_C(name,_it)), \
IT_SET(M_C(name,_it_set)), \
IT_END(M_C(name,_it_end)), \
IT_END_P(M_C(name,_end_p)), \
IT_EQUAL_P(M_C(name,_it_equal_p)), \
IT_NEXT(M_C(name,_next)), \
IT_CREF(M_C(name,_cref)), \
CLEAN(M_C(name,_clean)), \
GET_MIN(M_C(name,_min)), \
GET_MAX(M_C(name,_max)), \
KEY_TYPE(M_C(name, _key_type_t)), \
VALUE_TYPE(M_C(name, _value_type_t)), \
SET_KEY(M_C(name, _set_at)), \
GET_KEY(M_C(name, _get)), \
ERASE_KEY(M_C(name, _erase)), \
KEY_OPLIST(key_oplist), \
VALUE_OPLIST(value_oplist), \
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)(GET_STR(M_C(name, _get_str)),), \
M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)(PARSE_STR(M_C(name, _parse_str)),), \
M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)(OUT_STR(M_C(name, _out_str)),), \
M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)(IN_STR(M_C(name, _in_str)),), \
M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)(OUT_SERIAL(M_C(name, _out_serial)),), \
M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)(IN_SERIAL(M_C(name, _in_serial)),), \
M_IF_METHOD_BOTH(EQUAL, key_oplist, value_oplist)(EQUAL(M_C(name, _equal_p)),), \
M_IF_METHOD_BOTH(HASH, key_oplist, value_oplist)(HASH(M_C(name, _hash)),) \
,M_IF_METHOD(NEW, key_oplist)(NEW(M_GET_NEW oplist),) \
,M_IF_METHOD(REALLOC, key_oplist)(REALLOC(M_GET_REALLOC oplist),) \
,M_IF_METHOD(DEL, key_oplist)(DEL(M_GET_DEL oplist),) \
)
/* Internal contract of a B+TREE node 'node' or root 'root' */
#ifdef NDEBUG
# define BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, node, root) do { } while (0)
#else
@@ -213,6 +244,18 @@
so that all arguments are evaluated before further expansion */
#define BPTREEI_DEF_P1(arg) BPTREEI_DEF_P2 arg
/* Validate the key oplist before going further */
#define BPTREEI_DEF_P2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t) \
M_IF_OPLIST(key_oplist)(BPTREEI_DEF_P3, BPTREEI_DEF_FAILURE)(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t)
/* Validate the value oplist before going further */
#define BPTREEI_DEF_P3(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t) \
M_IF_OPLIST(value_oplist)(BPTREEI_DEF_P4, BPTREEI_DEF_FAILURE)(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t)
/* Stop processing with a compilation failure */
#define BPTREEI_DEF_FAILURE(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(BPTREE*_DEF): one of the given argument is not a valid oplist: " M_AS_STR(key_oplist) " / " M_AS_STR(value_oplist))
/* Internal b+tree definition
- name: prefix to be used
- N: size of the node
@@ -227,7 +270,7 @@
- node_t: alias for M_C(name, _node_t) [ node ]
- pit_t: alias for M_C(name, _pit_t) [parent iterator]
*/
#define BPTREEI_DEF_P2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t) \
#define BPTREEI_DEF_P4(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t) \
\
M_IF(isMap)( \
/* Type returned by the iterator. Due to having key and value \
@@ -275,7 +318,11 @@
int idx; \
} it_t[1]; \
\
/* TODO: Can be optimized to alloc for leaf or for node */ \
M_CHECK_COMPATIBLE_OPLIST(name, 1, key_t, key_oplist) \
M_CHECK_COMPATIBLE_OPLIST(name, 2, value_t, value_oplist) \
\
/* Allocate a new node */ \
/* TODO: Can be specialized to alloc for leaf or for non leaf */ \
static inline node_t M_C(name, _new_node)(void) \
{ \
node_t n = M_CALL_NEW(key_oplist, struct M_C(name, _node_s)); \
@@ -295,13 +342,15 @@
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
} \
\
static inline bool M_C(name, _is_leaf)(node_t n) \
static inline bool M_C(name, _is_leaf)(const node_t n) \
{ \
/* We consider the empty node as a leaf */ \
/* We consider the empty node as a leaf */ \
/* Only the root node can be empty */ \
return n->num <= 0; \
} \
\
static inline int M_C(name, _get_num)(node_t n) \
/* Return the number of keys of the node */ \
static inline int M_C(name, _get_num)(const node_t n) \
{ \
int num = n->num; \
num = num < 0 ? -num : num; \
@@ -314,8 +363,9 @@
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
node_t next, n = b->root; \
pit_t pit; \
/* np is the heigh of the tree */ \
int np = 0; \
/* Scan down the nodes */ \
/* Scan down the nodes to the left down node */ \
while (!M_C(name, _is_leaf)(n)) { \
pit->parent[np++] = n; \
assert (np <= BPTREEI_MAX_STACK); \
@@ -339,6 +389,7 @@
/* Next node of the same height */ \
next = n->next; \
if (i != 0) { \
/* Free the node if non root */ \
M_CALL_DEL(key_oplist, n); \
} \
n = next; \
@@ -359,57 +410,71 @@
b->root = NULL; \
} \
\
/* Copy recursively the node 'o' of root node 'root' */ \
static inline node_t M_C(name, _copy_node)(const node_t o, const node_t root) \
{ \
node_t n = M_C(name, _new_node)(); \
n->num = o->num; \
n->next = NULL; \
int num = M_C(name, _get_num)(o); \
for(int i = 0; i < num; i++) { \
{ \
node_t n = M_C(name, _new_node)(); \
/* Set default number of keys and type to copy */ \
n->num = o->num; \
/* By default it is not linked to its brother. \
Only the parent of this node can do it. It is fixed by it */ \
n->next = NULL; \
/* Get number of keys in the node and copy them */ \
int num = M_C(name, _get_num)(o); \
for(int i = 0; i < num; i++) { \
M_CALL_INIT_SET(key_oplist, n->key[i], o->key[i]); \
} \
if (M_C(name, _is_leaf)(o)) { \
M_IF(isMap)( \
for(int i = 0; i < num; i++) { \
M_CALL_INIT_SET(value_oplist, n->kind.value[i], o->kind.value[i]); \
} \
,) \
} else { \
for(int i = 0; i <= num; i++) { \
} \
if (M_C(name, _is_leaf)(o)) { \
/* Copy the associated values if it is a leaf and a MAP */ \
M_IF(isMap)( \
for(int i = 0; i < num; i++) { \
M_CALL_INIT_SET(value_oplist, n->kind.value[i], o->kind.value[i]); \
} \
, /* End of isMap */) \
} else { \
/* Copy recursively the associated nodes if it is not a leaf */ \
for(int i = 0; i <= num; i++) { \
assert(o->kind.node[i] != root); \
n->kind.node[i] = M_C(name, _copy_node)(o->kind.node[i], root); \
} \
for(int i = 0; i < num; i++) { \
node_t current = n->kind.node[i]; \
n->kind.node[i] = M_C(name, _copy_node)(o->kind.node[i], root); \
} \
/* The copied nodes don't have their next field correct */ \
/* Fix the next field for the copied nodes */ \
for(int i = 0; i < num; i++) { \
node_t current = n->kind.node[i]; \
node_t next = n->kind.node[i+1]; \
current->next = next; \
/* Go down the tree up to the leaf \
and fix the final 'next' link with the copied node */ \
while (!M_C(name, _is_leaf)(current)) { \
assert(!M_C(name, _is_leaf)(next)); \
current = current->kind.node[current->num]; \
next = next->kind.node[0]; \
current->next = next; \
} \
} \
} \
} \
} \
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, (o==root) ? n : root); \
return n; \
} \
\
static inline void M_C(name, _init_set)(tree_t b, const tree_t o) \
{ \
return n; \
} \
\
static inline void M_C(name, _init_set)(tree_t b, const tree_t o) \
{ \
BPTREEI_CONTRACT(N, isMulti, key_oplist, o); \
assert (b != NULL); \
assert (b != NULL); \
/* Just copy recursively the root node */ \
b->root = M_C(name, _copy_node)(o->root, o->root); \
b->size = o->size; \
b->size = o->size; \
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
} \
\
static inline void M_C(name, _set)(tree_t b, const tree_t o) \
{ \
M_C(name, _clear)(b); \
M_C(name, _init_set)(b, o); \
} \
\
} \
\
static inline void M_C(name, _set)(tree_t b, const tree_t o) \
{ \
/* NOTE: We could reuse the already allocated nodes of 'b'. \
Not sure if it worth the effort */ \
M_C(name, _clear)(b); \
M_C(name, _init_set)(b, o); \
} \
\
static inline bool M_C(name, _empty_p)(const tree_t b) \
{ \
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
@@ -428,19 +493,22 @@
node_t n = b->root; \
int np = 0; \
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
/* Go down the tree while searching for key */ \
while (!M_C(name, _is_leaf)(n)) { \
assert (np <= BPTREEI_MAX_STACK); \
int i, hi = n->num; \
assert (hi > 0); \
/* Linear search is usually faster than binary search for \
B+TREE (due to cache effect). If a binary tree is faster for \
the choosen type and size , it simply means that the \
size of B+TREE is too big (TBC) and shall be reduced. */ \
the choosen type and size , it probably means that the \
size of B+TREE is too big and should be reduced. */ \
for(i = 0; i < hi; i++) { \
if (M_CALL_CMP(key_oplist, key, n->key[i]) <= 0) \
break; \
} \
/* Update the Parent iterator */ \
pit->parent[np++] = n; \
/* Select the new node to go down to */ \
n = n->kind.node[i]; \
assert (n != NULL); \
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
@@ -453,20 +521,25 @@
{ \
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
pit_t pit; \
/* Get the leaf node where the key can be */ \
node_t n = M_C(name, _search_for_leaf)(pit, b, key); \
int cmp = 0; \
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
/* Search in the leaf for key */ \
for(int i = 0; cmp >= 0 && i < -n->num; i++) { \
cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \
if (cmp == 0) \
if (cmp == 0) { \
/* Return the value if MAP mode or the key if SET mode */ \
return M_IF(isMap)(&n->kind.value[i],&n->key[i]); \
} \
} \
/* Key not found */ \
return NULL; \
} \
\
static inline const value_t *M_C(name, _cget)(const tree_t b, key_t const key) \
static inline value_t const *M_C(name, _cget)(const tree_t b, key_t const key) \
{ \
return M_CONST_CAST(value_t, M_C(name, _get)(b, key)); \
return M_CONST_CAST(value_t, M_C(name, _get)(b, key)); \
} \
\
static inline int \
@@ -476,6 +549,7 @@
assert (M_C(name, _is_leaf)(n)); \
int i, num = M_C(name, _get_num)(n); \
assert (num <= N); \
/* Search for the key in the node n (a leaf) for insertion */ \
for(i = 0; i < num; i++) { \
int cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \
if (cmp <= 0) { \
@@ -492,8 +566,10 @@
break; \
} \
} \
/* Insert key & value if MAP mode */ \
M_CALL_INIT_SET(key_oplist, n->key[i], key); \
M_IF(isMap)(M_CALL_INIT_SET(value_oplist, n->kind.value[i], value);,) \
/* Increase the number of key in the node */ \
n->num += -1; /* Increase num as num<0 for leaf */ \
return i; \
} \
@@ -504,6 +580,7 @@
assert (!M_C(name, _is_leaf)(n)); \
int i, num = M_C(name, _get_num)(n); \
assert (num <= N); \
/* Search for the key in the node n (not a leaf) for insertion */ \
for(i = 0; i < num; i++) { \
if (n->kind.node[i] == l) { \
/* Move tables to make space for insertion */ \
@@ -512,8 +589,10 @@
break; \
} \
} \
/* Insert key in node */ \
/* TBC: DO_INIT_MOVE instead ? If key was in a node !*/ \
M_CALL_INIT_SET(key_oplist, n->key[i], key); \
/* Increase the number of key in the node */ \
n->num += 1; \
return i; \
} \
@@ -715,7 +794,7 @@
M_IF(isMap)(memmove(&left->kind.value[num_left], &right->kind.value[0], sizeof(value_t)*num_right);,) \
left->num = -num_left - num_right; \
} else { \
assert (num_left + num_right <= N -1); \
assert (num_left + num_right <= N -1); \
memmove(&left->key[num_left+1], &right->key[0], sizeof(key_t)*num_right); \
memmove(&left->kind.node[num_left+1], &right->kind.node[0], sizeof(node_t)*(num_right+1)); \
M_CALL_INIT_SET(key_oplist, left->key[num_left], parent->key[k]); \
@@ -742,7 +821,7 @@
return i; \
} \
assert(false); \
return -1; /* unreachable */ \
return -1; /* unreachable */ \
} \
\
static inline bool M_C(name, _erase)(tree_t b, key_t const key) \
@@ -888,31 +967,31 @@
); \
} \
\
static inline const M_C(name, _type_t) * \
static inline M_C(name, _type_t) const * \
M_C(name, _cref)(it_t it) \
{ \
return M_CONST_CAST(M_C(name, _type_t), M_C(name, _ref)(it)); \
} \
\
\
\
static inline void \
M_C(name, _it_from)(it_t it, const tree_t b, key_t const key) \
M_C(name, _it_from)(it_t it, const tree_t b, key_t const key) \
{ \
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
assert (it != NULL); \
pit_t pit; \
pit_t pit; \
node_t n = M_C(name, _search_for_leaf)(pit, b, key); \
it->node = n; \
int i; \
int i; \
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
for(i = 0; i < -n->num; i++) { \
if (M_CALL_CMP(key_oplist, key, n->key[i]) <= 0) \
break; \
for(i = 0; i < -n->num; i++) { \
if (M_CALL_CMP(key_oplist, key, n->key[i]) <= 0) \
break; \
} \
if (i == -n->num && n->next != NULL) { \
it->node = n->next; \
i = 0; \
} \
if (i == -n->num && n->next != NULL) { \
it->node = n->next; \
i = 0; \
} \
it->idx = i; \
} \
\
@@ -920,9 +999,9 @@
M_C(name, _it_until_p)(it_t it, key_t const key) \
{ \
assert (it != NULL); \
node_t n = it->node; \
if (it->idx >= -n->num) return true; \
int cmp = M_CALL_CMP(key_oplist, n->key[it->idx], key); \
node_t n = it->node; \
if (it->idx >= -n->num) return true; \
int cmp = M_CALL_CMP(key_oplist, n->key[it->idx], key); \
return (cmp >= 0); \
} \
\
@@ -930,88 +1009,88 @@
M_C(name, _it_while_p)(it_t it, key_t const key) \
{ \
assert (it != NULL); \
node_t n = it->node; \
if (it->idx >= -n->num) return false; \
int cmp = M_CALL_CMP(key_oplist, n->key[it->idx], key); \
node_t n = it->node; \
if (it->idx >= -n->num) return false; \
int cmp = M_CALL_CMP(key_oplist, n->key[it->idx], key); \
return (cmp <= 0); \
} \
\
static inline bool M_ATTR_DEPRECATED \
M_C(name, _it_to_p)(it_t it, key_t const key) \
M_C(name, _it_to_p)(it_t it, key_t const key) \
{ \
return M_C(name, _it_until_p)(it, key); \
} \
\
static inline value_t * \
M_C(name, _min)(const tree_t b) \
static inline value_t * \
M_C(name, _min)(const tree_t b) \
{ \
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
assert (b->size > 0); \
assert (b->size > 0); \
node_t n = b->root; \
/* Scan down the nodes */ \
while (!M_C(name, _is_leaf)(n)) { \
n = n->kind.node[0]; \
} \
return &n->M_IF(isMap)(kind.value, key)[0]; \
return &n->M_IF(isMap)(kind.value, key)[0]; \
} \
\
static inline value_t * \
M_C(name, _max)(const tree_t b) \
\
static inline value_t * \
M_C(name, _max)(const tree_t b) \
{ \
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
node_t n = b->root; \
/* Scan down the nodes */ \
while (!M_C(name, _is_leaf)(n)) { \
n = n->kind.node[n->num]; \
n = n->kind.node[n->num]; \
} \
return &n->M_IF(isMap)(kind.value, key)[-n->num-1]; \
return &n->M_IF(isMap)(kind.value, key)[-n->num-1]; \
} \
\
static inline const value_t * \
M_C(name, _cmin)(const tree_t tree) \
\
static inline value_t const * \
M_C(name, _cmin)(const tree_t tree) \
{ \
return M_CONST_CAST(value_t, M_C(name, _min)(tree)); \
return M_CONST_CAST(value_t, M_C(name, _min)(tree)); \
} \
\
static inline const value_t * \
M_C(name, _cmax)(const tree_t tree) \
\
static inline value_t const * \
M_C(name, _cmax)(const tree_t tree) \
{ \
return M_CONST_CAST(value_t, M_C(name, _max)(tree)); \
return M_CONST_CAST(value_t, M_C(name, _max)(tree)); \
} \
\
\
static inline void \
M_C(name, _init_move)(tree_t b, tree_t ref) \
M_C(name, _init_move)(tree_t b, tree_t ref) \
{ \
BPTREEI_CONTRACT(N, isMulti, key_oplist, ref); \
assert (b != NULL && b != ref); \
b->size = ref->size; \
b->root = ref->root; \
assert (b != NULL && b != ref); \
b->size = ref->size; \
b->root = ref->root; \
ref->root = NULL; \
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
} \
\
static inline void \
M_C(name, _move)(tree_t b, tree_t ref) \
M_C(name, _move)(tree_t b, tree_t ref) \
{ \
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
BPTREEI_CONTRACT(N, isMulti, key_oplist, ref); \
assert (b != ref); \
M_C(name,_clear)(b); \
M_C(name,_init_move)(b, ref); \
assert (b != ref); \
M_C(name,_clear)(b); \
M_C(name,_init_move)(b, ref); \
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
} \
\
\
static inline void \
M_C(name, _swap)(tree_t tree1, tree_t tree2) \
M_C(name, _swap)(tree_t tree1, tree_t tree2) \
{ \
BPTREEI_CONTRACT(N, isMulti, key_oplist, tree1); \
BPTREEI_CONTRACT(N, isMulti, key_oplist, tree2); \
M_SWAP(size_t, tree1->size, tree2->size); \
M_SWAP(node_t, tree1->root, tree2->root); \
M_SWAP(node_t, tree1->root, tree2->root); \
BPTREEI_CONTRACT(N, isMulti, key_oplist, tree1); \
BPTREEI_CONTRACT(N, isMulti, key_oplist, tree2); \
} \
\
\
BPTREEI_FUNC_ADDITIONAL_DEF2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t)
@@ -1139,7 +1218,7 @@
{ \
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
assert (str != NULL); \
M_C(name,_clean)(t1); \
M_C(name,_clean)(t1); \
bool success = false; \
int c = *str++; \
if (M_UNLIKELY (c != '[')) goto exit; \
@@ -1147,28 +1226,28 @@
if (M_UNLIKELY (c == ']')) { success = true; goto exit;} \
if (M_UNLIKELY (c == 0)) goto exit; \
str--; \
key_t key; \
M_CALL_INIT(key_oplist, key); \
M_IF(isMap)(value_t value; \
M_CALL_INIT(value_oplist, value); \
,) \
key_t key; \
M_CALL_INIT(key_oplist, key); \
M_IF(isMap)(value_t value; \
M_CALL_INIT(value_oplist, value); \
, /* No isMap */) \
do { \
bool b = M_CALL_PARSE_STR(key_oplist, key, str, &str); \
do { c = *str++; } while (isspace(c)); \
if (b == false) goto exit; \
M_IF(isMap)(if (c != ':') goto exit; \
if (b == false) goto exit_clear; \
M_IF(isMap)(if (c != ':') goto exit_clear; \
b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \
do { c = *str++; } while (isspace(c)); \
if (b == false || c == 0) goto exit; \
M_C(name, _set_at)(t1, key, value) \
, \
M_C(name, _push)(t1, key) \
); \
} while (c == M_GET_SEPARATOR key_oplist); \
M_CALL_CLEAR(key_oplist, key); \
M_IF(isMap)(M_CALL_CLEAR(value_oplist, value); \
,) \
do { c = *str++; } while (isspace(c)); \
if (b == false || c == 0) goto exit_clear; \
M_C(name, _set_at)(t1, key, value); \
, \
M_C(name, _push)(t1, key); \
) \
} while (c == M_GET_SEPARATOR key_oplist); \
success = (c == ']'); \
exit_clear: \
M_CALL_CLEAR(key_oplist, key); \
M_IF(isMap)(M_CALL_CLEAR(value_oplist, value); , /* No isMap */ ) \
exit: \
if (endp) *endp = str; \
return success; \
+41 -7
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Fixed size (Bounded) QUEUE & STACK interface
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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,9 +31,9 @@
/* Define the different kind of policy a lock-based buffer can have:
* - the buffer can be either a queue (policy is FIFO) or a stack (policy is FILO),
* - if the push method is by default blocking (waiting for the buffer to has some space) or not,
* - if the pop method is by default blocking (waiting for the buffer to has some data) or not,
* - if both methods are blocking,
* - if the push method is by default blocking (waiting for the buffer to has some space) or not, *** deprecated ***
* - if the pop method is by default blocking (waiting for the buffer to has some data) or not, *** deprecated ***
* - if both methods are blocking, *** deprecated ***
* - if it shall be thread safe or not (i.e. remove the mutex lock and atomic costs),
* - if the buffer has to be init with empty elements, or if it shall init an element when it is pushed (and moved when popped),
* - if the buffer has to overwrite the last element if the buffer is full,
@@ -106,7 +106,15 @@ typedef enum {
so that all arguments are evaluated before further expansion */
#define BUFFERI_DEF_P1(arg) BUFFERI_DEF_P2 arg
/* Validate the value oplist before going further */
#define BUFFERI_DEF_P2(name, type, m_size, policy, oplist, buffer_t) \
M_IF_OPLIST(oplist)(BUFFERI_DEF_P3, BUFFERI_DEF_FAILURE)(name, type, m_size, policy, oplist, buffer_t)
/* Stop processing with a compilation failure */
#define BUFFERI_DEF_FAILURE(name, type, m_size, policy, oplist, buffer_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(BUFFER_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
#define BUFFERI_DEF_P3(name, type, m_size, policy, oplist, buffer_t) \
\
typedef struct M_C(name, _s) { \
m_mutex_t mutexPush; /* MUTEX used for pushing elements */ \
@@ -129,6 +137,8 @@ typedef enum {
typedef union { M_C(name, _srcptr) cptr; M_C(name, _ptr) ptr; } M_C(name, _uptr); \
typedef type M_C(name, _type_t); \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void \
M_C(name, _init)(buffer_t v, size_t size) \
{ \
@@ -584,6 +594,14 @@ M_C(name, _init)(buffer_t v, size_t size) \
so that all arguments are evaluated before further expansion */
#define QUEUEI_MPMC_DEF_P1(arg) QUEUEI_MPMC_DEF_P2 arg
/* Validate the value oplist before going further */
#define QUEUEI_MPMC_DEF_P2(name, type, policy, oplist, buffer_t) \
M_IF_OPLIST(oplist)(QUEUEI_MPMC_DEF_P3, QUEUEI_MPMC_DEF_FAILURE)(name, type, policy, oplist, buffer_t)
/* Stop processing with a compilation failure */
#define QUEUEI_MPMC_DEF_FAILURE(name, type, policy, oplist, buffer_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(QUEUE_MPMC_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
#ifdef NDEBUG
# define QUEUEI_MPMC_CONTRACT(v) /* nothing */
#else
@@ -598,7 +616,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
} while (0)
#endif
#define QUEUEI_MPMC_DEF_P2(name, type, policy, oplist, buffer_t) \
#define QUEUEI_MPMC_DEF_P3(name, type, policy, oplist, buffer_t) \
\
/* The sequence number of an element will be equal to either \
- 2* the index of the production which creates it, \
@@ -784,6 +802,14 @@ M_C(name, _init)(buffer_t v, size_t size) \
so that all arguments are evaluated before further expansion */
#define QUEUEI_SPSC_DEF_P1(arg) QUEUEI_SPSC_DEF_P2 arg
/* Validate the value oplist before going further */
#define QUEUEI_SPSC_DEF_P2(name, type, policy, oplist, buffer_t) \
M_IF_OPLIST(oplist)(QUEUEI_SPSC_DEF_P3, QUEUEI_SPSC_DEF_FAILURE)(name, type, policy, oplist, buffer_t)
/* Stop processing with a compilation failure */
#define QUEUEI_SPSC_DEF_FAILURE(name, type, policy, oplist, buffer_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(QUEUE_SPSC_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
#ifdef NDEBUG
#define QUEUEI_SPSC_CONTRACT(table) do { } while (0)
#else
@@ -798,7 +824,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
} while (0)
#endif
#define QUEUEI_SPSC_DEF_P2(name, type, policy, oplist, buffer_t) \
#define QUEUEI_SPSC_DEF_P3(name, type, policy, oplist, buffer_t) \
\
typedef struct M_C(name, _el_s) { \
type x; \
@@ -1042,8 +1068,16 @@ M_C(name, _init)(buffer_t v, size_t size) \
so that all arguments are evaluated before further expansion */
#define BUFFERI_OPLIST_P1(arg) BUFFERI_OPLIST_P2 arg
/* OPLIST defininition of a buffer */
/* Validation of the given oplist */
#define BUFFERI_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(BUFFERI_OPLIST_P3, BUFFERI_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define BUFFERI_OPLIST_FAILURE(name, oplist) \
M_LIB_ERROR(ARGUMENT_OF_BUFFER_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
/* OPLIST defininition of a buffer */
#define BUFFERI_OPLIST_P3(name, oplist) \
(INIT(M_C(name, _int_init)) \
,INIT_SET(M_C(name, _init_set)) \
,SET(M_C(name, _set)) \
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Concurrent memory pool allocator
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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 -4
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Basic Protected Concurrent module over container.
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -62,12 +62,20 @@
so that all arguments are evaluated before further expansion */
#define CONCURRENTI_OPLIST_P1(arg) CONCURRENTI_OPLIST_P2 arg
/* Validation of the given oplist */
#define CONCURRENTI_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(CONCURRENTI_OPLIST_P3, CONCURRENTI_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define CONCURRENTI_OPLIST_FAILURE(name, oplist) \
M_LIB_ERROR(ARGUMENT_OF_CONCURRENT_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
/* OPLIST definition
GET_KEY is not present as its interface is not compatible with a concurrent
container (_get returns a pointer to an internal data, data that may be
destroyed by another thread).
*/
#define CONCURRENTI_OPLIST_P2(name, oplist) \
#define CONCURRENTI_OPLIST_P3(name, oplist) \
(M_IF_METHOD(INIT, oplist)(INIT(M_C(name, _init)),) \
,M_IF_METHOD(INIT_SET, oplist)(INIT_SET(M_C(name, _init_set)),) \
,M_IF_METHOD(SET, oplist)(SET(M_C(name, _set)),) \
@@ -115,13 +123,21 @@
so that all arguments are evaluated before further expansion */
#define CONCURRENTI_DEF_P1(arg) CONCURRENTI_DEF_P2 arg
/* Validate the value oplist before going further */
#define CONCURRENTI_DEF_P2(name, type, oplist, concurrent_t) \
M_IF_OPLIST(oplist)(CONCURRENTI_DEF_P3, CONCURRENTI_DEF_FAILURE)(name, type, oplist, concurrent_t)
/* Stop processing with a compilation failure */
#define CONCURRENTI_DEF_FAILURE(name, type, oplist, concurrent_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(CONCURRENT_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
/* Internal concurrent definition
- name: prefix to be used
- type: type of the sub container
- oplist: oplist of the type of the sub container
- concurrent_t: alias for M_C(name, _t) [ type of the container ]
*/
#define CONCURRENTI_DEF_P2(name, type, oplist, concurrent_t) \
#define CONCURRENTI_DEF_P3(name, type, oplist, concurrent_t) \
\
typedef struct M_C(name, _s) { \
struct M_C(name, _s) *self; \
@@ -135,6 +151,8 @@
\
typedef type M_C(name, _type_t); \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
/* Define the lock strategy (global & shared lock) */ \
static inline void \
M_C(name, _internal_init)(concurrent_t out) \
@@ -641,13 +659,21 @@
so that all arguments are evaluated before further expansion */
#define CONCURRENTI_RP_DEF_P1(arg) CONCURRENTI_RP_DEF_P2 arg
/* Validate the value oplist before going further */
#define CONCURRENTI_RP_DEF_P2(name, type, oplist, concurrent_t) \
M_IF_OPLIST(oplist)(CONCURRENTI_RP_DEF_P3, CONCURRENTI_RP_DEF_FAILURE)(name, type, oplist, concurrent_t)
/* Stop processing with a compilation failure */
#define CONCURRENTI_RP_DEF_FAILURE(name, type, oplist, concurrent_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(CONCURRENT_RP_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
/* Internal RP concurrent definition
- name: prefix to be used
- type: type of the sub container
- oplist: oplist of the type of the sub container
- concurrent_t: alias for M_C(name, _t) [ type of the container ]
*/
#define CONCURRENTI_RP_DEF_P2(name, type, oplist, concurrent_t) \
#define CONCURRENTI_RP_DEF_P3(name, type, oplist, concurrent_t) \
\
typedef struct M_C(name, _s) { \
struct M_C(name, _s) *self; \
+332 -140
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Extended Pre-processing macros module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
@@ -52,7 +52,7 @@
/* Define M*LIB version */
#define M_CORE_VERSION_MAJOR 0
#define M_CORE_VERSION_MINOR 3
#define M_CORE_VERSION_PATCHLEVEL 0
#define M_CORE_VERSION_PATCHLEVEL 1
/* M_ASSUME is equivalent to assert, but gives hints to compiler
about how to optimize the code if NDEBUG is defined.
@@ -103,12 +103,7 @@
#define M_ATTR_EXTENSION
#endif
/* Overwrite NO DEFAULT to give a proper error message */
#if defined(__GNUC__) \
&& (__GNUC__ * 100 + __GNUC_MINOR__) >= 403
extern void m_no_default_function(void) __attribute__((error("The requested operator has no method registered in the given OPLIST. ")));
#define M_NO_DEFAULT(...) m_no_default_function()
#endif
/***************************************************************/
@@ -369,238 +364,238 @@ extern void m_no_default_function(void) __attribute__((error("The requested op
/* Return the nth argument (either variable or static).
Generated by:
for i in $(seq 1 53 ) ; do printf "#define M_RETI_ARG%d(" $i; for j in $(seq 1 $i) ; do printf "_%d, " $j ; done ; printf "...) _%d\n#define M_RET_ARG%d(...) M_RETI_ARG%d(__VA_ARGS__)\n\n" $i $i $i ; done
for i in $(seq 1 53 ) ; do printf "#define M_RETI_ARG%d(" $i; for j in $(seq 1 $i) ; do printf "_%d, " $j ; done ; printf "...) _%d\n#define M_RET_ARG%d(...) M_RETI_ARG%d(__VA_ARGS__,)\n\n" $i $i $i ; done
*/
#define M_RETI_ARG(f, ...) f(__VA_ARGS__)
#define M_RET_ARG(n, ...) M_RETI_ARG(M_C(M_RET_ARG, n), __VA_ARGS__)
#define M_RETI_ARG1(_1, ...) _1
#define M_RET_ARG1(...) M_RETI_ARG1(__VA_ARGS__)
#define M_RET_ARG1(...) M_RETI_ARG1(__VA_ARGS__,)
#define M_RETI_ARG2(_1, _2, ...) _2
#define M_RET_ARG2(...) M_RETI_ARG2(__VA_ARGS__)
#define M_RET_ARG2(...) M_RETI_ARG2(__VA_ARGS__,)
#define M_RETI_ARG3(_1, _2, _3, ...) _3
#define M_RET_ARG3(...) M_RETI_ARG3(__VA_ARGS__)
#define M_RET_ARG3(...) M_RETI_ARG3(__VA_ARGS__,)
#define M_RETI_ARG4(_1, _2, _3, _4, ...) _4
#define M_RET_ARG4(...) M_RETI_ARG4(__VA_ARGS__)
#define M_RET_ARG4(...) M_RETI_ARG4(__VA_ARGS__,)
#define M_RETI_ARG5(_1, _2, _3, _4, _5, ...) _5
#define M_RET_ARG5(...) M_RETI_ARG5(__VA_ARGS__)
#define M_RET_ARG5(...) M_RETI_ARG5(__VA_ARGS__,)
#define M_RETI_ARG6(_1, _2, _3, _4, _5, _6, ...) _6
#define M_RET_ARG6(...) M_RETI_ARG6(__VA_ARGS__)
#define M_RET_ARG6(...) M_RETI_ARG6(__VA_ARGS__,)
#define M_RETI_ARG7(_1, _2, _3, _4, _5, _6, _7, ...) _7
#define M_RET_ARG7(...) M_RETI_ARG7(__VA_ARGS__)
#define M_RET_ARG7(...) M_RETI_ARG7(__VA_ARGS__,)
#define M_RETI_ARG8(_1, _2, _3, _4, _5, _6, _7, _8, ...) _8
#define M_RET_ARG8(...) M_RETI_ARG8(__VA_ARGS__)
#define M_RET_ARG8(...) M_RETI_ARG8(__VA_ARGS__,)
#define M_RETI_ARG9(_1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9
#define M_RET_ARG9(...) M_RETI_ARG9(__VA_ARGS__)
#define M_RET_ARG9(...) M_RETI_ARG9(__VA_ARGS__,)
#define M_RETI_ARG10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) _10
#define M_RET_ARG10(...) M_RETI_ARG10(__VA_ARGS__)
#define M_RET_ARG10(...) M_RETI_ARG10(__VA_ARGS__,)
#define M_RETI_ARG11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) _11
#define M_RET_ARG11(...) M_RETI_ARG11(__VA_ARGS__)
#define M_RET_ARG11(...) M_RETI_ARG11(__VA_ARGS__,)
#define M_RETI_ARG12(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) _12
#define M_RET_ARG12(...) M_RETI_ARG12(__VA_ARGS__)
#define M_RET_ARG12(...) M_RETI_ARG12(__VA_ARGS__,)
#define M_RETI_ARG13(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) _13
#define M_RET_ARG13(...) M_RETI_ARG13(__VA_ARGS__)
#define M_RET_ARG13(...) M_RETI_ARG13(__VA_ARGS__,)
#define M_RETI_ARG14(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) _14
#define M_RET_ARG14(...) M_RETI_ARG14(__VA_ARGS__)
#define M_RET_ARG14(...) M_RETI_ARG14(__VA_ARGS__,)
#define M_RETI_ARG15(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15
#define M_RET_ARG15(...) M_RETI_ARG15(__VA_ARGS__)
#define M_RET_ARG15(...) M_RETI_ARG15(__VA_ARGS__,)
#define M_RETI_ARG16(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) _16
#define M_RET_ARG16(...) M_RETI_ARG16(__VA_ARGS__)
#define M_RET_ARG16(...) M_RETI_ARG16(__VA_ARGS__,)
#define M_RETI_ARG17(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, ...) _17
#define M_RET_ARG17(...) M_RETI_ARG17(__VA_ARGS__)
#define M_RET_ARG17(...) M_RETI_ARG17(__VA_ARGS__,)
#define M_RETI_ARG18(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, ...) _18
#define M_RET_ARG18(...) M_RETI_ARG18(__VA_ARGS__)
#define M_RET_ARG18(...) M_RETI_ARG18(__VA_ARGS__,)
#define M_RETI_ARG19(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) _19
#define M_RET_ARG19(...) M_RETI_ARG19(__VA_ARGS__)
#define M_RET_ARG19(...) M_RETI_ARG19(__VA_ARGS__,)
#define M_RETI_ARG20(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, ...) _20
#define M_RET_ARG20(...) M_RETI_ARG20(__VA_ARGS__)
#define M_RET_ARG20(...) M_RETI_ARG20(__VA_ARGS__,)
#define M_RETI_ARG21(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, ...) _21
#define M_RET_ARG21(...) M_RETI_ARG21(__VA_ARGS__)
#define M_RET_ARG21(...) M_RETI_ARG21(__VA_ARGS__,)
#define M_RETI_ARG22(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, ...) _22
#define M_RET_ARG22(...) M_RETI_ARG22(__VA_ARGS__)
#define M_RET_ARG22(...) M_RETI_ARG22(__VA_ARGS__,)
#define M_RETI_ARG23(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, ...) _23
#define M_RET_ARG23(...) M_RETI_ARG23(__VA_ARGS__)
#define M_RET_ARG23(...) M_RETI_ARG23(__VA_ARGS__,)
#define M_RETI_ARG24(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, ...) _24
#define M_RET_ARG24(...) M_RETI_ARG24(__VA_ARGS__)
#define M_RET_ARG24(...) M_RETI_ARG24(__VA_ARGS__,)
#define M_RETI_ARG25(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, ...) _25
#define M_RET_ARG25(...) M_RETI_ARG25(__VA_ARGS__)
#define M_RET_ARG25(...) M_RETI_ARG25(__VA_ARGS__,)
#define M_RETI_ARG26(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, ...) _26
#define M_RET_ARG26(...) M_RETI_ARG26(__VA_ARGS__)
#define M_RET_ARG26(...) M_RETI_ARG26(__VA_ARGS__,)
#define M_RETI_ARG27(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, ...) _27
#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__)
#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__,)
#define M_RETI_ARG28(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, ...) _28
#define M_RET_ARG28(...) M_RETI_ARG28(__VA_ARGS__)
#define M_RET_ARG28(...) M_RETI_ARG28(__VA_ARGS__,)
#define M_RETI_ARG29(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, ...) _29
#define M_RET_ARG29(...) M_RETI_ARG29(__VA_ARGS__)
#define M_RET_ARG29(...) M_RETI_ARG29(__VA_ARGS__,)
#define M_RETI_ARG30(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, ...) _30
#define M_RET_ARG30(...) M_RETI_ARG30(__VA_ARGS__)
#define M_RET_ARG30(...) M_RETI_ARG30(__VA_ARGS__,)
#define M_RETI_ARG31(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, ...) _31
#define M_RET_ARG31(...) M_RETI_ARG31(__VA_ARGS__)
#define M_RET_ARG31(...) M_RETI_ARG31(__VA_ARGS__,)
#define M_RETI_ARG32(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, ...) _32
#define M_RET_ARG32(...) M_RETI_ARG32(__VA_ARGS__)
#define M_RET_ARG32(...) M_RETI_ARG32(__VA_ARGS__,)
#define M_RETI_ARG33(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, ...) _33
#define M_RET_ARG33(...) M_RETI_ARG33(__VA_ARGS__)
#define M_RET_ARG33(...) M_RETI_ARG33(__VA_ARGS__,)
#define M_RETI_ARG34(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, ...) _34
#define M_RET_ARG34(...) M_RETI_ARG34(__VA_ARGS__)
#define M_RET_ARG34(...) M_RETI_ARG34(__VA_ARGS__,)
#define M_RETI_ARG35(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, ...) _35
#define M_RET_ARG35(...) M_RETI_ARG35(__VA_ARGS__)
#define M_RET_ARG35(...) M_RETI_ARG35(__VA_ARGS__,)
#define M_RETI_ARG36(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, ...) _36
#define M_RET_ARG36(...) M_RETI_ARG36(__VA_ARGS__)
#define M_RET_ARG36(...) M_RETI_ARG36(__VA_ARGS__,)
#define M_RETI_ARG37(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, ...) _37
#define M_RET_ARG37(...) M_RETI_ARG37(__VA_ARGS__)
#define M_RET_ARG37(...) M_RETI_ARG37(__VA_ARGS__,)
#define M_RETI_ARG38(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, ...) _38
#define M_RET_ARG38(...) M_RETI_ARG38(__VA_ARGS__)
#define M_RET_ARG38(...) M_RETI_ARG38(__VA_ARGS__,)
#define M_RETI_ARG39(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, ...) _39
#define M_RET_ARG39(...) M_RETI_ARG39(__VA_ARGS__)
#define M_RET_ARG39(...) M_RETI_ARG39(__VA_ARGS__,)
#define M_RETI_ARG40(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, ...) _40
#define M_RET_ARG40(...) M_RETI_ARG40(__VA_ARGS__)
#define M_RET_ARG40(...) M_RETI_ARG40(__VA_ARGS__,)
#define M_RETI_ARG41(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, ...) _41
#define M_RET_ARG41(...) M_RETI_ARG41(__VA_ARGS__)
#define M_RET_ARG41(...) M_RETI_ARG41(__VA_ARGS__,)
#define M_RETI_ARG42(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, ...) _42
#define M_RET_ARG42(...) M_RETI_ARG42(__VA_ARGS__)
#define M_RET_ARG42(...) M_RETI_ARG42(__VA_ARGS__,)
#define M_RETI_ARG43(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, ...) _43
#define M_RET_ARG43(...) M_RETI_ARG43(__VA_ARGS__)
#define M_RET_ARG43(...) M_RETI_ARG43(__VA_ARGS__,)
#define M_RETI_ARG44(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, ...) _44
#define M_RET_ARG44(...) M_RETI_ARG44(__VA_ARGS__)
#define M_RET_ARG44(...) M_RETI_ARG44(__VA_ARGS__,)
#define M_RETI_ARG45(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, ...) _45
#define M_RET_ARG45(...) M_RETI_ARG45(__VA_ARGS__)
#define M_RET_ARG45(...) M_RETI_ARG45(__VA_ARGS__,)
#define M_RETI_ARG46(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, ...) _46
#define M_RET_ARG46(...) M_RETI_ARG46(__VA_ARGS__)
#define M_RET_ARG46(...) M_RETI_ARG46(__VA_ARGS__,)
#define M_RETI_ARG47(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, ...) _47
#define M_RET_ARG47(...) M_RETI_ARG47(__VA_ARGS__)
#define M_RET_ARG47(...) M_RETI_ARG47(__VA_ARGS__,)
#define M_RETI_ARG48(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, ...) _48
#define M_RET_ARG48(...) M_RETI_ARG48(__VA_ARGS__)
#define M_RET_ARG48(...) M_RETI_ARG48(__VA_ARGS__,)
#define M_RETI_ARG49(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, ...) _49
#define M_RET_ARG49(...) M_RETI_ARG49(__VA_ARGS__)
#define M_RET_ARG49(...) M_RETI_ARG49(__VA_ARGS__,)
#define M_RETI_ARG50(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, ...) _50
#define M_RET_ARG50(...) M_RETI_ARG50(__VA_ARGS__)
#define M_RET_ARG50(...) M_RETI_ARG50(__VA_ARGS__,)
#define M_RETI_ARG51(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, ...) _51
#define M_RET_ARG51(...) M_RETI_ARG51(__VA_ARGS__)
#define M_RET_ARG51(...) M_RETI_ARG51(__VA_ARGS__,)
#define M_RETI_ARG52(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, ...) _52
#define M_RET_ARG52(...) M_RETI_ARG52(__VA_ARGS__)
#define M_RET_ARG52(...) M_RETI_ARG52(__VA_ARGS__,)
#define M_RETI_ARG53(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, ...) _53
#define M_RET_ARG53(...) M_RETI_ARG53(__VA_ARGS__)
#define M_RET_ARG53(...) M_RETI_ARG53(__VA_ARGS__,)
#define M_RETI_ARG54(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, ...) _54
#define M_RET_ARG54(...) M_RETI_ARG54(__VA_ARGS__)
#define M_RET_ARG54(...) M_RETI_ARG54(__VA_ARGS__,)
#define M_RETI_ARG55(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, ...) _55
#define M_RET_ARG55(...) M_RETI_ARG55(__VA_ARGS__)
#define M_RET_ARG55(...) M_RETI_ARG55(__VA_ARGS__,)
#define M_RETI_ARG56(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, ...) _56
#define M_RET_ARG56(...) M_RETI_ARG56(__VA_ARGS__)
#define M_RET_ARG56(...) M_RETI_ARG56(__VA_ARGS__,)
#define M_RETI_ARG57(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, ...) _57
#define M_RET_ARG57(...) M_RETI_ARG57(__VA_ARGS__)
#define M_RET_ARG57(...) M_RETI_ARG57(__VA_ARGS__,)
#define M_RETI_ARG58(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, ...) _58
#define M_RET_ARG58(...) M_RETI_ARG58(__VA_ARGS__)
#define M_RET_ARG58(...) M_RETI_ARG58(__VA_ARGS__,)
#define M_RETI_ARG59(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, ...) _59
#define M_RET_ARG59(...) M_RETI_ARG59(__VA_ARGS__)
#define M_RET_ARG59(...) M_RETI_ARG59(__VA_ARGS__,)
#define M_RETI_ARG60(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, ...) _60
#define M_RET_ARG60(...) M_RETI_ARG60(__VA_ARGS__)
#define M_RET_ARG60(...) M_RETI_ARG60(__VA_ARGS__,)
#define M_RETI_ARG61(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, ...) _61
#define M_RET_ARG61(...) M_RETI_ARG61(__VA_ARGS__)
#define M_RET_ARG61(...) M_RETI_ARG61(__VA_ARGS__,)
#define M_RETI_ARG62(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, ...) _62
#define M_RET_ARG62(...) M_RETI_ARG62(__VA_ARGS__)
#define M_RET_ARG62(...) M_RETI_ARG62(__VA_ARGS__,)
#define M_RETI_ARG63(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, ...) _63
#define M_RET_ARG63(...) M_RETI_ARG63(__VA_ARGS__)
#define M_RET_ARG63(...) M_RETI_ARG63(__VA_ARGS__,)
#define M_RETI_ARG64(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, ...) _64
#define M_RET_ARG64(...) M_RETI_ARG64(__VA_ARGS__)
#define M_RET_ARG64(...) M_RETI_ARG64(__VA_ARGS__,)
#define M_RETI_ARG65(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, ...) _65
#define M_RET_ARG65(...) M_RETI_ARG65(__VA_ARGS__)
#define M_RET_ARG65(...) M_RETI_ARG65(__VA_ARGS__,)
#define M_RETI_ARG66(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, ...) _66
#define M_RET_ARG66(...) M_RETI_ARG66(__VA_ARGS__)
#define M_RET_ARG66(...) M_RETI_ARG66(__VA_ARGS__,)
#define M_RETI_ARG67(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, ...) _67
#define M_RET_ARG67(...) M_RETI_ARG67(__VA_ARGS__)
#define M_RET_ARG67(...) M_RETI_ARG67(__VA_ARGS__,)
#define M_RETI_ARG68(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, ...) _68
#define M_RET_ARG68(...) M_RETI_ARG68(__VA_ARGS__)
#define M_RET_ARG68(...) M_RETI_ARG68(__VA_ARGS__,)
#define M_RETI_ARG69(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, ...) _69
#define M_RET_ARG69(...) M_RETI_ARG69(__VA_ARGS__)
#define M_RET_ARG69(...) M_RETI_ARG69(__VA_ARGS__,)
#define M_RETI_ARG70(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, ...) _70
#define M_RET_ARG70(...) M_RETI_ARG70(__VA_ARGS__)
#define M_RET_ARG70(...) M_RETI_ARG70(__VA_ARGS__,)
#define M_RETI_ARG71(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, ...) _71
#define M_RET_ARG71(...) M_RETI_ARG71(__VA_ARGS__)
#define M_RET_ARG71(...) M_RETI_ARG71(__VA_ARGS__,)
#define M_RETI_ARG72(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, ...) _72
#define M_RET_ARG72(...) M_RETI_ARG72(__VA_ARGS__)
#define M_RET_ARG72(...) M_RETI_ARG72(__VA_ARGS__,)
#define M_RETI_ARG73(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, ...) _73
#define M_RET_ARG73(...) M_RETI_ARG73(__VA_ARGS__)
#define M_RET_ARG73(...) M_RETI_ARG73(__VA_ARGS__,)
#define M_RETI_ARG74(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, ...) _74
#define M_RET_ARG74(...) M_RETI_ARG74(__VA_ARGS__)
#define M_RET_ARG74(...) M_RETI_ARG74(__VA_ARGS__,)
#define M_RETI_ARG75(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, ...) _75
#define M_RET_ARG75(...) M_RETI_ARG75(__VA_ARGS__)
#define M_RET_ARG75(...) M_RETI_ARG75(__VA_ARGS__,)
#define M_RETI_ARG76(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, ...) _76
#define M_RET_ARG76(...) M_RETI_ARG76(__VA_ARGS__)
#define M_RET_ARG76(...) M_RETI_ARG76(__VA_ARGS__,)
/* For a pair of argument (arg0, arg1), return either the first or the second.
Needed in case where M_RET_ARGn cannot be used */
@@ -798,9 +793,43 @@ extern void m_no_default_function(void) __attribute__((error("The requested op
M_IF_EMPTY(arguments)(action if empty, action if not empty) */
#define M_IF_EMPTY(...) M_IF(M_EMPTY_P(__VA_ARGS__))
/* Return 1 if argument is "()" or "(x)" */
#define M_PARENTHESISI_DETECT(...) 0, 1,
#define M_PARENTHESIS_P(...) M_AND(M_COMMA_P(M_PARENTHESISI_DETECT __VA_ARGS__), M_INV(M_COMMA_P(__VA_ARGS__)))
/* Return 1 if argument is "()" or "(x)"
* Test if () or (x) can be transformed into a comma,
* and that there is no (toplevel) comma
* and that there is nothing beyond the parenthesis.
*/
#define M_PARENTHESISI_DETECT1(...) ,
#define M_PARENTHESISI_DETECT2(...)
#define M_PARENTHESIS_P(...) \
M_AND(M_AND(M_COMMA_P(M_PARENTHESISI_DETECT1 __VA_ARGS__), M_INV(M_COMMA_P(__VA_ARGS__))), \
M_EMPTY_P(M_PARENTHESISI_DETECT2 __VA_ARGS__))
/* Return 1 if argument type or variable or function is the keyword.
- refFunc is the reference keyword.
It shall be either 'and', 'or', 'sum' (equivalent to 'add'), 'bool'
- testedFunc is the tested keyword.
It cannot start with a special character */
#define M_KEYWORD_P(refFunc, testedFunc) \
M_COMMA_P(M_C4(M_PATTERN_, refFunc, _, testedFunc))
/* The different special recognized patterns: */
#define M_PATTERN_and_and ,
#define M_PATTERN_or_or ,
#define M_PATTERN_sum_sum ,
#define M_PATTERN_sum_add ,
#define M_PATTERN_add_add ,
#define M_PATTERN_add_sum ,
#define M_PATTERN_product_product ,
#define M_PATTERN_product_mul ,
#define M_PATTERN_bool_bool ,
#define M_PATTERN_char_char ,
#define M_PATTERN_short_short ,
#define M_PATTERN_int_int ,
#define M_PATTERN_long_long ,
#define M_PATTERN_float_float ,
#define M_PATTERN_double_double ,
#define M_PATTERN_void_void ,
/* Necessary macros to handle recursivity,
delaying the evaluation by one (or more) level of macro expansion.
@@ -1229,6 +1258,15 @@ extern void m_no_default_function(void) __attribute__((error("The requested op
#define M_NDEBUG_TEST 0
#define M_IF_DEBUG(a) M_IF(M_TEST_NDEBUG_P())(,a)
/* If the Function Object is included, expands the code,
otherwise do nothing.
M_FUNCOBJ_IS_NOT_DEFINED is defined to 0.
NOTE: M_IF is the variable is not defined assummes yes.
*/
#define M_IF_FUNCOBJ(a) M_IF(M_FUNCOBJ_IS_NOT_DEFINED)( ,a)
/* Helper macro to redefine a function with a default value :
If there is only one variable as the __VA_ARGS__, print
__VA_ARGS__ then ', value', instead only __VA_ARGS__.
@@ -1597,8 +1635,10 @@ M_PARSE_DEFAULT_TYPE_DEF(m_core_parse_ldouble, long double, strtold, )
NOTE: C definition is safer than the C++ one.
*/
#ifndef __cplusplus
/* Cast the object n into type only if it is C assignable */
# define M_ASSIGN_CAST(type, n) ((type) { 0 } = (n))
#else
/* Cast the object n into type using a static_cast */
# define M_ASSIGN_CAST(type, n) static_cast<type>(n)
#endif
@@ -1887,6 +1927,7 @@ m_core_hash (const void *str, size_t length)
/******************** METHODS handling **********************/
/************************************************************/
/* Helper macros to make M_GET_METHOD works.
List of supported methods for an oplist */
#define M_INIT_INIT(a) ,a,
@@ -1908,6 +1949,7 @@ m_core_hash (const void *str, size_t length)
#define M_CMP_CMP(a) ,a,
#define M_TYPE_TYPE(a) ,a,
#define M_SUBTYPE_SUBTYPE(a) ,a,
#define M_NAME_NAME(a) ,a,
#define M_OPLIST_OPLIST(a) ,a,
#define M_SORT_SORT(a) ,a,
#define M_UPDATE_UPDATE(a) ,a,
@@ -1988,13 +2030,14 @@ m_core_hash (const void *str, size_t length)
#define M_GET_CMP(...) M_GET_METHOD(CMP, M_CMP_DEFAULT, __VA_ARGS__)
#define M_GET_UPDATE(...) M_GET_METHOD(UPDATE, M_SET_DEFAULT, __VA_ARGS__)
#define M_GET_UPDATE_TYPE(...) M_GET_METHOD(UPDATE_TYPE, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_TYPE(...) M_GET_METHOD(TYPE, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_SUBTYPE(...) M_GET_METHOD(SUBTYPE, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_TYPE(...) M_GET_METHOD(TYPE, M_NO_DEF_TYPE, __VA_ARGS__)
#define M_GET_SUBTYPE(...) M_GET_METHOD(SUBTYPE, M_NO_DEF_TYPE, __VA_ARGS__)
#define M_GET_NAME(...) M_GET_METHOD(NAME, M_NO_DEF_TYPE, __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_SPLICE_BACK(...) M_GET_METHOD(SPLICE_BACK, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_SPLICE_AT(...) M_GET_METHOD(SPLICE_AT, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_IT_TYPE(...) M_GET_METHOD(IT_TYPE, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_IT_TYPE(...) M_GET_METHOD(IT_TYPE, M_NO_DEF_TYPE, __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__)
#define M_GET_IT_END(...) M_GET_METHOD(IT_END, M_NO_DEFAULT, __VA_ARGS__)
@@ -2014,10 +2057,10 @@ m_core_hash (const void *str, size_t length)
#define M_GET_MUL(...) M_GET_METHOD(MUL, M_MUL_DEFAULT, __VA_ARGS__)
#define M_GET_DIV(...) M_GET_METHOD(DIV, M_DIV_DEFAULT, __VA_ARGS__)
#define M_GET_CLEAN(...) M_GET_METHOD(CLEAN, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_KEY_TYPE(...) M_GET_METHOD(KEY_TYPE, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_VALUE_TYPE(...) M_GET_METHOD(VALUE_TYPE, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_KEY_OPLIST(...) M_GET_METHOD(KEY_OPLIST, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_VALUE_OPLIST(...) M_GET_METHOD(VALUE_OPLIST, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_KEY_TYPE(...) M_GET_METHOD(KEY_TYPE, M_NO_DEF_TYPE, __VA_ARGS__)
#define M_GET_VALUE_TYPE(...) M_GET_METHOD(VALUE_TYPE, M_NO_DEF_TYPE, __VA_ARGS__)
#define M_GET_KEY_OPLIST(...) M_GET_METHOD(KEY_OPLIST, M_NO_DEF_TYPE, __VA_ARGS__)
#define M_GET_VALUE_OPLIST(...) M_GET_METHOD(VALUE_OPLIST, M_NO_DEF_TYPE, __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_GET_SET_KEY(...) M_GET_METHOD(GET_SET_KEY, M_NO_DEFAULT, __VA_ARGS__)
@@ -2027,7 +2070,6 @@ m_core_hash (const void *str, size_t length)
#define M_GET_POP(...) M_GET_METHOD(POP, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_PUSH_MOVE(...) M_GET_METHOD(PUSH_MOVE, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_POP_MOVE(...) M_GET_METHOD(POP_MOVE, M_NO_DEFAULT, __VA_ARGS__)
// TODO: PUSH_NEW?
#define M_GET_REVERSE(...) M_GET_METHOD(REVERSE, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_GET_STR(...) M_GET_METHOD(GET_STR, M_NO_DEFAULT, __VA_ARGS__)
#define M_GET_PARSE_STR(...) M_GET_METHOD(PARSE_STR, M_NO_DEFAULT, __VA_ARGS__)
@@ -2042,6 +2084,7 @@ m_core_hash (const void *str, size_t length)
#define M_GET_OOR_EQUAL(...) M_GET_METHOD(OOR_EQUAL, M_NO_DEFAULT, __VA_ARGS__)
// Calling method with support of defined transformation API
// operators that are not methods are commented
#define M_CALL_INIT(oplist, ...) M_APPLY_API(M_GET_INIT oplist, oplist, __VA_ARGS__)
#define M_CALL_INIT_SET(oplist, ...) M_APPLY_API(M_GET_INIT_SET oplist, oplist, __VA_ARGS__)
#define M_CALL_INIT_MOVE(oplist, ...) M_APPLY_API(M_GET_INIT_MOVE oplist, oplist, __VA_ARGS__)
@@ -2060,13 +2103,14 @@ m_core_hash (const void *str, size_t length)
#define M_CALL_EQUAL(oplist, ...) M_APPLY_API(M_GET_EQUAL oplist, oplist, __VA_ARGS__)
#define M_CALL_CMP(oplist, ...) M_APPLY_API(M_GET_CMP oplist, oplist, __VA_ARGS__)
#define M_CALL_UPDATE(oplist, ...) M_APPLY_API(M_GET_UPDATE oplist, oplist, __VA_ARGS__)
#define M_CALL_TYPE(oplist, ...) M_APPLY_API(M_GET_TYPE oplist, oplist, __VA_ARGS__)
#define M_CALL_SUBTYPE(oplist, ...) M_APPLY_API(M_GET_SUBTYPE oplist, oplist, __VA_ARGS__)
#define M_CALL_OPLIST(oplist, ...) M_APPLY_API(M_GET_OPLIST oplist, oplist, __VA_ARGS__)
//#define M_CALL_TYPE(oplist, ...) M_APPLY_API(M_GET_TYPE oplist, oplist, __VA_ARGS__)
//#define M_CALL_SUBTYPE(oplist, ...) M_APPLY_API(M_GET_SUBTYPE oplist, oplist, __VA_ARGS__)
//#define M_CALL_NAME(oplist, ...) M_APPLY_API(M_GET_NAME oplist, oplist, __VA_ARGS__)
//#define M_CALL_OPLIST(oplist, ...) M_APPLY_API(M_GET_OPLIST oplist, oplist, __VA_ARGS__)
#define M_CALL_SORT(oplist, ...) M_APPLY_API(M_GET_SORT oplist, oplist, __VA_ARGS__)
#define M_CALL_SPLICE_BACK(oplist, ...) M_APPLY_API(M_GET_SPLICE_BACK oplist, oplist, __VA_ARGS__)
#define M_CALL_SPLICE_AT(oplist, ...) M_APPLY_API(M_GET_SPLICE_AT oplist, oplist, __VA_ARGS__)
#define M_CALL_IT_TYPE(oplist, ...) M_APPLY_API(M_GET_IT_TYPE oplist, oplist, __VA_ARGS__)
//#define M_CALL_IT_TYPE(oplist, ...) M_APPLY_API(M_GET_IT_TYPE oplist, oplist, __VA_ARGS__)
#define M_CALL_IT_FIRST(oplist, ...) M_APPLY_API(M_GET_IT_FIRST oplist, oplist, __VA_ARGS__)
#define M_CALL_IT_LAST(oplist, ...) M_APPLY_API(M_GET_IT_LAST oplist, oplist, __VA_ARGS__)
#define M_CALL_IT_END(oplist, ...) M_APPLY_API(M_GET_IT_END oplist, oplist, __VA_ARGS__)
@@ -2102,8 +2146,8 @@ m_core_hash (const void *str, size_t length)
#define M_CALL_IN_STR(oplist, ...) M_APPLY_API(M_GET_IN_STR oplist, oplist, __VA_ARGS__)
#define M_CALL_OUT_SERIAL(oplist, ...) M_APPLY_API(M_GET_OUT_SERIAL oplist, oplist, __VA_ARGS__)
#define M_CALL_IN_SERIAL(oplist, ...) M_APPLY_API(M_GET_IN_SERIAL oplist, oplist, __VA_ARGS__)
#define M_CALL_SEPARATOR(oplist, ...) M_APPLY_API(M_GET_SEPARATOR oplist, oplist, __VA_ARGS__)
#define M_CALL_EXT_ALGO(oplist, ...) M_APPLY_API(M_GET_EXT_ALGO oplist, oplist, __VA_ARGS__)
//#define M_CALL_SEPARATOR(oplist, ...) M_APPLY_API(M_GET_SEPARATOR oplist, oplist, __VA_ARGS__)
//#define M_CALL_EXT_ALGO(oplist, ...) M_APPLY_API(M_GET_EXT_ALGO oplist, oplist, __VA_ARGS__)
#define M_CALL_INC_ALLOC(oplist, ...) M_APPLY_API(M_GET_INC_ALLOC oplist, oplist, __VA_ARGS__)
#define M_CALL_OOR_SET(oplist, ...) M_APPLY_API(M_GET_OOR_SET oplist, oplist, __VA_ARGS__)
#define M_CALL_OOR_EQUAL(oplist, ...) M_APPLY_API(M_GET_OOR_EQUAL oplist, oplist, __VA_ARGS__)
@@ -2146,17 +2190,79 @@ m_core_hash (const void *str, size_t length)
#define M_OPLAPI_INDIRECT_API_7(...) M_OPLAPI_7
#define M_OPLAPI_EXTRACT_API_7(...) __VA_ARGS__
/* Define the no default function that generates a compiler error
if the method is expanded. Compiler extensions may have already defined
it to provide a better error message
if the method is expanded.
*/
#ifndef M_NO_DEFAULT
#define M_NO_DEFAULT(...) m_no_default_function
#define M_NO_DEFAULT(...) \
M_STATIC_FAILURE(M_LIB_MISSING_METHOD, "The requested operator has no method registered in the given OPLIST. ")
#define M_NO_DEF_TYPE \
M_STATIC_FAILURE(M_LIB_MISSING_METHOD, "The requested operator has no type/subtype/suboplist registered in the given OPLIST. ")
/* Test if the given variable is a basic C variable:
int, float, enum, bool or compatible.
NOTE: Not perfect, but catch some errors */
#define M_CHECK_DEFAULT_TYPE(a) \
M_STATIC_ASSERT(sizeof (a) <= M_MAX(sizeof(long long), \
M_MAX(sizeof (long double), \
sizeof (uintmax_t))), \
M_LIB_NOT_A_DEFAULT_TYPE, \
"The given variable is too big to be a default type," \
"but the used macro can only be used with such one." \
"It is likely the given oplist is not right.")
/* Check if both variables are of the same type.
The test compare their size.
NOTE: Not perfect but catch some errors */
#define M_CHECK_SAME(a, b) \
M_STATIC_ASSERT(sizeof(a) == sizeof(b), \
M_LIB_NOT_SAME_TYPE, \
"The variable " M_AS_STR(a) " and " M_AS_STR(b) \
" are not of same type.")
/* Check if the oplist is compatible with the type.
The oplist should define a TYPE method, in which case it is tested.
If it is not exported, do nothing.
Compare the type in C11, the size in C99 or C++ */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define M_CHECK_COMPATIBLE_OPLIST(name, inst, type, oplist) \
M_IF_METHOD(TYPE, oplist) \
( \
static inline void M_C3(name, _int_control_type, inst)(void) \
{ \
type x; \
M_STATIC_ASSERT(_Generic(&x, \
M_GET_TYPE oplist *: 1 /* Ok, type matches */, \
default: 0 /* NOK, type doesn't match */ ), \
M_LIB_TYPE_MISTMACH, \
"The given type " M_AS_STR(type) \
" and the type of the oplist does not match: " \
M_AS_STR(oplist) ); \
} \
, /* End of TYPE */)
#else
#define M_CHECK_COMPATIBLE_OPLIST(name, inst, type, oplist) \
M_IF_METHOD(TYPE, oplist) \
( \
static inline void M_C3(name, _int_control_type, inst)(void) \
{ \
M_STATIC_ASSERT(sizeof (type) == sizeof (M_GET_TYPE oplist), \
M_LIB_TYPE_MISTMACH, \
"The given type " M_AS_STR(type) \
" and the type of the oplist does not match: " \
M_AS_STR(oplist) ); \
} \
, /* End of TYPE */)
#endif
/* Define the default method. */
/* Define the default method.
NOTE: M_SET_DEFAULT may be called in conditions where a and b
are different but compatible type.
*/
#define M_INIT_DEFAULT(a) ((a) = 0)
#define M_SET_DEFAULT(a,b) ((a) = (b))
#define M_SET_DEFAULT(a,b) (M_CHECK_DEFAULT_TYPE(a), (a) = (b))
#define M_NOTHING_DEFAULT(...) ((void)(__VA_ARGS__))
#define M_EMPTY_DEFAULT(...) ((void)1)
#define M_TRUE_DEFAULT(...) true
@@ -2176,13 +2282,14 @@ m_core_hash (const void *str, size_t length)
/* NOTE: Theses operators are NOT compatible with the '[1]' tricks
if the variable is defined as a parameter of a function
(sizeof (a) is not portable). */
#define M_MOVE_DEFAULT(a,b) (M_STATIC_ASSERT(sizeof(a)==sizeof(b)), M_MEMCPY_DEFAULT(a, b), memset(&(b), 0, sizeof (a)))
#define M_MEMCPY_DEFAULT(a,b) (M_STATIC_ASSERT(sizeof(a)==sizeof(b)), memcpy(&(a), &(b), sizeof (a)))
#define M_MOVE_DEFAULT(a,b) (M_CHECK_SAME(a, b), M_MEMCPY_DEFAULT(a, b), memset(&(b), 0, sizeof (a)))
#define M_MEMCPY_DEFAULT(a,b) (M_CHECK_SAME(a, b), memcpy(&(a), &(b), sizeof (a)))
#define M_MEMSET_DEFAULT(a) (memset(&(a), 0, sizeof (a)))
#define M_MEMCMP1_DEFAULT(a,b) (M_STATIC_ASSERT(sizeof(a)==sizeof(b)), memcmp(&(a), &(b), sizeof (a)) == 0)
#define M_MEMCMP2_DEFAULT(a,b) (M_STATIC_ASSERT(sizeof(a)==sizeof(b)), memcmp(&(a), &(b), sizeof (a)))
#define M_MEMCMP1_DEFAULT(a,b) (M_CHECK_SAME(a, b), memcmp(&(a), &(b), sizeof (a)) == 0)
#define M_MEMCMP2_DEFAULT(a,b) (M_CHECK_SAME(a, b), memcmp(&(a), &(b), sizeof (a)))
#define M_SWAP_DEFAULT(el1, el2) do { \
char _tmp[sizeof (el1)]; \
M_CHECK_SAME(el1, el2); \
memcpy(&_tmp, &(el1), sizeof (el1)); \
memcpy(&(el1), &(el2), sizeof (el1)); \
memcpy(&(el2), &_tmp, sizeof (el1)); \
@@ -2191,11 +2298,11 @@ m_core_hash (const void *str, size_t length)
/* 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_STATIC_ASSERT(sizeof(a[0])==sizeof(b[0])), M_MEMCPY_A1_DEFAULT(a, b), M_MEMSET_A1_DEFAULT(b))
#define M_MEMCPY_A1_DEFAULT(a,b) (M_STATIC_ASSERT(sizeof(a[0])==sizeof(b[0])), memcpy(&(a[0]), &(b[0]), sizeof (a[0])))
#define M_MOVE_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0], b[0]), M_MEMCPY_A1_DEFAULT(a, b), M_MEMSET_A1_DEFAULT(b))
#define M_MEMCPY_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0], b[0]), 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) (M_STATIC_ASSERT(sizeof(a[0])==sizeof(b[0])), memcmp(&(a[0]), &(b[0]), sizeof (a[0])) == 0)
#define M_MEMCMP2_A1_DEFAULT(a,b) (M_STATIC_ASSERT(sizeof(a[0])==sizeof(b[0])), memcmp(&(a[0]), &(b[0]), sizeof (a[0])))
#define M_MEMCMP1_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0],b[0]), memcmp(&(a[0]), &(b[0]), sizeof (a[0])) == 0)
#define M_MEMCMP2_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0], b[0]), 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 */
@@ -2232,6 +2339,8 @@ 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) , \
ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \
MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \
HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT) , \
IN_STR(M_FSCAN_ARG M_IPTR), OUT_STR(M_FPRINT_ARG), \
IN_SERIAL(M_IN_SERIAL_DEFAULT_ARG M_IPTR), OUT_SERIAL(M_OUT_SERIAL_DEFAULT_ARG), \
@@ -2242,6 +2351,8 @@ 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) , \
ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \
MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \
HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT) , \
IN_SERIAL(M_IN_SERIAL_DEFAULT_ARG M_IPTR), OUT_SERIAL(M_OUT_SERIAL_DEFAULT_ARG), \
PARSE_STR(M_PARSE_DEFAULT_TYPE M_IPTR), M_GET_STR_METHOD_FOR_DEFAULT_TYPE)
@@ -2251,6 +2362,8 @@ 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) , \
ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \
MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \
HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT) )
#endif
@@ -2373,9 +2486,13 @@ m_core_hash (const void *str, size_t length)
NOTE: Incomplete test.
*/
#define M_OPLIST_P(a) \
M_AND(M_AND(M_PARENTHESIS_P(a), M_INV(M_PARENTHESIS_P (M_OPFLAT a))), \
M_EMPTY_P(M_EAT a))
M_AND(M_PARENTHESIS_P(a), M_INV(M_PARENTHESIS_P (M_OPFLAT a)))
/* Valid if the argument is a valid oplist, or raise a failure otherwise */
#define M_VALID_OPLIST(oplist) \
M_IF(M_OPLIST_P(oplist))(oplist, M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "The given oplist is invalid: " #oplist))
#define M_IF_OPLIST(a) M_IF(M_OPLIST_P(a))
/* If 'a' seems to be an oplist, it returns a,
else if a symbol composed of M_OPL_##a() exists and is defined as an oplist, it returns it
@@ -2390,6 +2507,9 @@ m_core_hash (const void *str, size_t length)
#define M_GLOBALI_OPLIST_ELSE(a) M_GLOBALI_OPLIST_ELSE2(a, M_C(M_OPL_, a)())
#define M_GLOBALI_OPLIST_ELSE2(a, op) M_IF( M_OPLIST_P (op))(op, a)
#define M_GLOBAL_TYPE(a) \
M_IF( M_OPLIST_P(a))(M_GLOBALI_TYPE_GET, M_GLOBALI_ID)(a)
#define M_GLOBALI_TYPE_GET(a) M_GET_TYPE a
/* If a symbol composed of M_OPL_##a() exists and is defined as an oplist,
it returns it otherwise it returns M_DEFAULT_OPLIST.
@@ -2403,15 +2523,38 @@ m_core_hash (const void *str, size_t length)
#define M_GLOBALI_OPLIST_OR_DEF_ELSE2(a, op) M_IF( M_OPLIST_P(op))(M_C(M_OPL_, a), M_GLOBALI_OPLIST_DEFAULT2)
/* Register simple classic C types (no qualifier) */
#define M_OPL_char() M_DEFAULT_OPLIST
#define M_OPL_short() M_DEFAULT_OPLIST
#define M_OPL_int() M_DEFAULT_OPLIST
#define M_OPL_long() M_DEFAULT_OPLIST
#define M_OPL_float() M_DEFAULT_OPLIST
#define M_OPL_double() M_DEFAULT_OPLIST
/* Add as suffix for the given function the number of arguments of the calls.
Can be used to call different function in function of the number of arguments. */
#define M_SUFFIX_FUNCTION_BY_NARGS(function, ...) M_C3(function, _, M_NARGS(__VA_ARGS__))
/* Call different INIT_WITH method in function of the number of arguments of the call,
* to be used in an OPLIST.
* Shall be used with API_1 call (example INIT_WITH(API_1(M_INIT_WITH_NVAR)) )
* Shall define a NAME base method
* All INIT_WITH methods shall be named as name ## _init_with_ ## NARGS
*/
#define M_INIT_WITH_NVAR(oplist, ...) \
M_SUFFIX_FUNCTION_BY_NARGS(M_C(M_GET_NAME oplist, _init_with), __VA_ARGS__)(__VA_ARGS__)
/************************************************************/
/******************** Syntax Enhancing **********************/
/************************************************************/
/* Define M_EACH macro allowing to iterate over a container
First argument will be a created pointer to the underlying type.
/* M_EACH enables iterating over a container using a for loop.
First argument will be a created pointer var to the underlying type.
Second argument is the container to iterate.
Third argument can be the oplist of the list or the type of the list if a global
oplist has been recorded.
Example: for M_EACH(item, list, LIST_OPLIST) { action; }
USAGE: for M_EACH(item, list, LIST_OPLIST) { M_LETaction; }
*/
#define M_EACH(item, container, oplist) \
M_EACHI_OPLIST(item, container, M_GLOBAL_OPLIST(oplist))
@@ -2443,14 +2586,15 @@ m_core_hash (const void *str, size_t length)
M_GET_IT_NEXT oplist (iterator))
/* Define M_LET macro allowing to define, auto init & auto clear an object
within the next bracket.
Example:
M_LET(a, STRING_OPLIST) { do something with a } or
M_LET(a, b, c, STRING_OPLIST) { do something with a, b & c }
M_LET((a, b), c, STRING_OPLIST) { do something with a(init with b) & c }
NOTE: The user code can not perform a return or a goto within the {}
other wise the clear code of the object won't be called .
/* M_LET defines, initializes & clears an object available within the next bracket.
USAGE:
M_LET(variable_list, variable_oplist|variable_type) { code }
* variable_list can be a comma separated list of variable.
* A variable alone is initialized to its default value.
* A variable with initializer (like '(var, init value...)'
is initialized with this init values.
NOTE: The code within {} can not perform return or goto command.
break is supported and will exit the braket (calling the clear method)
Last argument can be the oplist or the type itself if a global
oplist has been recorded for this type.
*/
@@ -2462,25 +2606,31 @@ m_core_hash (const void *str, size_t length)
// 1b. Generate a unique name based on the first variable and the line number
#define M_LETI_VAR_NAME_A(var) M_C3(_local_cont_, M_RET_ARG1 var, __LINE__)
#define M_LETI_VAR_NAME_B(var) M_C3(_local_cont_, var, __LINE__)
// 2. Evaluate with or without
// 2. Evaluate with or without and inject oplist
#define M_LETI1(cont, oplist, ...) \
M_LETI2(cont, M_GLOBAL_OPLIST(oplist), __VA_ARGS__)
// 3. Map all variables to their own LET
// 3. Validate oplist before going any further
#define M_LETI2(cont, oplist, ...) \
M_IF_OPLIST(oplist)(M_LETI3, M_LETI2_FAILURE)(cont, oplist, __VA_ARGS__)
// Stop with a failure (invalid oplist)
#define M_LETI2_FAILURE(cont, oplist, ...) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(M_LET): the given argument is not a valid oplist: " M_AS_STR(oplist))
// 4. Map all variables to their own LET
#define M_LETI3(cont, oplist, ...) \
for(bool cont = true; cont ; /* unused */) \
M_MAP2(M_LETI_SINGLE, (cont, oplist), __VA_ARGS__)
// 4. Dispatch the right LET in function of having or not arguments
// 5. Dispatch the right LET in function of having or not arguments
#define M_LETI_SINGLE(data, name) \
M_IF(M_PARENTHESIS_P(name))( \
M_LETI_SINGLE2_SET(M_PAIR_1 data, M_PAIR_2 data, M_RET_ARG1 name, M_SKIPI_1 name), \
M_LETI_SINGLE2(M_PAIR_1 data, M_PAIR_2 data, name))
// 5a. Define without argument ==> use INIT
// 6a. Define without argument ==> use INIT
#define M_LETI_SINGLE2(cont, oplist, name) \
for(M_GET_TYPE oplist name; \
cont && (M_GET_INIT oplist (name), true); \
(M_GET_CLEAR oplist (name), cont = false)) \
for(;cont;cont = false)
// 5b. Define with arguments ==> use INIT_SET (INIT_WITH support pending)
// 6b. Define with arguments ==> use INIT_SET (or INIT_WITH support pending)
#define M_LETI_SINGLE2_SET(cont, oplist, name, ...) \
for(M_GET_TYPE oplist name; \
cont && (M_LETI_SINGLE2_INIT(oplist, name, __VA_ARGS__), true); \
@@ -2504,6 +2654,14 @@ m_core_hash (const void *str, size_t length)
#define M_INIT_VAI_FUNC(d, a) \
M_PAIR_2 d (M_PAIR_1 d, a)
/* Initialize the container 'dest' as per 'oplist'
and fill it with the given VA arguments which are pair of (key,value) */
#define M_INIT_KEY_VAI(oplist, dest, ...) \
(void)(M_GET_INIT oplist (dest) , \
M_MAP2_C(M_INIT_KEY_VAI_FUNC, (dest, M_GET_SET_KEY oplist) , __VA_ARGS__))
#define M_INIT_KEY_VAI_FUNC(d, a) \
M_PAIR_2 d (M_PAIR_1 d, M_PAIR_1 a, M_PAIR_2 a)
/************************************************************/
/********************* MEMORY handling **********************/
@@ -2555,7 +2713,12 @@ m_core_hash (const void *str, size_t length)
} while (0)
#endif
/* Always perform a runtime check of the condition */
/************************************************************/
/********************* ERROR handling **********************/
/************************************************************/
/* Always perform a runtime check of the given condition */
#ifndef M_ASSERT_INIT
#define M_ASSERT_INIT(expr, object) { \
if (!(expr)) { \
@@ -2565,12 +2728,41 @@ m_core_hash (const void *str, size_t length)
} } while (0)
#endif
/* Force a compilation error if condition is false
In this case, it raises "error: negative width in bit-field <anonymous>" */
#if defined(__cplusplus)
#define M_STATIC_ASSERT(_e) (assert(_e))
/* Terminate the compilation of the current unit with an error message.
The error is classidied as error
with an optional message detailling the error.
Either use C11 to get a proper message, or at least a good hint in C99
error shall be a C name, msg a string.
Quite usefull to terminate with a proper error message rather than
a garbage of error due to incorrect code generation in the methods
expansion.
*/
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
# define M_STATIC_FAILURE(error, msg) static_assert(false, #error ": " msg);
#else
#define M_STATIC_ASSERT(_e) ((void) sizeof(struct { int a:1; int :-!(_e); }))
# define M_STATIC_FAILURE(error, msg) struct error { int error : 0;};
#endif
/* Test at compile time if the given condition is true.
The error is classidied as error
with an optional message detailling the error.
NOTE: Use bitfield to be compatible with most compilers
(so that it properly displays 'error' on the command line
NOTE: Cannot use C11 Static Assert as is not usable in expression.
NOTE: In C++, use of lambda to encapsulate static_assert in
an expression.
*/
#if defined(__cplusplus)
# define M_STATIC_ASSERT(cond, error, msg) \
([] { static_assert(cond, #error ": " msg); } ())
#elif defined(__GNUC__) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
# define M_STATIC_ASSERT(cond, error, msg) \
M_ATTR_EXTENSION ({ static_assert(cond, #error ": " msg); })
#else
# define M_STATIC_ASSERT(cond, error, msg) \
((void) sizeof(struct { int error : !!(cond);}))
#endif
+28 -9
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - DEQUE module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
@@ -67,15 +67,23 @@
so that all arguments are evaluated before further expansion */
#define DEQUEI_DEF_P1(arg) DEQUEI_DEF_P2 arg
/* Validate the oplist before going further */
#define DEQUEI_DEF_P2(name, type, oplist, deque_t, it_t, node_t) \
M_IF_OPLIST(oplist)(DEQUEI_DEF_P3, DEQUEI_DEF_FAILURE)(name, type, oplist, deque_t, it_t, node_t)
/* Stop processing with a compilation failure */
#define DEQUEI_DEF_FAILURE(name, type, oplist, deque_t, it_t, node_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DEQUE_DEF): the given argument is not a valid oplist: " #oplist)
/* Internal deque definition
- name: prefix to be used
- type: type of the elements of the array
- type: type of the elements of the deque
- oplist: oplist of the type of the elements of the container
- deque_t: alias for M_C(name, _t) [ type of the container ]
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
- node_t: alias for M_C(name, _node_t) [ node ]
*/
#define DEQUEI_DEF_P2(name, type, oplist, deque_t, it_t, node_t) \
#define DEQUEI_DEF_P3(name, type, oplist, deque_t, it_t, node_t) \
\
/* It is a linked list of buckets of the types, \
each new created bucket size grows compared to the previous one \
@@ -131,6 +139,8 @@
\
typedef type M_C(name, _type_t); \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline M_C(name, _node_t)* \
M_C(name, _int_new_node)(deque_t d) \
{ \
@@ -837,7 +847,7 @@
{ \
DEQUEI_CONTRACT(deque); \
assert (str != NULL); \
M_C(name,_clean)(deque); \
M_C(name,_clean)(deque); \
bool success = false; \
int c = *str++; \
if (M_UNLIKELY (c != '[')) goto exit; \
@@ -850,12 +860,13 @@
do { \
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
do { c = *str++; } while (isspace(c)); \
if (b == false || c == 0) { goto exit; } \
M_C(name, _push_back)(deque, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_CALL_CLEAR(oplist, item); \
if (b == false || c == 0) { goto exit_clear; } \
M_C(name, _push_back)(deque, item); \
} while (c == M_GET_SEPARATOR oplist); \
DEQUEI_CONTRACT(deque); \
success = (c == ']'); \
exit_clear: \
M_CALL_CLEAR(oplist, item); \
exit: \
if (endp) *endp = str; \
return success; \
@@ -943,8 +954,16 @@
so that all arguments are evaluated before further expansion */
#define DEQUEI_OPLIST_P1(arg) DEQUEI_OPLIST_P2 arg
/* OPLIST definition of a deque */
/* Validation of the given oplist */
#define DEQUEI_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(DEQUEI_OPLIST_P3, DEQUEI_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define DEQUEI_OPLIST_FAILURE(name, oplist) \
M_LIB_ERROR(ARGUMENT_OF_DEQUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
/* OPLIST definition of a deque */
#define DEQUEI_OPLIST_P3(name, oplist) \
(INIT(M_C(name, _init)) \
,INIT_SET(M_C(name, _init_set)) \
,INIT_WITH(API_1(M_INIT_VAI)) \
+109 -20
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - DICTIONARY Module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
@@ -121,7 +121,23 @@
*/
/* Deferred evaluation for arg */
#define DICTI_DEF2_P1(arg) DICTI_DEF2_P2 arg
/* Validate the key oplist before going further */
#define DICTI_DEF2_P2(name, key_type, key_oplist, value_type, value_oplist) \
M_IF_OPLIST(key_oplist)(DICTI_DEF2_P3, DICTI_DEF2_FAILURE)(name, key_type, key_oplist, value_type, value_oplist)
/* Validate the value oplist before going further */
#define DICTI_DEF2_P3(name, key_type, key_oplist, value_type, value_oplist) \
M_IF_OPLIST(value_oplist)(DICTI_DEF2_P4, DICTI_DEF2_FAILURE)(name, key_type, key_oplist, value_type, value_oplist)
/* Stop processing with a compilation failure */
#define DICTI_DEF2_FAILURE(name, key_type, key_oplist, value_type, value_oplist) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_DEF2): at least one of the given argument is not a valid oplist: " M_AS_STR(key_oplist) " / " M_AS_STR(value_oplist) )
#define DICTI_DEF2_P4(name, key_type, key_oplist, value_type, value_oplist) \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \
M_CHECK_COMPATIBLE_OPLIST(name, 2, value_type, value_oplist) \
\
TUPLE_DEF2(M_C(name, _pair), (key, key_type, key_oplist), (value, value_type, value_oplist)) \
\
@@ -138,7 +154,7 @@
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, 0, M_C(name, _t), M_C(name, _it_t))
DICTI_FUNC_DEF2_P5(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.
@@ -148,8 +164,24 @@
*/
/* Defered evaluation for arg */
#define DICTI_SHASH_DEF2_P1(arg) DICTI_SHASH_DEF2_P2 arg
/* Validate the key oplist before going further */
#define DICTI_SHASH_DEF2_P2(name, key_type, key_oplist, value_type, value_oplist) \
M_IF_OPLIST(key_oplist)(DICTI_SHASH_DEF2_P3, DICTI_SHASH_DEF2_FAILURE)(name, key_type, key_oplist, value_type, value_oplist)
/* Validate the value oplist before going further */
#define DICTI_SHASH_DEF2_P3(name, key_type, key_oplist, value_type, value_oplist) \
M_IF_OPLIST(value_oplist)(DICTI_SHASH_DEF2_P4, DICTI_SHASH_DEF2_FAILURE)(name, key_type, key_oplist, value_type, value_oplist)
/* Stop processing with a compilation failure */
#define DICTI_SHASH_DEF2_FAILURE(name, key_type, key_oplist, value_type, value_oplist) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_STOREHASH_DEF2): at least one of the given argument is not a valid oplist: " M_AS_STR(key_oplist) " / " M_AS_STR(value_oplist) )
#define DICTI_SHASH_DEF2_P4(name, key_type, key_oplist, value_type, value_oplist) \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \
M_CHECK_COMPATIBLE_OPLIST(name, 2, 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) \
@@ -165,7 +197,7 @@
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))
DICTI_FUNC_DEF2_P5(name, key_type, key_oplist, value_type, value_oplist, 0, 1, M_C(name, _t), M_C(name, _it_t))
/* Define a set with the key key_type
@@ -173,8 +205,19 @@
representing a bucket).
*/
#define DICTI_SET_DEF_P1(arg) DICTI_SET_DEF_P2 arg
/* Validate the key oplist before going further */
#define DICTI_SET_DEF_P2(name, key_type, key_oplist) \
M_IF_OPLIST(key_oplist)(DICTI_SET_DEF_P4, DICTI_SET_DEF_FAILURE)(name, key_type, key_oplist)
/* Stop processing with a compilation failure */
#define DICTI_SET_DEF_FAILURE(name, key_type, key_oplist)\
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_SET_DEF): the given argument is not a valid oplist: " M_AS_STR(key_oplist) )
#define DICTI_SET_DEF_P4(name, key_type, key_oplist) \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \
\
TUPLE_DEF2(M_C(name, _pair), (key, key_type, key_oplist)) \
\
M_IF_METHOD(MEMPOOL, key_oplist) \
@@ -189,12 +232,12 @@
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))) \
\
DICTI_FUNC_DEF2(name, key_type, key_oplist, key_type, \
DICTI_FUNC_DEF2_P5(name, key_type, key_oplist, key_type, \
M_EMPTY_OPLIST, 1, 0, M_C(name, _t), M_C(name, _it_t))
/* Define the structure of a chained dictionnary */
#define DICTI_FUNC_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, isStoreHash, dict_t, dict_it_t) \
#define DICTI_FUNC_DEF2_P5(name, key_type, key_oplist, value_type, value_oplist, isSet, isStoreHash, dict_t, dict_it_t) \
\
/* NOTE: \
if isSet is true, all methods of value_oplist are NOP methods */ \
@@ -700,7 +743,7 @@
M_C(name, _parse_str)(dict_t dict, const char str[], const char **endp) \
{ \
assert (str != NULL); \
M_C(name, _clean)(dict); \
M_C(name, _clean)(dict); \
bool success = false; \
int c = *str++; \
if (M_UNLIKELY (c != '{')) goto exit; \
@@ -716,20 +759,21 @@
while (isspace((int) *str)) str++; \
bool b = M_CALL_PARSE_STR(key_oplist, key, str, &str); \
M_IF(isSet)( \
if (b == false) { break; } \
if (b == false) { goto exit_clear; } \
M_C(name, _push)(dict, key); \
, \
do { c = *str++; } while (isspace(c)); \
if (b == false || c != ':') { goto exit; } \
if (b == false || c != ':') { goto exit_clear; } \
b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \
if (b == false) { goto exit; } \
if (b == false) { goto exit_clear; } \
M_C(name, _set_at)(dict, key, value); \
) \
) \
do { c = *str++; } while (isspace(c)); \
} while (c == ','); \
} while (c == ','); \
success = (c == '}'); \
exit_clear: \
M_CALL_CLEAR(key_oplist, key); \
M_CALL_CLEAR(value_oplist, value); \
success = (c == '}'); \
exit: \
if (endp) *endp = str; \
return success; \
@@ -917,10 +961,23 @@
so that all arguments are evaluated before further expansion */
#define DICTI_OPLIST_P1(arg) DICTI_OPLIST_P2 arg
/* Define the oplist of a dictionnary */
#define DICTI_OPLIST_P2(name, key_oplist, value_oplist) \
/* Validation of the given oplists */
#define DICTI_OPLIST_P2(name, key_oplist, value_oplist) \
M_IF_OPLIST(key_oplist)(DICTI_OPLIST_P3, DICTI_OPLIST_FAILURE)(name, key_oplist, value_oplist)
#define DICTI_OPLIST_P3(name, key_oplist, value_oplist) \
M_IF_OPLIST(value_oplist)(DICTI_OPLIST_P4, DICTI_OPLIST_FAILURE)(name, key_oplist, value_oplist)
/* Prepare a clean compilation failure */
#define DICTI_OPLIST_FAILURE(name, key_oplist, value_oplist) \
M_LIB_ERROR(ARGUMENT_OF_DICT_OPLIST_IS_NOT_AN_OPLIST, name, key_oplist, value_oplist)
/* Define the oplist of a dictionnary
NOTE: IT_REF is not exported so that the contained appears as not modifiable
by algorithm.*/
#define DICTI_OPLIST_P4(name, key_oplist, value_oplist) \
(INIT(M_C(name, _init)), \
INIT_SET(M_C(name, _init_set)), \
INIT_WITH(API_1(M_INIT_KEY_VAI)), \
SET(M_C(name, _set)), \
CLEAR(M_C(name, _clear)), \
INIT_MOVE(M_C(name, _init_move)), \
@@ -937,7 +994,6 @@
IT_END_P(M_C(name,_end_p)), \
IT_LAST_P(M_C(name,_last_p)), \
IT_NEXT(M_C(name,_next)), \
IT_REF(M_C(name,_ref)), \
IT_CREF(M_C(name,_cref)) \
,KEY_TYPE(M_C(name, _key_type_t)) \
,VALUE_TYPE(M_C(name, _value_type_t)) \
@@ -964,8 +1020,16 @@
so that all arguments are evaluated before further expansion */
#define DICTI_SET_OPLIST_P1(arg) DICTI_SET_OPLIST_P2 arg
/* Validation of the given oplist */
#define DICTI_SET_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(DICTI_SET_OPLIST_P3, DICTI_SET_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define DICTI_SET_OPLIST_FAILURE(name, oplist) \
M_LIB_ERROR(ARGUMENT_OF_DICT_SET_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
/* Define the oplist of a set */
#define DICTI_SET_OPLIST_P2(name, oplist) \
#define DICTI_SET_OPLIST_P3(name, oplist) \
(INIT(M_C(name, _init)), \
INIT_SET(M_C(name, _init_set)), \
INIT_WITH(API_1(M_INIT_VAI)), \
@@ -1066,16 +1130,38 @@ typedef enum {
} while (0)
#define DICTI_OA_DEF_P1(args) DICTI_OA_DEF_P2 args
/* Validate the key oplist before going further */
#define DICTI_OA_DEF_P2(name, key_type, key_oplist, value_type, value_oplist) \
DICTI_OA_DEF_P3(name, key_type, key_oplist, value_type, value_oplist, 0, \
M_IF_OPLIST(key_oplist)(DICTI_OA_DEF_P3, DICTI_OA_DEF_FAILURE)(name, key_type, key_oplist, value_type, value_oplist)
/* Validate the value oplist before going further */
#define DICTI_OA_DEF_P3(name, key_type, key_oplist, value_type, value_oplist) \
M_IF_OPLIST(value_oplist)(DICTI_OA_DEF_P4, DICTI_OA_DEF_FAILURE)(name, key_type, key_oplist, value_type, value_oplist)
/* Stop processing with a compilation failure */
#define DICTI_OA_DEF_FAILURE(name, key_type, key_oplist, value_type, value_oplist) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_OA_DEF2): at least one of the given argument is not a valid oplist: " M_AS_STR(key_oplist) " / " M_AS_STR(value_oplist) )
#define DICTI_OA_DEF_P4(name, key_type, key_oplist, value_type, value_oplist) \
DICTI_OA_DEF_P5(name, key_type, key_oplist, value_type, value_oplist, 0, \
DICTI_OA_LOWER_BOUND, DICTI_OA_UPPER_BOUND, M_C(name,_t), M_C(name, _it_t) )
#define DICTI_OASET_DEF_P1(args) DICTI_OASET_DEF_P2 args
#define DICTI_OASET_DEF_P2(name, key_type, key_oplist) \
DICTI_OA_DEF_P3(name, key_type, key_oplist, key_type, M_EMPTY_OPLIST, 1, \
/* Validate the value oplist before going further */
#define DICTI_OASET_DEF_P2(name, key_type, key_oplist) \
M_IF_OPLIST(key_oplist)(DICTI_OASET_DEF_P4, DICTI_OASET_DEF_FAILURE)(name, key_type, key_oplist)
/* Stop processing with a compilation failure */
#define DICTI_OASET_DEF_FAILURE(name, key_type, key_oplist) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_OASET_DEF): the given argument is not a valid oplist: " M_AS_STR(key_oplist) )
#define DICTI_OASET_DEF_P4(name, key_type, key_oplist) \
DICTI_OA_DEF_P5(name, key_type, key_oplist, key_type, M_EMPTY_OPLIST, 1, \
DICTI_OA_LOWER_BOUND, DICTI_OA_UPPER_BOUND, M_C(name,_t), M_C(name, _it_t) )
#define DICTI_OA_DEF_P3(name, key_type, key_oplist, value_type, value_oplist, isSet, coeff_down, coeff_up, dict_t, dict_it_t) \
#define DICTI_OA_DEF_P5(name, key_type, key_oplist, value_type, value_oplist, isSet, coeff_down, coeff_up, dict_t, dict_it_t) \
\
/* NOTE: \
if isSet is true, all methods of value_oplist are NOP methods */ \
@@ -1092,6 +1178,9 @@ typedef enum {
typedef key_type M_C(name, _key_type_t); \
typedef value_type M_C(name, _value_type_t); \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \
M_CHECK_COMPATIBLE_OPLIST(name, 2, value_type, value_oplist) \
\
/* NOTE: We don't want a real oplist for this sub type */ \
ARRAY_DEF(M_C(name, _array_pair), M_C(name, _pair_t), \
(INIT(M_NOTHING_DEFAULT), SET(M_MEMCPY_DEFAULT), \
+345
View File
@@ -0,0 +1,345 @@
/*
* M*LIB - Function Object module
*
* Copyright (c) 2017-2020, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MSTARLIB_FUNCOBJ_H
#define MSTARLIB_FUNCOBJ_H
#include "m-core.h"
/* Define a function object interface of name 'name'
* with a function like retcode, type of param1, type of param 2, ...
* USAGE:
* FUNC_OBJ_ITF_DEF(name, retcode type, type of param1, type of param 2, ...)
*/
#define FUNC_OBJ_ITF_DEF(name, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_ITF_NO_PARAM_DEF, FUNCOBJI_ITF_PARAM_DEF)(name, __VA_ARGS__)
/* Define a function object instance of name 'name' based on the interface 'base_name'
* The function is defined as per :
* - the prototype of the inherited interface
* - the parameters of the function are named as per the list param_list
* - the core of the function shall be defined in callback_core
* - optionals member attributes of the function object can be defined after the core
* (just like for tuple & variant: (name, type [, oplist])
*
* In the core of the function, parameters are accessible just like a normal like
* and a special variable 'self' which refers to the function object itself
* can be used to access member attributes.
*
* There shall be **exactly** the same number of parameters in 'param_list' than
* the number of parameters of the interface 'base_name'
*
* USAGE/EXAMPLE:
* FUNC_OBJ_INS_DEF(name, base_name, (param1, ...), { return param1 * self->member1 }, (member1, int), ...)
*/
#define FUNC_OBJ_INS_DEF(name, base_name, param_list, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_DEF, FUNCOBJI_INS_ATTR_DEF)(name, base_name, param_list, __VA_ARGS__)
/* OPLIST of the instanced function object
* USAGE:
* FUNC_OBJ_INS_OPLIST(name, oplist of the attr1, ...)
*/
#define FUNC_OBJ_INS_OPLIST(...) \
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_OPLIST, FUNCOBJI_INS_ATTR_OPLIST_P1)( __VA_ARGS__)
/********************************************************************************/
/********************************** INTERNAL ************************************/
/********************************************************************************/
/* To be used by M_IF_FUNCOBJ macro.
NOTE: It is reversed (0 instead of 1) so that it can be used in M_IF reliabely.
*/
#define M_FUNCOBJ_IS_NOT_DEFINED 0
/* Design Constraints:
* callback SHALL be the first member of the structures in all the definitions.
*
* Structure definitions are specialized in function of the presence or not
* of parameters and/or attributes
* FIXME: How to factorize reasonnably well between the definitions?
*/
/* Specialization of the OPLIST in function if there is at least one member or not */
#define FUNCOBJI_INS_NO_ATTR_OPLIST(name) \
(NAME(name), TYPE(M_C(name, _t)), \
CLEAR(M_C(name, _clear)), \
INIT(M_C(name,_init)) \
)
/* Validate the oplist before going further */
#define FUNCOBJI_INS_ATTR_OPLIST_P1(name, ...) \
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(FUNCOBJI_INS_ATTR_OPLIST_P3, FUNCOBJI_INS_ATTR_OPLIST_FAILURE)(name, __VA_ARGS__)
/* Prepare a clean compilation failure */
#define FUNCOBJI_INS_ATTR_OPLIST_FAILURE(name, ...) \
M_LIB_ERROR(ONE_ARGUMENT_OF_FUNC_OBJ_INS_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)
/* Define at least the oplist */
#define FUNCOBJI_INS_ATTR_OPLIST_P3(name, ...) \
(NAME(name), TYPE(M_C(name, _t)), \
INIT_WITH(M_C(name, _init_with)), \
CLEAR(M_C(name, _clear)), \
M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
)
/* Specialization of the definition a function object interface of name 'name'
* with a function like retcode () that doesn't have any input parameters.
*/
#define FUNCOBJI_ITF_NO_PARAM_DEF(name, retcode) \
typedef retcode M_C(name, _retcode_t); \
\
struct M_C(name, _s); \
\
/* No parameters to the callback */ \
typedef retcode(*M_C(name, _callback_t))(struct M_C(name, _s) *); \
\
typedef struct M_C(name, _s) { \
M_C(name, _callback_t) callback; \
} M_C(name, _t)[1]; \
\
static inline retcode \
M_C(name, _call)(M_C(name, _t) funcobj) \
{ \
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
funcobj->callback(funcobj); \
}
/* Specialization of the definition a function object interface of name 'name'
* with a function like retcode, type of param1, type of param 2, ...
* with mandatory input parameters.
*/
#define FUNCOBJI_ITF_PARAM_DEF(name, retcode, ...) \
typedef retcode M_C(name, _retcode_t); \
\
/* Define types for all paremeters */ \
M_MAP3(FUNCOBJI_BASE_TYPE, name, __VA_ARGS__) \
\
struct M_C(name, _s); \
\
typedef retcode(*M_C(name, _callback_t))(struct M_C(name, _s) *, __VA_ARGS__); \
\
typedef struct M_C(name, _s) { \
M_C(name, _callback_t) callback; \
} M_C(name, _t)[1]; \
\
static inline retcode \
M_C(name, _call)(M_C(name, _t) funcobj \
M_MAP3(FUNCOBJI_BASE_ARGLIST, name, __VA_ARGS__) ) \
{ \
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
funcobj->callback(funcobj M_MAP3(FUNCOBJI_BASE_ARGCALL, name, __VA_ARGS__) ); \
}
/* Specialization of the definition a function object instance of name 'name'
* with no member attribute.
*/
#define FUNCOBJI_INS_NO_ATTR_DEF(name, base_name, param_list, callback_core) \
typedef struct M_C(name, _s) { \
M_C(base_name, _callback_t) callback; \
} M_C(name, _t)[1]; \
\
static inline M_C(base_name, _retcode_t) \
M_C(name, _callback)(M_C(base_name, _t) _self \
M_IF_EMPTY(M_OPFLAT param_list)( \
/* No param */, \
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list)\
) \
) \
{ \
struct M_C(name, _s) *self = (struct M_C(name, _s) *)_self; \
(void) self; /* maybe unused */ \
callback_core; \
} \
\
static inline void \
M_C(name, _init_with)(M_C(name, _t) obj) \
{ \
obj->callback = M_C(name, _callback); \
} \
\
static inline void \
M_C(name, _clear)(M_C(name, _t) obj) \
{ \
(void) obj; /* nothing to do */ \
} \
\
static inline struct M_C(base_name, _s) * \
M_C(name, _as_interface)(M_C(name, _t) obj) \
{ \
return (struct M_C(base_name, _s) *) obj; \
} \
\
static inline void \
M_C(name, _init)(M_C(name, _t) obj) \
{ \
obj->callback = M_C(name, _callback); \
} \
/* Specialization of the definition a function object instance of name 'name'
* with mandatory member attribute.
* First inject oplist in member attributes.
*/
#define FUNCOBJI_INS_ATTR_DEF(name, base_name, param_list, callback_core, ...) \
FUNCOBJI_INS_ATTR_DEF_P2(name, base_name, param_list, callback_core, FUNCOBJI_INJECT_GLOBAL(__VA_ARGS__) )
/* Inject the oplist within the list of arguments */
#define FUNCOBJI_INJECT_GLOBAL(...) \
M_MAP_C(FUNCOBJI_INJECT_OPLIST_A, __VA_ARGS__)
/* Transform (x, type) into (x, type, oplist) if there is global registered oplist
or (x, type, M_DEFAULT_OPLIST) if there is no global one,
or keep (x, type, oplist) if oplist was already present */
#define FUNCOBJI_INJECT_OPLIST_A( duo_or_trio ) \
FUNCOBJI_INJECT_OPLIST_B duo_or_trio
#define FUNCOBJI_INJECT_OPLIST_B( f, ... ) \
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
// Test if all third argument of all arguments is an oplist
#define FUNCOBJI_IF_ALL_OPLIST(...) \
M_IF(M_REDUCE(FUNCOBJI_IS_OPLIST_P, M_AND, __VA_ARGS__))
// Test if the third argument is an oplist
#define FUNCOBJI_IS_OPLIST_P(a) \
M_OPLIST_P(M_RET_ARG3 a)
/* Validate the oplist before going further */
#define FUNCOBJI_INS_ATTR_DEF_P2(name, base_name, param_list, callback_core, ...) \
FUNCOBJI_IF_ALL_OPLIST(__VA_ARGS__)(FUNCOBJI_INS_ATTR_DEF_P3, FUNCOBJI_INS_ATTR_DEF_FAILURE)(name, base_name, param_list, callback_core, __VA_ARGS__)
/* Stop processing with a compilation failure */
#define FUNCOBJI_INS_ATTR_DEF_FAILURE(name, base_name, param_list, callback_core, ...) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(FUNC_OBJ_INS_DEF): at least one of the given argument is not a valid oplist: " #__VA_ARGS__)
/* Expand the Function Object with members */
#define FUNCOBJI_INS_ATTR_DEF_P3(name, base_name, param_list, callback_core, ...) \
typedef struct M_C(name, _s) { \
/* Callback is the mandatory first argument */ \
M_C(base_name, _callback_t) callback; \
/* All the member attribute of the Function Object */ \
M_MAP(FUNCOBJI_INS_ATTR_STRUCT, __VA_ARGS__) \
} M_C(name, _t)[1]; \
\
FUNCOBJI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
\
static inline M_C(base_name, _retcode_t) \
M_C(name, _callback)(M_C(base_name, _t) _self \
M_IF_EMPTY(M_OPFLAT param_list)( \
/* No param */, \
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list)\
) \
) \
{ \
struct M_C(name, _s) *self = (struct M_C(name, _s) *)_self; \
(void) self; /* maybe unused */ \
callback_core; \
} \
\
static inline void \
M_C(name, _init_with)(M_C(name, _t) obj M_MAP(FUNCOBJI_INS_ATTR_LIST, __VA_ARGS__)) \
{ \
obj->callback = M_C(name, _callback); \
M_MAP(FUNCOBJI_INS_ATTR_INIT_SET, __VA_ARGS__); \
} \
\
static inline void \
M_C(name, _clear)(M_C(name, _t) obj) \
{ \
M_MAP(FUNCOBJI_INS_ATTR_CLEAR, __VA_ARGS__); \
} \
\
static inline struct M_C(base_name, _s) * \
M_C(name, _as_interface)(M_C(name, _t) obj) \
{ \
return (struct M_C(base_name, _s) *) obj; \
} \
\
M_IF(FUNCOBJI_TEST_METHOD_P(INIT, __VA_ARGS)) \
( \
static inline void \
M_C(name, _init)(M_C(name, _t) obj) \
{ \
obj->callback = M_C(name, _callback); \
M_MAP(FUNCOBJI_INS_ATTR_INIT, __VA_ARGS__); \
} \
, /* END OF INIT METHOD */ ) \
/* Define a numbered type of a parameter of the callback*/
#define FUNCOBJI_BASE_TYPE(name, num, type) \
typedef type M_C4(name, _param_, num, _t);
/* Define a list of the type of arguments for a function definition */
#define FUNCOBJI_BASE_ARGLIST(name, num, type) \
M_DEFERRED_COMMA type M_C(param_, num)
/* Define a list of arguments for a function call */
#define FUNCOBJI_BASE_ARGCALL(name, num, type) \
M_DEFERRED_COMMA M_C(param_, num)
/* Helper macros */
/* arg = (name, type [, oplist]) */
#define FUNCOBJI_INS_ATTR_STRUCT(arg) \
M_RET_ARG2 arg M_RET_ARG1 arg;
#define FUNCOBJI_INS_ATTR_LIST(arg) \
M_DEFERRED_COMMA M_RET_ARG2 arg const M_RET_ARG1 arg
#define FUNCOBJI_INS_ATTR_INIT(arg) \
M_CALL_INIT(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg);
#define FUNCOBJI_INS_ATTR_INIT_SET(arg) \
M_CALL_INIT_SET(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg, M_RET_ARG1 arg);
#define FUNCOBJI_INS_ATTR_CLEAR(arg) \
M_CALL_CLEAR(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg);
/* Define the list of arguments of the instance of the callback */
#define FUNCOBJI_INS_ARGLIST(name, num, param) \
M_DEFERRED_COMMA M_C4(name, _param_, num, _t) param
/* Macros for testing for a method presence in all the attributes */
#define FUNCOBJI_TEST_METHOD2_P(method, op) \
M_TEST_METHOD_P(method, op)
#define FUNCOBJI_TEST_METHOD1_P(method, arg) \
M_APPLY(FUNCOBJI_TEST_METHOD2_P, method, M_RET_ARG3 arg)
#define FUNCOBJI_TEST_METHOD_P(method, ...) \
M_IF(M_REDUCE2(FUNCOBJI_TEST_METHOD1_P, M_AND, method, __VA_ARGS__))
/* Macro for checking compatible type and oplist for all the attributes */
#define FUNCOBJI_CONTROL_ALL_OPLIST(name, ...) \
M_MAP2(FUNCOBJI_CONTROL_OPLIST, name, __VA_ARGS__)
#define FUNCOBJI_CONTROL_OPLIST(name, a) \
M_CHECK_COMPATIBLE_OPLIST(name, M_RET_ARG1 a, M_RET_ARG2 a, M_RET_ARG3 a)
#endif
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - GENINT module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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 -5
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Intrusive List module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
@@ -70,8 +70,16 @@ typedef struct ilist_head_s {
/* Indirection call to allow expanding all arguments */
#define ILISTI_OPLIST_P1(arg) ILISTI_OPLIST_P2 arg
/* Validation of the given oplist */
#define ILISTI_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(ILISTI_OPLIST_P3, ILISTI_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define ILISTI_OPLIST_FAILURE(name, oplist) \
M_LIB_ERROR(ARGUMENT_OF_ILIST_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
/* Define the oplist of an ilist of type */
#define ILISTI_OPLIST_P2(name,oplist) \
#define ILISTI_OPLIST_P3(name, oplist) \
(INIT(M_C(name, _init)), \
CLEAR(M_C(name, _clear)), \
INIT_MOVE(M_C(name, _init_move)), \
@@ -95,8 +103,6 @@ typedef struct ilist_head_s {
IT_REMOVE(M_C(name,_remove)), \
M_IF_METHOD(NEW, oplist)(IT_INSERT(M_C(name,_insert)),), \
OPLIST(oplist), \
PUSH(M_C(name,_push_back)), \
POP(M_C(name,_pop_back)) \
SPLICE_BACK(M_C(name,_splice_back)) \
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
@@ -122,6 +128,14 @@ typedef struct ilist_head_s {
/* Indirection call to allow expanding all arguments (TBC) */
#define ILISTI_DEF_P1(arg) ILISTI_DEF_P2 arg
/* Validate the oplist before going further */
#define ILISTI_DEF_P2(name, type, oplist, list_t, it_t) \
M_IF_OPLIST(oplist)(ILISTI_DEF_P3, ILISTI_DEF_FAILURE)(name, type, oplist, list_t, it_t)
/* Stop processing with a compilation failure */
#define ILISTI_DEF_FAILURE(name, type, oplist, list_t, it_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ILIST_DEF): the given argument is not a valid oplist: " #oplist)
/* Definition of the type and function for an intrusive doubly-linked list.
USAGE:
name: name of the intrusive list
@@ -130,7 +144,7 @@ typedef struct ilist_head_s {
list_t: type of the intrusive list (name##_t)
it_t: iterator of the intrusive list (name##_it_t)
*/
#define ILISTI_DEF_P2(name, type, oplist, list_t, it_t) \
#define ILISTI_DEF_P3(name, type, oplist, list_t, it_t) \
\
typedef struct M_C(name, _s) { \
struct ilist_head_s name; \
@@ -147,6 +161,8 @@ typedef struct ilist_head_s {
struct ilist_head_s *next; \
} it_t[1]; \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void M_C(name, _init)(list_t list) \
{ \
assert (list != NULL); \
+25 -4
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - INTRUSIVE SHARED PTR Module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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,8 +42,9 @@
#define ISHARED_PTR_INTERFACE(name, type) \
atomic_int M_C(name, _cpt)
/* Define the intrusive shared pointer type and its static inline functions.
USAGE: ISHARED_PTR_DEF(name[, oplist]) */
USAGE: ISHARED_PTR_DEF(name, type, [, oplist]) */
#define ISHARED_PTR_DEF(name, ...) \
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
@@ -55,14 +56,22 @@
// Deferred evaluation
#define ISHAREDI_PTR_OPLIST_P1(arg) ISHAREDI_PTR_OPLIST_P2 arg
/* Validation of the given oplist */
#define ISHAREDI_PTR_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(ISHAREDI_PTR_OPLIST_P3, ISHAREDI_PTR_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define ISHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
M_LIB_ERROR(ARGUMENT_OF_ISHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
// Define the oplist
#define ISHAREDI_PTR_OPLIST_P2(name, oplist) ( \
#define ISHAREDI_PTR_OPLIST_P3(name, oplist) ( \
INIT(M_INIT_DEFAULT), \
INIT_SET(M_C(name, _init_set2) M_IPTR), \
SET(M_C(name, _set) M_IPTR), \
CLEAR(M_C(name, _clear)), \
CLEAN(M_C(name, _clean) M_IPTR), \
TYPE(M_C(name, _type_t)), \
TYPE(M_C(name, _t)), \
OPLIST(oplist), \
SUBTYPE(M_C(name, _type_t)) \
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
@@ -73,11 +82,21 @@
// Deferred evaluatioin
#define ISHAREDI_PTR_DEF_P1(arg) ISHAREDI_PTR_DEF_P2 arg
/* Validate the oplist before going further */
#define ISHAREDI_PTR_DEF_P2(name, type, oplist) \
M_IF_OPLIST(oplist)(ISHAREDI_PTR_DEF_P3, ISHAREDI_PTR_DEF_FAILURE)(name, type, oplist)
/* Stop processing with a compilation failure */
#define ISHAREDI_PTR_DEF_FAILURE(name, type, oplist) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ISHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
#define ISHAREDI_PTR_DEF_P3(name, type, oplist) \
\
typedef type *M_C(name,_t); \
typedef type M_C(name, _type_t); \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline M_C(name,_t) \
M_C(name, _init)(type *ptr) \
{ \
@@ -103,6 +122,7 @@
*ptr = M_C(name, _init_set)(shared); \
} \
\
M_IF_METHOD2(INIT, NEW, oplist)( \
static inline M_C(name,_t) \
M_C(name, _init_new)(void) \
{ \
@@ -115,6 +135,7 @@
atomic_init (&ptr->M_C(name, _cpt), 1); \
return ptr; \
} \
, /* End of INIT/NEW */) \
\
static inline void \
M_C(name, _clear)(M_C(name,_t) shared) \
+50 -19
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - LIST module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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,13 +34,15 @@
((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 a singly linked list of a given type allowing both push.
USAGE: LIST_DUAL_PUSH_DEF(name, type [, oplist_of_the_type]) */
#define LIST_DUAL_PUSH_DEF(name, ...) \
LISTI_DUAL_PUSH_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name, _it_t) ), \
(name, __VA_ARGS__, M_C(name,_t), M_C(name, _it_t) )))
/* Define the oplist of a list of type.
USAGE: LIST_OPLIST(name [, oplist_of_the_type]) */
#define LIST_OPLIST(...) \
@@ -55,8 +57,16 @@
so that all arguments are evaluated before further expansion */
#define LISTI_OPLIST_P1(arg) LISTI_OPLIST_P2 arg
/* Validation of the given oplist */
#define LISTI_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(LISTI_OPLIST_P3, LISTI_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define LISTI_OPLIST_FAILURE(name, oplist) \
M_LIB_ERROR(ARGUMENT_OF_LIST_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
/* OPLIST definition of a list and list_dual_push */
#define LISTI_OPLIST_P2(name, oplist) \
#define LISTI_OPLIST_P3(name, oplist) \
(INIT(M_C(name, _init)), \
INIT_SET(M_C(name, _init_set)), \
INIT_WITH(API_1(M_INIT_VAI)), \
@@ -106,6 +116,14 @@
so that all arguments are evaluated before further expansion */
#define LISTI_DEF_P1(arg) LISTI_DEF_P2 arg
/* Validate the oplist before going further */
#define LISTI_DEF_P2(name, type, oplist, list_t, it_t) \
M_IF_OPLIST(oplist)(LISTI_DEF_P3, LISTI_DEF_FAILURE)(name, type, oplist, list_t, it_t)
/* Stop processing with a compilation failure */
#define LISTI_DEF_FAILURE(name, type, oplist, list_t, it_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(LIST_DEF): the given argument is not a valid oplist: " #oplist)
/* 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)( \
@@ -132,13 +150,13 @@
/* Internal list definition
- name: prefix to be used
- type: type of the elements of the array
- type: type of the elements of the list
- oplist: oplist of the type of the elements of the container
- list_t: alias for M_C(name, _t) [ type of the container ]
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
- node_t: alias for M_C(name, _node_t) [ node ]
*/
#define LISTI_DEF_P2(name, type, oplist, list_t, it_t) \
#define LISTI_DEF_P3(name, type, oplist, list_t, it_t) \
\
typedef struct M_C(name, _s) { \
struct M_C(name, _s) *next; \
@@ -154,8 +172,10 @@
struct M_C(name, _s) *current; \
} it_t[1]; \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
LISTI_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
LISTI_DEF_P3(name, type, oplist, list_t, it_t) \
LISTI_DEF_P4(name, type, oplist, list_t, it_t) \
LISTI_ITBASE_DEF(name, type, oplist, list_t, it_t)
@@ -168,13 +188,13 @@
/* Internal list function definition
- name: prefix to be used
- type: type of the elements of the array
- type: type of the elements of the list
- oplist: oplist of the type of the elements of the container
- list_t: alias for M_C(name, _t) [ type of the container ]
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
- node_t: alias for M_C(name, _node_t) [ node ]
*/
#define LISTI_DEF_P3(name, type, oplist, list_t, it_t) \
#define LISTI_DEF_P4(name, type, oplist, list_t, it_t) \
\
static inline void \
M_C(name, _init)(list_t v) \
@@ -612,7 +632,7 @@
/* Internal list function definition based on iterator functions
(common for all kind of lists)
- name: prefix to be used
- type: type of the elements of the array
- type: type of the elements of the list
- oplist: oplist of the type of the elements of the container
- list_t: alias for M_C(name, _t) [ type of the container ]
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
@@ -677,12 +697,13 @@
do { \
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
do { c = *str++; } while (isspace(c)); \
if (b == false || c == 0) { goto exit; } \
M_C(name, _push_back)(list, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_CALL_CLEAR(oplist, item); \
M_C(name, _reverse)(list); \
if (b == false || c == 0) { goto exit_clear; } \
M_C(name, _push_back)(list, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_C(name, _reverse)(list); \
success = (c == ']'); \
exit_clear: \
M_CALL_CLEAR(oplist, item); \
exit: \
if (endp) *endp = str; \
return success; \
@@ -812,15 +833,22 @@
so that all arguments are evaluated before further expansion */
#define LISTI_DUAL_PUSH_DEF_P1(arg) LISTI_DUAL_PUSH_DEF_P2 arg
/* Validate the oplist before going further */
#define LISTI_DUAL_PUSH_DEF_P2(name, type, oplist, list_t, it_t) \
M_IF_OPLIST(oplist)(LISTI_DUAL_PUSH_DEF_P3, LISTI_DUAL_PUSH_DEF_FAILURE)(name, type, oplist, list_t, it_t)
/* Stop processing with a compilation failure */
#define LISTI_DUAL_PUSH_DEF_FAILURE(name, type, oplist, list_t, it_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(LIST_DUAL_PUSH_DEF): the given argument is not a valid oplist: " #oplist)
/* Internal dual-push list definition
- name: prefix to be used
- type: type of the elements of the array
- oplist: oplist of the type of the elements of the container
- list_t: alias for M_C(name, _t) [ type of the container ]
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
- node_t: alias for M_C(name, _node_t) [ node ]
*/
#define LISTI_DUAL_PUSH_DEF_P2(name, type, oplist, list_t, it_t) \
#define LISTI_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \
\
struct M_C(name, _s) { \
struct M_C(name, _s) *next; \
@@ -846,10 +874,13 @@
struct M_C(name, _s) *current; \
} it_t[1]; \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
LISTI_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
LISTI_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \
LISTI_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \
LISTI_ITBASE_DEF(name, type, oplist, list_t, it_t)
/* Define the internal contract of an dual-push list */
#define LISTI_DUAL_PUSH_CONTRACT(l) do { \
assert (l != NULL); \
@@ -865,7 +896,7 @@
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
- node_t: alias for M_C(name, _node_t) [ node ]
*/
#define LISTI_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \
#define LISTI_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \
\
static inline void \
M_C(name, _init)(list_t v) \
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - MEMPOOL module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
+80 -1
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Thin Mutex & Thread wrapper
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
@@ -35,63 +35,84 @@
#include <stdbool.h>
#include "m-core.h"
/* Define a mutex type based on C11 definition */
typedef mtx_t m_mutex_t[1];
/* Define a condition variable type based on C11 definition */
typedef cnd_t m_cond_t[1];
/* Define a thread type based on C11 definition */
typedef thrd_t m_thread_t[1];
/* Initialize the mutex (constructor) */
static inline void m_mutex_init(m_mutex_t m)
{
int rc = mtx_init(m, mtx_plain);
// Abort program in case of initialization failure
// There is really nothing else to do if a mutex cannot be constructed
M_ASSERT_INIT (rc == 0, "mutex");
}
/* Clear the mutex (destructor) */
static inline void m_mutex_clear(m_mutex_t m)
{
mtx_destroy(m);
}
/* Lock the mutex */
static inline void m_mutex_lock(m_mutex_t m)
{
mtx_lock(m);
}
/* Unlock the mutex */
static inline void m_mutex_unlock(m_mutex_t m)
{
mtx_unlock(m);
}
/* Initialize the condition variable (constructor) */
static inline void m_cond_init(m_cond_t c)
{
int rc = cnd_init(c);
// Abort program in case of initialization failure
// There is really nothing else to do if the object cannot be constructed
M_ASSERT_INIT (rc == 0, "conditional variable");
}
/* Clear the condition variable (destructor) */
static inline void m_cond_clear(m_cond_t c)
{
cnd_destroy(c);
}
/* Signal the condition variable to at least one waiting thread */
static inline void m_cond_signal(m_cond_t c)
{
cnd_signal(c);
}
/* Signal the condition variable to all waiting threads */
static inline void m_cond_broadcast(m_cond_t c)
{
cnd_broadcast(c);
}
/* Wait for signaling the condition variable by another thread */
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
{
cnd_wait(c, m);
}
/* Create the thread (constructor) and start it */
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void* arg)
{
int rc = thrd_create(t, (int(*)(void*))(void(*)(void))func, arg);
// Abort program in case of initialization failure
M_ASSERT_INIT (rc == thrd_success, "thread");
}
/* Wait for the thread to terminate and destroy it (destructor) */
static inline void m_thread_join(m_thread_t t)
{
int rc = thrd_join(*t, NULL);
@@ -100,11 +121,15 @@ static inline void m_thread_join(m_thread_t t)
(void) rc;
}
/* The thread has nothing meaningfull to do.
Inform the OS to let other threads be scheduled */
static inline void m_thread_yield(void)
{
thrd_yield();
}
/* Sleep the thread for at least usec microseconds.
Return true if the sleep was successful */
static inline bool m_thread_sleep(unsigned long long usec)
{
struct timespec tv;
@@ -116,12 +141,17 @@ static inline bool m_thread_sleep(unsigned long long usec)
// Internal type, not exported.
typedef once_flag m_oncei_t[1];
// Initial value for m_oncei_t
#define M_ONCEI_INIT_VALUE { ONCE_FLAG_INIT }
// Call the function exactly once
static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
{
call_once(o,func);
}
// Attribute to use to allocate a global variable to a thread.
#define M_THREAD_ATTR _Thread_local
@@ -142,61 +172,77 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
#include <stdbool.h>
#include "m-core.h"
/* Define a thread type based on WINDOWS definition */
typedef HANDLE m_thread_t[1];
/* Define a mutex type based on WINDOWS definition */
typedef CRITICAL_SECTION m_mutex_t[1];
/* Define a condition variable type based on WINDOWS definition */
typedef CONDITION_VARIABLE m_cond_t[1];
/* Initialize a mutex (Constructor)*/
static inline void m_mutex_init(m_mutex_t m)
{
InitializeCriticalSection(m);
}
/* Clear a mutex (destructor) */
static inline void m_mutex_clear(m_mutex_t m)
{
DeleteCriticalSection(m);
}
/* Lock a mutex */
static inline void m_mutex_lock(m_mutex_t m)
{
EnterCriticalSection(m);
}
/* Unlock a mutex */
static inline void m_mutex_unlock(m_mutex_t m)
{
LeaveCriticalSection(m);
}
/* Initialize a condition variable (constructor) */
static inline void m_cond_init(m_cond_t c)
{
InitializeConditionVariable(c);
}
/* Clear a condition variable (destructor) */
static inline void m_cond_clear(m_cond_t c)
{
(void) c; // There is no destructor for this object.
}
/* Signal a condition variable to at least one waiting thread */
static inline void m_cond_signal(m_cond_t c)
{
WakeConditionVariable(c);
}
/* Signal a condition variable to all waiting threads */
static inline void m_cond_broadcast(m_cond_t c)
{
WakeAllConditionVariable(c);
}
/* Wait for a condition variable */
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
{
SleepConditionVariableCS(c, m, INFINITE);
}
/* Create a thread (constructor) and start it */
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void *arg)
{
*t = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) (uintptr_t) func, arg, 0, NULL);
M_ASSERT_INIT (*t != NULL, "thread");
}
/* Wait for the thread to terminate and destroy it (destructor) */
static inline void m_thread_join(m_thread_t t)
{
DWORD dwWaitResult = WaitForSingleObject(*t, INFINITE);
@@ -205,11 +251,15 @@ static inline void m_thread_join(m_thread_t t)
CloseHandle(*t);
}
/* The thread has nothing meaningfull to do.
Inform the OS to let other threads be scheduled */
static inline void m_thread_yield(void)
{
Sleep(0);
}
/* Sleep the thread for at least usec microseconds
Return true if the sleep was successful */
static inline bool m_thread_sleep(unsigned long long usec)
{
LARGE_INTEGER ft;
@@ -241,8 +291,10 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
}
#if defined(_MSC_VER)
// Attribute to use to allocate a global variable to a thread (MSVC def).
# define M_THREAD_ATTR __declspec( thread )
#else
// Attribute to use to allocate a global variable to a thread (GCC def).
# define M_THREAD_ATTR __thread
#endif
@@ -261,69 +313,92 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
#include <stdbool.h>
#include "m-core.h"
/* Define a mutex type based on PTHREAD definition */
typedef pthread_mutex_t m_mutex_t[1];
/* Define a condition variable type based on PTHREAD definition */
typedef pthread_cond_t m_cond_t[1];
/* Define a thread type based on PTHREAD definition */
typedef pthread_t m_thread_t[1];
/* Initialize the mutex (constructor) */
static inline void m_mutex_init(m_mutex_t m)
{
int _rc = pthread_mutex_init(m, NULL);
// Abort program in case of initialization failure
// There is really nothing else to do if a mutex cannot be constructed
M_ASSERT_INIT (_rc == 0, "mutex");
}
/* Clear the mutex (destructor) */
static inline void m_mutex_clear(m_mutex_t m)
{
pthread_mutex_destroy(m);
}
/* Lock the mutex */
static inline void m_mutex_lock(m_mutex_t m)
{
pthread_mutex_lock(m);
}
/* Unlock the mutex */
static inline void m_mutex_unlock(m_mutex_t m)
{
pthread_mutex_unlock(m);
}
/* Lazy lock initialization */
#define M_MUTEXI_INIT_VALUE { PTHREAD_MUTEX_INITIALIZER }
/* Internal function compatible with lazy lock */
static inline void m_mutexi_lazy_lock(m_mutex_t m)
{
pthread_mutex_lock(m);
}
/* Initialize the condition variable (constructor) */
static inline void m_cond_init(m_cond_t c)
{
int _rc = pthread_cond_init(c, NULL);
// Abort program in case of initialization failure
// There is really nothing else to do if a mutex cannot be constructed
M_ASSERT_INIT (_rc == 0, "conditional variable");
}
/* Clear the condition variable (destructor) */
static inline void m_cond_clear(m_cond_t c)
{
pthread_cond_destroy(c);
}
/* Signal a condition variable to at least a waiting thread */
static inline void m_cond_signal(m_cond_t c)
{
pthread_cond_signal(c);
}
/* Signal a condition variable to all waiting threads */
static inline void m_cond_broadcast(m_cond_t c)
{
pthread_cond_broadcast(c);
}
/* Waiting for a condition variable */
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
{
pthread_cond_wait(c, m);
}
/* Create a thread (constructor) and start it */
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void *arg)
{
int _rc = pthread_create(t, NULL, (void*(*)(void*))(void(*)(void))func, arg);
M_ASSERT_INIT (_rc == 0, "thread");
}
/* Wait for the thread to terminate and destroy it (destructor) */
static inline void m_thread_join(m_thread_t t)
{
int _rc = pthread_join(*t, NULL);
@@ -331,6 +406,8 @@ static inline void m_thread_join(m_thread_t t)
assert (_rc == 0);
}
/* The thread has nothing meaningfull to do.
Inform the OS to let other threads be scheduled */
static inline void m_thread_yield(void)
{
#ifdef _POSIX_PRIORITY_SCHEDULING
@@ -338,6 +415,8 @@ static inline void m_thread_yield(void)
#endif
}
/* Sleep for at least usec microseconds
Return true if the sleep was successful */
static inline bool m_thread_sleep(unsigned long long usec)
{
struct timeval tv;
+27 -5
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - dynamic priority queue module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
@@ -52,10 +52,17 @@
/* Deferred evaluation for the definition,
so that all arguments are evaluated before further expansion */
#define PRIOQUEUEI_OPLIST_P1(arg) PRIOQUEUEI_OPLIST_P2 arg
#define PRIOQUEUEI_DEF_P1(arg) PRIOQUEUEI_DEF_P2 arg
/* Validation of the given oplist */
#define PRIOQUEUEI_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(PRIOQUEUEI_OPLIST_P3, PRIOQUEUEI_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define PRIOQUEUEI_OPLIST_FAILURE(name, oplist) \
M_LIB_ERROR(ARGUMENT_OF_PRIOQUEUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
/* Define oplist of a priority queue */
#define PRIOQUEUEI_OPLIST_P2(name, oplist) \
#define PRIOQUEUEI_OPLIST_P3(name, oplist) \
(INIT(M_C(name, _init)) \
,INIT_SET(M_C(name, _init_set)) \
,INIT_WITH(API_1(M_INIT_VAI)) \
@@ -74,6 +81,19 @@
,GET_SIZE(M_C(name, _size)) \
)
/* Deferred evaluation for the definition,
so that all arguments are evaluated before further expansion */
#define PRIOQUEUEI_DEF_P1(arg) PRIOQUEUEI_DEF_P2 arg
/* Validate the oplist before going further */
#define PRIOQUEUEI_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
M_IF_OPLIST(oplist)(PRIOQUEUEI_DEF_P3, PRIOQUEUEI_DEF_FAILURE)(name, type, oplist, prioqueue_t, it_t)
/* Stop processing with a compilation failure */
#define PRIOQUEUEI_DEF_FAILURE(name, type, oplist, prioqueue_t, it_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(PRIOQUEUE_DEF): the given argument is not a valid oplist: " #oplist)
/* Define the priority queue:
- name: prefix to use,
- type: type of the contained objects,
@@ -81,7 +101,7 @@
- prioqueue_t: type of the container,
- it_t: iterator of the container
*/
#define PRIOQUEUEI_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
#define PRIOQUEUEI_DEF_P3(name, type, oplist, prioqueue_t, it_t) \
ARRAY_DEF(M_C(name, _array), type, oplist) \
\
typedef type M_C(name, _type_t); \
@@ -94,6 +114,8 @@
\
typedef M_C(name, _array_it_t) it_t; \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void \
M_C(name, _init)(prioqueue_t p) \
{ \
@@ -354,7 +376,7 @@
} \
} \
\
, /* No EQUAL */ \) \
, /* No EQUAL */ ) \
// TODO: set all & remove all function
+230 -171
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - RED BLACK TREE module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,6 +36,7 @@
(name, __VA_ARGS__ , \
M_C(name, _t), M_C(name, _node_t), M_C(name, _it_t))))
/* Define the oplist of a rbtree of type.
USAGE: RBTREE_OPLIST(name [, oplist_of_the_type]) */
#define RBTREE_OPLIST(...) \
@@ -50,8 +51,18 @@
so that all arguments are evaluated before further expansion */
#define RBTREEI_OPLIST_P1(arg) RBTREEI_OPLIST_P2 arg
/* OPLIST definition of a rbtree */
#define RBTREEI_OPLIST_P2(name, oplist) \
/* Validation of the given oplist */
#define RBTREEI_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(RBTREEI_OPLIST_P3, RBTREEI_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define RBTREEI_OPLIST_FAILURE(name, oplist) \
M_LIB_ERROR(ARGUMENT_OF_RBTREE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
/* OPLIST definition of a rbtree
NOTE: IT_REF is not exported so that the contained appears as not modifiable
by algorithm.*/
#define RBTREEI_OPLIST_P3(name, oplist) \
(INIT(M_C(name, _init)), \
INIT_SET(M_C(name, _init_set)), \
INIT_WITH(API_1(M_INIT_VAI)), \
@@ -73,7 +84,6 @@
IT_LAST_P(M_C(name,_last_p)), \
IT_EQUAL_P(M_C(name,_it_equal_p)), \
IT_NEXT(M_C(name,_next)), \
IT_REF(M_C(name,_ref)), \
IT_CREF(M_C(name,_cref)), \
CLEAN(M_C(name,_clean)), \
PUSH(M_C(name,_push)), \
@@ -110,88 +120,114 @@
#define RBTREEI_GET_CHILD(x, n) ((x)->child[n])
#define RBTREEI_SET_CHILD(x, n, y) ((x)->child[n] = (y))
// Color of a node of a Red/Black tree
typedef enum {
RBTREE_BLACK = 0, RBTREE_RED
} rbtreei_color_e;
// General contact of a tree
#define RBTREEI_CONTRACT(tree) do { \
assert ((tree) != NULL); \
assert ((tree)->node == NULL || RBTREEI_IS_BLACK((tree)->node)); \
assert ((tree)->size != 0 || (tree)->node == NULL); \
// General contact of a Read/Black tree
#define RBTREEI_CONTRACT(tree) do { \
assert ((tree) != NULL); \
assert ((tree)->node == NULL || RBTREEI_IS_BLACK((tree)->node)); \
assert ((tree)->size != 0 || (tree)->node == NULL); \
} while (0)
// Contract of a node (doesn't check for equal depth in black)
#define RBTREEI_CONTRACT_NODE(node) do { \
assert((node) != NULL); \
assert(RBTREEI_IS_BLACK(node) || RBTREEI_IS_RED(node)); \
assert(RBTREEI_IS_BLACK(node) \
|| (((node)->child[0] == NULL || RBTREEI_IS_BLACK(node->child[0])) \
#define RBTREEI_CONTRACT_NODE(node) do { \
assert((node) != NULL); \
assert(RBTREEI_IS_BLACK(node) || RBTREEI_IS_RED(node)); \
assert(RBTREEI_IS_BLACK(node) \
|| (((node)->child[0] == NULL || RBTREEI_IS_BLACK(node->child[0])) \
&& ((node)->child[1] == NULL || RBTREEI_IS_BLACK(node->child[1])))); \
} while (0)
//TODO: UPDATE shall use a separate method than push
//TODO: UPDATE method shall be a separate method than push method
/* Deferred evaluation for the rbtree definition,
so that all arguments are evaluated before further expansion */
#define RBTREEI_DEF_P1(arg) RBTREEI_DEF_P2 arg
/* Validate the oplist before going further */
#define RBTREEI_DEF_P2(name, type, oplist, tree_t, node_t, it_t) \
M_IF_OPLIST(oplist)(RBTREEI_DEF_P3, RBTREEI_DEF_FAILURE)(name, type, oplist, tree_t, node_t, it_t)
/* Stop processing with a compilation failure */
#define RBTREEI_DEF_FAILURE(name, type, oplist, tree_t, note_t, it_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(RBTREE_DEF): the given argument is not a valid oplist: " #oplist)
/* Internal rbtree definition
- name: prefix to be used
- type: type of the elements of the array
- type: type of the elements of the rbtree
- oplist: oplist of the type of the elements of the container
- tree_t: alias for M_C(name, _t) [ type of the container ]
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
- node_t: alias for M_C(name, _node_t) [ node ]
*/
#define RBTREEI_DEF_P2(name, type, oplist, tree_t, node_t, it_t) \
#define RBTREEI_DEF_P3(name, type, oplist, tree_t, node_t, it_t) \
\
/* Node of Red/Black tree. \
Each node has up to two child, a color (Red or black) \
and the data stored in it */ \
typedef struct M_C(name, _node_s) { \
struct M_C(name, _node_s) *child[2]; \
type data; \
rbtreei_color_e color; \
} node_t; \
\
typedef struct M_C(name, _s) { \
size_t size; \
node_t *node; \
/* Red/Black tree */ \
typedef struct M_C(name, _s) { \
size_t size; /* Number of elements in the tree */ \
node_t *node; /* Root node of the tree */ \
} tree_t[1]; \
typedef struct M_C(name, _s) *M_C(name, _ptr); \
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
\
typedef struct M_C(name, _it_s) { \
\
/* Iterator on a tree. The iterator stores the full path to the \
current node through all its parents and its depth */ \
typedef struct M_C(name, _it_s) { \
node_t *stack[RBTREEI_MAX_STACK]; \
int8_t which[RBTREEI_MAX_STACK]; \
unsigned int cpt; \
} it_t[1]; \
\
typedef type M_C(name, _type_t); \
typedef type M_C(name, _type_t); \
\
/* Link with fast memory allocator if requested */ \
M_IF_METHOD(MEMPOOL, oplist)( \
/* Definition of the memory pool of this kind of node */ \
MEMPOOL_DEF(M_C(name, _mempool), node_t) \
/* Definition of the global variable used to reference this pool */ \
M_GET_MEMPOOL_LINKAGE oplist M_C(name, _mempool_t) M_GET_MEMPOOL oplist; \
static inline node_t *M_C(name,_int_new)(void) { \
return M_C(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \
/* Allocator function */ \
static inline node_t *M_C(name,_int_new)(void) { \
return M_C(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \
} \
static inline void M_C(name,_int_del)(node_t *ptr) { \
M_C(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \
/* Deallocator function */ \
static inline void M_C(name,_int_del)(node_t *ptr) { \
M_C(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \
} \
\
\
, /* No mempool allocation */ \
\
static inline node_t *M_C(name,_int_new)(void) { \
/* Callic allocator function (common case) */ \
static inline node_t *M_C(name,_int_new)(void) { \
return M_CALL_NEW(oplist, node_t); \
} \
static inline void M_C(name,_int_del)(node_t *ptr) { \
/* Callic deallocator function (common case) */ \
static inline void M_C(name,_int_del)(node_t *ptr) { \
M_CALL_DEL(oplist, ptr); \
} ) \
\
RBTREEI_DEF_P3(name, type, oplist, tree_t, node_t, it_t)
\
/* Check if the given oplist is compatible with the given type */ \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
/* Generate all functions */ \
RBTREEI_DEF_P4(name, type, oplist, tree_t, node_t, it_t)
#define RBTREEI_DEF_P3(name, type, oplist, tree_t, node_t, it_t) \
\
#define RBTREEI_DEF_P4(name, type, oplist, tree_t, node_t, it_t) \
\
static inline void \
M_C(name, _init)(tree_t tree) \
M_C(name, _init)(tree_t tree) \
{ \
assert (tree != NULL); \
tree->size = 0; \
@@ -205,57 +241,70 @@ typedef enum {
RBTREEI_CONTRACT(tree); \
node_t *stack[RBTREEI_MAX_STACK]; \
unsigned int cpt = 0; \
/* If nothing (no node) nothing to clean: return */ \
if (tree->node == NULL) return; \
/* Parse all the tree */ \
stack[cpt++] = tree->node; \
while (cpt > 0) { \
node_t *n = stack[cpt-1]; \
/* Go down to the bottom left node that exists */ \
while (true) { \
RBTREEI_CONTRACT_NODE(n); \
/* If there is a left child, get it */ \
if (n->child[0] != NULL) { \
assert (cpt < RBTREEI_MAX_STACK); \
stack[cpt++] = n->child[0]; \
n = n->child[0]; \
stack[cpt-2]->child[0] = NULL; \
/* If there is a right child, get it */ \
} else if (n->child[1] != NULL) { \
assert (cpt < RBTREEI_MAX_STACK); \
stack[cpt++] = n->child[1]; \
n = n->child[1]; \
stack[cpt-2]->child[1] = NULL; \
} else \
/* No left nor right child, node can be deleted */ \
} else { \
break; \
} \
} \
assert (n == stack[cpt - 1]); \
/* Clear the bottom left node */ \
M_CALL_CLEAR(oplist, n->data); \
M_C(name,_int_del) (n); \
M_C(name,_int_del) (n); \
assert((stack[cpt-1] = NULL) == NULL); \
/* Go up to the parent */ \
cpt--; \
} \
/* Mark the root node as empty */ \
tree->node = NULL; \
tree->size = 0; \
} \
\
static inline void \
M_C(name, _clear)(tree_t tree) \
M_C(name, _clear)(tree_t tree) \
{ \
M_C(name, _clean)(tree); \
/* Nothing more than clean the tree as everything is cleared */ \
M_C(name, _clean)(tree); \
} \
\
static inline void \
M_C(name, _push)(tree_t tree, type const data) \
M_C(name, _push)(tree_t tree, type const data) \
{ \
RBTREEI_CONTRACT(tree); \
node_t *tab[RBTREEI_MAX_STACK]; \
int8_t which[RBTREEI_MAX_STACK]; \
unsigned int cpt = 0; \
node_t *n = tree->node; \
/* If nothing, create new node */ \
/* If there is no root node, create a new node */ \
if (n == NULL) { \
n = M_C(name,_int_new)(); \
n = M_C(name,_int_new)(); \
if (M_UNLIKELY (n == NULL)) { \
M_MEMORY_FULL(sizeof (node_t)); \
return; \
} \
/* Copy the data in the root node */ \
M_CALL_INIT_SET(oplist, n->data, data); \
/* Mark the root node as black */ \
n->child[0] = n->child[1] = NULL; \
RBTREEI_SET_BLACK (n); \
tree->node = n; \
@@ -264,46 +313,50 @@ typedef enum {
RBTREEI_CONTRACT(tree); \
return; \
} \
/* Search for insertion point */ \
/* Search for insertion point in the tree */ \
tab[cpt] = n; \
while (n != NULL) { \
RBTREEI_CONTRACT_NODE(n); \
int cmp = M_CALL_CMP(oplist, n->data, data); \
if (cmp == 0) { \
/* key found ==> stop analysis */ \
break; \
} else if (cmp > 0) { \
which[cpt++] = 0; \
n = n->child[0]; \
} else { \
which[cpt++] = 1; \
n = n->child[1]; \
/* go left (if cmp > 0) or right (if cmp < 0) */ \
int s = (cmp < 0); \
which[cpt++] = s; \
n = n->child[s]; \
} \
/* We cannot overflow the max depth of a tree */ \
assert (cpt < RBTREEI_MAX_STACK); \
tab[cpt] = n; \
} \
/* If found, update the data (default is set) */ \
if (n != NULL) { \
/* FIXME: Use of SET method instead of UPDATE ? */ \
M_IF_METHOD (UPDATE, oplist)(M_CALL_UPDATE(oplist, n->data, data) \
, M_CALL_SET(oplist, n->data, data)); \
RBTREEI_CONTRACT (tree); \
return; \
} \
/* Create new */ \
n = M_C(name,_int_new)(); \
/* Create new node to store the data */ \
n = M_C(name,_int_new)(); \
if (M_UNLIKELY (n == NULL) ) { \
M_MEMORY_FULL (sizeof (node_t)); \
return; \
} \
/* Copy the data and mark the node as red */ \
M_CALL_INIT_SET(oplist, n->data, data); \
n->child[0] = n->child[1] = NULL; \
RBTREEI_SET_RED (n); \
/* Add it in the iterator */ \
assert (tab[cpt] == NULL); \
tab[cpt] = n; \
tree->size ++; \
/* Add it in the tree */ \
tree->size ++; \
assert(tab[cpt-1]->child[0+which[cpt-1]] == NULL); \
tab[cpt-1]->child[0+which[cpt-1]] = n; \
/* Fix the tree */ \
/* Fix the tree to still respect the red/back properties */ \
while (cpt >= 2 \
&& RBTREEI_IS_RED(tab[cpt-1]) \
&& tab[cpt-2]->child[1-which[cpt-2]] != NULL \
@@ -363,14 +416,15 @@ typedef enum {
} \
\
static inline size_t \
M_C(name, _size)(const tree_t tree) \
M_C(name, _size)(const tree_t tree) \
{ \
RBTREEI_CONTRACT (tree); \
return tree->size; \
} \
\
/* Set the iterator to the first (child=0) or last (child=1) element */ \
static inline void \
M_C(name, _int_it)(it_t it, const tree_t tree, int child) \
M_C(name, _int_it)(it_t it, const tree_t tree, int child) \
{ \
RBTREEI_CONTRACT (tree); \
assert (it != NULL); \
@@ -379,6 +433,7 @@ typedef enum {
if (tree->node != NULL) { \
it->which[cpt] = child; \
node_t *n = it->stack[cpt++] = tree->node; \
/* Go down the tree and fill in the iterator */ \
while (n->child[child] != NULL) { \
assert (cpt < RBTREEI_MAX_STACK); \
n = n->child[child]; \
@@ -391,47 +446,49 @@ typedef enum {
} \
\
static inline void \
M_C(name, _it)(it_t it, const tree_t tree) \
M_C(name, _it)(it_t it, const tree_t tree) \
{ \
M_C(name, _int_it)(it, tree, 0); \
M_C(name, _int_it)(it, tree, 0); \
} \
\
static inline void \
M_C(name, _it_last)(it_t it, const tree_t tree) \
M_C(name, _it_last)(it_t it, const tree_t tree) \
{ \
M_C(name,_int_it)(it, tree, 1); \
M_C(name,_int_it)(it, tree, 1); \
} \
\
static inline void \
M_C(name, _it_end)(it_t it, const tree_t tree) \
M_C(name, _it_end)(it_t it, const tree_t tree) \
{ \
RBTREEI_CONTRACT (tree); \
assert (it != NULL); \
assert (it != NULL); \
it->cpt = 0; \
} \
\
static inline void \
M_C(name, _it_set)(it_t it, const it_t ref) \
M_C(name, _it_set)(it_t it, const it_t ref) \
{ \
assert (it != NULL && ref != NULL); \
*it = *ref; \
} \
\
static inline bool \
M_C(name, _end_p)(const it_t it) \
M_C(name, _end_p)(const it_t it) \
{ \
assert (it != NULL); \
return it->cpt == 0; \
} \
\
/* Go to the next (child = 0)or previous element (child = 1) */ \
static inline void \
M_C(name, _int_next)(it_t it, int child) \
M_C(name, _int_next)(it_t it, int child) \
{ \
assert (it != NULL); \
assert (child == 0 || child == 1); \
if (it->cpt == 0) return; \
unsigned int cpt = it->cpt - 1; \
node_t *n = it->stack[cpt]; \
/* Get the other child */ \
const int right = 1 ^ child; \
if (n->child[right] != NULL && it->which[cpt] == child) { \
/* Going right */ \
@@ -456,19 +513,19 @@ typedef enum {
} \
\
static inline void \
M_C(name, _next)(it_t it) \
M_C(name, _next)(it_t it) \
{ \
M_C(name, _int_next)(it, 0); \
M_C(name, _int_next)(it, 0); \
} \
\
static inline void \
M_C(name, _previous)(it_t it) \
M_C(name, _previous)(it_t it) \
{ \
M_C(name, _int_next)(it, 1); \
M_C(name, _int_next)(it, 1); \
} \
\
static inline type * \
M_C(name, _ref)(const it_t it) \
M_C(name, _ref)(const it_t it) \
{ \
assert(it != NULL && it->cpt > 0); \
/* NOTE: partially unsafe if the user modify the order of the el */ \
@@ -476,23 +533,22 @@ typedef enum {
} \
\
static inline type const * \
M_C(name, _cref)(const it_t it) \
M_C(name, _cref)(const it_t it) \
{ \
return M_CONST_CAST(type, M_C(name, _ref)(it)); \
return M_CONST_CAST(type, M_C(name, _ref)(it)); \
} \
\
static inline bool \
M_C(name, _it_equal_p)(const it_t it1, \
const it_t it2) \
M_C(name, _it_equal_p)(const it_t it1, const it_t it2) \
{ \
assert(it1 != NULL && it2 != NULL); \
return it1->cpt == it2->cpt \
&& it1->stack[it1->cpt-1] == it2->stack[it2->cpt-1]; \
} \
\
\
static inline void \
M_C(name, _it_from)(it_t it, \
const tree_t tree, type const data) \
M_C(name, _it_from)(it_t it, const tree_t tree, type const data) \
{ \
RBTREEI_CONTRACT (tree); \
assert (it != NULL); \
@@ -535,13 +591,13 @@ typedef enum {
} \
\
static inline bool M_ATTR_DEPRECATED \
M_C(name, _it_to_p)(it_t it, type const data) \
M_C(name, _it_to_p)(it_t it, type const data) \
{ \
return M_C(name, _it_until_p)(it, data); \
} \
\
static inline type * \
M_C(name, _min)(const tree_t tree) \
M_C(name, _min)(const tree_t tree) \
{ \
RBTREEI_CONTRACT (tree); \
node_t *n = tree->node; \
@@ -552,9 +608,9 @@ typedef enum {
} \
return &n->data; \
} \
\
\
static inline type * \
M_C(name, _max)(const tree_t tree) \
M_C(name, _max)(const tree_t tree) \
{ \
RBTREEI_CONTRACT (tree); \
node_t *n = tree->node; \
@@ -565,82 +621,84 @@ typedef enum {
} \
return &n->data; \
} \
\
\
static inline type const * \
M_C(name, _cmin)(const tree_t tree) \
M_C(name, _cmin)(const tree_t tree) \
{ \
return M_CONST_CAST(type, M_C(name, _min)(tree)); \
return M_CONST_CAST(type, M_C(name, _min)(tree)); \
} \
\
\
static inline type const * \
M_C(name, _cmax)(const tree_t tree) \
M_C(name, _cmax)(const tree_t tree) \
{ \
return M_CONST_CAST(type, M_C(name, _max)(tree)); \
return M_CONST_CAST(type, M_C(name, _max)(tree)); \
} \
\
\
static inline type * \
M_C(name, _get)(const tree_t tree, type const data) \
M_C(name, _get)(const tree_t tree, type const data) \
{ \
RBTREEI_CONTRACT (tree); \
node_t *n = tree->node; \
/* Go down the tree */ \
while (n != NULL) { \
RBTREEI_CONTRACT_NODE (n); \
int cmp = M_CALL_CMP(oplist, n->data, data); \
if (cmp == 0) { \
return &n->data; \
} else if (cmp > 0) { \
n = n->child[0]; \
} else { \
n = n->child[1]; \
/* Go left (if cmp > 0) or right (if cmp < 0) */ \
n = n->child[cmp < 0]; \
} \
} \
return NULL; \
} \
\
static inline type const * \
M_C(name, _cget)(const tree_t tree, type const data) \
M_C(name, _cget)(const tree_t tree, type const data) \
{ \
return M_CONST_CAST(type, M_C(name, _get)(tree, data)); \
return M_CONST_CAST(type, M_C(name, _get)(tree, data)); \
} \
\
\
/* Create a copy of the given node (recursively) */ \
static inline node_t * \
M_C(name, _int_copyn)(const node_t *o) \
M_C(name, _int_copyn)(const node_t *o) \
{ \
if (o == NULL) return NULL; \
node_t *n = M_C(name,_int_new)(); \
node_t *n = M_C(name,_int_new)(); \
if (M_UNLIKELY (n == NULL) ) { \
M_MEMORY_FULL (sizeof (node_t)); \
return NULL; \
} \
M_CALL_INIT_SET(oplist, n->data, o->data); \
n->child[0] = M_C(name, _int_copyn)(o->child[0]); \
n->child[1] = M_C(name, _int_copyn)(o->child[1]); \
n->child[0] = M_C(name, _int_copyn)(o->child[0]); \
n->child[1] = M_C(name, _int_copyn)(o->child[1]); \
RBTREEI_COPY_COLOR (n, o); \
return n; \
} \
\
\
static inline void \
M_C(name, _init_set)(tree_t tree, const tree_t ref) \
M_C(name, _init_set)(tree_t tree, const tree_t ref) \
{ \
RBTREEI_CONTRACT (ref); \
assert (tree != NULL && tree != ref); \
tree->size = ref->size; \
tree->node = M_C(name, _int_copyn)(ref->node); \
/* Copy the root node recursively */ \
tree->node = M_C(name, _int_copyn)(ref->node); \
RBTREEI_CONTRACT (tree); \
} \
\
static inline void \
M_C(name, _set)(tree_t tree, const tree_t ref) \
M_C(name, _set)(tree_t tree, const tree_t ref) \
{ \
RBTREEI_CONTRACT (tree); \
RBTREEI_CONTRACT (ref); \
if (tree == ref) return; \
M_C(name,_clear)(tree); \
M_C(name,_init_set)(tree, ref); \
M_C(name,_clear)(tree); \
M_C(name,_init_set)(tree, ref); \
} \
\
static inline void \
M_C(name, _init_move)(tree_t tree, tree_t ref) \
M_C(name, _init_move)(tree_t tree, tree_t ref) \
{ \
RBTREEI_CONTRACT (ref); \
assert (tree != NULL && tree != ref); \
@@ -652,18 +710,18 @@ typedef enum {
} \
\
static inline void \
M_C(name, _move)(tree_t tree, tree_t ref) \
M_C(name, _move)(tree_t tree, tree_t ref) \
{ \
RBTREEI_CONTRACT (tree); \
RBTREEI_CONTRACT (ref); \
assert (tree != ref); \
M_C(name,_clear)(tree); \
M_C(name,_init_move)(tree, ref); \
M_C(name,_clear)(tree); \
M_C(name,_init_move)(tree, ref); \
RBTREEI_CONTRACT (tree); \
} \
\
\
static inline void \
M_C(name, _swap)(tree_t tree1, tree_t tree2) \
M_C(name, _swap)(tree_t tree1, tree_t tree2) \
{ \
RBTREEI_CONTRACT (tree1); \
RBTREEI_CONTRACT (tree2); \
@@ -674,7 +732,7 @@ typedef enum {
} \
\
static inline bool \
M_C(name, _empty_p)(const tree_t tree) \
M_C(name, _empty_p)(const tree_t tree) \
{ \
RBTREEI_CONTRACT (tree); \
return tree->size == 0; \
@@ -682,7 +740,7 @@ typedef enum {
\
/* Take care of the case n == NULL too */ \
static inline bool \
M_C(name, _int_is_black)(const node_t *n) \
M_C(name, _int_is_black)(const node_t *n) \
{ \
return (n == NULL) ? true : RBTREEI_IS_BLACK(n); \
} \
@@ -694,7 +752,7 @@ typedef enum {
} \
\
static inline node_t * \
M_C(name, _int_rotate)(node_t *pp, node_t *ppp, const bool right) \
M_C(name, _int_rotate)(node_t *pp, node_t *ppp, const bool right) \
{ \
assert (pp != NULL && ppp != NULL); \
bool left = !right; \
@@ -709,12 +767,13 @@ typedef enum {
} \
\
M_IF_DEBUG( \
/* Compute the depth of a node */ \
static size_t \
M_C(name, _int_depth)(const node_t *n) \
M_C(name, _int_depth)(const node_t *n) \
{ \
if (n == NULL) return 1; \
return RBTREEI_IS_BLACK (n) \
+ M_C(name, _int_depth)(n->child[0]); \
+ M_C(name, _int_depth)(n->child[0]); \
} \
) \
\
@@ -732,8 +791,8 @@ typedef enum {
tab[cpt] = n; \
while (n != NULL) { \
RBTREEI_CONTRACT_NODE (n); \
assert(M_C(name, _int_depth)(n->child[0]) \
== M_C(name, _int_depth)(n->child[1])); \
assert(M_C(name, _int_depth)(n->child[0]) \
== M_C(name, _int_depth)(n->child[1])); \
int cmp = M_CALL_CMP(oplist, n->data, key); \
if (cmp == 0) { \
break; \
@@ -763,8 +822,8 @@ typedef enum {
while (v != NULL) { \
/* Always left node */ \
RBTREEI_CONTRACT_NODE (v); \
assert(M_C(name, _int_depth)(v->child[0]) \
== M_C(name, _int_depth)(v->child[1])); \
assert(M_C(name, _int_depth)(v->child[0]) \
== M_C(name, _int_depth)(v->child[1])); \
which[cpt++] = 0; \
v = v->child[0]; \
assert (cpt < RBTREEI_MAX_STACK); \
@@ -842,10 +901,10 @@ typedef enum {
rbtreei_color_e p_color = RBTREEI_GET_COLOR (p); \
if (childIsRight != nbChild) { \
/* left-left or right-right case */ \
p = M_C(name, _int_rotate) (p, tab[cpt-1], childIsRight); \
p = M_C(name, _int_rotate) (p, tab[cpt-1], childIsRight); \
} else { \
s = M_C(name, _int_rotate) (s, p, childIsRight); \
p = M_C(name, _int_rotate) (p, tab[cpt-1], !nbChild); \
s = M_C(name, _int_rotate) (s, p, childIsRight); \
p = M_C(name, _int_rotate) (p, tab[cpt-1], !nbChild); \
} \
RBTREEI_SET_COLOR(p, p_color); \
assert(p->child[0] != NULL && p->child[1] != NULL); \
@@ -886,22 +945,22 @@ typedef enum {
structuraly different but functionnaly equal (you get this by \
constructing the tree in a different way). We have to \
compare the ordered value within the tree. */ \
M_C(name, _it)(it1, t1); \
M_C(name, _it)(it2, t2); \
while (!M_C(name, _end_p)(it1) \
&& !M_C(name, _end_p)(it2)) { \
type const *ref1 = M_C(name, _cref)(it1); \
type const *ref2 = M_C(name, _cref)(it2); \
M_C(name, _it)(it1, t1); \
M_C(name, _it)(it2, t2); \
while (!M_C(name, _end_p)(it1) \
&& !M_C(name, _end_p)(it2)) { \
type const *ref1 = M_C(name, _cref)(it1); \
type const *ref2 = M_C(name, _cref)(it2); \
if (M_CALL_EQUAL(oplist, *ref1, *ref2) == false) \
return false; \
M_C(name, _next)(it1); \
M_C(name, _next)(it2); \
M_C(name, _next)(it1); \
M_C(name, _next)(it2); \
} \
return M_C(name, _end_p)(it1) \
&& M_C(name, _end_p)(it2); \
return M_C(name, _end_p)(it1) \
&& M_C(name, _end_p)(it2); \
} \
, /* NO EQUAL METHOD */ ) \
\
\
M_IF_METHOD(HASH, oplist)( \
static inline size_t M_C(name,_hash)(const tree_t t1) { \
RBTREEI_CONTRACT(t1); \
@@ -909,57 +968,57 @@ typedef enum {
/* NOTE: We can't compute the hash directly for the same reason \
than for EQUAL operator. */ \
it_t it1; \
M_C(name, _it)(it1, t1); \
while (!M_C(name, _end_p)(it1)) { \
type const *ref1 = M_C(name, _cref)(it1); \
M_C(name, _it)(it1, t1); \
while (!M_C(name, _end_p)(it1)) { \
type const *ref1 = M_C(name, _cref)(it1); \
M_HASH_UP(hash, M_CALL_HASH(oplist, *ref1)); \
M_C(name, _next)(it1); \
M_C(name, _next)(it1); \
} \
return M_HASH_FINAL (hash); \
return M_HASH_FINAL (hash); \
} \
, /* NO HASH METHOD */ ) \
\
\
M_IF_METHOD(GET_STR, oplist)( \
static inline void M_C(name, _get_str)(string_t str, \
tree_t const t1, bool append) { \
tree_t const t1, bool append) { \
RBTREEI_CONTRACT(t1); \
assert(str != NULL); \
(append ? string_cat_str : string_set_str) (str, "["); \
/* NOTE: The print is really naive, and not really efficient */ \
bool commaToPrint = false; \
it_t it1; \
M_C(name, _it)(it1, t1); \
while (!M_C(name, _end_p)(it1)) { \
M_C(name, _it)(it1, t1); \
while (!M_C(name, _end_p)(it1)) { \
if (commaToPrint) \
string_push_back (str, M_GET_SEPARATOR oplist); \
commaToPrint = true; \
type const *ref1 = M_C(name, _cref)(it1); \
type const *ref1 = M_C(name, _cref)(it1); \
M_CALL_GET_STR(oplist, str, *ref1, true); \
M_C(name, _next)(it1); \
M_C(name, _next)(it1); \
} \
string_push_back (str, ']'); \
} \
, /* NO GET_STR */ ) \
\
\
M_IF_METHOD(OUT_STR, oplist)( \
static inline void \
M_C(name, _out_str)(FILE *file, tree_t const rbtree) \
M_C(name, _out_str)(FILE *file, tree_t const rbtree) \
{ \
RBTREEI_CONTRACT(rbtree); \
assert (file != NULL); \
fputc ('[', file); \
fputc ('[', file); \
it_t it; \
bool commaToPrint = false; \
for (M_C(name, _it)(it, rbtree) ; \
!M_C(name, _end_p)(it); \
M_C(name, _next)(it)){ \
for (M_C(name, _it)(it, rbtree) ; \
!M_C(name, _end_p)(it); \
M_C(name, _next)(it)){ \
if (commaToPrint) \
fputc (M_GET_SEPARATOR oplist, file); \
commaToPrint = true; \
type const *item = M_C(name, _cref)(it); \
type const *item = M_C(name, _cref)(it); \
M_CALL_OUT_STR(oplist, file, *item); \
} \
fputc (']', file); \
fputc (']', file); \
} \
, /* no out_str */ ) \
\
@@ -969,7 +1028,7 @@ typedef enum {
{ \
RBTREEI_CONTRACT(rbtree); \
assert (str != NULL); \
M_C(name,_clean)(rbtree); \
M_C(name,_clean)(rbtree); \
bool success = false; \
int c = *str++; \
if (M_UNLIKELY (c != '[')) goto exit; \
@@ -982,11 +1041,12 @@ typedef enum {
do { \
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
do { c = *str++; } while (isspace(c)); \
if (b == false || c == 0) goto exit; \
M_C(name, _push)(rbtree, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_CALL_CLEAR(oplist, item); \
if (b == false || c == 0) goto exit_clear; \
M_C(name, _push)(rbtree, item); \
} while (c == M_GET_SEPARATOR oplist); \
success = (c == ']'); \
exit_clear: \
M_CALL_CLEAR(oplist, item); \
exit: \
if (endp) *endp = str; \
return success; \
@@ -999,8 +1059,8 @@ typedef enum {
{ \
RBTREEI_CONTRACT(rbtree); \
assert (file != NULL); \
M_C(name,_clean)(rbtree); \
int c = fgetc(file); \
M_C(name,_clean)(rbtree); \
int c = fgetc(file); \
if (M_UNLIKELY (c != '[')) return false; \
c = fgetc(file); \
if (M_UNLIKELY (c == ']')) return true; \
@@ -1011,37 +1071,36 @@ typedef enum {
do { \
bool b = M_CALL_IN_STR(oplist, item, file); \
do { c = fgetc(file); } while (isspace(c)); \
if (b == false || c == EOF) break; \
M_C(name, _push)(rbtree, item); \
} while (c == M_GET_SEPARATOR oplist); \
if (b == false || c == EOF) break; \
M_C(name, _push)(rbtree, item); \
} while (c == M_GET_SEPARATOR oplist); \
M_CALL_CLEAR(oplist, item); \
return c == ']'; \
} \
, /* no in_str */ ) \
\
\
\
M_IF_METHOD(OUT_SERIAL, oplist)( \
static inline m_serial_return_code_t \
M_C(name, _out_serial)(m_serial_write_t f, tree_t const t1) \
{ \
RBTREEI_CONTRACT(t1); \
assert (f != NULL && f->m_interface != NULL); \
assert (f != NULL && f->m_interface != NULL); \
m_serial_local_t local; \
m_serial_return_code_t ret; \
const M_C(name, _type_t) *item; \
bool first_done = false; \
it_t it; \
ret = f->m_interface->write_array_start(local, f, t1->size); \
ret = f->m_interface->write_array_start(local, f, t1->size); \
for (M_C(name, _it)(it, t1) ; \
!M_C(name, _end_p)(it); \
M_C(name, _next)(it)){ \
item = M_C(name, _cref)(it); \
if (first_done) \
ret |= f->m_interface->write_array_next(local, f); \
ret |= f->m_interface->write_array_next(local, f); \
ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \
first_done = true; \
} \
ret |= f->m_interface->write_array_end(local, f); \
ret |= f->m_interface->write_array_end(local, f); \
return ret & M_SERIAL_FAIL; \
} \
, /* no OUT_SERIAL */ ) \
@@ -1051,13 +1110,13 @@ typedef enum {
M_C(name, _in_serial)(tree_t t1, m_serial_read_t f) \
{ \
RBTREEI_CONTRACT(t1); \
assert (f != NULL && f->m_interface != NULL); \
assert (f != NULL && f->m_interface != NULL); \
m_serial_local_t local; \
m_serial_return_code_t ret; \
size_t estimated_size = 0; \
type key; \
M_C(name,_clean)(t1); \
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
type key; \
M_C(name,_clean)(t1); \
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
M_CALL_INIT(oplist, key); \
do { \
+9 -19
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Serial BIN
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
@@ -87,22 +87,17 @@ m_serial_bin_write_float(m_serial_write_t serial, const long double data, const
size_t n;
FILE *f = (FILE *)serial->data[0].p;
switch (size_of_type) {
case sizeof f1:
if (size_of_type == sizeof f1) {
f1 = data;
n = fwrite (M_ASSIGN_CAST(const void*, &f1), sizeof f1, 1, f);
break;
case sizeof f2:
} else if (size_of_type == sizeof f2) {
f2 = data;
n = fwrite (M_ASSIGN_CAST(const void*, &f2), sizeof f2, 1, f);
break;
case sizeof f3:
} else if (size_of_type == sizeof f3) {
f3 = data;
n = fwrite (M_ASSIGN_CAST(const void*, &f3), sizeof f3, 1, f);
break;
default:
} else {
M_ASSERT_INIT(false, "a float of suitable size");
break;
}
return n == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
}
@@ -323,22 +318,17 @@ m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
long double f3;
size_t n;
FILE *f = (FILE *)serial->data[0].p;
switch (size_of_type) {
case sizeof f1:
if (size_of_type == sizeof f1) {
n = fread (M_ASSIGN_CAST(void*, &f1), sizeof f1, 1, f);
*r = f1;
break;
case sizeof f2:
} else if (size_of_type == sizeof f2) {
n = fread (M_ASSIGN_CAST(void*, &f2), sizeof f2, 1, f);
*r = f2;
break;
case sizeof f3:
} else if (size_of_type == sizeof f3) {
n = fread (M_ASSIGN_CAST(void*, &f3), sizeof f3, 1, f);
*r = f3;
break;
default:
} else {
M_ASSERT_INIT(false, "a float of suitable size");
break;
}
return n == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
}
+19 -3
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Serial JSON
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
@@ -232,7 +232,7 @@ m_serial_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
return n > 0 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
}
/* The exported interface. */
/* The internal exported interface of m_serial_write_json. */
static const m_serial_write_interface_t m_serial_write_json_interface = {
m_serial_json_write_boolean,
m_serial_json_write_integer,
@@ -252,19 +252,27 @@ static const m_serial_write_interface_t m_serial_write_json_interface = {
m_serial_json_write_variant_end
};
/* Initialize the JSON serial object for writing any object to JSON format in the given FILE */
static inline void m_serial_json_write_init(m_serial_write_t serial, FILE *f)
{
serial->m_interface = &m_serial_write_json_interface;
serial->data[0].p = M_ASSIGN_CAST(void*, f);
}
/* CLear the JSON serial object for writing*/
static inline void m_serial_json_write_clear(m_serial_write_t serial)
{
(void) serial; // Nothing to do
}
/* Define a synonym to the JSON serializer with a proper OPLIST */
typedef m_serial_write_t m_serial_json_write_t;
#define M_OPL_m_serial_json_write_t() \
(INIT_WITH(m_serial_json_write_init), CLEAR(m_serial_json_write_clear), TYPE(m_serial_json_write_t) )
/* Helper function */
/* Helper function to skip a space */
static inline int
m_serial_json_read_skip (FILE *f)
{
@@ -528,15 +536,23 @@ static const m_serial_read_interface_t m_serial_json_read_interface = {
m_serial_json_read_variant_end
};
/* Initialize the JSON serial object for reading any object from JSON format in the given FILE */
static inline void m_serial_json_read_init(m_serial_read_t serial, FILE *f)
{
serial->m_interface = &m_serial_json_read_interface;
serial->data[0].p = M_ASSIGN_CAST(void*, f);
}
/* Clear the JSON serial object for reading from the FILE */
static inline void m_serial_json_read_clear(m_serial_read_t serial)
{
(void) serial; // Nothing to do
}
/* Define a synonym of m_serial_read_t
to the JSON serializer with its proper OPLIST */
typedef m_serial_read_t m_serial_json_read_t;
#define M_OPL_m_serial_json_read_t() \
(INIT_WITH(m_serial_json_read_init), CLEAR(m_serial_json_read_clear), TYPE(m_serial_json_read_t) )
#endif
+44 -10
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - SHARED Module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -34,7 +34,8 @@
#define SHARED_PTR_OPLIST(...) \
SHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
_OPLIST(__VA_ARGS__ )))
(__VA_ARGS__ )))
/* Define shared pointer and its function.
USAGE: SHARED_PTR_DEF(name, type, [, oplist]) */
@@ -43,6 +44,7 @@
((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, ...) \
@@ -50,6 +52,7 @@
((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]) */
@@ -62,10 +65,18 @@
/********************************** INTERNAL ************************************/
// deferred
// deferred evaluation
#define SHAREDI_PTR_OPLIST_P1(arg) SHAREDI_PTR_OPLIST_P2 arg
#define SHAREDI_PTR_OPLIST_P2(name, oplist) ( \
/* Validation of the given oplist */
#define SHAREDI_PTR_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(SHAREDI_PTR_OPLIST_P3, SHAREDI_PTR_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define SHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
M_LIB_ERROR(ARGUMENT_OF_SHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
#define SHAREDI_PTR_OPLIST_P3(name, oplist) ( \
INIT(M_C(name, _init)), \
CLEAR(M_C(name, _clear)), \
INIT_SET(M_C(name, _init_set)), \
@@ -74,14 +85,12 @@
CLEAN(M_C(name, _clean)), \
MOVE(M_C(name, _move)), \
SWAP(M_C(name, _swap)) \
,TYPE(M_C(name, _t)) \
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
)
// deferred
#define SHAREDI_PTR_DEF_P1(arg) SHAREDI_PTR_DEF_P2 arg
// OPLIST to handle a counter of atomic type
#define SHAREDI_ATOMIC_OPLIST (TYPE(atomic_int), \
INIT_SET(atomic_init), \
@@ -89,23 +98,38 @@
SUB(atomic_fetch_sub), \
IT_CREF(atomic_load))
// OPLIST to handle a counter of non-atomic type with its helper functions.
// OPLIST to handle a counter of non-atomic type
#define SHAREDI_INTEGER_OPLIST (TYPE(int), \
INIT_SET(sharedi_integer_init_set), \
ADD(sharedi_integer_add), \
SUB(sharedi_integer_sub), \
IT_CREF(sharedi_integer_cref))
/* Atomic like interface for basic integers */
static inline void sharedi_integer_init_set(int *p, int val) { *p = val; }
static inline int sharedi_integer_add(int *p, int val) { int r = *p; *p += val; return r; }
static inline int sharedi_integer_sub(int *p, int val) { int r = *p; *p -= val; return r; }
static inline int sharedi_integer_cref(int *p) { return *p; }
/* Contract of a shared pointer */
#define SHAREDI_CONTRACT(shared, cpt_oplist) do { \
assert(shared != NULL); \
assert(*shared == NULL || M_CALL_IT_CREF(cpt_oplist, &(*shared)->cpt) >= 1); \
} while (0)
#define SHAREDI_PTR_DEF_P2(name, type, oplist, cpt_oplist) \
// deferred evaluation
#define SHAREDI_PTR_DEF_P1(arg) SHAREDI_PTR_DEF_P2 arg
/* Validate the oplist before going further */
#define SHAREDI_PTR_DEF_P2(name, type, oplist, cpt_oplist_t) \
M_IF_OPLIST(oplist)(SHAREDI_PTR_DEF_P3, SHAREDI_PTR_DEF_FAILURE)(name, type, oplist, cpt_oplist_t)
/* Stop processing with a compilation failure */
#define SHAREDI_PTR_DEF_FAILURE(name, type, oplist, cpt_oplist) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
/* Code generation */
#define SHAREDI_PTR_DEF_P3(name, type, oplist, cpt_oplist) \
\
typedef struct M_C(name, _s){ \
type *data; /* Pointer to the data */ \
@@ -120,6 +144,8 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
struct M_C(name, _s) ptr; \
} M_C(name, combine_t)[1]; \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void \
M_C(name, _init)(M_C(name, _t) shared) \
{ \
@@ -299,7 +325,15 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
// deferred
#define SHAREDI_RESOURCE_DEF_P1(arg) SHAREDI_RESOURCE_DEF_P2 arg
#define SHAREDI_RESOURCE_DEF_P2(name, type, oplist) \
/* Validate the oplist before going further */
#define SHAREDI_RESOURCE_DEF_P2(name, type, oplist) \
M_IF_OPLIST(oplist)(SHAREDI_RESOURCE_DEF_P3, SHAREDI_RESOURCE_DEF_FAILURE)(name, type, oplist)
/* Stop processing with a compilation failure */
#define SHAREDI_RESOURCE_DEF_FAILURE(name, type, oplist) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_RESOURCE_DEF): the given argument is not a valid oplist: " #oplist)
#define SHAREDI_RESOURCE_DEF_P3(name, type, oplist) \
\
/* Create an aligned type to avoid false sharing between threads */ \
typedef struct M_C(name, _atype_s) { \
+49 -8
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - SNAPSHOT Module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,6 +36,7 @@
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
(name, __VA_ARGS__ )))
/* Define a Single Producer Multiple Consummer snapshot and its functions
USAGE: SNAPSHOT_SPMC_DEF(name, type[, oplist]) */
#define SNAPSHOT_SPMC_DEF(name, ...) \
@@ -43,6 +44,7 @@
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
(name, __VA_ARGS__ )))
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
USAGE: SNAPSHOT_MPMC_DEF(name, type[, oplist]) */
#define SNAPSHOT_MPMC_DEF(name, ...) \
@@ -50,6 +52,7 @@
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
(name, __VA_ARGS__ )))
/* Define the oplist of a snapshot (SPSC, SPMC or MPMC).
USAGE: SNAPSHOT_OPLIST(name[, oplist]) */
#define SNAPSHOT_OPLIST(...) \
@@ -63,8 +66,16 @@
// deferred evaluation of the input
#define SNAPSHOTI_OPLIST_P1(arg) SNAPSHOTI_OPLIST_P2 arg
/* Validation of the given oplist */
#define SNAPSHOTI_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(SNAPSHOTI_OPLIST_P3, SNAPSHOTI_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define SNAPSHOTI_OPLIST_FAILURE(name, oplist) \
M_LIB_ERROR(ARGUMENT_OF_SNAPSHOT_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
/* Define the oplist of a snapshot */
#define SNAPSHOTI_OPLIST_P2(name, oplist) \
#define SNAPSHOTI_OPLIST_P3(name, oplist) \
(INIT(M_C(name, _init)) \
,INIT_SET(M_C(name, _init_set)) \
,SET(M_C(name, _set)) \
@@ -109,14 +120,22 @@
SNAPSHOTI_SPSC_FLAGS_CONTRACT(f); \
} while (0)
// Defered evaluation of the arguments.
#define SNAPSHOTI_SPSC_DEF_P1(arg) SNAPSHOTI_SPSC_DEF_P2 arg
// A snapshot is basically an atomic triple buffer (Lock Free)
// between a single producer thread and a single consummer thread.
#define SNAPSHOTI_SPSC_MAX_BUFFER 3
#define SNAPSHOTI_SPSC_DEF_P2(name, type, oplist) \
// Defered evaluation of the arguments.
#define SNAPSHOTI_SPSC_DEF_P1(arg) SNAPSHOTI_SPSC_DEF_P2 arg
/* Validate the oplist before going further */
#define SNAPSHOTI_SPSC_DEF_P2(name, type, oplist) \
M_IF_OPLIST(oplist)(SNAPSHOTI_SPSC_DEF_P3, SNAPSHOTI_SPSC_DEF_FAILURE)(name, type, oplist)
/* Stop processing with a compilation failure */
#define SNAPSHOTI_SPSC_DEF_FAILURE(name, type, oplist) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_SPSC_DEF): the given argument is not a valid oplist: " #oplist)
#define SNAPSHOTI_SPSC_DEF_P3(name, type, oplist) \
\
/* Create an aligned type to avoid false sharing between threads */ \
typedef struct M_C(name, _aligned_type_s) { \
@@ -133,6 +152,8 @@
\
typedef type M_C(name, _type_t); \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void M_C(name, _init)(M_C(name, _t) snap) \
{ \
assert(snap != NULL); \
@@ -490,7 +511,15 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in
// Defered evaluation
#define SNAPSHOTI_SPMC_DEF_P1(arg) SNAPSHOTI_SPMC_DEF_P2 arg
#define SNAPSHOTI_SPMC_DEF_P2(name, type, oplist) \
/* Validate the oplist before going further */
#define SNAPSHOTI_SPMC_DEF_P2(name, type, oplist) \
M_IF_OPLIST(oplist)(SNAPSHOTI_SPMC_DEF_P3, SNAPSHOTI_SPMC_DEF_FAILURE)(name, type, oplist)
/* Stop processing with a compilation failure */
#define SNAPSHOTI_SPMC_DEF_FAILURE(name, type, oplist) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_SPMC_DEF): the given argument is not a valid oplist: " #oplist)
#define SNAPSHOTI_SPMC_DEF_P3(name, type, oplist) \
\
/* Create an aligned type to avoid false sharing between threads */ \
typedef struct M_C(name, _aligned_type_s) { \
@@ -505,6 +534,8 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in
\
typedef type M_C(name, _type_t); \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
static inline void M_C(name, _init)(M_C(name, _t) snap, size_t nReader) \
{ \
assert (snap != NULL); \
@@ -579,7 +610,15 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in
// Defered evaluation
#define SNAPSHOTI_MPMC_DEF_P1(arg) SNAPSHOTI_MPMC_DEF_P2 arg
#define SNAPSHOTI_MPMC_DEF_P2(name, type, oplist) \
/* Validate the oplist before going further */
#define SNAPSHOTI_MPMC_DEF_P2(name, type, oplist) \
M_IF_OPLIST(oplist)(SNAPSHOTI_MPMC_DEF_P3, SNAPSHOTI_MPMC_DEF_FAILURE)(name, type, oplist)
/* Stop processing with a compilation failure */
#define SNAPSHOTI_MPMC_DEF_FAILURE(name, type, oplist) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_MPMC_DEF): the given argument is not a valid oplist: " #oplist)
#define SNAPSHOTI_MPMC_DEF_P3(name, type, oplist) \
\
SNAPSHOTI_SPMC_DEF_P1((M_C(name, _mrsw), type, oplist)) \
\
@@ -589,6 +628,8 @@ static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned in
\
typedef type M_C(name, _type_t); \
\
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
\
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 ); \
+241 -19
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - Dynamic Size String Module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
@@ -81,21 +81,29 @@ typedef union string_union_u {
string_heap_t heap;
string_stack_t stack;
} string_union_t;
// main structure
// Dynamic string
typedef struct string_s {
string_union_t u;
char *ptr;
} string_t[1];
// Pointer to a Dynamic string
typedef struct string_s *string_ptr;
// Constant pointer to a Dynamic string
typedef const struct string_s *string_srcptr;
/* Input option for the fgets function */
/* Input option for string_fgets
STRING_READ_LINE (read line),
STRING_READ_PURE_LINE (read line and remove CR and LF)
STRING_READ_FILE (read all file)
*/
typedef enum string_fgets_s {
STRING_READ_LINE = 0, STRING_READ_PURE_LINE = 1, STRING_READ_FILE = 2
} string_fgets_t;
/* Test if the string is stack based or heap based */
/* Internal method to test if the string is stack based or heap based */
static inline bool
stringi_stack_p(const string_t s)
{
@@ -115,6 +123,7 @@ stringi_set_size(string_t s, size_t size)
s->u.heap.size = size;
}
/* Return the number of characters of the string */
static inline size_t
string_size(const string_t s)
{
@@ -125,6 +134,7 @@ string_size(const string_t s)
return stringi_stack_p(s) ? s_stack : s_heap;
}
/* Return the capacity of the string */
static inline size_t
string_capacity(const string_t s)
{
@@ -145,6 +155,7 @@ stringi_get_str(string_t v)
return stringi_stack_p(v) ? ptr_stack : ptr_heap;
}
/* Return the string view a classic C string (const char *) */
static inline const char*
string_get_cstr(const string_t v)
{
@@ -155,6 +166,8 @@ string_get_cstr(const string_t v)
return stringi_stack_p(v) ? ptr_stack : ptr_heap;
}
/* Initialize the dynamic string (constructor)
and make it empty */
static inline void
string_init(string_t s)
{
@@ -164,6 +177,7 @@ string_init(string_t s)
STRINGI_CONTRACT(s);
}
/* Clear the Dynamic string (destructor) */
static inline void
string_clear(string_t v)
{
@@ -180,8 +194,10 @@ string_clear(string_t v)
/* NOTE: Internaly used by STRING_DECL_INIT */
static inline void stringi_clear2(string_t *v) { string_clear(*v); }
/* NOTE: The ownership of the data is transfered back to the caller
and the returned pointer has to be released by M_MEMORY_FREE. */
/* Clear the Dynamic string (destructor)
and return a heap pointer to the string.
The ownership of the data is transfered back to the caller
and the returned pointer has to be released by M_MEMORY_FREE. */
static inline char *
string_clear_get_str(string_t v)
{
@@ -206,6 +222,7 @@ string_clear_get_str(string_t v)
return p;
}
/* Make the string empty */
static inline void
string_clean(string_t v)
{
@@ -215,6 +232,7 @@ string_clean(string_t v)
STRINGI_CONTRACT (v);
}
/* Return the selected character of the string */
static inline char
string_get_char(const string_t v, size_t index)
{
@@ -223,6 +241,7 @@ string_get_char(const string_t v, size_t index)
return string_get_cstr(v)[index];
}
/* Test if the string is empty or not */
static inline bool
string_empty_p(const string_t v)
{
@@ -254,7 +273,7 @@ stringi_fit2size (string_t v, size_t size_alloc)
char *ptr = M_MEMORY_REALLOC (char, v->ptr, alloc);
if (M_UNLIKELY (ptr == NULL)) {
M_MEMORY_FULL(sizeof (char) * alloc);
// NOTE: Return is broken...
// NOTE: Return is currently broken.
abort();
return NULL;
}
@@ -270,6 +289,8 @@ stringi_fit2size (string_t v, size_t size_alloc)
return stringi_get_str(v);
}
/* Modify the string capacity to be able to handle at least 'alloc'
characters (including final nul char) */
static inline void
string_reserve(string_t v, size_t alloc)
{
@@ -304,6 +325,7 @@ string_reserve(string_t v, size_t alloc)
STRINGI_CONTRACT (v);
}
/* Set the string to the C string str */
static inline void
string_set_str(string_t v, const char str[])
{
@@ -316,6 +338,7 @@ string_set_str(string_t v, const char str[])
STRINGI_CONTRACT (v);
}
/* Set the string to the n first characters of the C string str */
static inline void
string_set_strn(string_t v, const char str[], size_t n)
{
@@ -330,6 +353,7 @@ string_set_strn(string_t v, const char str[], size_t n)
STRINGI_CONTRACT (v);
}
/* Set the string to the other one */
static inline void
string_set (string_t v1, const string_t v2)
{
@@ -344,6 +368,7 @@ string_set (string_t v1, const string_t v2)
STRINGI_CONTRACT (v1);
}
/* Set the string to the n first characters of other one */
static inline void
string_set_n(string_t v, const string_t ref, size_t offset, size_t length)
{
@@ -358,6 +383,8 @@ string_set_n(string_t v, const string_t ref, size_t offset, size_t length)
STRINGI_CONTRACT (v);
}
/* Initialize the string and set it to the other one
(constructor) */
static inline void
string_init_set(string_t v1, const string_t v2)
{
@@ -365,6 +392,8 @@ string_init_set(string_t v1, const string_t v2)
string_set(v1,v2);
}
/* Initialize the string and set it to the C string
(constructor) */
static inline void
string_init_set_str(string_t v1, const char str[])
{
@@ -372,6 +401,9 @@ string_init_set_str(string_t v1, const char str[])
string_set_str(v1, str);
}
/* Initialize the string, set it to the other one,
and destroy the other one.
(constructor & destructor) */
static inline void
string_init_move(string_t v1, string_t v2)
{
@@ -382,6 +414,7 @@ string_init_move(string_t v1, string_t v2)
STRINGI_CONTRACT (v1);
}
/* Swap the string */
static inline void
string_swap(string_t v1, string_t v2)
{
@@ -394,6 +427,9 @@ string_swap(string_t v1, string_t v2)
STRINGI_CONTRACT (v2);
}
/* Set the string to the other one,
and destroy the other one.
(destructor) */
static inline void
string_move(string_t v1, string_t v2)
{
@@ -401,6 +437,7 @@ string_move(string_t v1, string_t v2)
string_init_move(v1,v2);
}
/* Push a character in a string */
static inline void
string_push_back (string_t v, char c)
{
@@ -413,6 +450,7 @@ string_push_back (string_t v, char c)
STRINGI_CONTRACT (v);
}
/* Concatene the string with the C string */
static inline void
string_cat_str(string_t v, const char str[])
{
@@ -426,6 +464,7 @@ string_cat_str(string_t v, const char str[])
STRINGI_CONTRACT (v);
}
/* Concatene the string with the other string */
static inline void
string_cat(string_t v, const string_t v2)
{
@@ -442,6 +481,8 @@ string_cat(string_t v, const string_t v2)
STRINGI_CONTRACT (v);
}
/* Compare the string to the C string and
return the sort order (-1 if less, 0 if equal, 1 if greater) */
static inline int
string_cmp_str(const string_t v1, const char str[])
{
@@ -450,6 +491,8 @@ string_cmp_str(const string_t v1, const char str[])
return strcmp(string_get_cstr(v1), str);
}
/* Compare the string to the other string and
return the sort order (-1 if less, 0 if equal, 1 if greater) */
static inline int
string_cmp(const string_t v1, const string_t v2)
{
@@ -458,6 +501,7 @@ string_cmp(const string_t v1, const string_t v2)
return strcmp(string_get_cstr(v1), string_get_cstr(v2));
}
/* Test if the string is equal to the given C string */
static inline bool
string_equal_str_p(const string_t v1, const char str[])
{
@@ -466,6 +510,7 @@ string_equal_str_p(const string_t v1, const char str[])
return string_cmp_str(v1, str) == 0;
}
/* Test if the string is equal to the other string */
static inline bool
string_equal_p(const string_t v1, const string_t v2)
{
@@ -475,16 +520,20 @@ string_equal_p(const string_t v1, const string_t v2)
*/
assert(v1 != NULL);
assert(v2 != NULL);
/* Optimization: both strings shall have at least the same size */
return string_size(v1) == string_size(v2) && string_cmp(v1, v2) == 0;
}
// Note: doesn't work with UTF-8 strings...
/* Test if the string is equal to the C string
(case insentive according to the current locale)
Note: doesn't work with UTF-8 strings.
*/
static inline int
string_cmpi_str(const string_t v1, const char p2[])
{
STRINGI_CONTRACT (v1);
M_ASSUME (p2 != NULL);
// strcasecmp is POSIX
// strcasecmp is POSIX only
const char *p1 = string_get_cstr(v1);
int c1, c2;
do {
@@ -497,12 +546,21 @@ string_cmpi_str(const string_t v1, const char p2[])
return c1 - c2;
}
/* Test if the string is equal to the other string
(case insentive according to the current locale)
Note: doesn't work with UTF-8 strings.
*/
static inline int
string_cmpi(const string_t v1, const string_t v2)
{
return string_cmpi_str(v1, string_get_cstr(v2));
}
/* Search for the position of the character c
from the position 'start' (include) in the string
Return STRING_FAILURE if not found.
By default, start is zero.
*/
static inline size_t
string_search_char (const string_t v, char c, size_t start)
{
@@ -513,6 +571,11 @@ string_search_char (const string_t v, char c, size_t start)
return p == NULL ? STRING_FAILURE : (size_t) (p-string_get_cstr(v));
}
/* Reverse Search for the position of the character c
from the position 'start' (include) in the string
Return STRING_FAILURE if not found.
By default, start is zero.
*/
static inline size_t
string_search_rchar (const string_t v, char c, size_t start)
{
@@ -526,6 +589,9 @@ string_search_rchar (const string_t v, char c, size_t start)
return p == NULL ? STRING_FAILURE : (size_t) (p-string_get_cstr(v));
}
/* Search for the sub C string in the string from the position start
Return STRING_FAILURE if not found.
By default, start is zero. */
static inline size_t
string_search_str (const string_t v, const char str[], size_t start)
{
@@ -537,6 +603,9 @@ string_search_str (const string_t v, const char str[], size_t start)
return p == NULL ? STRING_FAILURE : (size_t) (p-string_get_cstr(v));
}
/* Search for the sub other string v2 in the string v1 from the position start
Return STRING_FAILURE if not found.
By default, start is zero. */
static inline size_t
string_search (const string_t v1, const string_t v2, size_t start)
{
@@ -545,6 +614,10 @@ string_search (const string_t v1, const string_t v2, size_t start)
return string_search_str(v1, string_get_cstr(v2), start);
}
/* Search for the first matching character in the given C string
in the string v1 from the position start
Return STRING_FAILURE if not found.
By default, start is zero. */
static inline size_t
string_search_pbrk(const string_t v1, const char first_of[], size_t start)
{
@@ -556,6 +629,7 @@ string_search_pbrk(const string_t v1, const char first_of[], size_t start)
return p == NULL ? STRING_FAILURE : (size_t) (p-string_get_cstr(v1));
}
/* Compare the string to the C string using strcoll */
static inline int
string_strcoll_str(const string_t v, const char str[])
{
@@ -563,6 +637,7 @@ string_strcoll_str(const string_t v, const char str[])
return strcoll(string_get_cstr(v), str);
}
/* Compare the string to the other string using strcoll */
static inline int
string_strcoll (const string_t v1, const string_t v2)
{
@@ -570,6 +645,8 @@ string_strcoll (const string_t v1, const string_t v2)
return string_strcoll_str(v1, string_get_cstr(v2));
}
/* Return the number of bytes of the segment of s
that consists entirely of bytes in accept */
static inline size_t
string_spn(const string_t v1, const char accept[])
{
@@ -578,6 +655,8 @@ string_spn(const string_t v1, const char accept[])
return strspn(string_get_cstr(v1), accept);
}
/* Return the number of bytes of the segment of s
that consists entirely of bytes not in reject */
static inline size_t
string_cspn(const string_t v1, const char reject[])
{
@@ -586,6 +665,7 @@ string_cspn(const string_t v1, const char reject[])
return strcspn(string_get_cstr(v1), reject);
}
/* Return the string left truncated to the first 'index' bytes */
static inline void
string_left(string_t v, size_t index)
{
@@ -598,7 +678,7 @@ string_left(string_t v, size_t index)
STRINGI_CONTRACT (v);
}
// Note: this is an index, not the size to keep from the right !
/* Return the string right truncated from the 'index' position to the last position */
static inline void
string_right(string_t v, size_t index)
{
@@ -617,6 +697,7 @@ string_right(string_t v, size_t index)
STRINGI_CONTRACT (v);
}
/* Return the string from position index to size bytes */
static inline void
string_mid (string_t v, size_t index, size_t size)
{
@@ -624,6 +705,9 @@ string_mid (string_t v, size_t index, size_t size)
string_left(v, size);
}
/* Return in the string the C string str1 into the C string str2 from start
By default, start is zero.
*/
static inline size_t
string_replace_str (string_t v, const char str1[], const char str2[], size_t start)
{
@@ -646,6 +730,9 @@ string_replace_str (string_t v, const char str1[], const char str2[], size_t sta
return i;
}
/* Return in the string the string str1 into the string str2 from start
By default, start is zero.
*/
static inline size_t
string_replace (string_t v, const string_t v1, const string_t v2, size_t start)
{
@@ -655,6 +742,8 @@ string_replace (string_t v, const string_t v1, const string_t v2, size_t start)
return string_replace_str(v, string_get_cstr(v1), string_get_cstr(v2), start);
}
/* Replace tin the string the sub-string at position 'pos' for 'len' bytes
into the C string str2. */
static inline void
string_replace_at (string_t v, size_t pos, size_t len, const char str2[])
{
@@ -677,6 +766,7 @@ string_replace_at (string_t v, size_t pos, size_t len, const char str2[])
STRINGI_CONTRACT (v);
}
/* Format in the string the given printf format */
static inline int
string_printf (string_t v, const char format[], ...)
{
@@ -706,6 +796,7 @@ string_printf (string_t v, const char format[], ...)
return size;
}
/* Append to the string the formatted string of the given printf format */
static inline int
string_cat_printf (string_t v, const char format[], ...)
{
@@ -740,6 +831,7 @@ string_cat_printf (string_t v, const char format[], ...)
return size;
}
/* Get a line/pureline/file from the FILE and store it in the string */
static inline bool
string_fgets(string_t v, FILE *f, string_fgets_t arg)
{
@@ -774,6 +866,10 @@ string_fgets(string_t v, FILE *f, string_fgets_t arg)
return retcode; /* Abnormal terminaison */
}
/* Get a word from the FILE and store it in the string.
Words are supposed to be separated each other by the given list of separator
separator shall be a CONSTANT C array.
*/
static inline bool
string_fget_word (string_t v, const char separator[], FILE *f)
{
@@ -827,6 +923,7 @@ string_fget_word (string_t v, const char separator[], FILE *f)
return retcode;
}
/* Put the string in the given FILE without formatting */
static inline bool
string_fputs(FILE *f, const string_t v)
{
@@ -835,6 +932,7 @@ string_fputs(FILE *f, const string_t v)
return fputs(string_get_cstr(v), f) >= 0;
}
/* Test if the string starts with the given C string */
static inline bool
string_start_with_str_p(const string_t v, const char str[])
{
@@ -850,6 +948,7 @@ string_start_with_str_p(const string_t v, const char str[])
return true;
}
/* Test if the string starts with the other string */
static inline bool
string_start_with_string_p(const string_t v, const string_t v2)
{
@@ -857,6 +956,7 @@ string_start_with_string_p(const string_t v, const string_t v2)
return string_start_with_str_p (v, string_get_cstr(v2));
}
/* Test if the string ends with the C string */
static inline bool
string_end_with_str_p(const string_t v, const char str[])
{
@@ -874,6 +974,7 @@ string_end_with_str_p(const string_t v, const char str[])
return true;
}
/* Test if the string ends with the other string */
static inline bool
string_end_with_string_p(const string_t v, const string_t v2)
{
@@ -881,6 +982,7 @@ string_end_with_string_p(const string_t v, const string_t v2)
return string_end_with_str_p (v, string_get_cstr(v2));
}
/* Compute a hash for the string */
static inline size_t
string_hash(const string_t v)
{
@@ -899,6 +1001,8 @@ stringi_strim_char(char c, const char charac[])
return false;
}
/* Remove any characters from charac that are present
in the begining of the string and the end of the string. */
static inline void
string_strim(string_t v, const char charac[])
{
@@ -920,12 +1024,14 @@ string_strim(string_t v, const char charac[])
STRINGI_CONTRACT (v);
}
/* Test if the string is equal to the OOR value */
static inline bool
string_oor_equal_p(const string_t s, unsigned char n)
{
return (s->ptr == NULL) & (s->u.heap.alloc == ~(size_t)n);
}
/* Set the unitialized string to the OOR value */
static inline void
string_oor_set(string_t s, unsigned char n)
{
@@ -938,6 +1044,9 @@ string_oor_set(string_t s, unsigned char n)
Replace " by \" within the string (and \ to \\)
\n, \t & \r by their standard representation
and other not printable character with \0xx */
/* Transform the string 'v2' into a formatted string
and set it to (or append in) the string 'v'. */
static inline void
string_get_str(string_t v, const string_t v2, bool append)
{
@@ -988,6 +1097,8 @@ string_get_str(string_t v, const string_t v2, bool append)
STRINGI_CONTRACT (v);
}
/* Transform the string 'v2' into a formatted string
and output it in the given FILE */
static inline void
string_out_str(FILE *f, const string_t v)
{
@@ -1022,6 +1133,9 @@ string_out_str(FILE *f, const string_t v)
fputc('"', f);
}
/* Read the formatted string from the FILE
and set the converted value in the string 'v'.
Return true in case of success */
static inline bool
string_in_str(string_t v, FILE *f)
{
@@ -1066,6 +1180,11 @@ string_in_str(string_t v, FILE *f)
return c == '"';
}
/* Read the formatted string from the C string
and set the converted value in the string 'v'.
Return true in case of success
If endptr is not null, update the position of the parsing.
*/
static inline bool
string_parse_str(string_t v, const char str[], const char **endptr)
{
@@ -1114,6 +1233,10 @@ string_parse_str(string_t v, const char str[], const char **endptr)
return success;
}
/* Transform the string 'v2' into a formatted string
and output it in the given serializer
See serialization for return code.
*/
static inline m_serial_return_code_t
string_out_serial(m_serial_write_t serial, const string_t v)
{
@@ -1121,6 +1244,10 @@ string_out_serial(m_serial_write_t serial, const string_t v)
return serial->m_interface->write_string(serial, string_get_cstr(v));
}
/* Read the formatted string from the serializer
and set the converted value in the string 'v'.
See serialization for return code.
*/
static inline m_serial_return_code_t
string_in_serial(string_t v, m_serial_read_t serial)
{
@@ -1128,7 +1255,7 @@ string_in_serial(string_t v, m_serial_read_t serial)
return serial->m_interface->read_string(serial, v);
}
/* UTF8 Handling */
/* State of the UTF8 decoding machine state */
typedef enum {
STRINGI_UTF8_STARTING = 0,
STRINGI_UTF8_DECODING_1 = 8,
@@ -1137,7 +1264,10 @@ typedef enum {
STRINGI_UTF8_ERROR = 32
} stringi_utf8_state_e;
/* An unicode value */
typedef unsigned int string_unicode_t;
/* Error in case of decoding */
#define STRING_UNICODE_ERROR (-1U)
/* UTF8 character classification:
@@ -1158,7 +1288,8 @@ typedef unsigned int string_unicode_t;
* 3|I2IIIIII
* I|IIIIIIII
*/
/* The use of a string allows the compiler/linker to factorize it. */
/* The use of a string enables the compiler/linker to factorize it. */
#define STRINGI_UTF8_STATE_TAB \
"\000\040\010\020\030\040\040\040" \
"\040\000\040\040\040\040\040\040" \
@@ -1266,6 +1397,30 @@ string_it(string_it_t it, const string_t str)
it->u = 0;
}
/* Set the iterator to the end of string
The iterator references therefore nothong.
*/
static inline void
string_it_end(string_it_t it, const string_t str)
{
STRINGI_CONTRACT(str);
assert(it != NULL);
it->ptr = &string_get_cstr(str)[string_size(str)];
it->next_ptr = 0;
it->u = 0;
}
/* Set the iterator to the same position than the other one */
static inline void
string_it_set(string_it_t it, const string_it_t itsrc)
{
assert(it != NULL && itsrc != NULL);
it->ptr = itsrc->ptr;
it->next_ptr = itsrc->next_ptr;
it->u = itsrc->u;
}
/* Test if the iterator has reached the end of the string */
static inline bool
string_end_p (string_it_t it)
{
@@ -1284,6 +1439,17 @@ string_end_p (string_it_t it)
return false;
}
/* Test if the iterator is equal to the other one */
static inline bool
string_it_equal_p(const string_it_t it1, const string_it_t it2)
{
assert(it1 != NULL && it2 != NULL);
// IT1.ptr == IT2.ptr ==> IT1 == IT2 ==> All fields are equal
assert(it1->ptr != it2->ptr || (it1->next_ptr == it2->next_ptr && it1->u == it2->u));
return it1->ptr == it2->ptr;
}
/* Advance the iterator to the next UTF8 unicode character */
static inline void
string_next (string_it_t it)
{
@@ -1291,6 +1457,7 @@ string_next (string_it_t it)
it->ptr = it->next_ptr;
}
/* Return the unicode value associated to the iterator */
static inline string_unicode_t
string_get_cref (const string_it_t it)
{
@@ -1298,6 +1465,14 @@ string_get_cref (const string_it_t it)
return it->u;
}
/* Return the unicode value associated to the iterator */
static inline const string_unicode_t *
string_cref (const string_it_t it)
{
assert (it != NULL);
return &it->u;
}
/* Push unicode into string, encoding it in UTF8 */
static inline void
string_push_u (string_t str, string_unicode_t u)
@@ -1383,10 +1558,11 @@ string_utf8_p(string_t str)
.ptr = s}})
which produces faster code.
Note: This code doesn't work with C++ (use of c99 feature
of recursive struct definition). As such, there is a separate
C++ definition.
of recursive struct definition and compound literral).
As such, there is a separate C++ definition.
*/
#ifndef __cplusplus
/* Initialize a constant string with the given C string */
# define STRING_CTE(s) \
((const string_t){{.u.heap = { .size = sizeof(s)-1, .alloc = sizeof(s) } , \
.ptr = ((struct { long long _n; char _d[sizeof (s)]; }){ 0, s })._d }})
@@ -1408,17 +1584,34 @@ namespace m_string {
}
};
}
/* Initialize a constant string with the given C string (C++ mode) */
#define STRING_CTE(s) \
m_string::m_aligned_string<sizeof (s)>(s).string
#endif
#define STRING_INIT_PRINTF(v, ...) \
/* Initialize and set a string to the given formatted value. */
#define STRINGI_INIT_PRINTF(v, ...) \
(string_init (v), string_printf (v, __VA_ARGS__) )
/* NOTE: Use GCC extension FIXME: To keep? */
/* Initialize a string with the given list of arguments.
Check if it is a formatted input or not by counting the number of arguments.
If there is only one argument, it can only be a set to C string.
It is much faster in this case to call string_init_set_str.
In C11 mode, it uses the fact that string_init_set is overloaded to handle both
C string and string. */
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
#define STRINGI_INIT_WITH(v, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__)(string_init_set, STRINGI_INIT_PRINTF)(v, __VA_ARGS__)
#else
#define STRINGI_INIT_WITH(v, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__)(string_init_set_str, STRINGI_INIT_PRINTF)(v, __VA_ARGS__)
#endif
/* NOTE: Use GCC extension (OBSOLETE) */
#define STRING_DECL_INIT(v) \
string_t v __attribute__((cleanup(stringi_clear2))) = {{ 0, 0, NULL}}
/* NOTE: Use GCC extension (OBSOLETE) */
#define STRING_DECL_INIT_PRINTF(v, format, ...) \
STRING_DECL_INIT(v); \
string_printf (v, format, __VA_ARGS__)
@@ -1427,7 +1620,7 @@ namespace m_string {
/* Define the OPLIST of a STRING */
#define STRING_OPLIST \
(INIT(string_init),INIT_SET(string_init_set), SET(string_set), \
INIT_WITH(STRING_INIT_PRINTF), \
INIT_WITH(STRINGI_INIT_WITH), \
INIT_MOVE(string_init_move), MOVE(string_move), \
SWAP(string_swap), CLEAN(string_clean), \
TEST_EMPTY(string_empty_p), \
@@ -1438,6 +1631,15 @@ namespace m_string {
OUT_SERIAL(string_out_serial), IN_SERIAL(string_in_serial), \
EXT_ALGO(STRING_SPLIT), \
OOR_EQUAL(string_oor_equal_p), OOR_SET(string_oor_set) \
,SUBTYPE(string_unicode_t) \
,IT_TYPE(string_it_t) \
,IT_FIRST(string_it) \
,IT_END(string_it_end) \
,IT_SET(string_it_set) \
,IT_END_P(string_end_p) \
,IT_EQUAL_P(string_it_equal_p) \
,IT_NEXT(string_next) \
,IT_CREF(string_cref) \
)
/* Register the OPLIST as a global one */
@@ -1445,27 +1647,36 @@ namespace m_string {
/* Macro encapsulation to give a default value of 0 for start offset */
/* Search for a character in a string (string, character[, start=0]) */
#define string_search_char(v, ...) \
M_APPLY(string_search_char, v, M_IF_DEFAULT1(0, __VA_ARGS__))
/* Reverse Search for a character in a string (string, character[, start=0]) */
#define string_search_rchar(v, ...) \
M_APPLY(string_search_rchar, v, M_IF_DEFAULT1(0, __VA_ARGS__))
/* Search for a C string in a string (string, c_string[, start=0]) */
#define string_search_str(v, ...) \
M_APPLY(string_search_str, v, M_IF_DEFAULT1(0, __VA_ARGS__))
/* Search for a string in a string (string, string[, start=0]) */
#define string_search(v, ...) \
M_APPLY(string_search, v, M_IF_DEFAULT1(0, __VA_ARGS__))
/* PBRK for a string in a string (string, string[, start=0]) */
#define string_search_pbrk(v, ...) \
M_APPLY(string_search_pbrk, v, M_IF_DEFAULT1(0, __VA_ARGS__))
/* Replace a C string to another C string in a string (string, c_src_string, c_dst_string, [, start=0]) */
#define string_replace_str(v, s1, ...) \
M_APPLY(string_replace_str, v, s1, M_IF_DEFAULT1(0, __VA_ARGS__))
/* Replace a string to another string in a string (string, src_string, dst_string, [, start=0]) */
#define string_replace(v, s1, ...) \
M_APPLY(string_replace, v, s1, M_IF_DEFAULT1(0, __VA_ARGS__))
/* Strim a string from the given set of characters (default is " \n\r\t") */
#define string_strim(...) \
M_APPLY(string_strim, M_IF_DEFAULT1(" \n\r\t", __VA_ARGS__))
@@ -1488,20 +1699,31 @@ namespace m_string {
default : func1 \
)(a,b,c)
#define string_set(a,b) STRINGI_SELECT2(string_set, string_set_str, a, b)
/* Init & Set the string a to the string (or C string) b (constructor) */
#define string_init_set(a,b) STRINGI_SELECT2(string_init_set, string_init_set_str, a, b)
/* Set the string a to the string (or C string) b */
#define string_set(a,b) STRINGI_SELECT2(string_set, string_set_str, a, b)
/* Concatene the string (or C string) b to the string a */
#define string_cat(a,b) STRINGI_SELECT2(string_cat, string_cat_str, a, b)
/* Compare the string a to the string (or C string) b and return the sort order */
#define string_cmp(a,b) STRINGI_SELECT2(string_cmp, string_cmp_str, a, b)
/* Compare for equality the string a to the string (or C string) b */
#define string_equal_p(a,b) STRINGI_SELECT2(string_equal_p, string_equal_str_p, a, b)
/* strcoll the string a to the string (or C string) b */
#define string_strcoll(a,b) STRINGI_SELECT2(string_strcoll, string_strcoll_str, a, b)
#undef string_search
/* Search for a string in a string (or C string) (string, string[, start=0]) */
#define string_search(v, ...) \
M_APPLY(STRINGI_SELECT3, string_search, string_search_str, \
v, M_IF_DEFAULT1(0, __VA_ARGS__))
/* Provide GET_STR method to default type */
/* Internal Macro: Provide GET_STR method to default type */
#undef M_GET_STR_METHOD_FOR_DEFAULT_TYPE
#define M_GET_STR_METHOD_FOR_DEFAULT_TYPE GET_STR(M_GET_STRING_ARG)
+88 -17
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - TUPLE module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
@@ -35,6 +35,7 @@
#define TUPLE_DEF2(name, ...) \
TUPLEI_DEF2_P1( (name, TUPLEI_INJECT_GLOBAL(__VA_ARGS__)) )
/* Define the oplist of a tuple.
USAGE: TUPLE_OPLIST(name[, oplist of the first type, ...]) */
#define TUPLE_OPLIST(...) \
@@ -42,7 +43,8 @@
(TUPLEI_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST )), \
TUPLEI_OPLIST_P1((__VA_ARGS__ )))
/* Return an array suitable for the _cmp_order function.
/* Return an array suitable for the WIP _cmp_order function.
As compound literals are not supported in C++,
provide a separate definition for C++ using initializer_list
(shall be constexpr, but only supported in C++14).
@@ -71,9 +73,18 @@ namespace m_tuple {
/********************************** INTERNAL ************************************/
/* Contract of a tuple. Nothing notable */
#define TUPLEI_CONTRACT(tup) do { \
assert(tup != NULL); \
} while (0)
/* Inject the oplist within the list of arguments */
#define TUPLEI_INJECT_GLOBAL(...) \
M_MAP_C(TUPLEI_INJECT_OPLIST_A, __VA_ARGS__)
/* Transform (x, type) into (x, type, oplist) if there is global registered oplist
or (x, type, M_DEFAULT_OPLIST) if there is no global one,
or keep (x, type, oplist) if oplist was already present */
#define TUPLEI_INJECT_OPLIST_A( duo_or_trio ) \
TUPLEI_INJECT_OPLIST_B duo_or_trio
@@ -83,9 +94,26 @@ namespace m_tuple {
// Deferred evaluation
#define TUPLEI_DEF2_P1(...) TUPLEI_DEF2_P2 __VA_ARGS__
#define TUPLEI_DEF2_P2(name, ...) \
// Test if all third argument of all arguments is an oplist
#define TUPLEI_IF_ALL_OPLIST(...) \
M_IF(M_REDUCE(TUPLEI_IS_OPLIST_P, M_AND, __VA_ARGS__))
// Test if the third argument is an oplist
#define TUPLEI_IS_OPLIST_P(a) \
M_OPLIST_P(M_RET_ARG3 a)
/* Validate the oplist before going further */
#define TUPLEI_DEF2_P2(name, ...) \
TUPLEI_IF_ALL_OPLIST(__VA_ARGS__)(TUPLEI_DEF2_P3, TUPLEI_DEF2_FAILURE)(name, __VA_ARGS__)
/* Stop processing with a compilation failure */
#define TUPLEI_DEF2_FAILURE(name, ...) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(TUPLE_DEF2): at least one of the given argument is not a valid oplist: " #__VA_ARGS__)
/* Define the tuple */
#define TUPLEI_DEF2_P3(name, ...) \
TUPLE_DEFINE_TYPE(name, __VA_ARGS__) \
TUPLE_DEFINE_ENUM(name, __VA_ARGS__) \
TUPLE_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
TUPLEI_IF_ALL(INIT, __VA_ARGS__) \
(TUPLE_DEFINE_INIT(name, __VA_ARGS__),) \
TUPLE_DEFINE_INIT_SET(name, __VA_ARGS__) \
@@ -188,6 +216,12 @@ namespace m_tuple {
#define TUPLE_DEFINE_ENUM_ELE(name, a) \
M_C4(name, _, TUPLE_GET_FIELD a, _value)
#define TUPLE_CONTROL_ALL_OPLIST(name, ...) \
M_MAP2(TUPLE_CONTROL_OPLIST, name, __VA_ARGS__)
#define TUPLE_CONTROL_OPLIST(name, a) \
M_CHECK_COMPATIBLE_OPLIST(name, TUPLE_GET_FIELD a, \
TUPLE_GET_TYPE a, TUPLE_GET_OPLIST a)
#define TUPLE_DEFINE_INIT(name, ...) \
static inline void M_C(name, _init)(M_C(name,_t) my) { \
@@ -199,12 +233,13 @@ namespace m_tuple {
#define TUPLE_DEFINE_INIT_SET(name, ...) \
static inline void M_C(name, _init_set)(M_C(name,_t) my , M_C(name,_t) const org) { \
TUPLEI_CONTRACT(org); \
M_MAP(TUPLE_DEFINE_INIT_SET_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_INIT_SET_FUNC(a) \
TUPLE_CALL_INIT_SET(a, my -> TUPLE_GET_FIELD a , org -> TUPLE_GET_FIELD a );
/* NOTE: More a _init_with method */
#define TUPLE_DEFINE_INIT_SET2(name, ...) \
static inline void M_C(name, _init_set2)(M_C(name,_t) my \
M_MAP(TUPLE_DEFINE_INIT_SET2_PROTO, __VA_ARGS__) \
@@ -220,6 +255,8 @@ namespace m_tuple {
#define TUPLE_DEFINE_SET(name, ...) \
static inline void M_C(name, _set)(M_C(name,_t) my , \
M_C(name,_t) const org) { \
TUPLEI_CONTRACT(my); \
TUPLEI_CONTRACT(org); \
M_MAP(TUPLE_DEFINE_SET_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_SET_FUNC(a) \
@@ -230,6 +267,7 @@ namespace m_tuple {
static inline void M_C(name, _set2)(M_C(name,_t) my \
M_MAP(TUPLE_DEFINE_SET2_PROTO, __VA_ARGS__) \
) { \
TUPLEI_CONTRACT(my); \
M_MAP(TUPLE_DEFINE_SET2_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_SET2_PROTO(a) \
@@ -240,6 +278,7 @@ namespace m_tuple {
#define TUPLE_DEFINE_CLEAR(name, ...) \
static inline void M_C(name, _clear)(M_C(name,_t) my) { \
TUPLEI_CONTRACT(my); \
M_MAP(TUPLE_DEFINE_CLEAR_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_CLEAR_FUNC(a) \
@@ -251,9 +290,11 @@ namespace m_tuple {
#define TUPLE_DEFINE_GETTER_FIELD_PROTO(name, a) \
static inline TUPLE_GET_TYPE a * M_C3(name, _get_at_, TUPLE_GET_FIELD a) \
(M_C(name,_t) my) { \
TUPLEI_CONTRACT(my); \
return &(my->TUPLE_GET_FIELD a);} \
static inline TUPLE_GET_TYPE a const * M_C3(name, _cget_at_, TUPLE_GET_FIELD a) \
(M_C(name,_t) const my) { \
TUPLEI_CONTRACT(my); \
return &(my->TUPLE_GET_FIELD a);}
@@ -262,6 +303,7 @@ namespace m_tuple {
#define TUPLE_DEFINE_SETTER_FIELD_PROTO(name, a) \
static inline void M_C3(name, _set_, TUPLE_GET_FIELD a) \
(M_C(name,_t) my, TUPLE_GET_TYPE a const TUPLE_GET_FIELD a) { \
TUPLEI_CONTRACT(my); \
TUPLE_CALL_SET(a, my ->TUPLE_GET_FIELD a, TUPLE_GET_FIELD a);}
@@ -269,6 +311,8 @@ namespace m_tuple {
static inline int M_C(name, _cmp)(M_C(name,_t) const e1 , \
M_C(name,_t) const e2) { \
int i; \
TUPLEI_CONTRACT(e1); \
TUPLEI_CONTRACT(e2); \
M_MAP(TUPLE_DEFINE_CMP_FUNC , __VA_ARGS__) \
return 0; \
}
@@ -282,6 +326,8 @@ namespace m_tuple {
M_C(name,_t) const e2, \
const int order[]) { \
int i, r; \
TUPLEI_CONTRACT(e1); \
TUPLEI_CONTRACT(e2); \
while ((i=*order++) != 0) { \
switch (i) { \
M_MAP2(TUPLE_DEFINE_CMP_ORDER_FUNC , name, __VA_ARGS__) \
@@ -307,6 +353,8 @@ namespace m_tuple {
#define TUPLE_DEFINE_CMP_FIELD_FUNC(name, field, func_cmp) \
static inline int M_C3(name, _cmp_, field)(M_C(name,_t) const e1 , \
M_C(name,_t) const e2) { \
TUPLEI_CONTRACT(e1); \
TUPLEI_CONTRACT(e2); \
return func_cmp ( e1 -> field , e2 -> field ); \
}
@@ -315,6 +363,8 @@ namespace m_tuple {
static inline bool M_C(name, _equal_p)(M_C(name,_t) const e1 , \
M_C(name,_t) const e2) { \
bool b; \
TUPLEI_CONTRACT(e1); \
TUPLEI_CONTRACT(e2); \
M_MAP(TUPLE_DEFINE_EQUAL_FUNC , __VA_ARGS__) \
return true; \
}
@@ -325,6 +375,7 @@ namespace m_tuple {
#define TUPLE_DEFINE_HASH(name, ...) \
static inline size_t M_C(name, _hash)(M_C(name,_t) const e1) { \
TUPLEI_CONTRACT(e1); \
M_HASH_DECL(hash); \
M_MAP(TUPLE_DEFINE_HASH_FUNC , __VA_ARGS__) \
return M_HASH_FINAL (hash); \
@@ -338,7 +389,8 @@ namespace m_tuple {
M_C(name,_t) const el, \
bool append) { \
bool comma = false; \
assert (str != NULL && el != NULL); \
TUPLEI_CONTRACT(el); \
assert (str != NULL); \
(append ? string_cat_str : string_set_str) (str, "("); \
M_MAP(TUPLE_DEFINE_GET_STR_FUNC , __VA_ARGS__) \
string_push_back (str, ')'); \
@@ -353,7 +405,8 @@ namespace m_tuple {
static inline void M_C(name, _out_str)(FILE *f, \
M_C(name,_t) const el) { \
bool comma = false; \
assert (f != NULL && el != NULL); \
TUPLEI_CONTRACT(el); \
assert (f != NULL); \
fputc('(', f); \
M_MAP(TUPLE_DEFINE_OUT_STR_FUNC , __VA_ARGS__) \
fputc (')', f); \
@@ -367,8 +420,9 @@ namespace m_tuple {
#define TUPLE_DEFINE_IN_STR(name, ...) \
static inline bool M_C(name, _in_str)(M_C(name,_t) el, FILE *f) { \
bool comma = false; \
assert (f != NULL && el != NULL); \
int c = fgetc(f); \
TUPLEI_CONTRACT(el); \
assert (f != NULL); \
int c = fgetc(f); \
if (c != '(') return false; \
M_MAP(TUPLE_DEFINE_IN_STR_FUNC , __VA_ARGS__) \
c = fgetc(f); \
@@ -377,7 +431,7 @@ namespace m_tuple {
#define TUPLE_DEFINE_IN_STR_FUNC(a) \
if (comma) { \
c = fgetc (f); \
if (c != ',' || c == EOF) return false; \
if (c != ',' || c == EOF) return false; \
} \
comma = true; \
if (TUPLE_CALL_IN_STR(a, el -> TUPLE_GET_FIELD a, f) == false) \
@@ -388,10 +442,11 @@ namespace m_tuple {
static inline bool M_C(name, _parse_str)(M_C(name,_t) el, \
const char str[], \
const char **endptr) { \
assert (str != NULL && el != NULL); \
TUPLEI_CONTRACT(el); \
assert (str != NULL); \
bool success = false; \
bool comma = false; \
int c = *str++; \
int c = *str++; \
if (c != '(') goto exit; \
M_MAP(TUPLE_DEFINE_PARSE_STR_FUNC , __VA_ARGS__) \
c = *str++; \
@@ -416,17 +471,18 @@ namespace m_tuple {
static inline m_serial_return_code_t \
M_C(name, _out_serial)(m_serial_write_t f, \
M_C(name,_t) const el) { \
assert (f != NULL && f->m_interface != NULL && el != NULL); \
TUPLEI_CONTRACT(el); \
assert (f != NULL && f->m_interface != NULL); \
const int field_max = M_NARGS(__VA_ARGS__); \
static const char *const field_name[] = \
{ M_REDUCE(TUPLE_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
int index = 0; \
m_serial_local_t local; \
m_serial_return_code_t ret; \
ret = f->m_interface->write_tuple_start(local, f); \
ret = f->m_interface->write_tuple_start(local, f); \
M_MAP(TUPLE_DEFINE_OUT_SERIAL_FUNC , __VA_ARGS__) \
assert( index == field_max); \
ret |= f->m_interface->write_tuple_end(local, f); \
ret |= f->m_interface->write_tuple_end(local, f); \
return ret & M_SERIAL_FAIL; \
}
#define TUPLE_DEFINE_OUT_SERIAL_FUNC(a) \
@@ -434,17 +490,19 @@ namespace m_tuple {
TUPLE_CALL_OUT_SERIAL(a, f, el -> TUPLE_GET_FIELD a); \
index++; \
#define TUPLE_DEFINE_IN_SERIAL(name, ...) \
static inline m_serial_return_code_t \
M_C(name, _in_serial)(M_C(name,_t) el, m_serial_read_t f) { \
assert (f != NULL && el != NULL); \
TUPLEI_CONTRACT(el); \
assert (f != NULL && f->m_interface != NULL); \
int index = -1; \
const int field_max = M_NARGS(__VA_ARGS__); \
static const char *const field_name[] = \
{ M_REDUCE(TUPLE_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
m_serial_local_t local; \
m_serial_return_code_t ret; \
ret = f->m_interface->read_tuple_start(local, f); \
ret = f->m_interface->read_tuple_start(local, f); \
while (ret == M_SERIAL_OK_CONTINUE) { \
ret = f->m_interface->read_tuple_id(local, f, field_name, field_max, &index); \
if (ret == M_SERIAL_OK_CONTINUE) { \
@@ -466,6 +524,7 @@ namespace m_tuple {
#define TUPLE_DEFINE_INIT_MOVE(name, ...) \
static inline void M_C(name, _init_move)(M_C(name,_t) el, M_C(name,_t) org) { \
TUPLEI_CONTRACT(el); \
M_MAP(TUPLE_DEFINE_INIT_MOVE_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_INIT_MOVE_FUNC(a) \
@@ -474,6 +533,7 @@ namespace m_tuple {
#define TUPLE_DEFINE_MOVE(name, ...) \
static inline void M_C(name, _move)(M_C(name,_t) el, M_C(name,_t) org) { \
TUPLEI_CONTRACT(el); \
M_MAP(TUPLE_DEFINE_MOVE_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_MOVE_FUNC(a) \
@@ -482,6 +542,8 @@ namespace m_tuple {
#define TUPLE_DEFINE_SWAP(name, ...) \
static inline void M_C(name, _swap)(M_C(name,_t) el1, M_C(name,_t) el2) { \
TUPLEI_CONTRACT(el1); \
TUPLEI_CONTRACT(el2); \
M_MAP(TUPLE_DEFINE_SWAP_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_SWAP_FUNC(a) \
@@ -490,6 +552,7 @@ namespace m_tuple {
#define TUPLE_DEFINE_CLEAN(name, ...) \
static inline void M_C(name, _clean)(M_C(name,_t) el1) { \
TUPLEI_CONTRACT(el1); \
M_MAP(TUPLE_DEFINE_CLEAN_FUNC , __VA_ARGS__) \
}
#define TUPLE_DEFINE_CLEAN_FUNC(a) \
@@ -508,7 +571,15 @@ namespace m_tuple {
// deferred
#define TUPLEI_OPLIST_P1(arg) TUPLEI_OPLIST_P2 arg
#define TUPLEI_OPLIST_P2(name, ...) \
/* Validate the oplist before going further */
#define TUPLEI_OPLIST_P2(name, ...) \
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(TUPLEI_OPLIST_P3, TUPLEI_OPLIST_FAILURE)(name, __VA_ARGS__)
/* Prepare a clean compilation failure */
#define TUPLEI_OPLIST_FAILURE(name, ...) \
M_LIB_ERROR(ONE_ARGUMENT_OF_TUPLE_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)
#define TUPLEI_OPLIST_P3(name, ...) \
(M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
INIT_SET(M_C(name, _init_set)), \
INIT_WITH(M_C(name, _init_set2)), \
+86 -13
View File
@@ -1,7 +1,7 @@
/*
* M*LIB - VARIANT module
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,6 +36,7 @@
#define VARIANT_DEF2(name, ...) \
VARIANTI_DEF2_P1( (name, VARIANTI_INJECT_GLOBAL(__VA_ARGS__)) )
/* Define the oplist of a variant.
USAGE: VARIANT_OPLIST(name[, oplist of the first type, ...]) */
#define VARIANT_OPLIST(...) \
@@ -46,9 +47,20 @@
/********************************** INTERNAL ************************************/
/* Contract of a variant. */
#define VARIANTI_CONTRACT(name, my) do { \
assert(my != NULL); \
assert(my->type >= M_C(name, _EMPTY)); \
assert(my->type <= (enum M_C(name, _enum)) M_C(name, _MAX_TYPE)); \
} while (0)
/* Inject the oplist within the list of arguments */
#define VARIANTI_INJECT_GLOBAL(...) \
M_MAP_C(VARIANTI_INJECT_OPLIST_A, __VA_ARGS__)
/* Transform (x, type) into (x, type, oplist) if there is global registered oplist
or (x, type, M_DEFAULT_OPLIST) if there is no global one,
or keep (x, type, oplist) if oplist was already present */
#define VARIANTI_INJECT_OPLIST_A( duo_or_trio ) \
VARIANTI_INJECT_OPLIST_B duo_or_trio
@@ -58,8 +70,25 @@
// Deferred evaluation
#define VARIANTI_DEF2_P1(...) VARIANTI_DEF2_P2 __VA_ARGS__
#define VARIANTI_DEF2_P2(name, ...) \
// Test if all third argument of all arguments is an oplist
#define VARIANTI_IF_ALL_OPLIST(...) \
M_IF(M_REDUCE(VARIANTI_IS_OPLIST_P, M_AND, __VA_ARGS__))
// Test if the third argument is an oplist
#define VARIANTI_IS_OPLIST_P(a) \
M_OPLIST_P(M_RET_ARG3 a)
/* Validate the oplist before going further */
#define VARIANTI_DEF2_P2(name, ...) \
VARIANTI_IF_ALL_OPLIST(__VA_ARGS__)(VARIANTI_DEF2_P3, VARIANTI_DEF2_FAILURE)(name, __VA_ARGS__)
/* Stop processing with a compilation failure */
#define VARIANTI_DEF2_FAILURE(name, ...) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(VARIANT_DEF2): at least one of the given argument is not a valid oplist: " #__VA_ARGS__)
/* Define the variant */
#define VARIANTI_DEF2_P3(name, ...) \
VARIANTI_DEFINE_TYPE(name, __VA_ARGS__) \
VARIANTI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
VARIANTI_DEFINE_INIT(name, __VA_ARGS__) \
VARIANTI_DEFINE_CLEAR(name, __VA_ARGS__) \
VARIANTI_DEFINE_INIT_SET(name, __VA_ARGS__) \
@@ -141,6 +170,9 @@
enum M_C(name, _enum) { M_C(name, _EMPTY) \
M_MAP2(VARIANTI_DEFINE_UNION_ELE, name, __VA_ARGS__) \
}; \
enum M_C(name, _enum_max) { \
M_C(name, _MAX_TYPE) = M_NARGS(__VA_ARGS__) \
}; \
typedef struct M_C(name, _s) { \
enum M_C(name, _enum) type; \
union { \
@@ -155,6 +187,13 @@
VARIANTI_GET_TYPE a VARIANTI_GET_FIELD a ;
#define VARIANTI_CONTROL_ALL_OPLIST(name, ...) \
M_MAP2(VARIANTI_CONTROL_OPLIST, name, __VA_ARGS__)
#define VARIANTI_CONTROL_OPLIST(name, a) \
M_CHECK_COMPATIBLE_OPLIST(name, VARIANTI_GET_FIELD a, \
VARIANTI_GET_TYPE a, VARIANTI_GET_OPLIST a)
#define VARIANTI_DEFINE_INIT(name, ...) \
static inline void M_C(name, _init)(M_C(name,_t) my) { \
my->type = M_C(name, _EMPTY); \
@@ -164,6 +203,7 @@
#define VARIANTI_DEFINE_INIT_SET(name, ...) \
static inline void M_C(name, _init_set)(M_C(name,_t) my , \
M_C(name,_t) const org) { \
VARIANTI_CONTRACT(name, org); \
my->type = org->type; \
switch (org->type) { \
case M_C(name, _EMPTY): break; \
@@ -181,6 +221,8 @@
#define VARIANTI_DEFINE_SET(name, ...) \
static inline void M_C(name, _set)(M_C(name,_t) my , \
M_C(name,_t) const org) { \
VARIANTI_CONTRACT(name, my); \
VARIANTI_CONTRACT(name, org); \
if (my->type != org->type) { \
/* Different types: clear previous one and create new */ \
M_C(name, _clear)(my); \
@@ -203,6 +245,7 @@
#define VARIANTI_DEFINE_CLEAR(name, ...) \
static inline void M_C(name, _clear)(M_C(name,_t) my) { \
VARIANTI_CONTRACT(name, my); \
switch (my->type) { \
case M_C(name, _EMPTY): break; \
M_MAP2(VARIANTI_DEFINE_CLEAR_FUNC, name, __VA_ARGS__) \
@@ -218,16 +261,19 @@
#define VARIANTI_DEFINE_TEST_P(name, ...) \
static inline bool M_C(name, _empty_p)(M_C(name,_t) const my) { \
VARIANTI_CONTRACT(name, my); \
return my->type == M_C(name, _EMPTY); \
} \
static inline enum M_C(name, _enum) \
M_C(name, _type)(M_C(name,_t) my) { \
VARIANTI_CONTRACT(name, my); \
return my->type; \
} \
M_MAP2(VARIANTI_DEFINE_TEST_FUNC, name, __VA_ARGS__)
#define VARIANTI_DEFINE_TEST_FUNC(name, a) \
static inline bool \
M_C4(name, _, VARIANTI_GET_FIELD a, _p)(M_C(name,_t) const my) { \
VARIANTI_CONTRACT(name, my); \
return my->type == M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
}
@@ -261,6 +307,7 @@
static inline void \
M_C3(name, _set_, VARIANTI_GET_FIELD a)(M_C(name,_t) my, \
VARIANTI_GET_TYPE a const VARIANTI_GET_FIELD a ) { \
VARIANTI_CONTRACT(name, my); \
if (my->type == M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \
VARIANTI_CALL_SET(a, my -> value. VARIANTI_GET_FIELD a, \
VARIANTI_GET_FIELD a); \
@@ -279,6 +326,7 @@
#define VARIANTI_DEFINE_GETTER_FIELD_FUNC(name, a) \
static inline VARIANTI_GET_TYPE a * \
M_C3(name, _get_, VARIANTI_GET_FIELD a)(M_C(name,_t) my) { \
VARIANTI_CONTRACT(name, my); \
if (my->type != M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \
return NULL; \
} \
@@ -287,6 +335,7 @@
\
static inline VARIANTI_GET_TYPE a const * \
M_C3(name, _cget_, VARIANTI_GET_FIELD a)(M_C(name,_t) const my) { \
VARIANTI_CONTRACT(name, my); \
if (my->type != M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \
return NULL; \
} \
@@ -298,6 +347,8 @@
static inline bool M_C(name, _equal_p)(M_C(name,_t) const e1 , \
M_C(name,_t) const e2) { \
bool b; \
VARIANTI_CONTRACT(name, e1); \
VARIANTI_CONTRACT(name, e2); \
if (e1->type != e2->type) return false; \
switch (e1->type) { \
case M_C(name, _EMPTY): break; \
@@ -316,6 +367,7 @@
#define VARIANTI_DEFINE_HASH(name, ...) \
static inline size_t M_C(name, _hash)(M_C(name,_t) const e1) { \
VARIANTI_CONTRACT(name, e1); \
M_HASH_DECL(hash); \
M_HASH_UP (hash, e1 -> type); \
switch (e1->type) { \
@@ -334,6 +386,7 @@
#define VARIANTI_DEFINE_INIT_MOVE(name, ...) \
static inline void \
M_C(name, _init_move)(M_C(name,_t) el, M_C(name,_t) org) { \
VARIANTI_CONTRACT(name, org); \
el -> type = org -> type; \
switch (el->type) { \
case M_C(name, _EMPTY): break; \
@@ -352,6 +405,8 @@
#define VARIANTI_DEFINE_MOVE(name, ...) \
static inline void \
M_C(name, _move)(M_C(name,_t) el, M_C(name,_t) org) { \
VARIANTI_CONTRACT(name, el); \
VARIANTI_CONTRACT(name, org); \
M_C(name, _clear)(el); \
M_C(name, _init_move)(el , org); \
}
@@ -363,6 +418,7 @@
static inline void \
M_C3(name, _move_, VARIANTI_GET_FIELD a)(M_C(name,_t) my, \
VARIANTI_GET_TYPE a VARIANTI_GET_FIELD a ) { \
VARIANTI_CONTRACT(name, my); \
M_C(name, _clear)(my); \
/* Reinit variable with the given value */ \
my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \
@@ -374,6 +430,8 @@
#define VARIANTI_DEFINE_SWAP(name, ...) \
static inline void \
M_C(name, _swap)(M_C(name,_t) el1, M_C(name,_t) el2) { \
VARIANTI_CONTRACT(name, el1); \
VARIANTI_CONTRACT(name, el2); \
if (el1->type == el2->type) { \
switch (el1->type) { \
case M_C(name, _EMPTY): break; \
@@ -407,7 +465,8 @@
static inline void M_C(name, _get_str)(string_t str, \
M_C(name,_t) const el, \
bool append) { \
assert (str != NULL && el != NULL); \
VARIANTI_CONTRACT(name, el); \
assert (str != NULL); \
void (*func)(string_t, const char *); \
func = append ? string_cat_str : string_set_str; \
switch (el->type) { \
@@ -428,7 +487,8 @@
static inline bool M_C(name, _parse_str)(M_C(name,_t) el, \
const char str[], \
const char **endp) { \
assert (str != NULL && el != NULL); \
VARIANTI_CONTRACT(name, el); \
assert (str != NULL); \
bool success = false; \
char variantTypeBuf[M_MAX_IDENTIFIER_LENGTH+1]; \
int c = *str++; \
@@ -467,7 +527,8 @@
#define VARIANTI_DEFINE_OUT_STR(name, ...) \
static inline void M_C(name, _out_str)(FILE *f, \
M_C(name,_t) const el) { \
assert (f != NULL && el != NULL); \
VARIANTI_CONTRACT(name, el); \
assert (f != NULL); \
switch (el->type) { \
case M_C(name, _EMPTY): fprintf(f, "@EMPTY@"); break; \
M_MAP2(VARIANTI_DEFINE_OUT_STR_FUNC , name, __VA_ARGS__) \
@@ -485,15 +546,16 @@
#define VARIANTI_DEFINE_IN_STR(name, ...) \
static inline bool M_C(name, _in_str)(M_C(name,_t) el, \
FILE *f) { \
assert (f != NULL && el != NULL); \
VARIANTI_CONTRACT(name, el); \
assert (f != NULL); \
char variantTypeBuf[M_MAX_IDENTIFIER_LENGTH+1]; \
M_C(name, _clean)(el); \
if (fgetc(f) != '@') return false; \
/* First read the name of the type */ \
bool b = true; \
int c = fgetc(f); \
int c = fgetc(f); \
unsigned int i = 0; \
while (c != '@' && c != EOF && i < sizeof(variantTypeBuf) - 1) { \
while (c != '@' && c != EOF && i < sizeof(variantTypeBuf) - 1) { \
variantTypeBuf[i++] = c; \
c = fgetc(f); \
} \
@@ -522,10 +584,11 @@
static inline m_serial_return_code_t \
M_C(name, _out_serial)(m_serial_write_t f, \
M_C(name,_t) const el) { \
VARIANTI_CONTRACT(name, el); \
const int field_max = M_NARGS(__VA_ARGS__); \
static const char *const field_name[] = \
{ M_REDUCE(VARIANTI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
assert (f != NULL && f->m_interface != NULL && el != NULL); \
assert (f != NULL && f->m_interface != NULL); \
m_serial_local_t local; \
m_serial_return_code_t ret; \
switch (el->type) { \
@@ -535,7 +598,7 @@
M_MAP2(VARIANTI_DEFINE_OUT_SERIAL_FUNC , name, __VA_ARGS__) \
default: assert(false); break; \
} \
ret |= f->m_interface->write_variant_end(local, f); \
ret |= f->m_interface->write_variant_end(local, f); \
return ret & M_SERIAL_FAIL; \
}
#define VARIANTI_DEFINE_OUT_SERIAL_FUNC(name, a) \
@@ -550,10 +613,11 @@
static inline m_serial_return_code_t \
M_C(name, _in_serial)(M_C(name,_t) el, \
m_serial_read_t f) { \
VARIANTI_CONTRACT(name, el); \
const int field_max = M_NARGS(__VA_ARGS__); \
static const char *const field_name[] = \
{ M_REDUCE(VARIANTI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
assert (f != NULL && f->m_interface != NULL && el != NULL); \
assert (f != NULL && f->m_interface != NULL); \
m_serial_local_t local; \
m_serial_return_code_t ret; \
int id = -1; \
@@ -567,7 +631,7 @@
default: assert(false); break; \
} \
if (ret == M_SERIAL_OK_DONE) \
ret = f->m_interface->read_variant_end(local, f); \
ret = f->m_interface->read_variant_end(local, f); \
return ret; \
}
#define VARIANTI_DEFINE_IN_SERIAL_FUNC(name, a) \
@@ -580,6 +644,7 @@
#define VARIANTI_DEFINE_CLEAN_FUNC(name, ...) \
static inline void M_C(name, _clean)(M_C(name,_t) my) \
{ \
VARIANTI_CONTRACT(name, my); \
M_C(name, _clear)(my); \
M_C(name, _init)(my); \
} \
@@ -588,7 +653,15 @@
// deferred
#define VARIANTI_OPLIST_P1(arg) VARIANTI_OPLIST_P2 arg
#define VARIANTI_OPLIST_P2(name, ...) \
/* Validate the oplist before going further */
#define VARIANTI_OPLIST_P2(name, ...) \
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(VARIANTI_OPLIST_P3, VARIANTI_OPLIST_FAILURE)(name, __VA_ARGS__)
/* Prepare a clean compilation failure */
#define VARIANTI_OPLIST_FAILURE(name, ...) \
M_LIB_ERROR(ONE_ARGUMENT_OF_VARIANT_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)
#define VARIANTI_OPLIST_P3(name, ...) \
(INIT(M_C(name,_init)), \
INIT_SET(M_C(name, _init_set)), \
SET(M_C(name,_set)), \
+102 -62
View File
@@ -1,7 +1,7 @@
/*
* M*LIB / WORKER - Extra worker interface
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
@@ -93,16 +93,16 @@
# error M_USE_WORKER_CPP_FUNCTION and M_USE_WORKER_CLANG_BLOCK are both defined. This is not supported.
#endif
/* This type defines a work order */
/* Definition of a work order */
typedef struct work_order_s {
struct worker_sync_s *block;
void * data;
void (*func) (void *data);
struct worker_sync_s *block; // Reference to the shared Synchronization block
void * data; // The work order data
void (*func) (void *data); // The work order function (for GCC)
#if M_USE_WORKER_CLANG_BLOCK
void (^blockFunc)(void *data);
void (^blockFunc)(void *data); // The work order function (block for clang)
#endif
#if M_USE_WORKER_CPP_FUNCTION
std::function<void(void*)> function;
std::function<void(void*)> function; // The work order function (for C++)
#endif
} worker_order_t;
@@ -111,42 +111,47 @@ typedef struct work_order_s {
* * MACRO to complete the not-used fields
*/
#if M_USE_WORKER_CLANG_BLOCK || M_USE_WORKER_CPP_FUNCTION
# define WORKER_EMPTY_ORDER { NULL, NULL, NULL, NULL }
# define WORKER_EXTRA_ORDER , NULL
# define WORKERI_EMPTY_ORDER { NULL, NULL, NULL, NULL }
# define WORKERI_EXTRA_ORDER , NULL
#else
# define WORKER_EMPTY_ORDER { NULL, NULL, NULL }
# define WORKER_EXTRA_ORDER
# define WORKERI_EMPTY_ORDER { NULL, NULL, NULL }
# define WORKERI_EXTRA_ORDER
#endif
/* As in C++, it uses std::function, M_POD_OPLIST
is not sufficient for initilization of the structure.
is not sufficient for initialization of the structure.
So let's use C++ constructor, destructor and copy constructor */
#if M_USE_WORKER_CPP_FUNCTION
# define WORKER_CPP_INIT(x) (new (&(x)) worker_order_t())
# define WORKER_CPP_INIT_SET(x, y) (new (&(x)) worker_order_t(y))
# define WORKER_CPP_SET(x, y) ((x) = (y))
# define WORKER_CPP_CLEAR(x) ((&(x))->~worker_order_t())
# define WORKER_CPP_INIT_MOVE(x,y) (new (&(x)) worker_order_t(y), ((&(y))->~worker_order_t()))
# define WORKER_OPLIST (INIT(WORKER_CPP_INIT), INIT_SET(WORKER_CPP_INIT_SET), SET(WORKER_CPP_SET), CLEAR(WORKER_CPP_CLEAR),INIT_MOVE(WORKER_CPP_INIT_MOVE) )
# define WORKERI_CPP_INIT(x) (new (&(x)) worker_order_t())
# define WORKERI_CPP_INIT_SET(x, y) (new (&(x)) worker_order_t(y))
# define WORKERI_CPP_SET(x, y) ((x) = (y))
# define WORKERI_CPP_CLEAR(x) ((&(x))->~worker_order_t())
# define WORKERI_CPP_INIT_MOVE(x,y) (new (&(x)) worker_order_t(y), ((&(y))->~worker_order_t()))
# define WORKER_OPLIST \
(INIT(WORKERI_CPP_INIT), INIT_SET(WORKERI_CPP_INIT_SET), \
SET(WORKERI_CPP_SET), CLEAR(WORKERI_CPP_CLEAR), INIT_MOVE(WORKERI_CPP_INIT_MOVE) )
#else
# define WORKER_OPLIST M_POD_OPLIST
#endif
/* This type defines a worker represented as a thread */
/* Definition of a worker (implemented by a thread) */
typedef struct worker_thread_s {
m_thread_t id;
} worker_thread_t;
/* Let's define the queue which will manage all work orders */
BUFFER_DEF(worker_queue, worker_order_t, 0, BUFFER_QUEUE|BUFFER_UNBLOCKING_PUSH|BUFFER_BLOCKING_POP|BUFFER_THREAD_SAFE|BUFFER_DEFERRED_POP, WORKER_OPLIST)
/* Definition of the queue that will record the work orders */
BUFFER_DEF(worker_queue, worker_order_t, 0,
BUFFER_QUEUE|BUFFER_UNBLOCKING_PUSH|BUFFER_BLOCKING_POP|BUFFER_THREAD_SAFE|BUFFER_DEFERRED_POP, WORKER_OPLIST)
/* This type defines the state of the workers */
/* Definition the global pool of workers */
typedef struct worker_s {
/* The work order queue */
worker_queue_t queue_g;
/* The table of workers */
/* The table of available workers */
worker_thread_t *worker;
/* Number of workers in the table */
unsigned int numWorker_g;
/* The global reset function */
@@ -156,15 +161,15 @@ typedef struct worker_s {
void (*clearFunc_g)(void);
m_mutex_t lock;
m_cond_t a_thread_ends;
m_cond_t a_thread_ends; // A worker has ended
} worker_t[1];
/* This type defines a synchronization point for workers */
/* Definition of the synchronization point for workers */
typedef struct worker_sync_s {
atomic_int num_spawn;
atomic_int num_terminated_spawn;
struct worker_s *worker;
atomic_int num_spawn; // Number of spawned workers accord this synchronization point
atomic_int num_terminated_spawn; // Number of terminated spawned workers
struct worker_s *worker; // Reference to the pool of workers
} worker_sync_t[1];
/* Return the number of CPU of the system */
@@ -190,20 +195,27 @@ workeri_get_cpu_count(void)
#endif
}
/* Execute the registered work order synchronously */
// (INTERNAL) Debug support for workers
#if 1
#define WORKERI_DEBUG(...) (void) 0
#else
#define WORKERI_DEBUG(...) printf(__VA_ARGS__)
#endif
/* Execute the registered work order **synchronously** */
static inline void
workeri_exec(worker_order_t *w)
{
assert (w!= NULL && w->block != NULL);
//printf ("Starting thread with data %p\n", w->data);
WORKERI_DEBUG ("Starting thread with data %p\n", w->data);
#if M_USE_WORKER_CLANG_BLOCK
//printf ("Running %s f=%p b=%p\n", (w->func == NULL) ? "Blocks" : "Function", w->func, w->blockFunc);
WORKERI_DEBUG ("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 M_USE_WORKER_CPP_FUNCTION
//printf ("Running %s f=%p b=%p\n", (w->function == NULL) ? "Lambda" : "Function", w->func, w->blockFunc);
WORKERI_DEBUG ("Running %s f=%p b=%p\n", (w->function == NULL) ? "Lambda" : "Function", w->func, w->blockFunc);
if (w->function)
w->function(w->data);
else
@@ -214,29 +226,42 @@ workeri_exec(worker_order_t *w)
}
/* The worker thread */
/* The worker thread main loop*/
static inline void
workeri_thread(void *arg)
{
// Get back the given argument
struct worker_s *g = M_ASSIGN_CAST(struct worker_s *, arg);
while (true) {
worker_order_t w;
if (g->resetFunc_g != NULL)
// If needed, reset the global state of the worker
if (g->resetFunc_g != NULL) {
g->resetFunc_g();
//printf ("Waiting for data (queue: %lu / %lu)\n", worker_queue_size(g->queue_g), worker_queue_capacity(g->queue_g));
}
// Waiting for data
WORKERI_DEBUG ("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);
// We received a work order
// Note: that the work order is still present in the queue
// preventing further work order to be pushed in the queue until it finishes doing the work
// If a stop request is received, terminate the thread
if (w.block == NULL) break;
// Execute the work order
workeri_exec(&w);
// Consumme fully the work order in the queue
worker_queue_pop_release(g->queue_g);
// Signal that a worker has finished.
m_mutex_lock(g->lock);
m_cond_broadcast(g->a_thread_ends);
m_mutex_unlock(g->lock);
}
if (g->clearFunc_g != NULL)
// If needed, clear global state of the thread
if (g->clearFunc_g != NULL) {
g->clearFunc_g();
}
}
/* Initialization of the worker module
/* Initialization of the worker module (constructor)
Input:
@numWorker: number of worker to create (0=autodetect, -1=2*autodetect)
@extraQueue: number of extra work order we can get if all workers are full
@@ -247,54 +272,64 @@ static inline void
worker_init(worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
{
assert (numWorker >= -1);
// Auto compute number of workers if the argument is 0
if (numWorker <= 0)
numWorker = (1 + (numWorker == -1))*workeri_get_cpu_count()-1;
//printf ("Starting queue with: %d\n", numWorker + extraQueue);
worker_queue_init(g->queue_g, numWorker + extraQueue);
WORKERI_DEBUG ("Starting queue with: %d\n", numWorker + extraQueue);
// Initialization
size_t numWorker_st = numWorker;
g->worker = M_MEMORY_REALLOC(worker_thread_t, NULL, numWorker_st);
if (g->worker == NULL) {
M_MEMORY_FULL(sizeof (worker_thread_t) * numWorker_st);
return;
}
worker_queue_init(g->queue_g, numWorker + extraQueue);
g->numWorker_g = numWorker_st;
g->resetFunc_g = resetFunc;
g->clearFunc_g = clearFunc;
m_mutex_init(g->lock);
m_cond_init(g->a_thread_ends);
// Create & start the workers
for(size_t i = 0; i < numWorker_st; i++) {
m_thread_create(g->worker[i].id, workeri_thread, M_ASSIGN_CAST(void*, g));
}
}
// Define function with default values.
/* Initialization of the worker module (constructor)
Input:
@numWorker: number of worker to create (0=autodetect, -1=2*autodetect)
@extraQueue: number of extra work order we can get if all workers are full
@resetFunc: function to reset the state of a worker between work orders (optional)
@clearFunc: function to clear the state of a worker before terminaning (optional)
*/
#define worker_init(...) worker_init(M_DEFAULT_ARGS(5, (0, 0, NULL, NULL), __VA_ARGS__))
/* Clear of the worker module */
/* Clear of the worker module (destructor) */
static inline void
worker_clear(worker_t g)
{
assert (worker_queue_empty_p (g->queue_g));
// Push the terminate order on the queue
for(unsigned int i = 0; i < g->numWorker_g; i++) {
worker_order_t w = WORKER_EMPTY_ORDER;
worker_order_t w = WORKERI_EMPTY_ORDER;
// Normaly all worker threads shall be waiting at this
// stage, so all push won't block as the queue is empty.
// But for robustness, let's wait.
worker_queue_push_blocking (g->queue_g, w, true);
}
// Wait for thread terminanison
for(unsigned int i = 0; i < g->numWorker_g; i++) {
m_thread_join(g->worker[i].id);
}
// Clear memory
M_MEMORY_FREE(g->worker);
m_mutex_clear(g->lock);
m_cond_clear(g->a_thread_ends);
worker_queue_clear(g->queue_g);
}
/* Start a new collaboration between workers
and define the synchronization point 'block' */
/* Start a new collaboration between workers of pool 'g'
by defining the synchronization point 'block' */
static inline void
worker_start(worker_sync_t block, worker_t g)
{
@@ -303,20 +338,23 @@ worker_start(worker_sync_t block, worker_t g)
block->worker = g;
}
/* Spawn or not the given work order to workers,
or do it ourself if no worker is available */
/* Spawn the given work order to workers if possible,
or do it ourself if no worker is available.
The synchronization point is defined a 'block'
The work order if composed of the function 'func' and its 'data'
*/
static inline void
worker_spawn(worker_sync_t block, void (*func)(void *data), void *data)
{
const worker_order_t w = { block, data, func WORKER_EXTRA_ORDER };
const worker_order_t w = { block, data, func WORKERI_EXTRA_ORDER };
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
&& worker_queue_push (block->worker->queue_g, w) == true) {
//printf ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
WORKERI_DEBUG ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
atomic_fetch_add (&block->num_spawn, 1);
return;
}
//printf ("Running data ourself: %p\n", data);
/* No thread available. Call the function ourself */
WORKERI_DEBUG ("Running data ourself: %p\n", data);
/* No worker available. Call the function ourself */
(*func) (data);
}
@@ -329,12 +367,12 @@ worker_spawn_block(worker_sync_t block, void (^func)(void *data), void *data)
const worker_order_t w = { block, data, NULL, func };
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
&& worker_queue_push (block->worker->queue_g, w) == true) {
//printf ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
WORKERI_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
atomic_fetch_add (&block->num_spawn, 1);
return;
}
//printf ("Running data ourself as block: %p\n", data);
/* No thread available. Call the function ourself */
WORKERI_DEBUG ("Running data ourself as block: %p\n", data);
/* No worker available. Call the function ourself */
func (data);
}
#endif
@@ -348,17 +386,17 @@ worker_spawn_function(worker_sync_t block, std::function<void(void *data)> func,
const worker_order_t w = { block, data, NULL, func };
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
&& worker_queue_push (block->worker->queue_g, w) == true) {
//printf ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
WORKERI_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
atomic_fetch_add (&block->num_spawn, 1);
return;
}
//printf ("Running data ourself as block: %p\n", data);
/* No thread available. Call the function ourself */
WORKERI_DEBUG ("Running data ourself as block: %p\n", data);
/* No worker available. Call the function ourself */
func (data);
}
#endif
/* Test if all work orders are finished */
/* Test if all work orders of the given synchronization point are finished */
static inline bool
worker_sync_p(worker_sync_t block)
{
@@ -368,12 +406,14 @@ worker_sync_p(worker_sync_t block)
return (atomic_load(&block->num_spawn) == atomic_load (&block->num_terminated_spawn));
}
/* Wait for all work orders to be finished */
/* Wait for all work orders of the given synchronization point to be finished */
static inline void
worker_sync(worker_sync_t block)
{
//printf ("Waiting for thread terminasion.\n");
WORKERI_DEBUG ("Waiting for thread terminasion.\n");
// Fast case: all workers have finished
if (worker_sync_p(block)) return;
// Slow case: perform a locked wait to put this thread to waiting state
m_mutex_lock(block->worker->lock);
while (!worker_sync_p(block)) {
m_cond_wait(block->worker->a_thread_ends, block->worker->lock);
@@ -381,7 +421,7 @@ worker_sync(worker_sync_t block)
m_mutex_unlock(block->worker->lock);
}
/* Flush any work order in the queue if some remains.*/
/* Flush any work order in the queue ourself if some remains.*/
static inline void
worker_flush(worker_t g)
{
+53
View File
@@ -0,0 +1,53 @@
REM Execute the test suite for Microsoft Visual Studio
REM
REM Load Micosoft Visual Studio environement file.
IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" (
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
)
IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" (
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
)
REM Remove previous results
DEL *.log *.dat
REM List the expected failure (compiler internal error)
set "expectedFailure=test-msnapshot.c"
echo "Compiler full version:"
cl /Bv
echo " "
echo "Disabled tests passed due to wrong errors C4002 C4003 preventing build"
exit /B 0
REM Perform for each test
for %%f in (test-*.c) do (
echo Testing %%f
REM Copy the test file as a C++ file as CL.EXE only support C++ file
copy %%f test.cpp
if ERRORLEVEL 1 EXIT /B 1
REM Compile the test suite
REM /experimental:preprocessor is mandatory to have a compliant preprocessor
REM /Zc:__cplusplus is needed to report the real value of __cplusplus, so that M*LIB uses the C++ atomic, and not its emulation.
echo Compiling %%f
cl.exe /I.. /O2 /std:c++14 /Zc:__cplusplus /experimental:preprocessor test.cpp > %%f.log 2>&1
if ERRORLEVEL 1 (
echo *** BUILD ERROR for %%f *** >> %%f.log
type %%f.log
if /i "%%f" NEQ "%expectedFailure%" EXIT /B 1
)
REM Execute it
echo Running %%f
test.exe >> %%f.log 2>&1
if ERRORLEVEL 1 (
echo *** RUNTIME ERROR for %%f *** >> %%f.log
type %%f.log
if /i "%%f" NEQ "%expectedFailure%" EXIT /B 1
) ELSE (
echo Test OK for %%f >> %%f.log
)
type %%f.log
)
echo "All tests passed (except %expectedFailure%)"
exit /B 0
+37 -15
View File
@@ -1,7 +1,7 @@
CC=cc -std=c99
WCFLAGS_GCC=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -ftrapv
WCFLAGS_CLANG=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -ftrapv
WCFLAGS_CPP=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wstrict-overflow=5 -Winline -Wundef -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wno-unused-function -ftrapv
WCFLAGS_CPP=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wstrict-overflow=5 -Winline -Wundef -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wno-unused-function -ftrapv
XCFLAGS=
CFLAGS=$(WCFLAGS_GCC) $(XCFLAGS)
CPPFLAGS=-I..
@@ -44,7 +44,7 @@ all:
cat $<.first.c $<.middle.c $<.end.c > $<.c
$(CC) $(CPPFLAGS) $(LDFLAGS) -ftest-coverage -fprofile-arcs -g $<.c -o $<.exe
$(LOG_COMPILER) ./$<.exe
gcov $<.gcno > `basename $< .c`.synt
LANG=C gcov $<.gcno > `basename $< .c`.synt
cat `basename $< .c`.synt
mv $<.c.gcov `basename $< .c`.gcov
$(RM) $<.first.c $<.end.c $<.middle.c $<.c $<.exe
@@ -64,7 +64,8 @@ depend:
#####################################################################################################
check: depend
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'`
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'` `ls fail-*.c|$(SED) 's/\.c/\.log/g'`
@echo All tests passed
clean:
$(RM) *.exe *.s *~ *.o *.log a*.dat
@@ -75,6 +76,26 @@ distclean: clean
$(RM) *.depend depend
#####################################################################################################
# Proper failure generation (test if the code properly fails to compile)
#####################################################################################################
# TODO: should grep failure message?
FAIL_BASE=
FAIL_SEQ=
fail-generic.log:
for i in `seq 1 $(FAIL_SEQ)` ; do \
if $(CC) $(CFLAGS) $(CPPFLAGS) -g -c $(FAIL_BASE).c -o tmp.o -DTEST=$$i 2> $(FAIL_BASE)-$$i.log ; then echo $(FAIL_BASE) -- TEST $$i : ERROR; false; else echo $(FAIL_BASE) -- TEST $$i : OK ; fi \
done
fail-no-oplist.log:
@$(MAKE) fail-generic.log FAIL_BASE=fail-no-oplist FAIL_SEQ=44
fail-chain-oplist.log:
@$(MAKE) fail-generic.log FAIL_BASE=fail-chain-oplist FAIL_SEQ=23
fail-incompatible.log:
@$(MAKE) fail-generic.log FAIL_BASE=fail-incompatible FAIL_SEQ=24
#####################################################################################################
# Code generation analysis
#####################################################################################################
@@ -118,6 +139,7 @@ SYNTHESIS_DATA= M-ALGO test-malgo.c.c test-malgo.synt \
M-CORE test-mcore.c.c test-mcore.synt \
M-DEQUE test-mdeque.c.c test-mdeque.synt \
M-DICT test-mdict.c.c test-mdict.synt \
M-FUNCOBJ test-mfuncobj.c.c test-mfuncobj.synt \
M-GENINT ../m-genint.h test-mgenint.synt \
M-I-LIST test-milist.c.c test-milist.synt \
M-LIST test-mlist.c.c test-mlist.synt \
@@ -167,15 +189,15 @@ sanitize:
#####################################################################################################
checkall:
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c99"
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c99 -m32"
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c11"
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c11 -m32"
@if which clang ; then $(MAKE) clean ; $(MAKE) check CC="clang -std=c99" WCFLAGS="$(WCFLAGS_CLANG)" ; else echo "SYSTEM CLANG not found: SKIP TEST" ; fi
@if which g++ ; then $(MAKE) clean ; $(MAKE) check CC="g++ -std=c++11" WCFLAGS="$(WCFLAGS_CPP)" ; else echo "SYSTEM G++ not found: SKIP TEST" ; fi
@if which clang++ ; then $(MAKE) clean ; $(MAKE) check CC="clang++ -std=c++11" WCFLAGS="$(WCFLAGS_CLANG)" ; else echo "SYSTEM CLANG++ not found: SKIP TEST" ; fi
@if which tcc ; then $(MAKE) clean ; $(MAKE) check CC="tcc -std=c99" ; else echo "SYSTEM TCC not found: SKIP TEST" ; fi
@if which musl-gcc ; then $(MAKE) clean ; $(MAKE) check CC="musl-gcc -std=c11" ; else echo "SYSTEM MUSL-GCC not found: SKIP TEST" ; fi
@for f in /opt/gcc* ; do if test -x "$$f/bin/gcc" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/gcc -std=c99" ; fi ; done
@for f in /opt/clang* ; do if test -x "$$f/bin/clang" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/clang -std=c99" WCFLAGS="$(WCFLAGS_CLANG)" ; fi ; done
@for f in /opt/tcc* ; do if test -x "$$f/bin/tcc" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/tcc -std=c99" ; fi ; done
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c99 -Werror"
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c99 -m32 -Werror"
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c11 -Werror"
@$(MAKE) clean ; $(MAKE) check CC="gcc -std=c11 -m32 -Werror"
@if which clang ; then $(MAKE) clean ; $(MAKE) check CC="clang -std=c99 -Werror" CFLAGS="$(WCFLAGS_CLANG)" ; else echo "SYSTEM CLANG not found: SKIP TEST" ; fi
@if which g++ ; then $(MAKE) clean ; $(MAKE) check CC="g++ -std=c++11 -Werror" CFLAGS="$(WCFLAGS_CPP)" ; else echo "SYSTEM G++ not found: SKIP TEST" ; fi
@if which clang++ ; then $(MAKE) clean ; $(MAKE) check CC="clang++ -std=c++11" CFLAGS="$(WCFLAGS_CLANG)" ; else echo "SYSTEM CLANG++ not found: SKIP TEST" ; fi
@if which tcc ; then $(MAKE) clean ; $(MAKE) check CC="tcc -std=c99 -Werror" ; else echo "SYSTEM TCC not found: SKIP TEST" ; fi
@if which musl-gcc ; then $(MAKE) clean ; $(MAKE) check CC="musl-gcc -std=c11 -Werror" ; else echo "SYSTEM MUSL-GCC not found: SKIP TEST" ; fi
@for f in /opt/gcc* ; do if test -x "$$f/bin/gcc" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/gcc -std=c99 -Werror" ; fi ; done
@for f in /opt/clang* ; do if test -x "$$f/bin/clang" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/clang -std=c99 -Werror" CFLAGS="$(WCFLAGS_CLANG)" ; fi ; done
@for f in /opt/tcc* ; do if test -x "$$f/bin/tcc" ; then $(MAKE) clean ; $(MAKE) check CC="$$f/bin/tcc -std=c99 -Werror" ; fi ; done
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
+227
View File
@@ -0,0 +1,227 @@
/*
* Copyright (c) 2017-2020, 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.
*/
/* The goal of this test file is to check that invalid constructs
are properly rejected, and that it generates a helpfull error
message in this case.
It tests invalid oplist in an _OPLIST constructor of a container.
*/
#include "m-core.h"
#if !defined(TEST)
# warning Please define TEST variable to select the test to run
#elif TEST == 1
#include "m-array.h"
ARRAY_DEF(array, int)
ARRAY_DEF(array2, array_t, ARRAY_OPLIST(array, DEFAULT_OPLIST))
#elif TEST == 2
#include "m-list.h"
LIST_DEF(list, int)
LIST_DEF(list2, list_t, LIST_OPLIST(list, DEFAULT_OPLIST))
#elif TEST == 3
#include "m-deque.h"
DEQUE_DEF(deque, int)
DEQUE_DEF(deque2, deque_t, DEQUE_OPLIST(deque, DEFAULT_OPLIST))
#elif TEST == 4
#include "m-bptree.h"
BPTREE_DEF(bptree, 4, int)
BPTREE_DEF(bptree2, 5, bptree_t, BPTREE_OPLIST(bptree, DEFAULT_OPLIST))
#elif TEST == 5
#include "m-bptree.h"
BPTREE_DEF2(bptree, 4, int, int)
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
#elif TEST == 6
#include "m-bptree.h"
BPTREE_DEF2(bptree, 4, int, int)
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, M_DEFAULT_OPLIST, DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
#elif TEST == 7
#include "m-buffer.h"
BUFFER_DEF(buffer, int, 4, BUFFER_THREAD_UNSAFE)
BUFFER_DEF(buffer2, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer, DEFAULT_OPLIST))
#elif TEST == 8
#include "m-array.h"
#include "m-concurrent.h"
ARRAY_DEF(array, int)
CONCURRENT_DEF(array2, array_t, ARRAY_OPLIST(array, M_DEFAULT_OPLIST))
ARRAY_DEF(array3, array2_t, CONCURRENT_OPLIST(array2, ARRAY_OPLIST(array, DEFAULT_OPLIST)))
#elif TEST == 9
#include "m-dict.h"
DICT_DEF2(dict, int, int)
DICT_DEF2(dict2, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict, DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
#elif TEST == 10
#include "m-dict.h"
DICT_DEF2(dict, int, int)
DICT_DEF2(dict2, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict, M_DEFAULT_OPLIST, DEFAULT_OPLIST) )
#elif TEST == 11
#include "m-dict.h"
#include "m-array.h"
DICT_SET_DEF(dict, int)
ARRAY_DEF(array, dict_t, DICT_SET_OPLIST(dict, DEFAULT_OPLIST) )
#elif TEST == 12
#include "m-i-list.h"
#include "m-concurrent.h"
typedef struct tmp_str_s {
ILIST_INTERFACE(tmpstr, struct tmp_str_s);
int n;
} tmp_str_t;
ILIST_DEF(tmpstr, tmp_str_t, (CLEAR(M_NOTHING_DEFAULT)))
CONCURRENT_DEF(array, tmpstr_t, ILIST_OPLIST(tmpstr, X()))
#elif TEST == 13
#include "m-i-shared.h"
#include "m-concurrent.h"
typedef struct tmp_str_s {
ISHARED_PTR_INTERFACE(tmpstr, struct tmp_str_s);
int n;
} tmp_str_t;
ISHARED_PTR_DEF(tmpstr, tmp_str_t, (CLEAR(M_NOTHING_DEFAULT)))
CONCURRENT_DEF(array, tmpstr_t, ISHARED_PTR_OPLIST(tmpstr, X()))
#elif TEST == 14
#include "m-prioqueue.h"
PRIOQUEUE_DEF(prioqueue, int)
PRIOQUEUE_DEF(prioqueue2, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue, M_DEFAULT_OPLIST()))
#elif TEST == 15
#include "m-rbtree.h"
RBTREE_DEF(rbtree, int)
RBTREE_DEF(rbtree2, rbtree_t, RBTREE_OPLIST(rbtree, M_DEFAULT_OPLIST2))
#elif TEST == 16
#include "m-shared.h"
SHARED_PTR_DEF(shared, int)
SHARED_PTR_DEF(shared2, shared_t, SHARED_PTR_OPLIST(shared, M_DEFAULT_OPLISTop))
#elif TEST == 17
#include "m-snapshot.h"
SNAPSHOT_SPSC_DEF(shared, int)
SNAPSHOT_SPSC_DEF(shared2, shared_t, SNAPSHOT_OPLIST(shared, M_DEFAULT_OPLIST x))
#elif TEST == 18
#include "m-tuple.h"
TUPLE_DEF2(aggregate, (x, int), (z, float))
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, DEFAULT_OPLIST, M_DEFAULT_OPLIST)))
#elif TEST == 19
#include "m-tuple.h"
TUPLE_DEF2(aggregate, (x, int), (z, float))
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST() )))
#elif TEST == 20
#include "m-variant.h"
VARIANT_DEF2(aggregate, (x, int), (z, float))
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, DEFAULT_OPLIST, M_DEFAULT_OPLIST)))
#elif TEST == 21
#include "m-variant.h"
VARIANT_DEF2(aggregate, (x, int), (z, float))
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, DEFAULT_OPLIST)))
#elif TEST == 22
#include "m-funcobj.h"
FUNC_OBJ_ITF_DEF(itf, int, int)
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_DEFAULT_OPLIST), (b, int, M_DEFAULT_OPLIST))
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, M_DEFAULT_OPLIST, DEFAULT_OPLIST)
int f(void) {
int r;
M_LET( (f, 1, 2), ins_t)
r = itf_call(ins_as_interface(f), 4);
return r;
}
#elif TEST == 23
#include "m-funcobj.h"
FUNC_OBJ_ITF_DEF(itf, int, int)
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_DEFAULT_OPLIST), (b, int, M_DEFAULT_OPLIST))
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, DEFAULT_OPLIST, M_DEFAULT_OPLIST)
int f(void) {
int r;
M_LET( (f, 1, 2), ins_t)
r = itf_call(ins_as_interface(f), 4);
return r;
}
#else
# warning TEST variable is out of range.
#endif
+263
View File
@@ -0,0 +1,263 @@
/*
* Copyright (c) 2017-2020, 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.
*/
/* The goal of this test file is to check that invalid constructs
are properly rejected, and that it generates a helpfull error
message in this case.
It tests incompatible type and oplist.
*/
#include "m-core.h"
// The test is only robust in C11 mode.
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#if !defined(TEST)
# warning Please define TEST variable to select the test to run
#elif TEST == 1
#include "m-array.h"
ARRAY_DEF(array, int)
ARRAY_DEF(array2, int)
ARRAY_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
#elif TEST == 2
#include "m-list.h"
LIST_DEF(list, int)
LIST_DEF(list2, int)
LIST_DEF(list3, list_t, LIST_OPLIST(list2, M_DEFAULT_OPLIST))
#elif TEST == 3
#include "m-deque.h"
DEQUE_DEF(deque, int)
DEQUE_DEF(deque2, int)
DEQUE_DEF(deque3, deque_t, DEQUE_OPLIST(deque2, M_DEFAULT_OPLIST))
#elif TEST == 4
#include "m-bptree.h"
BPTREE_DEF(bptree, 4, int)
BPTREE_DEF(bptree2, 4, int)
BPTREE_DEF(bptree3, 5, bptree_t, BPTREE_OPLIST(bptree2, M_DEFAULT_OPLIST))
#elif TEST == 5
#include "m-bptree.h"
BPTREE_DEF2(bptree, 4, int, int)
BPTREE_DEF2(bptree2, 4, int, int)
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
#elif TEST == 6
#include "m-bptree.h"
BPTREE_DEF2(bptree, 4, int, int)
BPTREE_DEF2(bptree2, 4, int, int)
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
#elif TEST == 7
#include "m-buffer.h"
BUFFER_DEF(buffer, int, 4, BUFFER_THREAD_UNSAFE)
BUFFER_DEF(buffer2, int, 4, BUFFER_THREAD_UNSAFE)
BUFFER_DEF(buffer3, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer2, M_DEFAULT_OPLIST))
#elif TEST == 8
#include "m-array.h"
#include "m-concurrent.h"
ARRAY_DEF(array, int)
ARRAY_DEF(array2, int)
CONCURRENT_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
#elif TEST == 9
#include "m-dict.h"
DICT_DEF2(dict, int, int)
DICT_DEF2(dict2, int, int)
DICT_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
#elif TEST == 10
#include "m-dict.h"
DICT_STOREHASH_DEF2(dict, int, int)
DICT_STOREHASH_DEF2(dict2, int, int)
DICT_STOREHASH_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
#elif TEST == 11
#include "m-dict.h"
#include "m-array.h"
ARRAY_DEF(array, int)
ARRAY_DEF(array2, int)
DICT_SET_DEF(dict, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST) )
#elif TEST == 12
#include "m-i-list.h"
#include "m-concurrent.h"
typedef struct tmp_str_s {
ILIST_INTERFACE(tmpstr, struct tmp_str_s);
int n;
} tmp_str_t;
ILIST_DEF(tmpstr, tmp_str_t, (TYPE(struct toto), CLEAR(M_NOTHING_DEFAULT)))
#elif TEST == 13
#include "m-i-shared.h"
#include "m-concurrent.h"
typedef struct tmp_str_s {
ISHARED_PTR_INTERFACE(tmpstr, struct tmp_str_s);
int n;
} tmp_str_t;
ISHARED_PTR_DEF(tmpstr, tmp_str_t, (TYPE(struct toto), CLEAR(M_NOTHING_DEFAULT)))
#elif TEST == 14
#include "m-prioqueue.h"
PRIOQUEUE_DEF(prioqueue, int)
PRIOQUEUE_DEF(prioqueue2, int)
PRIOQUEUE_DEF(prioqueue3, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue2, M_DEFAULT_OPLIST ))
#elif TEST == 15
#include "m-rbtree.h"
RBTREE_DEF(rbtree, int)
RBTREE_DEF(rbtree2, int)
RBTREE_DEF(rbtree3, rbtree_t, RBTREE_OPLIST(rbtree2, M_DEFAULT_OPLIST))
#elif TEST == 16
#include "m-shared.h"
SHARED_PTR_DEF(shared, int)
SHARED_PTR_DEF(shared2, int)
SHARED_PTR_DEF(shared3, shared_t, SHARED_PTR_OPLIST(shared2, M_DEFAULT_OPLIST))
#elif TEST == 17
#include "m-snapshot.h"
SNAPSHOT_SPSC_DEF(shared, int)
SNAPSHOT_SPSC_DEF(shared2, int)
SNAPSHOT_SPSC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
#elif TEST == 18
#include "m-snapshot.h"
SNAPSHOT_SPMC_DEF(shared, int)
SNAPSHOT_SPMC_DEF(shared2, int)
SNAPSHOT_SPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
#elif TEST == 19
#include "m-snapshot.h"
SNAPSHOT_MPMC_DEF(shared, int)
SNAPSHOT_MPMC_DEF(shared2, int)
SNAPSHOT_MPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
#elif TEST == 20
#include "m-tuple.h"
TUPLE_DEF2(aggregate, (x, int), (z, float))
TUPLE_DEF2(aggregate2, (x, int), (z, float))
TUPLE_DEF2(struct2,
(a, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
(b, aggregate_t, TUPLE_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
)
#elif TEST == 21
#include "m-tuple.h"
TUPLE_DEF2(aggregate, (x, int), (z, float))
TUPLE_DEF2(aggregate2, (x, int), (z, float))
TUPLE_DEF2(struct2,
(a, aggregate_t, TUPLE_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
(b, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
)
#elif TEST == 22
#include "m-variant.h"
VARIANT_DEF2(aggregate, (x, int), (z, float))
VARIANT_DEF2(aggregate2, (x, int), (z, float))
VARIANT_DEF2(struct2,
(a, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
(b, aggregate_t, VARIANT_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
)
#elif TEST == 23
#include "m-variant.h"
VARIANT_DEF2(aggregate, (x, int), (z, float))
VARIANT_DEF2(aggregate2, (x, int), (z, float))
VARIANT_DEF2(struct2,
(a, aggregate_t, VARIANT_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
(b, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
)
#elif TEST == 24
#include "m-array.h"
#include "m-funcobj.h"
ARRAY_DEF(array, int)
ARRAY_DEF(array2, int)
FUNC_OBJ_ITF_DEF(itf, int, int)
FUNC_OBJ_INS_DEF(ins, itf, (x), {
return x ;
},
(a, array_t, ARRAY_OPLIST(array)),
(b, array_t, ARRAY_OPLIST(array2)))
#else
# warning TEST variable is out of range.
#endif
#else
#error Test shall be run in C11 mode.
#endif
+329
View File
@@ -0,0 +1,329 @@
/*
* Copyright (c) 2017-2020, 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.
*/
/* The goal of this test file is to check that invalid constructs
are properly rejected, and that it generates a helpfull error
message in this case. */
#include "m-core.h"
#if !defined(TEST)
# warning Please define TEST variable to select the test to run
#elif TEST == 1
/* Test of the call to no default function */
#define OP (INIT(init))
void f(int x, int y) {
M_CALL_SWAP(OP, x, y);
}
#elif TEST == 2
void f(int x, int y) {
M_CALL_SET(M_VALID_OPLIST(DEFAULT_OPLIST), x, y);
}
#elif TEST == 3
#include "m-array.h"
ARRAY_DEF(array, int, DEFAULT_OPLIST)
#elif TEST == 4
#include "m-list.h"
LIST_DEF(list, int, DEFAULT_OPLIST)
#elif TEST == 5
#include "m-list.h"
LIST_DUAL_PUSH_DEF(list, int, DEFAULT_OPLIST)
#elif TEST == 6
#include "m-deque.h"
DEQUE_DEF(deque, int, DEFAULT_OPLIST)
#elif TEST == 7
#include "m-i-list.h"
typedef struct tmp_str_s {
ILIST_INTERFACE(tmpstr, struct tmp_str_s);
int n;
} tmp_str_t;
ILIST_DEF(tmpstr, tmp_str_t, DEFAULT_OPLIST)
#elif TEST == 8
#include "m-string.h"
void f(void)
{
M_LET(x, M_STRING_OPLIST) {
}
}
#elif TEST == 9
#include "m-string.h"
typedef string_t my_type;
#define M_OPL_my_type() MSTRING_OPLIST
void f(void)
{
M_LET(x, my_type) {
}
}
#elif TEST == 10
void f(void)
{
M_LET(x, () ) {
}
}
#elif TEST == 11
#include "m-algo.h"
#include "m-array.h"
ARRAY_DEF(array, int)
ALGO_DEF(array, M_ARRAY_OPLIST(array))
#elif TEST == 12
#include "m-algo.h"
#include "m-array.h"
ARRAY_DEF(array, int)
ALGO_DEF(array, (OPLIST(array)))
#elif TEST == 13
#include "m-bptree.h"
BPTREE_DEF2(tree, 4, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
#elif TEST == 14
#include "m-bptree.h"
BPTREE_DEF2(tree, 4, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
#elif TEST == 15
#include "m-bptree.h"
BPTREE_DEF(tree, 4, int, DEFAULT_OPLIST)
#elif TEST == 16
#include "m-bptree.h"
BPTREE_MULTI_DEF2(tree, 4, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
#elif TEST == 17
#include "m-bptree.h"
BPTREE_MULTI_DEF(tree, 4, int, DEFAULT_OPLIST)
#elif TEST == 18
#include "m-buffer.h"
BUFFER_DEF(buffer, int, 0, BUFFER_QUEUE, DEFAULT_OPLIST)
#elif TEST == 19
#include "m-buffer.h"
QUEUE_MPMC_DEF(buffer, int, BUFFER_QUEUE, DEFAULT_OPLIST)
#elif TEST == 20
#include "m-buffer.h"
QUEUE_SPSC_DEF(buffer, int, BUFFER_QUEUE, DEFAULT_OPLIST)
#elif TEST == 21
#include "m-array.h"
#include "m-concurrent.h"
ARRAY_DEF(array, int)
CONCURRENT_DEF(lock_array, array_t, M_ARRAY_OPLIST(array))
#elif TEST == 22
#include "m-array.h"
#include "m-concurrent.h"
ARRAY_DEF(array, int)
CONCURRENT_RP_DEF(lock_array, array_t, MARRAY_OPLIST(array))
#elif TEST == 23
#include "m-dict.h"
DICT_DEF2(array, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
#elif TEST == 24
#include "m-dict.h"
DICT_DEF2(array, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
#elif TEST == 25
#include "m-dict.h"
DICT_STOREHASH_DEF2(array, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
#elif TEST == 26
#include "m-dict.h"
DICT_STOREHASH_DEF2(array, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
#elif TEST == 27
#include "m-dict.h"
DICT_OA_DEF2(array, int, DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
#elif TEST == 28
#include "m-dict.h"
DICT_OA_DEF2(array, int, M_DEFAULT_OPLIST, int, DEFAULT_OPLIST)
#elif TEST == 29
#include "m-dict.h"
DICT_SET_DEF(array, int, DEFAULT_OPLIST)
#elif TEST == 30
#include "m-dict.h"
DICT_OASET_DEF(array, int, DEFAULT_OPLIST)
#elif TEST == 31
#include "m-i-shared.h"
typedef struct tmp_s {
ISHARED_PTR_INTERFACE(tmpi, struct_tmp_s);
const char *s;
} tmp_t;
ISHARED_PTR_DEF(tmpi, tmp_t, NOT_AN_OPLIST)
#elif TEST == 32
#include "m-prioqueue.h"
PRIOQUEUE_DEF(prio, int, DEFAULT_OPLIST)
#elif TEST == 33
#include "m-rbtree.h"
RBTREE_DEF(tree, int, M_DEFAULT_OPLIST() )
#elif TEST == 34
#include "m-shared.h"
SHARED_PTR_DEF(shared, int, M_DEFAULT_OPLIST2 )
#elif TEST == 35
#include "m-shared.h"
SHARED_RESOURCE_DEF(shared, int, M_DEFAULT_OPLIST3 )
#elif TEST == 36
#include "m-snapshot.h"
SNAPSHOT_SPSC_DEF(snap, int, M_DEFAULT_OPLIST2 )
#elif TEST == 37
#include "m-snapshot.h"
SNAPSHOT_SPMC_DEF(snap, int, M_DEFAULT_OPLIST2 )
#elif TEST == 38
#include "m-snapshot.h"
SNAPSHOT_MPMC_DEF(snap, int, M_DEFAULT_OPLIST8 )
#elif TEST == 39
#include "m-tuple.h"
TUPLE_DEF2(agregate, (x, int, M_DEFAULT_OPLIST), (y, float, DEFAULT_OPLIST) )
#elif TEST == 40
#include "m-tuple.h"
TUPLE_DEF2(agregate, (x, int, DEFAULT_OPLIST), (y, float) )
#elif TEST == 41
#include "m-variant.h"
VARIANT_DEF2(agregate, (x, int, M_DEFAULT_OPLIST), (y, float, DEFAULT_OPLIST) )
#elif TEST == 42
#include "m-variant.h"
VARIANT_DEF2(agregate, (x, int, DEFAULT_OPLIST), (y, float) )
#elif TEST == 43
#include "m-funcobj.h"
FUNC_OBJ_ITF_DEF(itf, int, int)
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, DEFAULT_OPLIST), (b, int, M_DEFAULT_OPLIST))
#elif TEST == 44
#include "m-funcobj.h"
FUNC_OBJ_ITF_DEF(itf, int, int)
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int), (b, int, M_DEFAULT_OPLIST() ))
#else
# warning TEST variable is out of range.
#endif
+212 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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,8 @@ DEQUE_DEF(deque_obj, testobj_t, TESTOBJ_CMP_OPLIST)
#define M_OPL_deque_obj_t() DEQUE_OPLIST(deque_obj, TESTOBJ_CMP_OPLIST)
DICT_DEF2(dict_obj, string_t, STRING_OPLIST, testobj_t, TESTOBJ_OPLIST)
LIST_DUAL_PUSH_DEF(dlist_int, int)
DICT_DEF2(dict_int, string_t, int)
#define M_OPL_dict_int_t() DICT_OPLIST(dict_int, STRING_OPLIST, M_DEFAULT_OPLIST)
#include "coverage.h"
START_COVERAGE
@@ -58,6 +60,12 @@ ALGO_DEF(algo_dict, DICT_OPLIST(dict_obj, STRING_OPLIST, TESTOBJ_OPLIST))
END_COVERAGE
ALGO_DEF(algo_dlist, LIST_OPLIST(list_int))
// Needs to be included ***AFTER*** so that the algorithms can be generated without Function Object before.
#include "m-funcobj.h"
ALGO_DEF(algo_array_fo, array_int_t)
ALGO_DEF(algo_list_fo, LIST_OPLIST(list_int))
/* Helper functions */
int g_min, g_max, g_count;
@@ -99,6 +107,10 @@ static bool func_test_both_even_or_odd(int a, int b)
return (a&1) == (b&1);
}
#define start_with(pattern, item) \
string_start_with_str_p((item).key, (pattern))
#define get_value(out, item) ((out) = (item).value)
/* Tests starts */
static void test_list(void)
@@ -133,6 +145,19 @@ static void test_list(void)
assert( algo_list_count_if(l, func_test_42) == 1);
assert( algo_list_count_if(l, func_test_101) == 0);
M_LET(tmp, LIST_OPLIST(list_int)) {
g_min = 0;
g_max = 99;
g_count = 0;
algo_list_transform(tmp, l, func_map);
assert(g_count == 101);
assert(list_int_size(tmp) == 101);
for(int i = 0; i < 100; i++) {
assert(*list_int_get(tmp, i) == i * i);
}
assert(*list_int_get(tmp, 100) == 17 * 17);
}
int *p = algo_list_min(l);
assert(p != NULL && *p == 0);
p = algo_list_max(l);
@@ -251,6 +276,38 @@ static void test_array(void)
assert(g_count == 101);
assert(n == (328350 + 17*17));
M_LET(tmp, array_int_t) {
g_count = 0;
algo_array_transform(tmp, l, func_map);
assert(g_count == 101);
assert(array_int_size(tmp) == 101);
for(int i = 0; i < 100; i++) {
assert(*array_int_get(l, i) == i);
assert(*array_int_get(tmp, i) == i * i);
}
assert(*array_int_get(l, 100) == 17);
assert(*array_int_get(tmp, 100) == 17 * 17);
array_int_clean(tmp);
#define FT(d,x) ((d) = (x) + 1)
ALGO_TRANSFORM(tmp, array_int_t, l, array_int_t, FT);
assert(array_int_size(tmp) == 101);
for(int i = 0; i < 100; i++) {
assert(*array_int_get(l, i) == i);
assert(*array_int_get(tmp, i) == i + 1);
}
array_int_clean(tmp);
#define FT2(d,x,a) ((d) = (x) + (a))
ALGO_TRANSFORM(tmp, array_int_t, l, array_int_t, FT2, 17);
assert(array_int_size(tmp) == 101);
for(int i = 0; i < 100; i++) {
assert(*array_int_get(l, i) == i);
assert(*array_int_get(tmp, i) == i + 17);
}
}
int *min, *max;
assert (*algo_array_min(l) == 0);
assert (*algo_array_max(l) == 99);
@@ -333,6 +390,36 @@ static void test_array(void)
assert (array_int_size(arr) == 3);
assert (algo_array_sort_p(arr) == true);
assert (algo_array_sort_dsc_p(arr) == false);
algo_array_fill(arr, 1789);
assert(*array_int_get(arr, 0) == 1789);
assert(*array_int_get(arr, 1) == 1789);
assert(*array_int_get(arr, 2) == 1789);
algo_array_fill_a(arr, 1789, 1);
assert(*array_int_get(arr, 0) == 1789);
assert(*array_int_get(arr, 1) == 1790);
assert(*array_int_get(arr, 2) == 1791);
algo_array_fill_a(arr, 0, 2);
assert(*array_int_get(arr, 0) == 0);
assert(*array_int_get(arr, 1) == 2);
assert(*array_int_get(arr, 2) == 4);
algo_array_fill_n(arr, 5, 1742);
assert (array_int_size(arr) == 5);
assert(*array_int_get(arr, 0) == 1742);
assert(*array_int_get(arr, 1) == 1742);
assert(*array_int_get(arr, 2) == 1742);
assert(*array_int_get(arr, 3) == 1742);
assert(*array_int_get(arr, 4) == 1742);
algo_array_fill_an(arr, 4, -1, 3);
assert (array_int_size(arr) == 4);
assert(*array_int_get(arr, 0) == -1);
assert(*array_int_get(arr, 1) == 2);
assert(*array_int_get(arr, 2) == 5);
assert(*array_int_get(arr, 3) == 8);
}
}
@@ -379,14 +466,26 @@ static void test_extract(void)
list_int_init (l);
for(int i = -100; i < 100; i++)
list_int_push_back (l, i);
list_int_reverse(l);
array_int_t a;
array_int_init(a);
ALGO_EXTRACT(a, ARRAY_OPLIST(array_int), l, LIST_OPLIST(list_int));
assert(array_int_size(a) == 200);
assert(*array_int_get(a, 0) == -100);
assert(*array_int_get(a, 199) == 99);
#define cond(d) ((d) > 0)
ALGO_EXTRACT(a, ARRAY_OPLIST(array_int), l, LIST_OPLIST(list_int), cond);
assert(array_int_size(a) == 99);
assert(*array_int_get(a, 0) == 1);
assert(*array_int_get(a, 98) == 99);
#define cond2(c, d) ((d) > (c))
ALGO_EXTRACT(a, ARRAY_OPLIST(array_int), l, LIST_OPLIST(list_int), cond2, 10);
assert(array_int_size(a) == 89);
assert(*array_int_get(a, 0) == 11);
assert(*array_int_get(a, 88) == 99);
int dst = 0;
#define inc(d, c) (d) += (c)
@@ -410,8 +509,31 @@ static void test_extract(void)
ALGO_REDUCE(dst, a, ARRAY_OPLIST(array_int), or);
assert (dst == 127);
unsigned long long dst_l;
ALGO_REDUCE( (dst_l, M_OPEXTEND(M_STANDARD_OPLIST, TYPE(unsigned long long))), a, array_int_t, sum);
assert (dst_l == 100*99/2-10*11/2);
array_int_clean(a);
for(int i = 1; i < 10; i++)
array_int_push_back(a, i);
ALGO_REDUCE(dst, a, ARRAY_OPLIST(array_int), product);
assert (dst == 362880);
array_int_clear(a);
list_int_clear(l);
M_LET(keys, array_int_t)
M_LET( (m, (STRING_CTE("foo"), 1), (STRING_CTE("bar"), 42), (STRING_CTE("bluez"), 7), (STRING_CTE("stop"), 789) ), tmp, dict_int_t) {
int s;
/* Extract all elements of 'm' that starts with 'b' */
ALGO_EXTRACT(tmp, dict_int_t, m, dict_int_t, start_with, "b");
/* Extract the values of theses elements */
ALGO_TRANSFORM(keys, array_int_t, tmp, dict_int_t, get_value);
/* Sum theses values */
ALGO_REDUCE(s, keys, array_int_t, sum);
assert(s == 49);
}
}
ARRAY_DEF(aint, int)
@@ -434,6 +556,93 @@ static void test_insert(void)
}
}
static void test_string_utf8(void)
{
M_LET( (s, "H€llo René Chaînôr¬"), string_t)
M_LET( (ref, 72, 8364, 108, 108, 111, 32, 82, 101, 110, 233, 32, 67, 104, 97, 238, 110, 244, 114, 172), a, array_int_t) {
// Convert the string into an array of unicode.
ALGO_EXTRACT(a, array_int_t, s, string_t);
// Compare the converted string into the reference array
assert(array_int_equal_p(a, ref));
}
}
/* Define some function objects */
FUNC_OBJ_INS_DEF(fo_test, algo_array_fo_test_obj,
(a), {
return a == self->x;
}, (x, int))
#define M_OPL_fo_test_t() FUNC_OBJ_INS_OPLIST(fo_test, M_DEFAULT_OPLIST)
FUNC_OBJ_INS_DEF(fo_eq, algo_array_fo_eq_obj,
(a, b), {
return a == b && self->x != a;
}, (x, int))
#define M_OPL_fo_eq_t() FUNC_OBJ_INS_OPLIST(fo_eq, M_DEFAULT_OPLIST)
FUNC_OBJ_INS_DEF(fo_cmp, algo_array_fo_cmp_obj,
(a, b), {
return a < b ? -self->x : a > b ? self->x : 0;
}, (x, int))
#define M_OPL_fo_cmp_t() FUNC_OBJ_INS_OPLIST(fo_cmp, M_DEFAULT_OPLIST)
FUNC_OBJ_INS_DEF(fol_cmp, algo_list_fo_cmp_obj,
(a, b), {
return a < b ? -self->x : a > b ? self->x : 0;
}, (x, int))
#define M_OPL_fol_cmp_t() FUNC_OBJ_INS_OPLIST(fol_cmp, M_DEFAULT_OPLIST)
static void test_fo(void)
{
M_LET(tab, array_int_t) {
for(int i = 0; i < 10; i++)
array_int_push_back(tab, i);
array_int_push_back(tab, 5);
array_int_it_t it;
M_LET( (obj, 6), fo_test_t)
algo_array_fo_find_fo(it, tab, fo_test_as_interface(obj));
assert(!array_int_end_p(it));
M_LET( (obj, 11), fo_test_t)
algo_array_fo_find_fo(it, tab, fo_test_as_interface(obj));
assert(array_int_end_p(it));
M_LET( (obj, 11), fo_test_t)
assert( 0 == algo_array_fo_count_fo(tab, fo_test_as_interface(obj)));
M_LET( (obj, 5), fo_test_t)
assert( 2 == algo_array_fo_count_fo(tab, fo_test_as_interface(obj)));
M_LET( (obj, 3), fo_test_t)
assert( false == algo_array_fo_all_of_fo_p(tab, fo_test_as_interface(obj)));
M_LET( (obj, 3), fo_test_t)
assert( true == algo_array_fo_any_of_fo_p(tab, fo_test_as_interface(obj)));
M_LET( (obj, 3), fo_test_t)
assert( false == algo_array_fo_none_of_fo_p(tab, fo_test_as_interface(obj)));
M_LET( (obj, -1), fo_test_t)
assert( true == algo_array_fo_none_of_fo_p(tab, fo_test_as_interface(obj)));
array_int_push_back(tab, -1);
M_LET( (obj, 1), fo_cmp_t)
algo_array_fo_sort_fo(tab, fo_cmp_as_interface(obj));
M_LET ( (ref, -1, 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9), array_int_t)
assert( array_int_equal_p(tab, ref));
}
M_LET(tab, LIST_OPLIST(list_int)) {
for(int i = 0; i < 10; i++)
list_int_push_back(tab, i);
list_int_push_back(tab, 5);
list_int_push_back(tab, -1);
M_LET( (obj, 1), fol_cmp_t)
algo_list_fo_sort_fo(tab, fol_cmp_as_interface(obj));
M_LET ( (ref, -1, 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9), LIST_OPLIST(list_int)) {
// NOTE: For a list, the order is revered by default
list_int_reverse(ref);
assert( list_int_equal_p(tab, ref));
}
}
}
int main(void)
{
test_list();
@@ -441,5 +650,7 @@ int main(void)
test_string();
test_extract();
test_insert();
test_string_utf8();
test_fo();
exit(0);
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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 - Test for Concurrent memory pool allocator
*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
+15 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
@@ -226,6 +226,9 @@ static void test_test(void)
assert(!M_PARENTHESIS_P(a,b));
assert(!M_PARENTHESIS_P(a));
assert(!M_PARENTHESIS_P());
assert(!M_PARENTHESIS_P(,));
assert(!M_PARENTHESIS_P((),));
assert(!M_PARENTHESIS_P(()x));
}
@@ -292,6 +295,15 @@ static void test_oplist(void)
#define A3(op) A4(M_GET_OPLIST op)
#define A4(op) M_GET_CLEAR op
assert (A1);
#define A5 (NAME(1))
assert (M_GET_NAME A5);
#define A6 (NAME(A6), INIT_WITH(API_1(M_INIT_WITH_NVAR)))
#define A6_init_with_1(x) 1
#define A6_init_with_2(x, y) 0
assert (M_CALL_INIT_WITH (A6, 0));
assert (!M_CALL_INIT_WITH (A6, 0, 0));
}
static void test_cast(void)
@@ -411,6 +423,7 @@ static void test_move_default(void)
assert(o == 0);
double u, k;
k = -1.0;
u = 9.5;
M_MOVE_DEFAULT(k, u);
assert(k == 9.5);
@@ -431,7 +444,7 @@ static void test_move_default(void)
f_ti(x);
assert(x[0] == 0);
ts y2, x2 = { .b = 2, .c = 3};
ts y2, x2 = { 2, 3};
M_MOVE_DEFAULT(y2, x2);
assert(y2.b == 2 && y2.c == 3);
assert(x2.b == 0 && x2.c == 0);
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
+127
View File
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2017-2020, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "test-obj.h"
#include "m-string.h"
#include "m-funcobj.h"
#include "coverage.h"
START_COVERAGE
/* Define one interface with some params
and 2 instances with some data and no data*/
FUNC_OBJ_ITF_DEF(interface1, int, int, const int *)
FUNC_OBJ_INS_DEF(instance11,
interface1,
(a, b), {
assert(string_equal_str_p(self->c, "INIT"));
string_set_str(self->c, "CALLED");
return self->sort_field*(a - *b);
},
(sort_field, int),
(c, string_t, STRING_OPLIST) )
FUNC_OBJ_INS_DEF(instance12,
interface1,
(a, b), {
return a - *b;
})
/* Define one interface with no param
and 2 instances with some data and no data*/
FUNC_OBJ_ITF_DEF(interface2, int)
FUNC_OBJ_INS_DEF(instance21,
interface2,
(), {
return 1;
})
FUNC_OBJ_INS_DEF(instance22,
interface2,
(), {
self->a ++;
return self->a;
}, (a, int) )
END_COVERAGE
#define M_OPL_instance22_t() FUNC_OBJ_INS_OPLIST(instance22, M_DEFAULT_OPLIST)
static void test_instance11(void)
{
instance11_t cmp;
int n = 2;
instance11_init_with(cmp, -1, STRING_CTE("INIT") );
int x = interface1_call(instance11_as_interface(cmp), 10, &n);
assert(x == -8);
assert(string_equal_str_p(cmp->c, "CALLED"));
instance11_clear(cmp);
instance11_init_with(cmp, 1, STRING_CTE("INIT") );
x = interface1_call(instance11_as_interface(cmp), 100, &n);
assert(x == 98);
assert(string_equal_str_p(cmp->c, "CALLED"));
instance11_clear(cmp);
}
static void test_instance12(void)
{
instance12_t cmp;
int n = 0;
instance12_init(cmp);
int x = interface1_call(instance12_as_interface(cmp), 10, &n);
assert(x == 10);
instance12_clear(cmp);
}
static void test_instance21(void)
{
instance21_t cmp;
instance21_init(cmp);
int x = interface2_call(instance21_as_interface(cmp));
assert(x == 1);
instance21_clear(cmp);
}
static void test_instance22(void)
{
M_LET( (cmp, 1), instance22_t) {
int x = interface2_call(instance22_as_interface(cmp));
assert(x == 2);
x = interface2_call(instance22_as_interface(cmp));
assert(x == 3);
x = interface2_call(instance22_as_interface(cmp));
assert(x == 4);
}
}
int main(void)
{
test_instance11();
test_instance12();
test_instance21();
test_instance22();
return 0;
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
+39 -17
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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,21 +26,6 @@
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));
}
M_LET((s1,"OK"),string_t) {
assert(string_equal_str_p(s1, "OK"));
}
M_LET((s1,"OK S=%d", 16),string_t) {
assert(string_equal_str_p(s1, "OK S=16"));
}
}
static void test_utf8_basic(void)
{
string_t s;
@@ -573,10 +558,47 @@ static void test_bounded_io(void)
string16_clear(d);
}
static void test_M_LET(void)
{
M_LET(s, string_t) {
assert(string_empty_p(s));
}
M_LET(s1, s2, string_t) {
assert(string_empty_p(s1));
assert(string_empty_p(s2));
string_set_str(s1, "Success!");
string_set(s2, s1);
assert(string_equal_p(s1, s2));
string_set_str(s1, "Try to create a very, very, very, very big string!!!!!!!!!!!!!!!!!!!!!!!");
string_set(s2, s1);
assert(string_equal_p(s1, s2));
}
M_LET((s1,"OK"),string_t) {
assert(string_equal_str_p(s1, "OK"));
}
M_LET((s1,"OK S=%d", 16),string_t) {
assert(string_equal_str_p(s1, "OK S=16"));
}
M_LET( (s1, "Hello %s", "world"), s2, (s3, "%d-%d", 42, 17), string_t) {
assert(string_equal_str_p(s1, "Hello world"));
assert(string_empty_p(s2));
assert(string_equal_str_p(s3, "42-17"));
}
M_LET( (s1, "Hello"), string_t) {
assert(string_equal_str_p(s1, "Hello"));
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
// Initalization with another string is only supported in C11 mode.
M_LET( (s2, s1), string_t) {
// In C11 mode, string_equal_p accept also C string
assert(string_equal_p(s2, "Hello"));
}
#endif
}
}
int main(void)
{
test0();
test1();
test_M_LET();
test_utf8_basic();
test_utf8_it();
test_bounded1();
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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:
@@ -71,7 +71,7 @@ TUPLE_DEF2(rtuple,
#define M_OPL_rtuple_t() TUPLE_OPLIST(rtuple, M_OPL_pair_str_t(), STRING_OPLIST)
TUPLE_DEF2(rtuple2, (name, string_t), (value, int))
#define M_OPL_rtuple2_t() TUPLE_OPLIST(rtuple2, STRING_OPLIST, M_DEFAULT_OPLIST)
#define M_OPL_rtuple2_t() TUPLE_OPLIST(rtuple2, string_t, int)
TUPLE_DEF2(rtuple3, (name, string_t), (ituple2, rtuple2_t), (ituple, rtuple_t) )
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
+4 -2
View File
@@ -44,8 +44,10 @@ static void testobj_init_set(testobj_t d, const testobj_t s)
static void testobj_set(testobj_t d, const testobj_t s)
{
testobj_clear(d);
testobj_init_set(d, s);
if (d != s) {
testobj_clear(d);
testobj_init_set(d, s);
}
}
static void testobj_set_ui(testobj_t d, unsigned int v)
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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-2019, Patrick Pelissier
* Copyright (c) 2017-2020, 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: