Author SHA1 Message Date
Leonardo Vencovsky bcfdc87cd6 Move everything out of src folder 2023-12-11 03:08:59 +01:00
Leonardo Vencovsky 2c1eb41280 Quickfix flags 2023-12-11 02:31:30 +01:00
Leonardo Vencovsky 53960a3bce List stabilization part 2 2023-12-10 20:44:17 +01:00
Leonardo Vencovsky e4dbeae46d List stabilization part 1 2023-12-10 20:44:17 +01:00
Leonardo Vencovsky 32deb8356c Add install dev deps target 2023-08-28 09:09:01 +02:00
Leonardo Vencovsky 3593957bb8 add phony targets 2023-08-21 08:56:45 +02:00
Leonardo Vencovsky a8735889c7 Quickfix for ALLOC_NODE 2023-03-09 16:51:48 +01:00
Leonardo Vencovsky 655b7fa825 Added FTABLE flag 2023-03-03 21:28:04 +01:00
Leonardo Vencovsky 78fe5c2b09 Libray 2023-02-28 16:42:49 +01:00
Leonardo Vencovsky 015d14216f Callbacks redone 2023-02-28 16:42:02 +01:00
Leonardo Vencovsky a46ba1f255 Add CNAME 2023-02-24 11:15:45 +01:00
Leonardo Vencovsky feb5dab0ce v0.26.0 2023-02-22 16:06:58 +01:00
Leonardo Vencovsky 6f8496d39e Last changes 2023-02-22 15:09:16 +01:00
Leonardo Vencovsky b330790bf9 Added list SAC and examples 2023-02-02 09:57:15 +01:00
Leonardo Vencovsky 82ac5a4748 Added CMC_DEV and an example 2023-02-01 11:56:16 +01:00
Leonardo Vencovsky 9a5e5d3aa7 Fix readme 2023-02-01 11:53:22 +01:00
Leonardo Vencovsky bd338f2fe3 Examples and fixing stuff 2023-01-25 13:35:16 +01:00
Leonardo Vencovsky a8c1619be6 More examples 2023-01-24 22:23:33 +01:00
Leonardo Vencovsky 301f080713 Refactored types test 2023-01-24 13:54:32 +01:00
Leonardo Vencovsky 84f73ab623 Fixing benchmark 2023-01-23 10:08:14 +01:00
Leonardo Vencovsky 1802771546 lcov for tests 2023-01-19 16:24:34 +01:00
Leonardo Vencovsky 71fd0b8ad5 More refactoring 2023-01-19 15:37:44 +01:00
Leonardo Vencovsky e4d58db474 More refactoring 2023-01-19 13:06:40 +01:00
Leonardo Vencovsky c1070c4858 More refactoring 2023-01-19 10:38:54 +01:00
Leonardo Vencovsky f6bc58a3d7 More refactoring 2023-01-17 17:09:48 +01:00
Leonardo Vencovsky 0e6c44ac46 Preparing pipeline 2023-01-17 11:32:23 +01:00
Leonardo Vencovsky bf02cede2b Refactored tests 2023-01-17 10:48:42 +01:00
Leonardo Vencovsky 2c9759e5ec Basic structure for V2 2023-01-06 21:56:35 +01:00
Leonardo Vencovsky 9cadaeea85 Merge pull request #17 from pxeger/patch-1
Fix colour blocks in README
2021-05-29 11:22:27 -03:00
Patrick Reader 26175688bd fix colour blocks in README
`placehold.it` has an expired SSL certificate, so the coloured blocks weren't rendering correctly in the README. It seems to have been replaced by `via.placeholder.com`.
2021-05-29 13:08:08 +01:00
Leonardo Vencovsky b58ff6a656 Merge branch 'dev' 2020-10-07 15:04:16 -03:00
Leonardo Vencovsky a7ee017bcd v0.25.0 2020-10-07 15:03:39 -03:00
Leonardo Vencovsky 09d1cb649d Final touches to SAC List 2020-10-07 15:02:27 -03:00
Leonardo Vencovsky 4925b5fa06 Merge branch 'dev' of https://github.com/LeoVen/C-Macro-Collections into dev 2020-10-07 08:10:07 -03:00
Leonardo Vencovsky 3d4733fd5f SAC List 2020-10-06 18:53:20 -03:00
Leonardo Vencovsky dba782ccd6 Adding License to src files 2020-10-04 23:00:48 -03:00
Leonardo Vencovsky 3a1d244286 Possibly fixing tests 2020-10-02 22:17:40 -03:00
Leonardo Vencovsky bd3198adf5 New architecture somewhat done 2020-10-02 22:06:21 -03:00
Leonardo Vencovsky 4e194f28ee WIP new architecture, tests will fail 2020-09-29 17:08:40 -03:00
Leonardo Vencovsky 1911415879 Adding unused to cmc_alloc_node_default 2020-09-28 20:41:54 -03:00
Leonardo Vencovsky 5740815a49 Formatting changes from last commit 2020-09-26 13:43:02 -03:00
Leonardo Vencovsky 2424f0d8cd New project architecture in progress: renaming, refactoring and adjustments 2020-09-26 13:35:28 -03:00
Leonardo Vencovsky 0226b91d81 Merge pull request #15 from timgates42/bugfix_typo_beginning
docs: Fix simple typo, beggining -> beginning
2020-09-26 09:17:28 -03:00
Tim Gates 1e16bc1c77 docs: Fix simple typo, beggining -> beginning
There is a small typo in src/utl/assert.h.

Should read `beginning` rather than `beggining`.
2020-09-26 21:09:23 +10:00
Leonardo Vencovsky 6cb2160456 Update .travis.yml 2020-07-08 23:43:56 -03:00
Leonardo Vencovsky 61aa8b879e Trying to fix CI, once again 2020-07-08 23:29:53 -03:00
Leonardo Vencovsky 209d45be5d TreeMap no longer depends on ITER 2020-07-08 23:00:24 -03:00
Leonardo Vencovsky b6343b4857 HashSet no longer depends on ITER 2020-07-06 22:38:15 -03:00
Leonardo Vencovsky f1ab010701 Update README and github action 2020-07-01 23:55:30 -03:00
Leonardo Vencovsky 18a8810c4c Formatting, HashMultiSet no longer depends on ITER 2020-07-01 23:46:36 -03:00
Leonardo Vencovsky 3f97fca40e Update autogen.py 2020-06-30 23:57:58 -03:00
Leonardo Vencovsky 27d70cb32c Trying to fix code coverage 2020-06-30 23:29:52 -03:00
Leonardo Vencovsky cf9c684ecb hashbidimap fixes 2020-06-29 17:50:30 -03:00
Leonardo Vencovsky 6308936e65 HashMultiMap no longer depends on ITER 2020-06-26 16:12:53 -03:00
Leonardo Vencovsky 4d8d49019d Merge branch 'dev' 2020-06-26 00:02:51 -03:00
Leonardo Vencovsky b51efa5c45 v0.24.0 2020-06-26 00:02:13 -03:00
Leonardo Vencovsky 835caa8333 Forwarding changes 2020-06-26 00:01:41 -03:00
Leonardo Vencovsky 645b02708d Create STATUS 2020-06-26 00:01:08 -03:00
Leonardo Vencovsky 7d4abfb66b Update issue templates 2020-06-25 22:30:36 -03:00
Leonardo Vencovsky fa2e3d1fcd Adding dfs example and fixing other examples 2020-06-24 21:55:20 -03:00
Leonardo Vencovsky 4d4f1256ee Some fixes to treeset and flags 2020-06-24 19:31:42 -03:00
Leonardo Vencovsky fe056c1b06 Some fixes to bitset 2020-06-24 16:57:38 -03:00
Leonardo Vencovsky ce470f50b5 Update .travis.yml 2020-06-23 23:17:54 -03:00
Leonardo Vencovsky a23dfb0ab0 Update .travis.yml 2020-06-23 22:34:30 -03:00
Leonardo Vencovsky c93f4bac6b Update autogen.py 2020-06-23 22:09:09 -03:00
Leonardo Vencovsky e1bb3542ee Updating autogen.py 2020-06-22 23:27:20 -03:00
Leonardo Vencovsky a1e0a4edbb Updating autogen script 2020-06-20 12:12:47 -03:00
Leonardo Vencovsky feaac16804 Update benchmark 2020-06-19 22:37:25 -03:00
Leonardo Vencovsky 66b6677afa Quick fix 2020-06-19 19:38:55 -03:00
Leonardo Vencovsky f80b17ff82 Updating script and formatting files 2020-06-17 21:38:00 -03:00
Leonardo Vencovsky c16ecd886c Fixing errors found in types.c tests 2020-06-16 23:43:15 -03:00
Leonardo Vencovsky 922d8b01b8 Update types.c 2020-06-16 23:38:20 -03:00
Leonardo Vencovsky 203516d8cf v0.24.0 preview 2020-06-12 12:34:33 -03:00
Leonardo Vencovsky 767fc0d7fd Update .travis.yml 2020-06-11 22:39:46 -03:00
Leonardo Vencovsky 10e0b4b397 Update .travis.yml 2020-06-11 22:16:34 -03:00
Leonardo Vencovsky 22ab6fdb64 Update .travis.yml 2020-06-11 22:11:22 -03:00
Leonardo Vencovsky e08a8f89f3 Update autogen.py and travis 2020-06-11 22:04:23 -03:00
Leonardo Vencovsky 4bebb90cb6 Tests reworked - CI might not work 2020-06-11 21:23:42 -03:00
Leonardo Vencovsky f8607e8cdc Now it is possible to have opaque collections
PUBLIC and PRIVATE are back
2020-06-11 00:39:56 -03:00
Leonardo Vencovsky 2b8f778c59 Fixing some things, tests resumed 2020-06-08 21:14:56 -03:00
Leonardo Vencovsky aec7efd4c3 Finishing migration to EXT 2020-06-08 20:07:46 -03:00
Leonardo Vencovsky 1987152b03 More things added to EXT 2020-06-07 16:30:23 -03:00
Leonardo Vencovsky 649f02665f Code formatting and moving more things around 2020-06-06 08:32:35 -03:00
Leonardo Vencovsky 59a1e2a682 Somewhat working optional callbacks 2020-06-05 15:46:52 -03:00
Leonardo Vencovsky e85bc72203 Moving more stuff to EXT and fixing typo 2020-06-05 10:47:57 -03:00
Leonardo Vencovsky aa033b0316 Massive changes, unit tests halted
Code format changes that significantly reduce file sizes
Working towards many new features at the same time
Callbacks are going to be optional
Everything is still breaking
2020-06-04 17:20:47 -03:00
Leonardo Vencovsky 770ec1c4c7 More migrations to EXT 2020-06-04 00:33:13 -03:00
Leonardo Vencovsky 90a6b4ef0d Hash CORE no longer depends on ITER and moved some other things to EXT 2020-06-03 20:07:03 -03:00
Leonardo Vencovsky 63eb525406 Moving more things to EXT 2020-06-03 18:38:49 -03:00
Leonardo Vencovsky 97f46b3a81 More stuff moved to EXT 2020-06-02 15:20:34 -03:00
Leonardo Vencovsky 424ba074ff Inlining string_fmt and fixing some unused warnings with __attribute__ 2020-06-02 11:14:34 -03:00
Leonardo Vencovsky 9209e0d5ec Refactoring
Now using CMC_DEF_FTAB macros
Renamed BODY to PARAMS
2020-06-01 20:01:54 -03:00
Leonardo Vencovsky 546ac80030 Adding more things to EXT and some changes to heap 2020-06-01 15:33:17 -03:00
Leonardo Vencovsky 69eed72838 Adding the folder path to file names 2020-06-01 13:59:03 -03:00
Leonardo Vencovsky ce4fadff01 Hotfix 2020-05-31 01:00:13 -03:00
Leonardo Vencovsky 624d1613f0 Adding and fixing things, documenting code and moving more stuff to EXT 2020-05-31 00:50:55 -03:00
Leonardo Vencovsky b85f3d1f81 Some refactoring and moving more stuff to EXT 2020-05-30 00:05:46 -03:00
Leonardo Vencovsky 89254ab5db Started migrating things to EXT 2020-05-29 20:19:47 -03:00
Leonardo Vencovsky e39d60ade9 Moving components to ext and updating tests/to_string.c for reference 2020-05-27 01:19:58 -03:00
Leonardo Vencovsky 77a7178857 Added ./cor/ftable.h and fast forward changes 2020-05-27 00:48:34 -03:00
Leonardo Vencovsky 85bef64551 Fast forward changes on new way to generate macros 2020-05-26 17:25:43 -03:00
Leonardo Vencovsky 720e55bfcc Moved params to core and some code cleanup 2020-05-26 15:32:34 -03:00
Leonardo Vencovsky 8e0183a7d7 Update autogen.py 2020-05-26 14:21:23 -03:00
Leonardo Vencovsky 7fa0eafd2c A lot of changes
Changed include guards
Removed struct cmc_flags, now using enum
Token concatenation now uses CMC_
Every concatenation with SNAME now uses a special macro (this allows customization)
Deleted some no longer needed test files
Deleted some very old implementations of dev and sac collections
2020-05-26 14:00:45 -03:00
Leonardo Vencovsky e9ee0a88b7 Added ext folder with some initial parts already using the new API 2020-05-25 22:09:45 -03:00
Leonardo Vencovsky ab776dd7f3 Added ./cor/params.h 2020-05-25 22:08:05 -03:00
Leonardo Vencovsky a9661c3485 Updating cor include guards and separating things from core.h 2020-05-24 13:40:54 -03:00
Leonardo Vencovsky 9680f6a923 v0.23.1 2020-05-23 09:01:28 -03:00
Leonardo Vencovsky aa53485d62 Added foreach tests 2020-05-23 08:49:17 -03:00
Leonardo Vencovsky 8112ea6f42 Bug fixes to hashmultiset 2020-05-23 07:46:23 -03:00
Leonardo 7340866da1 Added include guards to test src and formatting tests 2020-05-21 21:19:03 -03:00
Leonardo e4a7b01d3a Updating foreach macros with the new iterators API 2020-05-20 20:04:19 -03:00
Leonardo 7c82fff41d Added cor/bitset.h 2020-05-20 19:33:37 -03:00
Leonardo 160c6d4d1c v0.23.0
The version was reset to comply with SemVer
2020-05-19 14:08:56 -03:00
Leonardo 9081734fc9 Fixing includes in macro_collections.h 2020-05-19 13:04:07 -03:00
Leonardo 7c53d0c516 Added missing include guards to mutex.h and thread.h 2020-05-19 12:58:26 -03:00
Leonardo 4402a70415 Updating treeset iterator API 2020-05-18 19:17:57 -03:00
Leonardo 2a919483e0 Updating treemap iterator API 2020-05-18 15:46:03 -03:00
Leonardo 14251ea378 Added more bitset functions 2020-05-16 08:17:52 -03:00
Leonardo d0958c7d0c Update README.md
Added new badge
2020-05-15 00:01:51 -03:00
Leonardo f0e116293f Update github actions 2020-05-14 23:43:02 -03:00
Leonardo Vencovsky 0e34f21aab Create c.yml 2020-05-14 22:49:58 -03:00
Leonardo ea36906d02 Added mutex.h and thread.h 2020-05-14 20:18:00 -03:00
Leonardo f520c38583 Added flags.h
Separated flag definitions from the core header
2020-05-14 18:43:43 -03:00
Leonardo 1380d131ea Added bitset flip and flip_range 2020-05-14 16:10:04 -03:00
Leonardo bd96dfdc8f Update README.md 2020-05-13 15:20:39 -03:00
Leonardo e86950d4ab Update autogen.py 2020-05-13 01:42:39 -03:00
Leonardo 13e3f6047b Minor fixes 2020-05-12 16:04:40 -03:00
Leonardo 51d7a58424 Updating stack iterators 2020-05-12 16:02:42 -03:00
Leonardo 360e08b6b3 Updating sortedlist iterators 2020-05-12 13:53:28 -03:00
Leonardo 7fa41df65a Updating queue iterators API 2020-05-11 16:46:58 -03:00
Leonardo 66c829701d Updated list iterator API 2020-05-10 21:58:10 -03:00
Leonardo 9cd3bf3b31 Removed unused it_start and it_end 2020-05-10 21:52:27 -03:00
Leonardo 8fc432b76c Updating linkedlist iterator 2020-05-09 09:16:51 -03:00
Leonardo 2f59d5fcaf Updatating intervalheap iterator and other smaller things 2020-05-09 07:58:03 -03:00
Leonardo 3bb7f241f2 Added missing HeapIter test to the main unit test suit 2020-05-08 20:59:50 -03:00
Leonardo 9f596f7974 Updating heap API and fixing some things 2020-05-08 20:56:01 -03:00
Leonardo bf3535970e Added the possibility of running tests from each collection separately
Also added CMC_BITSET_WORD_TYPE so that the type of the bitset buffer can be defined with the -D flag
2020-05-07 22:19:09 -03:00
Leonardo 981fef3def Added CMC_TO_STRING macro 2020-05-07 21:50:22 -03:00
Leonardo 303e3b57b8 Updating hashset iterator API 2020-05-07 00:10:41 -03:00
Leonardo adfa5abbc0 Update README.md 2020-05-06 20:44:08 -03:00
Leonardo 2cacbc5348 Updating hashmultiset iterator API 2020-05-06 20:43:59 -03:00
Leonardo fdfb81d08c Updating hashmultimap iterator API 2020-05-06 14:55:44 -03:00
Leonardo 254bb3eacc Renamed multiset to hashmultiset 2020-05-05 18:13:17 -03:00
Leonardo c41ce371d3 Renamed multimap to hashmultimap 2020-05-05 18:00:56 -03:00
Leonardo 9962981047 Added initial bitset documentation 2020-05-05 17:42:06 -03:00
Leonardo b35281b8dc Renaming bidimap to hashbidimap 2020-05-04 23:02:57 -03:00
Leonardo c58f3df50a More added to bitset 2020-05-04 18:19:18 -03:00
Leonardo 963056c42d Update README.md 2020-05-02 01:14:33 -03:00
Leonardo fb0674b0c7 Update core.h 2020-05-02 00:32:40 -03:00
Leonardo 7ad2462254 Adding bitset checkpoint 2020-05-01 15:52:37 -03:00
Leonardo 53f6202709 Updating documentation 2020-04-30 23:39:09 -03:00
Leonardo 0702b7f51b Update hashmap tests and its iterator API 2020-04-29 22:40:07 -03:00
Leonardo 9ade952392 Fixing hashtables and added hashmap init and release 2020-04-29 20:08:42 -03:00
Leonardo 5d68dcc538 Fixing imports in tests 2020-04-29 00:39:20 -03:00
Leonardo 3c0ce0a623 Update deque tests and its iterator API 2020-04-28 22:52:01 -03:00
Leonardo 27ac934ab6 Added new functions to deque and changed iterator functions
New functions: init, init_custom, release
Added DequeIter unit tests
2020-04-27 20:19:47 -03:00
Leonardo db6f12d3e8 Update documentation 2020-04-23 00:11:16 -03:00
Leonardo Vencovsky 3d9abc66a7 Formatting some files 2020-04-23 00:03:57 -03:00
Leonardo Vencovsky af5abff115 Adding more deque tests and valgrind option to tests makefile
Also added a nice header for the main unit test
2020-04-23 00:03:17 -03:00
Leonardo Vencovsky 64201cb630 Fixing memory leaks and indexes out of bounds 2020-04-22 18:38:05 -03:00
Leonardo 6d4b8618bf Fixing autogen.py for linux 2020-04-22 15:34:51 -03:00
Leonardo fe78937150 Replaced unnecessary node struct from intervalheap to a buffer of array[2] 2020-04-22 11:51:05 -03:00
Leonardo 5af021ec0a Fixing some things with intervalheap and added more tests 2020-04-22 10:08:06 -03:00
Leonardo 2e48a033a0 Refactoring: renaming 'element' to 'value' 2020-04-21 01:38:26 -03:00
Leonardo 980fb6d432 Fixing test.h, fixing warnings and deque tests 2020-04-20 01:15:51 -03:00
Leonardo 181a8999a7 Update deque tests 2020-04-19 13:08:38 -03:00
Leonardo 05883903c9 Update documentation and quick fix to test.h 2020-04-18 00:05:20 -03:00
Leonardo 656c0e3b3a Added cmc_assert_total, cmc_assert_failed, better-looking unit test and other things
Started using functions from futils.h in unit test
Renamed unit tests
2020-04-17 16:29:52 -03:00
Leonardo 6f1fb7554e Update documentation 2020-04-17 01:33:49 -03:00
Leonardo 2a7aa8e4cb Added ./cor headers to macro_collections.h for completeness and added formatting 2020-04-17 01:03:13 -03:00
Leonardo 831037df42 Added cmc_flags_to_str 2020-04-16 21:45:58 -03:00
Leonardo 277139656e Fixing missing flag for treemap and treeset 2020-04-16 20:29:49 -03:00
Leonardo e1c736ab46 Adding futils.h to macro_collections.h 2020-04-16 02:10:20 -03:00
Leonardo 952292462a Update documentation 2020-04-16 02:08:42 -03:00
Leonardo 14845d9b23 Adding missing 'static inline' to futils functions 2020-04-15 20:18:35 -03:00
Leonardo cd8260a879 Update futils.h 2020-04-15 19:50:32 -03:00
Leonardo 5cf8904c58 Added futils.h with utility functions for Functions Table 2020-04-15 19:19:09 -03:00
Leonardo 75f2756611 Changed foreach include guard to CMC_FOREACH_H 2020-04-15 14:48:30 -03:00
Leonardo eb13fcad01 Simplified name for functions table ftab_key to fkey and ftab_val to fval 2020-04-14 23:18:56 -03:00
Leonardo 5e13c7ba91 Update travis and fixing tests 2020-04-13 13:10:04 -03:00
Leonardo 7701364f13 Merging tests codecov with main 2020-04-13 12:13:41 -03:00
Leonardo 1dd0f25ff8 Added script that automatically generates code for code coverage 2020-04-12 21:11:37 -03:00
Leonardo 8e73cde6ae Fast-forward codecov 2020-04-11 14:14:34 -03:00
Leonardo 67590790c4 Documentation for foreach.h, test.h, timer.h and other changes
Change in timer.h. Now cmc_timer_stop will calculate the result so goodbye cmc_timer_calc
2020-04-10 22:21:47 -03:00
Leonardo aa214d179e Some changes do log.h and adding its documentation 2020-04-09 22:04:19 -03:00
Leonardo da6f5ea05c Fixing logo 2020-04-09 13:45:15 -03:00
Leonardo 480b99b384 Update documentation 2020-04-09 01:05:04 -03:00
Leonardo 56326b2dd9 Updating tests for bidimap 2020-04-08 19:35:34 -03:00
Leonardo 07668aba75 v1.8.0 2020-04-01 16:28:13 -03:00
Leonardo e37cf42c12 Updating documentation 2020-04-01 00:23:58 -03:00
Leonardo 4c16cae56d Added callbacks to treemap and treeset 2020-03-31 15:41:27 -03:00
Leonardo ee1174d1b5 Added flags to queue, sortedlist and stack 2020-03-29 19:13:39 -03:00
Leonardo 0d665c46d0 Updating tests 2020-03-29 17:44:33 -03:00
Leonardo 2c732dbadf Added callbacks to multimap and multiset, removed enabled flag and more
The enabled flag from the previous commit was removed because it seemed pointless
PFX##_customize functions were changed, now callbacks can be NULL but not allloc_node
Added more code to callback test
Added some missing functions and changed some others
Added more TODO comments of missing code checks or possible improvements
Added more callback guards for set functions
2020-03-28 17:54:31 -03:00
Leonardo fcb8f3a005 Added enabled flag to cmc_callbacks 2020-03-21 23:39:51 -03:00
Leonardo 1e861383e7 Reviewing and writing comments in ./utl/ and adding more color to unit tests 2020-03-20 16:51:23 -03:00
Leonardo 701a24f47c Added callbacks to linkedlist and list 2020-03-20 15:18:12 -03:00
Leonardo 5b8f64b421 Added callbacks to heap and intervaheap, and reworked some min and max functions 2020-03-19 21:46:48 -03:00
Leonardo cf5ceb9c48 Added callbacks to deque, hashmap and hashset, and fixed some other missing things 2020-03-19 17:58:56 -03:00
Leonardo 062c03091c The documentation has been changed to mdbook
Check it out: https://rust-lang.github.io/mdBook/index.html
2020-03-19 00:14:45 -03:00
Leonardo 4e96d3aba0 Huge changes to bidimap and added callbacks to it
Callbacks lost their 'on_' prefix
Bidimap was simply not working properly. Many of its functions have been reworked:
- _update_key_by_val is now _update_key
- _update_val_by_key is now _update_val
- Removed _update_key and _update_val because they just weren't what a bidimap really is about
2020-03-18 16:36:05 -03:00
Leonardo 0089abc84a Added cor folder and cmc_callbacks is now common to all collections
Now every file includes core.h and hashtable-based collections include hashtable.h

The definition of cmc_heap_order has been kept inside heap.h because it is the only collection to use it
2020-03-17 16:10:12 -03:00
Leonardo d7f44e0dbe Added logo to documentation backup and updated TODO 2020-03-16 20:16:28 -03:00
Leonardo d4f30e3693 Added print function and renamed 'data' to 'value' in linkedlist 2020-03-16 19:55:47 -03:00
Leonardo 9999275ad0 Added flags to treeset and quickfix to treemap unit test 2020-03-16 19:53:02 -03:00
Leonardo 2391729541 Added flags to treemap 2020-03-16 14:30:41 -03:00
Leonardo ffb03890df Added flags to stack 2020-03-15 16:42:34 -03:00
Leonardo b3fa566725 Added flags to sortedlist 2020-03-14 17:39:33 -03:00
Leonardo db2de0b855 Added flags to queue 2020-03-13 14:29:29 -03:00
Leonardo f82fb45242 Added flags to multiset and fixing some more 2020-03-13 11:56:32 -03:00
Leonardo 101b839801 Fixing equals functions of list and intervalheap 2020-03-12 14:05:30 -03:00
Leonardo 0c8e12ce30 Renaming some ERROR flags to INVALID 2020-03-12 11:58:02 -03:00
Leonardo efcf831cb5 Update README and TODO 2020-03-12 11:53:48 -03:00
Leonardo 8f64d4bca2 Changed documentation backup folder and added generated documentation to docs/
This change is a preparation to migrate the documentation from the gh-pages branch to the docs/ folder in the master branch (once dev is merged)
2020-03-11 21:16:37 -03:00
Leonardo 01b8bee8b1 Added missing flags and tests 2020-03-11 15:10:52 -03:00
Leonardo f3192b731b Saving updated documentation 2020-03-11 01:20:25 -03:00
Leonardo 863a3a2d8d Added flags to multimap 2020-03-10 16:48:45 -03:00
Leonardo dea981c154 Adding flags to list and renaming OUT_OF_RANGE flag to RANGE 2020-03-09 15:47:32 -03:00
Leonardo 157aea6055 Added flags to linkedlist and renamed some functions 2020-03-05 13:49:36 -03:00
Leonardo 8bd297f4a3 Added flags to intervalheap 2020-03-04 14:25:44 -03:00
Leonardo e4bb9fde74 Adding flags to heap and print functions to collections that already have flags 2020-03-03 17:04:19 -03:00
Leonardo ecc0b51e4b Removing CMC_FOR_EACH and CMC_FOR_EACH_REV and small fix to multiset 2020-03-02 22:50:07 -03:00
Leonardo f020df12f6 Update README and TODO 2020-03-01 12:23:19 -03:00
Leonardo 6e49fb8174 Added flags to hashset 2020-02-29 21:15:04 -03:00
Leonardo 4b7678a621 Added flags to hashmap and added some hotfixes 2020-02-28 17:29:55 -03:00
Leonardo 5794760ceb Added flags to deque 2020-02-26 13:06:12 -03:00
Leonardo 9e206635be Added flags to bidimap 2020-02-26 13:01:35 -03:00
Leonardo 5ed65668e0 Adding functions table to treemap and treeset and some fixes to to_string 2020-02-11 15:58:39 -03:00
Leonardo 7efc0e26e0 Adding functions table to sortedlist and stack, and some fixes to queue 2020-02-10 22:47:54 -03:00
Leonardo aa7c5f775a Adding functions table to queue 2020-02-09 22:32:47 -03:00
Leonardo 147e622580 Adding functions table to multimap and multiset 2020-02-08 00:01:46 -03:00
Leonardo 683decfa64 Adding functions table to linkedlist and list and some minor fixes from previous commit 2020-02-06 17:13:24 -03:00
Leonardo 64c3a99922 Adding functions table to heap and intervalheap 2020-02-06 16:12:06 -03:00
Leonardo fa49fddd8f Adding functions table to hashset and fixing root makefile 2020-02-06 14:10:12 -03:00
Leonardo 7dd6218017 Adding functions table to hashmap and some fixes in bidimap and queue 2020-02-06 01:04:25 -03:00
Leonardo 13f63cea23 Trying to fix readme table (colors were not being set) 2020-02-05 15:17:03 -03:00
Leonardo 4c54567eec Update README.md 2020-01-31 23:27:33 -03:00
Leonardo 9344440f41 Fast forward changes (read desc)
Freezing tests outside of ./tests/main
Formatting all files in ./src and ./tests except for ./tests/codecov
Created makefile for automated code formatting using clang-format
Now bidimap and deque operate with Functions Tables
2020-01-30 18:20:35 -03:00
Leonardo b2bef4e3cc Fast forward changes 2020-01-29 23:58:56 -03:00
Leonardo cbf24ab217 Fixing new_custom use 2019-12-13 19:28:35 -03:00
Leonardo e34443233f Update TODO 2019-12-06 17:38:59 -03:00
Leonardo 8498b97f4c Fixing some left out custom allocation calls 2019-12-05 19:57:36 -03:00
Leonardo 87916ab71b Added maps benchmark 2019-12-04 01:05:53 -03:00
Leonardo 359f282784 Added .clang-format and formatted source code 2019-12-03 16:09:31 -03:00
Leonardo 26fa80f7e0 Removed cmc_string.h as it is no longer needed 2019-12-03 02:00:15 -03:00
Leonardo 74177f891d Fixing cmc_alloc_node_default error 2019-11-23 01:46:12 -03:00
Leonardo 3ee070b4dd Update TODO and added to_string visual test 2019-11-23 00:38:31 -03:00
Leonardo 49bed825c2 All collections now support custom allocation functions
Also some development was made towards callback functions
Now all files are independent and include all necessary definitions within it
2019-11-23 00:28:11 -03:00
Leonardo 26cc284618 Update TODO 2019-11-22 14:49:28 -03:00
Leonardo Vencovsky 345cedcfd3 Merge pull request #7 from TryExceptElse/master
Update Examples
2019-11-22 14:23:25 -03:00
TryExceptElse 994a168364 Remove brackets to be consistent with surrounding code. 2019-11-22 00:27:45 -08:00
TryExceptElse db7af704a6 Update examples. 2019-11-22 00:11:01 -08:00
TryExceptElse f388ed6808 Correct year in comment. 2019-11-22 00:11:01 -08:00
Leonardo f550b0dfa3 Custom allocation node to hashmap, hashset and heap 2019-11-22 00:51:23 -03:00
Leonardo 3b8182d751 Fixing more bidimap stuff and update deque 2019-11-21 23:58:05 -03:00
Leonardo 9996eefc69 Fixing bidimap and adding more tests 2019-11-21 01:52:54 -03:00
Leonardo ad2ae84c13 Finishing up some functions of bidimap that were left off
Also gearing up bidimap for next update containing callbacks and custom allocation functions
2019-11-13 23:23:54 -03:00
Leonardo 0d57698d2f Main header file now only uses a single concatenation macro 2019-11-13 21:24:38 -03:00
Leonardo e3a8745a0b v1.7.3 2019-10-30 00:05:34 -03:00
Leonardo 415720c6a6 Update benchmarks and examples 2019-10-29 12:00:46 -03:00
Leonardo 33c33e8947 Completely removed typedefs 2019-10-29 02:19:34 -03:00
Leonardo db61269d42 Added compile time benchmark and bidimap tests 2019-10-26 15:03:44 -03:00
Leonardo 8f06e8abce Replaced calls to malloc and memset with just calloc 2019-10-26 00:39:46 -03:00
Leonardo 122d012ffd Fast forward codecov 2019-10-23 01:14:10 -03:00
Leonardo 616327f054 Moved all collections from ext to cmc
ext no longer exists
2019-10-22 23:51:39 -03:00
Leonardo de744f5822 v1.7.2 2019-10-18 11:15:52 -03:00
Leonardo 5583ca38b3 Changed default_type functions to compound literals 2019-10-17 01:37:55 -03:00
Leonardo 2d3b441d74 Added resize to multimap, multiset and sortedlist 2019-10-16 21:34:30 -03:00
Leonardo 99cd01ba1e Added intervalheap resize 2019-10-15 23:52:09 -03:00
Leonardo 1f11b6d2da Added preview of bidimap 2019-10-14 22:37:39 -03:00
Leonardo e41fe14502 Refactoring multiset code to be at most 100 characters per line 2019-10-12 00:27:38 -03:00
Leonardo 63d0453341 Finally releasing sortedlist 2019-10-11 02:14:33 -03:00
Leonardo 5e1a26b72e Added queue and stack resize 2019-10-10 15:10:37 -03:00
Leonardo e06e795ed8 hashmap quickfix 2019-10-09 00:53:40 -03:00
Leonardo b9b507bf07 Added heap and list resize function and refactored some tests and added some more 2019-10-08 13:57:58 -03:00
Leonardo 9f8671f75f Added resize function to hashmap and hashset 2019-10-07 19:57:20 -03:00
Leonardo f0b7b125b9 Added deque.h resize and added more deque and hashmap tests 2019-10-05 00:31:29 -03:00
Leonardo 8483eda701 Added two working examples, hanoi and printer 2019-10-04 01:19:18 -03:00
Leonardo b870649627 Refactoring tests 2019-10-03 11:29:35 -03:00
Leonardo 93ac623ffe Update README and benchmark 2019-10-02 00:11:08 -03:00
Leonardo 5997302a8c Fixed deque and queue bug and added more tests 2019-10-01 00:48:09 -03:00
Leonardo f52a9ff702 Refactoring tests and added sortedlist test 2019-09-30 18:27:19 -03:00
Leonardo 376c0ad4e7 Minor optimization to list.h and added finished more TODOs from sortedlist.h 2019-09-30 18:26:31 -03:00
Leonardo 34e649d82a Removed all conditional IO 2019-09-29 15:49:10 -03:00
Leonardo bfb8426183 Fixing travis 2019-09-28 15:01:02 -03:00
Leonardo 4f755f0915 Redone tests
./codecov is a stalled version for code coverage. It will be merged with main when the library is done with breaking changes
2019-09-28 14:58:10 -03:00
Leonardo dea77b5ca2 A minor fix to intervalheap.h 2019-09-27 00:06:26 -03:00
Leonardo b300c889f3 Added cmc prefix to timer 2019-09-27 00:05:22 -03:00
Leonardo 2126da3f25 Removed unnecessary typedefs for log.h and test.h and fixed the latter 2019-09-26 01:17:18 -03:00
Leonardo fb7854ef5d Update assert.h and removed
Added 3 new assertion macros:

cmc_assert_array_equals_any
cmc_assert_array_within_any
cmc_assert_array_outside_any
cmc_assert_array_sorted_any (renamed)
2019-09-25 16:41:40 -03:00
Leonardo 1ff3142769 Update assert.h
Renamed the parameters to and from to to_index and from_index
2019-09-24 23:35:00 -03:00
Leonardo 331fb32b73 Small additions and fixes to sortedlist 2019-09-23 22:34:23 -03:00
Leonardo Vencovsky fa03379580 Merge pull request #5 from LeoVen/dev
v1.7.1 fast forward master
2019-09-22 01:20:01 -03:00
Leonardo 43f4ae9f16 v1.7.1 2019-09-21 19:19:36 -03:00
Leonardo d9171a11cf Fixed some include guards for cmc_hashtable_primes and cmc_entry_state
Also removed unnecessary typedef for enum cmc_entry_state
Now cmc_entry state is in another guard, separated from the cmc_hashtable_primes guard
2019-09-21 18:25:01 -03:00
Leonardo 344e9f77fe Renamed list and linkedlist functions
push - push_at
pop - pop_at

The list prepend, append and insert - seq_push_front, seq_push_back, seq_push_at
2019-09-21 00:37:56 -03:00
Leonardo 2c84c35264 Adding sortedlist skeleton
Some functions are already working but there is still too much to be optimized
2019-09-18 02:29:11 -03:00
Leonardo c27edd53f6 Added cmc_assert_sorted 2019-09-18 02:28:20 -03:00
Leonardo a0db76b50d Update README.md
Trying to fix the shield's icon
2019-09-17 12:00:40 -03:00
Leonardo bb3efd75ff Update README and TODO 2019-09-17 00:37:12 -03:00
Leonardo 3d7e218195 Move the string format to each collection files and quick fix on deque
Now the format to print them is only declared if you actually include the header
2019-09-16 23:50:06 -03:00
Leonardo 191c47fc7c v1.7.0 2019-09-16 14:47:54 -03:00
Leonardo f2f806612f Moving documentation to the docs folder 2019-09-16 14:47:42 -03:00
Leonardo 5e2e001265 Merge branch 'master' of https://github.com/LeoVen/C-Macro-Containers 2019-09-16 14:45:45 -03:00
Leonardo 2ca2210a77 Added CMC prefix to all macros and removed FMOD 2019-09-16 14:45:24 -03:00
Leonardo Vencovsky 747aa8cb4e Merge pull request #4 from LeoVen/dev
Merge pull request #2 from LeoVen/master
2019-09-16 14:35:55 -03:00
Leonardo 4fe4e96811 v1.6.3 2019-09-14 00:38:45 -03:00
Leonardo 0df0ebbdeb Update TODO, quick fixes in a makefile and in assert.h 2019-09-14 00:38:13 -03:00
Leonardo e834aaee81 Added iter_advance, iter_rewind and iter_go_to to all collections
Also reworked many iterator functions that could cause strange behavior
2019-09-13 18:46:00 -03:00
Leonardo 1928fdd6d5 Reworked assert.h and test.h and added the cmc prefix to the logging utility
Integrated the assert utility with the test utility. Now any assertion that fails inside the unit test will trigger failure and is no longer needed to manually pass or fail a test.
Also reworked makefiles.
2019-09-06 12:17:11 -03:00
Leonardo abdbfa2018 v1.6.2 2019-09-05 01:48:51 -03:00
Leonardo a1a940399a Unified _set and _update functions
Also _remove now accepts an optional parameter if to retrieve or not the removed value. _update also has the same optional parameter that retrieves the old value.
The multimap will allocate an array based on the amount of keys and add all the values to that array.
2019-09-05 01:33:54 -03:00
Leonardo 855e085996 Fixed benchmark 2019-09-05 01:09:06 -03:00
Leonardo e95379bdd7 Updated tests 2019-09-03 17:07:34 -03:00
Leonardo 762b95db26 Some fixes and improvements to hashmap, hashset and multimap 2019-09-03 17:07:15 -03:00
Leonardo 396066f289 Update README.md 2019-09-03 16:54:21 -03:00
Leonardo f070d274f4 Added _equals function to all collections and fixed some issues with multimap 2019-08-29 23:25:32 -03:00
Leonardo 1f50add1bb Added _copy_of functions to all collections 2019-08-28 16:34:15 -03:00
Leonardo e68b8a8e0e Fixing main unit test 2019-08-27 01:38:34 -03:00
Leonardo 5ee7bfa23a v1.6.1 2019-08-27 01:36:06 -03:00
Leonardo 8ec768d30e removed linkedqueue and now _free and _clear have a deallocator parameter 2019-08-27 01:33:58 -03:00
Leonardo Vencovsky 35d27ffb39 Merge pull request #2 from LeoVen/master
Fast forward dev
2019-08-08 15:43:04 -03:00
Leonardo 613392ae76 Changed how _update works and added _set
_update: retrieves old value
_set: ignores old value
2019-08-05 23:28:12 -03:00
Leonardo f74ce7519a Added update function for hashmap, treemap and multimap and added update_all for multimap 2019-08-03 01:55:36 -03:00
Leonardo 01d0b42e1a v1.6.0 2019-08-02 01:03:28 -03:00
Leonardo e470021d13 Added to_string to intervalheap and multimap 2019-08-02 00:53:35 -03:00
Leonardo 7de3ce5c0c Updating examples readme and added multiset to benchmark 2019-08-02 00:36:54 -03:00
Leonardo 976965bcfa Fixed integer overflow with hashtables when calculating their capacity 2019-08-02 00:18:22 -03:00
Leonardo 1254e657c5 Complete remake of multiset 2019-08-01 23:52:50 -03:00
Leonardo 90ee6a424d heap hotfix 2019-07-31 23:08:51 -03:00
Leonardo bf79616e7e Adding Code Review shields 2019-07-18 22:58:41 -03:00
Leonardo 09ebb1eae8 Thank you Code Review for your awesome community! 2019-07-17 13:57:13 -03:00
Leonardo ba6d8edde1 Update .travis.yml 2019-07-17 00:05:54 -03:00
Leonardo 2f76ad4b6f Update README.md 2019-07-16 23:59:38 -03:00
Leonardo 407141661a Fixing test 2019-07-16 23:58:02 -03:00
Leonardo 38620ba457 Added to_string methods to cmc, ./utl/cmc_string.h, fixed some variable names and fixed includes 2019-07-16 23:55:30 -03:00
Leonardo f8f704f432 Added intervalheap and multimap to benchmark 2019-07-14 22:33:30 -03:00
Leonardo 8ae83acd1a Update stack unit test 2019-07-13 00:17:31 -03:00
Leonardo af26f6c081 More fixes to ./cmc/stack.h 2019-07-13 00:17:01 -03:00
Leonardo d82be005da Fixing stack iter_init 2019-07-12 23:34:16 -03:00
Leonardo e37b54fc62 Added bool type assert 2019-07-12 23:33:35 -03:00
Leonardo 9eb8d5f682 Fixing tests and added linkedqueue tests 2019-07-10 17:26:31 -03:00
Leonardo 7ecb2e90fd Update TODO 2019-07-10 16:57:54 -03:00
Leonardo 354cd538f8 Added cmc prefixes to enums used by heap and hashtables and fixed return type on treeset and hashset 2019-07-10 16:57:46 -03:00
Leonardo 0c883b0a74 Multimap tests 2019-07-09 23:51:01 -03:00
Leonardo 9c23c3ca77 Update multimap to new standards 2019-07-08 19:55:48 -03:00
Leonardo d0244a0513 Update TODO 2019-07-06 01:24:07 -03:00
Leonardo 875678d7a9 Added intervalheap, simplified heap and moved multimap and multiset to the ext folder 2019-07-06 00:26:54 -03:00
Leonardo 65f2b79157 Merge branch 'dev' 2019-07-05 16:46:12 -03:00
LeoVen c60ee10185 Changing timer_t to cmc_timer to not generate conflicts 2019-07-05 13:30:07 -03:00
LeoVen f7a598efc8 Word Counter example using the pthread library 2019-07-05 00:52:03 -03:00
Leonardo e8142f96b1 v1.5.3 2019-07-04 15:49:56 -03:00
Leonardo 97d50bc3d9 Fixing and adding more tests 2019-07-04 15:34:25 -03:00
Leonardo 8c457eeb12 Fixing missing return statements 2019-07-04 14:55:17 -03:00
Leonardo 846d0bbba6 More tests 2019-07-04 02:18:05 -03:00
Leonardo a9314ee8f7 Update assert.h 2019-07-04 02:13:41 -03:00
Leonardo 9bff706bba test quickfix 2019-07-02 01:49:19 -03:00
Leonardo 31c871c4c2 Fixing CI shield 2019-07-02 01:38:08 -03:00
Leonardo 82b374ec83 Revert "Fixing CI shield and trying to fix code coverage through codecov.yml"
This reverts commit 940552d6cd.
2019-07-02 01:36:46 -03:00
Leonardo 940552d6cd Fixing CI shield and trying to fix code coverage through codecov.yml 2019-07-02 01:30:03 -03:00
Leonardo 6a2cb70fb5 Tests update 2019-07-02 01:05:16 -03:00
Leonardo 78cfc0c335 Create .gitattributes 2019-07-01 17:20:04 -03:00
Leonardo f454934b07 Reorganizing tests 2019-07-01 17:10:28 -03:00
Leonardo 5504f82052 Added codecov shield 2019-06-28 01:48:31 -03:00
Leonardo d01997b7cb v1.5.2 2019-06-28 01:08:55 -03:00
Leonardo 7b349ea426 Many minor fixes, changes and first attempt of codecov
Changes on assert.h, foreach.h, test.h and timer.h
Updated benchmarks, examples and tests
Updated tests/Makefile for future
Added list.c test
Added CMC namespace to CONCATC and CONCATH on macro_collections.h
2019-06-28 00:52:23 -03:00
Leonardo 1edb12a83c Added assert macros utility 2019-06-27 23:55:10 -03:00
Leonardo 176bbc66ad Added UnitTest utility and removed unnecessary logging functions 2019-06-26 01:32:44 -03:00
Leonardo 41eebe546a v1.5.1 2019-06-24 02:11:28 -03:00
Leonardo afaecb2dde Update TODO, CHANGELOG and headers 2019-06-24 02:11:10 -03:00
Leonardo 9062415322 Added sac/queue.h, moved timer.h to utl folder, new queue benchmark 2019-06-24 02:09:02 -03:00
Leonardo 6213b42d5a v1.5.0 2019-06-21 16:17:11 -03:00
Leonardo 8010cce8c7 Restructuring project
View CHANGELOG on v1.5.0 for more information
2019-06-21 16:07:03 -03:00
Leonardo dad9b7a81f Update README.md and Documentation.md 2019-06-19 01:23:18 -03:00
Leonardo 21a2bea746 Fixing previous commit 2019-06-13 00:44:41 -03:00
Leonardo b0a2e42cfe Minor fixes all around
Changed some input parameter names
Updated TODO
Changed how hashtables initialization works. Now the given initial capacity will be guaranteed to be reached before the hashtable rehashes (load is now considered in the calculation).
2019-06-13 00:40:55 -03:00
Leonardo b6cbadd8e2 v1.4.3 2019-06-11 00:44:10 -03:00
Leonardo 870cfe302d Added more set functions
Added is_subset, is_superset, is_proper_subset, is_proper_superset, is_disjointset
2019-06-11 00:42:11 -03:00
Leonardo ea04c7ddaa Quickfix function name 2019-06-09 23:53:34 -03:00
Leonardo a86140094c Update .travis.yml 2019-06-07 01:48:25 -03:00
Leonardo 85c49a92fd v1.4.2 2019-06-07 01:45:10 -03:00
Leonardo aac07a645c Now collections accept plain struct
Also fixed impl prefixes and function modifiers
Added new test for all possible data types
Fixed some READMEs
2019-06-07 01:44:15 -03:00
Leonardo efdb1c80a3 Changed TreeSet max and min to be compatible with the TreeMap and the hash collections 2019-06-06 23:42:14 -03:00
Leonardo a9c7439d15 Update .travis.yml 2019-05-30 21:29:41 -03:00
Leonardo 26555bc10a v1.4.1 2019-05-30 21:27:18 -03:00
Leonardo 0f84d65656 Removed PUBLIC and PRIVATE, corrected some examples and new test 2019-05-30 21:23:37 -03:00
Leonardo a9b775419d Update Documentation.md 2019-05-30 16:54:40 -03:00
Leonardo a384a8b180 Update .gitignore 2019-05-27 17:13:09 -03:00
Leonardo 424582f969 Update documentation and TODO 2019-05-23 23:08:03 -03:00
Leonardo 6044e92262 Update CONTRIBUTING.md 2019-05-17 23:41:31 -03:00
Leonardo ee96bcbc55 Update CHANGELOG
reversed changelog ~duh
2019-05-16 17:07:03 -03:00
Leonardo 37bfcbb9c4 Added multimap 2019-04-26 20:48:46 -03:00
Leonardo d2692a8dbe Added multiset 2019-04-10 17:23:37 -03:00
394 changed files with 63671 additions and 24776 deletions

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
# clang-format 9.0.0
Language: Cpp
BasedOnStyle: LLVM
AlignEscapedNewlines: DontAlign
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
BreakBeforeBraces: Allman
BreakStringLiterals: false
ColumnLimit: 120
Cpp11BracedListStyle: false
ForEachMacros: ["CMC_FOREACH", "CMC_FOREACH_REV"]
IndentCaseLabels: true
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 1
SpacesInContainerLiterals: false
TabWidth: 4
UseTab: Never
+5
View File
@@ -0,0 +1,5 @@
# Auto detect text files and perform LF normalization
* text=auto
*.h linguist-language=C
*.c linguist-language=C
+42
View File
@@ -0,0 +1,42 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
# Bug Report template
### Describe the bug
A clear and concise description of what the bug is.
### How to Reproduce
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
### Expected behavior
A clear and concise description of what you expected to happen.
### Screenshots
If applicable, add screenshots to help explain your problem.
### Please complete the following information:
- Type: [e.g. src, tests, examples, benchmarks]
- OS: [e.g. linux, win32]
- Compiler [e.g. gcc, clang]
- Compiler Version [e.g. 8.1.0]
### Additional context
Add any other context about the problem here.
+32
View File
@@ -0,0 +1,32 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature request
assignees: ''
---
# Feature Request Template
### What is the nature of this request?
* New functionalities
* Change in standards
* Change in source code details (names of variables, functions, parameters, etc)
### Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
### Describe the solution you'd like
A clear and concise description of what you want to happen.
### Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
### Additional context
Add any other context or screenshots about the feature request here.
+25
View File
@@ -0,0 +1,25 @@
name: Test Suit
on:
push:
branches: [ master, dev ]
jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Environment
run: sudo apt install make valgrind gcc
- name: Versions
run: |
gcc --version \
make --version \
valgrind --version \
- name: Test Suite
run: make tests --always-make
- name: Upload Coverage
uses: codecov/codecov-action@v3
with:
directory: ./tests
verbose: true
+10 -1
View File
@@ -52,4 +52,13 @@ Mkfile.old
dkms.conf
# vscode folder
.vscode
.vscode
# Experimental folder
experimental/
# Test / Code Coverage build folder
build
tests/coverage
tests/out
-22
View File
@@ -1,22 +0,0 @@
dist: trusty
os: linux
language: c
compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-7
script:
- sudo ln -s /usr/bin/gcc-6 /usr/local/bin/gcc
- export CC=gcc-7
- cd ./tests
- gcc foreach.c -Wall -Wextra -o foreach -std=c11
- ./foreach
- gcc iterators.c -Wall -Wextra -o iterators -std=c11
- ./iterators
- gcc contains.c -Wall -Wextra -o contains -std=c11
- ./contains
- gcc pointertype.c -Wall -Wextra -o pointertype -std=c11
- ./pointertype
+242 -67
View File
@@ -1,6 +1,246 @@
# MAJOR.MINOR.ADJUSTMENTS
# RELEASE.MAJOR.MINOR
1.0.0
0.26.0
Complete refactor of the library, using a different approach to code generation
0.25.0
New Project Architecture - Files are no longer separated in folders, but rather prefixed by their sub-library
Added sac_list.h
0.24.0
A lot of breaking changes, with the library more modular now
Comeback of PUBLIC and PRIVATE for the CMC sub-library
Callbacks are now optional and can be turned off by defining CMC_NO_CALLBACKS
Added EXT library
New macro CMC_CAMEL_CASE can change the library's style where the default is snake case
Added:
./cor/alloc.h
./cor/callbacks.h
./cor/heap.h
Complete rework of tests and code coverage using autogen.py
Removed cmc_flags, where now every flag is an enum (CMC_FLAGS_OK, CMC_FLAGS_ERROR, etc)
Different include guards
New way to generate code using PARAM
Code now completely changed by using the CMC_ macro to concatenate tokens
Token concatenation with SNAME now uses special macros that allow customization of the suffixes
0.23.1
Added ./cor/bitset.h
Added foreach tests
Updating foreach macros with the new iterators API
Bug fixes for ./cmc/hashmultiset.h
0.23.0
Added ./cmc/bitset.h
Added ./cor/flags.h
Added ./utl/futils.h
Added ./utl/mutex.h
Added ./utl/thread.h
Added cmc_flags_to_str
Added autogen.py for automated code generation for code coverage
Changed the iterator API
Merged ./tests/codecov and ./tests/main
Renamed ftab_key to fkey and ftab_val to fval
Renamed collections
- bidimap -> hashbidimap
- multimap -> hashmultimap
- multiset -> hashmultiset
-- Versioning restarted for compatibility with SemVer (https://semver.org/)
1.8.0 (0.22.0)
Added Function Tables
Added Error Codes
Added Callback Functions
Added custom allocation functions support
Added .clang-format
Added makefile in root folder for automated code formatting
Created into core folder for implementation of common data structures:
- ./cor/core.h
- ./cor/hashtable.h
Documentation changed to mdbook
Removed ./utl/cmc_string.h
Replaced CMC_FOR_EACH and CMC_FOR_EACH_REV by CMC_FOREACH and CMC_FOREACH_REV
1.7.3 (0.21.0)
Breaking changes:
- ext collections merged to cmc
- No more typedefs in code generated
Fast forwarded codecov
1.7.2 (0.20.0)
Added resize function to array based collections
Added the following functions to hashtable based collections:
- load
- full
Added more assert macros utility
Added plenty more tests
Substituted impl_default_value / key by compound literals
Removed unnecessary conditional input and output functions
Minor fixes throughout the library
1.7.1 (0.19.0)
Added new assert macro cmc_assert_sorted
Fixed some include guards for hashtables
Moved the cmc string format to each file
Renamed some list functions (sequence input/output)
Renamed list and linkedlist functions push and pop to push_at and pop_at
1.7.0 (0.18.0)
Removed FMOD (function modifier)
Added CMC prefix to all macros defined within the library
1.6.3 (0.17.0)
Added iterator functions to all collections:
- iter_advance
- iter_rewind
- iter_go_to
Added cmc prefix to the logging utility
Integrated the assert utility with the test utility. Now any assertion that fails inside the unit test will trigger failure and is no longer needed to manually pass or fail tests.
1.6.2 (0.16.0)
Added new functions to all collections:
- copy_of
- equals
Added the new collections to the tests
Fixed some collections and some improvements to the hashtables
Unified the functions set and update from the map implementations
1.6.1 (0.15.0)
Removed ./ext/linkedqueue.h
Added a deallocator parameter to all _free and _clear functions
1.6.0 (0.14.0)
Added ./ext/intervalheap.h
Added ./ext/multimap.h
Added ./ext/multiset.h
Added to_string function to most collections
Added the cmc prefix to the enum entry_state used by hashtables and to the enum heap_type used by the heap
Fixed return type on some functions from ./cmc/hashset.h and ./cmc/treeset.h
Fixed hashtables integer overflow when the capacity is divided by the load factor
Changed timer.h struct name from timer_t to cmc_timer to prevent name collisions on linux
1.5.3 (0.13.0)
Tests completely reorganized and now with full code coverage
Some fixes where there was a missing return statement
Expanded ./utl/assert.h
1.5.2 (0.12.0)
Added ./utl/test.h
Added ./utl/assert.h
Added ./tests/list.c - UnitTest for LIST
Small fixes on ./utl/foreach.h, ./utl/test.h and redone ./utl/timer.h
Removed ./utl/log.h functions that were unnecessary
Added the CMC namespace to CONCATC and CONCATH at macro_collections.h
1.5.1 (0.11.0)
New queue benchmark
Added ./sac/queue.h
Added ./utl/timer.h
Fixing descriptions and other minor fixes
1.5.0 (0.10.0)
Changed tests compilation and execution to a single Makefile
Changed project structure
./src/
./cmc/ - Main C Macro Collections Library
./dev/ - A copy of ./cmc/ used for development (logging utility)
./ext/ - Extra collections
./sac/ - Stack Allocated Collections
./utl/ - Utility like ForEach, logging, etc
Added ./utl/log.h a logging utility
Added ./dev/deque.h - A mirror of ./cmc/deque.h but with logging utility
Added ./ext/linkedqueue.h - A singly-linked list based queue
Added ./sac/stack.h - A Stack purely allocated on the stack
1.4.3 (0.9.0)
Fixed some functions names
Added set functions for both Tree and Hash Set
- is_subset
- is_proper_subset
- is_superset
- is_proper_subset
- is_disjointset
1.4.2 (0.8.0)
Adapted code so that plain struct type is accepted
Changed TreeSet max and min to be compatible with the TreeMap and the hash collections
Changed function modifier of all implementation detail to static
Fixed some implementation detail functions that were not prefixed with impl
Added types.c to test if it is possible to compile all the collections' generated code accepting all C data types
Removed pointertype.c (replaced by types.c)
1.4.1 (0.7.0)
Removed PUBLIC and PRIVATE from the main macro
Corrected examples and benchmark
Added new test consisting of compiling the header and source separately
1.4.0 (0.6.0)
New way on how iterators work to all collections
Added iter_init to work with stack allocated iterators
Added iter_new and iter_free to work with heap allocated iterators
Added two pointers to functions (it_start and it_end) that allow you to access iterators to both start and end of the target collection easily
iter_next and iter_prev now only move the iterator
To access the key, value and index, use a separate function
Removed FOR_EACH_MAP as it is no longer necessary since FOR_EACH also works to associative containers now
Updated benchmark, examples and tests to work on these new iterators
Changed pointertype test to be a pointer to struct instead of pointer to char
Added CHANGELOG and TODO
1.3.0 (0.5.0)
Changed how the linkedlist functions relative to nodes work
Removed reference to owner list on each node
Renamed some functions for consistency
1.2.4 (0.4.1)
Fixing some declarations in hashset and hashmap where a pointer type would cause problems
Added a test to make sure all collections support pointer type
Tests:
- pointertype
1.2.3 (0.4.0)
Added get_ref functions to all collections that support it (only included in hashmap, linkedlist, list and treemap)
1.2.2 (0.3.2)
Removed unnecessary modulo operation in hashtable functions
1.2.1 (0.3.1)
Optimized list - now using 'string.h' functions to shift elements around instead of for-loops:
- memset
- memcpy
- memmove
1.2.0 (0.3.0)
'contains' functions added to all collections
'contains' tests and benchmark
Unified Benchmark
Updated examples
1.1.3 (0.2.3)
Renamed deque's 'rear' struct member to 'back' to be more consistent with other collections
Better benchmark and foreach tests are alphabetically ordered
1.1.2 (0.2.2)
Fixing iterators for when they are initialized with an empty target
Better iterator tests
More examples
1.1.1 (0.2.1)
Reordering functions (implementation details are now at the end of each file)
1.1.0 (0.2.0)
Added new list functions:
- new_from
- prepend
- insert
- append
- remove
- fits
1.0.1 (0.1.1)
Fixed hashset logic in robin-hood hashing
1.0.0 (0.1.0)
First stable version
Includes the following collections:
- deque
@@ -18,68 +258,3 @@
Tests:
- foreach
- iterator
1.0.1
Fixed hashset logic in robin-hood hashing
1.1.0
Added new list functions:
- new_from
- prepend
- insert
- append
- remove
- fits
1.1.1
Reordering functions (implementation details are now at the end of each file)
1.1.2
Fixing iterators for when they are initialized with an empty target
Better iterator tests
More examples
1.1.3
Renamed deque's 'rear' struct member to 'back' to be more consistent with other collections
Better benchmark and foreach tests are alphabetically ordered
1.2.0
'contains' functions added to all collections
'contains' tests and benchmark
Unified Benchmark
Updated examples
1.2.1
Optimized list - now using 'string.h' functions to shift elements around instead of for-loops:
- memset
- memcpy
- memmove
1.2.2
Removed unnecessary modulo operation in hashtable functions
1.2.3
Added get_ref functions to all collections that support it (only included in hashmap, linkedlist, list and treemap)
1.2.4
Fixing some declarations in hashset and hashmap where a pointer type would cause problems
Added a test to make sure all collections support pointer type
Tests:
- pointertype
1.3.0
Changed how the linkedlist functions relative to nodes work
Removed reference to owner list on each node
Renamed some functions for consistency
1.4.0
New way on how iterators work to all collections
Added iter_init to work with stack allocated iterators
Added iter_new and iter_free to work with heap allocated iterators
Added two pointers to functions (it_start and it_end) that allow you to access iterators to both start and end of the target collection easily
iter_next and iter_prev now only move the iterator
To access the key, value and index, use a separate function
Removed FOR_EACH_MAP as it is no longer necessary since FOR_EACH also works to associative containers now
Updated benchmark, examples and tests to work on these new iterators
Changed pointertype test to be a pointer to struct instead of pointer to char
Added CHANGELOG and TODO
+2
View File
@@ -13,6 +13,8 @@ Check out `bug_report.md` and `feature_request.md` templates in the `.github` fo
## Here are things you could work on:
> You can check out the TODO file to see what I've planned on doing, in case you want to work on any of those topics
1. New features, new functions, new stuff!
* Before adding anything new, please, first create an issue for it to be discussed;
* Write tests to anything new you make.
-2766
View File
File diff suppressed because it is too large. Load diff
+35
View File
@@ -0,0 +1,35 @@
help:
@echo Welcome to the C Macro Collections Library. Targets:
@echo
@echo - tests: run tests
@echo - tests_dev: run tests for dev
@echo - format: formats the entire project
@echo - bench: runs benchmarks
@echo - docbuild: builds documentation to ./docs
@echo - docserve: serves mdbook docs
@echo - install_dev_deps: install dev dependencies
tests:
make -C ./tests
tests_dev:
make -C ./tests dev
format:
- find ./ -name *.h -type f | xargs clang-format --style=file --verbose -i
bench:
make -C ./benchmarks benchmark
docbuild:
mdbook build -d ../docs documentation
docserve:
mdbook serve documentation
install_dev_deps:
sudo apt install gcc make valgrind lcov clang-format hyperfine
cargo install mdbook
.PHONY: tests tests_dev format bench docbuild docserve install_dev_deps
+241 -73
View File
@@ -1,113 +1,281 @@
# C-Macro-Collections
# C Macro Collections
Generate Simple Data Structures of any type in C for you to use in your projects.
<p align="center">
<img src="https://leoven.github.io/C-Macro-Collections/img/logo.png" alt="C Macro Collections Logo" width="300"/>
</p>
![License](https://img.shields.io/badge/License-MIT-blue.svg)
![Version](https://img.shields.io/badge/Version-v1.4.0-orange.svg)
![Build](https://travis-ci.org/LeoVen/C-Macro-Collections.svg?branch=master)
<p align="center">Easy to use, modular, header only, macro based, generic and type-safe Data Structures in C</p>
<p align="center">
<a href="https://github.com/LeoVen/C-Macro-Collections"><img src="https://img.shields.io/badge/GitHub-C%20Macro%20Collections-2195F3.svg?logo=github" alt="LinkToRepo"/></a>
<a href="https://leoven.github.io/C-Macro-Collections/"><img style="color: #ffffff;" src="https://img.shields.io/badge/Read%20the%20Docs-D13636.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHN0eWxlPSIiPjxyZWN0IGlkPSJiYWNrZ3JvdW5kcmVjdCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgeD0iMCIgeT0iMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJub25lIi8%2BPHRpdGxlPmljbi9kb2MtdGV4dDwvdGl0bGU%2BPGcgY2xhc3M9ImN1cnJlbnRMYXllciIgc3R5bGU9IiI%2BPHRpdGxlPkxheWVyIDE8L3RpdGxlPjxwYXRoIGQ9Ik01IDFoNC4yNDRhMiAyIDAgMCAxIDEuNDM0LjYwNmwyLjc1NiAyLjgzNEEyIDIgMCAwIDEgMTQgNS44MzVWMTJhMyAzIDAgMCAxLTMgM0g1YTMgMyAwIDAgMS0zLTNWNGEzIDMgMCAwIDEgMy0zem0wIDJhMSAxIDAgMCAwLTEgMXY4YTEgMSAwIDAgMCAxIDFoNmExIDEgMCAwIDAgMS0xVjUuODM1TDkuMjQ0IDNINXptMS41IDdoM2EuNS41IDAgMSAxIDAgMWgtM2EuNS41IDAgMSAxIDAtMXptMC0yaDJhLjUuNSAwIDAgMSAwIDFoLTJhLjUuNSAwIDAgMSAwLTF6TTggMmwzIDEuOTk1TDEzIDdIOWExIDEgMCAwIDEtMS0xVjJ6IiBpZD0iYSIgY2xhc3M9IiIgZmlsbD0iI2ZmZmZmZiIgZmlsbC1vcGFjaXR5PSIxIi8%2BPC9nPjwvc3ZnPg%3D%3D" alt="LinkToDocs"/></a>
</p>
<p align="center">
<a href="https://github.com/LeoVen/C-Macro-Collections/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License"/></a>
<a href="https://github.com/LeoVen/C-Macro-Collections/releases"><img src="https://img.shields.io/badge/Version-v0.26.0-orange.svg" alt="Version"/></a>
<a href="https://travis-ci.org/LeoVen/C-Macro-Collections"><img src="https://travis-ci.org/LeoVen/C-Macro-Collections.svg?branch=master" alt="travis-ci"/></a>
<a href="https://codecov.io/gh/LeoVen/C-Macro-Collections"><img src="https://codecov.io/gh/LeoVen/C-Macro-Collections/branch/master/graph/badge.svg" alt="codecov"/></a>
<a href="https://github.com/LeoVen/C-Macro-Collections/actions"><img src="https://github.com/LeoVen/C-Macro-Collections/workflows/Test%20Suit/badge.svg?branch=master" alt="test_suit"/></a>
</p>
<p align="center">
<a href="https://github.com/LeoVen/C-Macro-Collections/stargazers"><img src="https://img.shields.io/github/stars/LeoVen/C-Macro-Collections?style=flat&color=ffa000" alt="Stars"/></a>
<a href="https://github.com/XAMPPRocky/tokei"><img src="https://img.shields.io/badge/Lines%20of%20Code-28513-007596.svg" alt="loc"/></a>
<a href="https://github.com/XAMPPRocky/tokei"><img src="https://img.shields.io/badge/Files-130-961c00.svg" alt="loc"/></a>
</p>
## Table of Contents
* [Installation](#installation)
* [Contributing](#contributing)
* [Usage](#usage)
* [Features](#features)
* [Project Structure](#project-structure)
* [Available Collections](#available-collections)
* [Other Features](#other-features)
* [Design Decisions](#design-decisions)
## Installation
No installation is required. The entire library is made of header files and can be directly included into your project.
## Contributing
There is a lot to be done. You can check the `TODO` file in the root of the repository or the issues in the github page. Also, tests and documentation are in constant development.
## Usage
Below is a minimal example that makes use of some core functionalities. And a lot of explanation too!
```c
// The C Macro Collections takes advantage of headers that can be included
// multiple times. You can check the contents of src/cmc/list.h and there are no
// include guards, meaning they can be included multiple times and this is what
// generates the code.
// Before including it though we need to define a few basic macros. You can
// check the documentation to see which ones are required.
#define V int // list value data type
#define PFX intl // list function's prefix
#define SNAME int_list // list struct name (struct int_list)
#define CMC_EXT_STR // Enables an extra functionality (STR) of the list
#include "cmc/list.h"
// This header file includes a lot of functions that can be used as methods to
// basic data types. In this case, cmc_i32_str is used
#include "cmc/utl/futils.h"
int main(void)
{
// Our list type is defined by SNAME and all functions are prefixed by PFX
// (PFX can also be thought as the function's namespace). Also, nodes,
// entries, iterators and other structures are prefixed by SNAME. So PFX is
// for functions and SNAME is for structs, where the main one is simply
// 'struct SNAME'.
// To initialize a list we need to pass in an initial capacity and something
// that is called a function table for the V type.
// This function table is a struct with methods that will extract some
// (sometimes) necessary behaviour from your custom data type. Things like
// hash, comparison and printing. A list doesn't require any of these
// functions. That is, the CORE module doesn't use any of them.
// But since we are using the STR module, we will need to define the 'str'
// function. Luckily, for the 'int' type, the library already provides such
// function (cmc_i32_str), provided by the cmc/utl/futils.h header file.
struct int_list *list = intl_new(32, &(struct int_list_fval){ .str = cmc_i32_str, NULL });
// Check if the list was successfully initialized. It could fail if the
// initial capacity is too big or if 'struct int_list_fval *' is NULL,
// because every data structure must have a valid function table.
if (!list)
return 1;
// Add some items to the list. The CMC data structures are all dynamically
// sized. So there can be as many items as you want as long as you have
// enough memory.
for (int i = 0; i < 100; i++)
{
// Try to add an element to the list. If it fails you can check what
// caused it by getting its flag.
if (!intl_push_back(list, i))
{
enum cmc_flags flag = intl_flag(list);
// Use cmc_flags_to_str (global variable) to map the enum error to a
// string.
fprintf(stderr, "%s : push_back failed\n", cmc_flags_to_str[flag]);
}
}
// Now we will use the STR module, the _print() function. This is where the
// '.str' from the function table comes into play. If we haven't defined it,
// the program would've crashed. We also need to define to which file we
// will be printing the list's content. In this case, the terminal. Also,
// some strings need to be defined. They will be printed: before all
// elements, between each one, and after all elements. This is very useful
// for debugging.
intl_print(list, stdout, "[ ", ", ", " ]\n");
// Free all of its resources
intl_free(list);
}
```
Now all you have to do is to compile the source code with `-I /path/to/library/src`. There is no required installation or pre-compilation.
## Features
The C Macro Collections library is organized into many other sub-libraries. The following table is a quick overview.
| Library | Name | Description |
| :-----: | -------------------------------- | ------------------------------------------------------------------------------------------- |
| CMC | Macro Collections | The main library with dynamically-sized collections |
| COR | Core | Core functionalities used by more than one collection, usually from different sub-libraries |
| EXT | Extensions | Extension to collections |
| SAC | Statically Allocated Collections | Collections with a fixed sized array that don't use any heap allocation |
| TSC | Thread-Safe Collections | Collections that allow multiple operations from multiple threads |
| UTL | Utilities | General utilities |
## Project Structure
* __benchmarks__ - Where all benchmarks are hosted
* __docs__ - A folder hosting the generated documentation by [mdBook](https://github.com/rust-lang/mdBook)
* __documentation__ - The markdowns used by [mdBook](https://github.com/rust-lang/mdBook) to generate the website
* __examples__ - Examples using the C Macro Collections Library
* __src__ - All headers part of the C Macro Collections Library
* __tests__ - Where all tests are hosted
## Available Collections
* List
* LinkedList
* Stack
* Queue
* Deque
* Heap
* TreeSet
* TreeMap
* HashSet
* HashMap
__The following table is an overview of all the currently available or upcoming data structures__:
## Available Collections in future updates
| Collection <img width=250/> | Abstract Data Type <img width=250/> | Data Structure <img width=250/> | Details |
| :--------------------------------: | :---------------------------------: | :-----------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------: |
| BitSet <br> _bitset.h_ | Set | Dynamic Array | A set of bits that can be individually modified and queried, each identified by a bit index |
| Deque <br> _deque.h_ | Double-Ended Queue | Dynamic Circular Array | A circular array that allows `push` and `pop` on both ends (only) at constant time |
| HashBidiMap <br> _hashbidimap.h_ | Bidirectional Map | Two Hashtables | A bijection between two sets of unique keys and unique values `K <-> V` using two hashtables |
| HashMap <br> _hashmap.h_ | Map | Flat Hashtable | A unique set of keys associated with a value `K -> V` with constant time look up using a hashtable with open addressing and robin hood hashing |
| HashMultiMap <br> _hashmultimap.h_ | Multimap | Hashtable | A mapping of multiple keys with one node per key using a hashtable with separate chaining |
| HashMultiSet <br> _hashmultiset.h_ | Multiset | Flat Hashtable | A mapping of a value and its multiplicity using a hashtable with open addressing and robin hood hashing |
| HashSet <br> _hashset.h_ | Set | Flat Hashtable | A unique set of values with constant time look up using a hashtable with open addressing and robin hood hashing |
| Heap <br> _heap.h_ | Priority Queue | Dynamic Array | A binary heap as a dynamic array as an implicit data structure |
| IntervalHeap <br> _intervalheap.h_ | Double-Ended Priority Queue | Custom Dynamic Array | A dynamic array of nodes, each hosting one value from the MinHeap and one from the MaxHeap |
| LinkedList <br> _linkedlist.h_ | List | Doubly-Linked List | A default doubly-linked list |
| List <br> _list.h_ | List | Dynamic Array | A dynamic array with `push` and `pop` anywhere on the array |
| Queue <br> _queue.h_ | FIFO | Dynamic Circular Array | A queue using a circular array with `enqueue` at the `back` index and `dequeue` at the `front` index |
| SkipList <br> _WIP_ | Sorted List | Skip List | A sorted Linked List with average O(log n) search, insertion and deletion complexity |
| SortedList <br> _sortedlist.h_ | Sorted List | Sorted Dynamic Array | A lazily sorted dynamic array that is sorted only when necessary |
| Stack <br> _stack.h_ | FILO | Dynamic Array | A stack with push and pop at the end of a dynamic array |
| TreeBidiMap <br> _WIP_ | Sorted Bidirectional Map | Two AVL Trees | A sorted bijection between two sets of unique keys and unique values `K <-> V` using two AVL trees |
| TreeMap <br> _treemap.h_ | Sorted Map | AVL Tree | A unique set of keys associated with a value `K -> V` using an AVL tree with `log(n)` look up and sorted iteration |
| TreeMultiMap <br> _WIP_ | Sorted Multimap | AVL Tree | A sorted mapping of multiple keys with one node per key using an AVL Tree of linked-lists |
| TreeMultiSet <br> _WIP_ | Sorted Multiset | AVL Tree | A sorted mapping of a value and its multiplicity using an AVL tree |
| TreeSet <br> _treeset.h_ | Sorted Set | AVL Tree | A unique set of keys using an AVL tree with `log(n)` look up and sorted iteration |
* Multimap
* Multiset
* Treehashmap
* Heap will be a MinMaxHeap
## Other Features
Check out **Documentation.md** for more information about each collection.
These are some features within the library that are implemented by all collections.
## What to use
## Two-way iterators
The following table shows how each collection is implemented and how well they do when using as common [abstract data types](https://en.wikipedia.org/wiki/Abstract_data_type).
All collections come with a two-way iterator. You can go back and forwards in constant time and access elements in constant time.
* **Ideal** - The collection implements correctly the abstract data type;
* **Not Ideal** - The implementation is fulfilled but some functionalities are either not part of the ADT or not present;
* **Bad** - It can be done, but its a bad idea.
## Custom Allocation
![DataStructuresDiagram](https://i.imgur.com/hFqBSlC.png)
All collections have a `cmc_alloc_node` which provides pointers to the four dynamic memory allocation functions in C: `malloc`, `calloc`, `realloc` and `free`. These pointers can be customized for each individual collection created or a default can be used, as specified in `cmc_alloc_node_default`.
![GoodColor](https://img.shields.io/badge/Ideal_Implementation-%236abf69.svg)
![AverageColor](https://img.shields.io/badge/Not_Ideal_Implementation-%2363a4ff.svg)
![BadColor](https://img.shields.io/badge/Bad_Implementation-%23ff6659.svg)
## Callbacks
## How to use
Every function that operates on a collection can be separated in 5 different types. Create, Read, Update, Delete and (an extra one besides CRUD) Resize. You can define one callback function for each operation. Check out the documentation to see when each callback function is called.
To generate the collection, all you need to do is to include the necessary header files. You can include the containers you want to use individually or you can include the master header, `macro_collections.h`, that comes with all collections and other functionalities like the `FOR_EACH` macro.
## Functions Table
There are three C standard headers that all collections use:
Functions table is a `struct` of function pointers containing 'methods' for a custom data type. Some methods are optional and others are needed in order for a collection to operate. They are:
* `<stdlib.h>`
* `<stdbool.h>`
* `<string.h>`
#### CMP
With the last one being used only by array based containers. These headers are already included by default.
A comparator function is used in sorted collections or when an equality is being checked like when trying to find a certain element in a list. It is responsible for taking two arguments of the same data type and comparing them. The return value is an `int` with the following definitions:
### Macros
* Return `1` if the first argument is greater than the second;
* Return `0` if the first argument equals the second;
* Return `-1` if the first argument is less than the second.
> Note here that `SNAME` represents the uppercase name of the collection.
#### CPY
Every collection is separated by two parts:
A copy function is used when a collection is being copied. It can be used to make a deep copy of of your custom data type. It must take a single parameter and return a new copy of that same data type. If this function is absent (`NULL`) the data type will be copied by assignment (for pointers this is a shallow copy).
* `HEADER` - Contains all struct definitions and function definitions.
* `SOURCE` - Contains all function implementations.
#### STR
All collections have three main macros:
A string function is responsible for taking a `FILE` pointer and a custom data type and outputting the string representation of that data returning a `bool` indication success or failure. It is useful for debugging.
* `SNAME_GENERATE` - Generates `SNAME_GENERATE_HEADER` and `SNAME_GENERATE_SOURCE`.
#### FREE
Or you can generate each part individually:
The free function is called when a collection is cleared (all elements removed) or freed (all elements removed and freed from memory) and it is responsible for completely freeing all resources that are usually acquired by your data type.
* `SNAME_GENERATE_HEADER` - Generates all struct definitions and function definitions.
* `SNAME_GENERATE_SOURCE` - Generates all function implementations.
#### HASH
### For Each
This function receives a custom data type as parameter and returns a `size_t` hash of that data. Used in hashtables.
There are 2 for-each macros:
#### PRI
* `FOR_EACH` - Starts at the start of the collection towards the end.
* `FOR_EACH_REV` - Starts at the end of the collection towards the start.
A priority function works much like the comparator function except that it compares the priority between two elements. It is used in collections whose structure is based on the priority of elements and not in their general comparison.
Check out the **Documentation.md** to know exactly what represents the *end* and the *start* of each collection.
* Return `1` if the first argument has a greater priority than the second;
* Return `0` if the first argument has the same priority as second;
* Return `-1` if the first argument has a lower priority than the second.
### Parameters
The following table shows which functions are required, optional or never used for each Collection:
When including `macro_collections.h` in your source code you gain access to a macro called `COLLECTION_GENERATE` with the following parameters:
| Collection | CMP | CPY | STR | FREE | HASH | PRI |
| ------------ | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: |
| BitSet | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| Deque | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| HashMap | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| HashBidiMap | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| HashMultiMap | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| HashMultiSet | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| HashSet | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| Heap | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) |
| IntervalHeap | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) |
| List | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| LinkedList | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| Queue | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| SortedList | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| Stack | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| TreeMap | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| TreeSet | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
> Note: in future updates, PRIVATE and PUBLIC will no longer exist
| Color | Label |
| :-------------------------------------------------------------: | ----------------------------------------- |
| ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | Required for basic functionality. |
| ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | Required for specific functions. |
| ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | Required for non-core specific functions. |
| ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | Optional. |
| ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | Not Used. |
* \*__C__ - Container name in uppercase (*LIST*, *LINKEDLIST*, *STACK*, *QUEUE*, *DEQUE*, *HEAP*, *TREESET*, *TREEMAP*, *HASHSET*, *HASHMAP*).
* \*__P__ - Permission (PRIVATE, PUBLIC). Only matters when header and source are declared in separate files.
* *PRIVATE* - Members of a struct are hidden in source file and only accessible through functions.
* *PUBLIC* - Members of a struct are visible.
* \*__PFX__ - Functions prefix or namespace.
* \*__SNAME__ - Structure name (`typedef struct SNAME##_s SNAME`).
* __FMOD__ - Function modifier (`static` or empty).
* \*\*__K__ - Key type. Only used in *HASHMAP* and *TREEMAP*; ignored by others.
* \*__V__ - Value type. Primary type for most collections, or value to be mapped by *HASHMAP* and *TREEMAP*.
## Design Decisions
\* Required parameters
### Stack vs Heap Allocation
\*\* Required only by *HASHMAP* and *TREEMAP*
Currently all collections need to be allocated on the heap. Iterators have both options but it is encouraged to allocate them on the stack since they don't require dynamic memory.
**In fact, all macros follow this pattern.** So whenever you see a macro with a bunch of parameters and you don't know what they are, you can check out the above list.
### Some collections overlap others in terms of functionality
When including `foreach.h` in your source code you gain access to all for-each macros with the following parameters:
Yes, you can use a Deque as a Queue or a List as a Stack without any major cost, but the idea is to have the least amount of code to fulfill the needs of a collection.
* __PFX__ - Functions prefix or namespace.
* __SNAME__ - Structure name.
* __TARGET__ - The variable name of the collection you wish to iterate over.
* __BODY__ - Block of code.
Take for example the Stack. It is simple, small and doesn't have many functions. If you generate a List to be used (only) as a Stack (which is one of the bulkiest collections) you'll end up with a lot of code generated and compiled for nothing.
Inside body you will have access to the iterator variable. With it you can use functions to access the key, value or index from the iterator.
The Deque versus Queue situation is a little less problematic, but again, you need to be careful when generating a lot of code as compilation times might go up to 15 seconds even with modern ultra-fast compilers.
Another example is using a HashMap/TreeMap as a HashSet/TreeSet (with a dummy value that is never used), but I just think that this is a bad thing to do and you would be wasting some memory. Also, the sets generate a lot of code related to set theory, whereas maps don't.
### But what about the LinkedList ?
You can use them as Stacks, Queues and Deques, but with modern memory hierarchy models, array-based data structures have a significantly faster runtime due to caching, so I didn't bother to have specific implementations of those aforementioned collections.
### You can't structurally modify a collection when iterating over it
Modifying a collection will possibly invalidate all iterators currently initialized by it. Currently, the only collection that allows this is the LinkedList (using the node-based functions, not the iterator).
## Special Macros
* `CMC_NO_ALLOC` - disables `"cor/alloc.h"`, useful for statically allocated collections (SAC)
* `CMC_NO_IMPORTS` - disables all imports from the standard library at `"cor/core.h"`
+95 -47
View File
@@ -1,56 +1,104 @@
TODO
[ ] Finish Documentation
[ ] Simplify PUBLIC and PRIVATE
[ ] Add multiset
[ ] Add multimap
[ ] Upgrade heap to a min-max heap
[ ] Add dispose function
Patch - Changes that can be released by a patch version
Minor - Changes that require a bit more time than a simple patch
Major - 1.0.0 version or breaking changes
The library follows https://semver.org/
Check out CHANGELOG
[/] - In Progress
[X] - Finished
#!! Next Patch -----------------------------------------------------------------
#!! Major ----------------------------------------------------------------------
[ ] Stabilize the library
[ ] Add SAC library
[ ] Add TSC library
[ ] Separate inner Data Structure implementation from the Collection's one
[ ] CMC_NAMES - Full customization of function names (see CMC_CAMEL_CASE)
[\] Tests
[\] Documentation
#!! Minor ----------------------------------------------------------------------
[ ] Fix BitSet, using capacity vs. counter
[ ] #13 - Properly implement HashBidiMap iterator
[ ] More SortedList functions
[ ] BidiMap's _is_mapping() to check if a mapping K <=> V exists
[ ] New asserts - _array_int(), _array_not_in() and str
[ ] Add Stack's _peek() and _top() (get by value, get by pointer)
[ ] CMC_TIMED for timed blocks
[ ] _iter_at() iterator
#!! Patch ----------------------------------------------------------------------
[ ] MultiSets replace existing value with the new added one
#!! Considerations -------------------------------------------------------------
[ ] rand.h utility
[ ] Redo `while (true)` in hashtables' _insert()
[ ] Add to_array and from_array functions
[ ] Serialization
[ ] Iterator based functions (like C++ collections)
[ ] save {all}
[ ] load {all}
[ ] serialize {all}
[ ] deserialize {all}
[ ] Zip Iterators
[ ] Consumer Iterators
MAYBE
#!! Optimizations --------------------------------------------------------------
[ ] Add conditional code generation based on variadic macros
[ ] Use binary search to find optimum hashtable prime size inside
impl_calculate_size
PLANNED
#!! Done -----------------------------------------------------------------------
Before 2.0
Get Documentation fixed and completed
1.5
Simplify PUBLIC and PRIVATE (simply remove them)
Conditional code generation
Add extra content macro (Insert/Remove/Append/Prepend) and let user decide if he wants to include them or not
Separate Implementation Detail into a different MACRO (LIST_GENERATE_DETAIL)
1.6
Iterator move and move_to
LinkedList - Insert/Remove/Append/Prepend/Extract
to_array - Creates an array with all the elements inside the collection
1.7
Add shrink function that shrinks the internal buffer to current count of elements
2.0
Add multiset, multimap and new heap implementation
2.1
Adapt multiset, multimap, treehashmap and new heap implementation to the current standards
Add dispose method to each collection in order to automatically free its data
2.2
Add serialization functions
Header:
%d - Type specifier (LIST = 0, DEQUE = 1, STACK = 2, etc) for quick check
%llu - How many elements there are
%d - If data varies in size
%llu - Data size
2.3
Iterator functions (functions that operate relative to iterators position) like add or remove ranges
Sometime
Add treehashmap
[X] Remove PUBLIC and PRIVATE
[X] Utility
[X] assert.h
[X] foreach.h
[X] log.h
[X] test.h
[X] timer.h
[X] Extra Collections
[X] Add MultiSet
[X] Add MultiMap
[X] Add IntervalHeap
[X] Add SortedList
[X] Add BidiMap
[X] Add functions
[X] update {hashmap, treemap, multimap}
[X] set {hashmap, treemap, multimap}
[X] to_string {all}
[X] iter_advance {all} (iterators)
[X] iter_rewind {all} (iterators)
[X] iter_go_to {all} (iterators)
[X] equals {all}
[X] copy_of {all}
[X] resize {array based collections}
[X] Custom allocators
[X] Each file needs to be independent without including external files
[X] Fix cases where new_custom() should be used instead of just new()
[X] Add Function Tables that contains data type functions
(compare, copy, display, free, hash, priority)
[X] Add error codes that can be accessed from the collection's struct
[X] Merge bidirectional map key_buffer and val_buffer to a single buffer and make key_dist and val_dist into dist[2]
[X] Callback utility
on_create, on_read, on_update, on_delete, on_resize
[X] Replace IntervalHeap node by a simple buffer of two pointers (V (*buffer)[2])
[X] PUBLIC and PRIVATE is back (opaque data structures)
[X] Add EXT library
[X] #12 - Fix the collections that depend on ITER
[X] #10 - Fix Benchmarks and Examples
+11
View File
@@ -0,0 +1,11 @@
CC=gcc
INCLUDE=-I ..
CFLAGS=-Wall -Wextra -Werror
benchmark: benchmark.c
$(CC) $(CFLAGS) $(INCLUDE) $< -o ./$@.exe -lm
./$@.exe
clean:
rm *.exe -f
rm *.txt -f
+203 -139
View File
@@ -12,14 +12,19 @@
* - Iteration
* - Output
*/
#include "macro_collections.h"
#include "util/timer.h"
#include "util/twister.c"
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <math.h>
#include <inttypes.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include "util/twister.c"
#include "cmc/cor/hashtable.h"
#include "cmc/cor/heap.h"
#include "cmc/utl/foreach.h"
#include "cmc/utl/futils.h"
#include "cmc/utl/timer.h"
#define NTOTAL UINT64_C(10000000)
#define NMIN UINT64_C(100)
@@ -27,23 +32,6 @@
// Percentage % macro
#define PC(x) x * 100.0
static int intcmp(int a, int b)
{
return a - b;
}
static size_t inthash(int t)
{
size_t a = t;
a += ~(a << 15);
a ^= (a >> 10);
a += (a << 3);
a ^= (a >> 6);
a += ~(a << 11);
a ^= (a >> 16);
return a;
}
size_t randsize(size_t min, size_t max, mt_state_ptr st)
{
return (size_t)floor(twist_real(st) * ((double)max - (double)min + 1.0) + (double)min);
@@ -60,128 +48,190 @@ void shuffle(int *array, mt_state_ptr st)
}
}
COLLECTION_GENERATE(LIST, PUBLIC, l, list, /* FMOD */, /* K */, int)
COLLECTION_GENERATE(STACK, PUBLIC, s, stack, /* FMOD */, /* K */, int)
COLLECTION_GENERATE(QUEUE, PUBLIC, q, queue, /* FMOD */, /* K */, int)
COLLECTION_GENERATE(DEQUE, PUBLIC, d, deque, /* FMOD */, /* K */, int)
COLLECTION_GENERATE(LINKEDLIST, PUBLIC, ll, linked, /* FMOD */, /* K */, int)
COLLECTION_GENERATE(HEAP, PUBLIC, h, heap, /* FMOD */, /* K */, int)
COLLECTION_GENERATE(TREESET, PUBLIC, ts, tset, /* FMOD */, /* K */, int)
COLLECTION_GENERATE(TREEMAP, PUBLIC, tm, tmap, /* FMOD */, int, int)
COLLECTION_GENERATE(HASHSET, PUBLIC, hs, hset, /* FMOD */, /* K */, int)
COLLECTION_GENERATE(HASHMAP, PUBLIC, hm, hmap, /* FMOD */, int, int)
struct
{
CMC_DEF_FTAB_CMP(size_t);
CMC_DEF_FTAB_CPY(size_t);
CMC_DEF_FTAB_STR(size_t);
CMC_DEF_FTAB_FREE(size_t);
CMC_DEF_FTAB_HASH(size_t);
CMC_DEF_FTAB_PRI(size_t);
} int_ftab = { cmc_size_cmp, NULL, cmc_size_str, NULL, cmc_size_hash, cmc_size_cmp };
#define BENCHMARK(NAME, PFX, sname, initfunc, insertbody, removebody, searchbody) \
void NAME##_io_benchmark(int *array, int *sarray, size_t s) \
{ \
printf("+------------------------------------------------------------ %10s\n", #NAME); \
printf("+------------------------------------------------------------ \n"); \
timer_t timer, total; \
int r, k, v; \
size_t j; \
\
sname *coll = initfunc; \
\
TIMER_START(total) \
TIMER_START(timer) \
\
for (size_t i = 0; i < NTOTAL; i++) \
{ \
insertbody; \
} \
\
TIMER_STOP(timer) \
\
TIMER_CALC(timer) \
\
size_t s1 = PFX##_count(coll); \
\
#define CMC_ARGS_FALLTHROUGH
#define V int
#define K int
#define CMC_EXT_ITER
#define SNAME bitset
#define PFX bs
#include "cmc/bitset.h"
#define SNAME deque
#define PFX d
#include "cmc/deque.h"
#define SNAME hashbidimap
#define PFX hbm
#include "cmc/hashbidimap.h"
#define SNAME hashmap
#define PFX hm
#include "cmc/hashmap.h"
#define SNAME hashmultimap
#define PFX hmm
#include "cmc/hashmultimap.h"
#define SNAME hashmultiset
#define PFX hms
#include "cmc/hashmultiset.h"
#define SNAME hashset
#define PFX hs
#include "cmc/hashset.h"
#define SNAME heap
#define PFX h
#include "cmc/heap.h"
#define SNAME intervalheap
#define PFX ih
#include "cmc/intervalheap.h"
#define SNAME linkedlist
#define PFX ll
#include "cmc/linkedlist.h"
#define SNAME list
#define PFX l
#include "cmc/list.h"
#define SNAME queue
#define PFX q
#include "cmc/queue.h"
#define SNAME sortedlist
#define PFX sl
#include "cmc/sortedlist.h"
#define SNAME stack
#define PFX s
#include "cmc/stack.h"
#define SNAME treemap
#define PFX tm
#include "cmc/treemap.h"
#define SNAME treeset
#define PFX ts
#include "cmc/treeset.h"
#undef CMC_ARGS_FALLTHROUGH
#include "cmc/cor/undef.h"
#define BENCHMARK(NAME, PFX, SNAME, initfunc, insertbody, removebody, searchbody) \
void NAME##_io_benchmark(int *array, int *sarray, size_t s) \
{ \
printf("+------------------------------------------------------------ %10s\n", #NAME); \
printf("+------------------------------------------------------------ \n"); \
struct cmc_timer timer, total; \
CMC_UNUSED int r; \
\
struct SNAME *coll = initfunc; \
\
cmc_timer_start(total); \
cmc_timer_start(timer); \
\
for (size_t i = 0; i < NTOTAL; i++) \
{ \
insertbody; \
} \
\
cmc_timer_stop(timer); \
\
size_t s1 = PFX##_count(coll); \
\
printf(" INPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
\
double input_time = timer.result; \
\
TIMER_START(timer) \
\
for (size_t i = 0; i < s; i++) \
{ \
searchbody; \
} \
\
TIMER_STOP(timer) \
\
TIMER_CALC(timer) \
\
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
\
double search_time = timer.result; \
\
sname##_iter iter; \
\
TIMER_START(timer) \
\
for (PFX##_iter_init(&iter, coll); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
{ \
} \
\
TIMER_STOP(timer) \
\
TIMER_CALC(timer) \
\
\
double input_time = timer.result; \
\
cmc_timer_start(timer); \
\
for (size_t i = 0; i < s; i++) \
{ \
searchbody; \
} \
\
cmc_timer_stop(timer); \
\
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
\
double search_time = timer.result; \
\
cmc_timer_start(timer); \
\
CMC_FOREACH (PFX, SNAME, iter, coll) \
{ \
} \
\
cmc_timer_stop(timer); \
\
printf("ITERATION %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
\
double iter_time = timer.result; \
\
TIMER_START(timer); \
\
for (size_t i = 0; i < NTOTAL; i++) \
{ \
removebody; \
} \
\
TIMER_STOP(timer) \
\
TIMER_CALC(timer) \
\
size_t s2 = PFX##_count(coll); \
\
\
double iter_time = timer.result; \
\
cmc_timer_start(timer); \
\
for (size_t i = 0; i < NTOTAL; i++) \
{ \
removebody; \
} \
\
cmc_timer_stop(timer); \
\
size_t s2 = PFX##_count(coll); \
\
printf(" OUTPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
\
double output_time = timer.result; \
\
TIMER_STOP(total) \
TIMER_CALC(total) \
\
PFX##_free(coll); \
\
double adj_search_time = (total.result - search_time) + (search_time * (double)NTOTAL) / (double)s; \
double no_search = input_time + iter_time + output_time; \
\
printf("+------------------------------------------------------------ \n"); \
printf("TOTAL TIME : %.0lf milliseconds\n", total.result); \
printf("ADJUSTED TIME : %.0lf milliseconds\n", adj_search_time); \
\
printf("+------------------------------------------------------------ \n"); \
printf(" INPUT : %5.2lf%% (%5.2f%%)\n", PC(input_time / total.result), PC(input_time / no_search)); \
printf(" SEARCH : %5.2lf%%\n", PC(search_time / total.result)); \
printf("ITERATION : %5.2lf%% (%5.2f%%)\n", PC(iter_time / total.result), PC(iter_time / no_search)); \
\
double output_time = timer.result; \
\
cmc_timer_stop(total); \
\
PFX##_free(coll); \
\
double adj_search_time = (total.result - search_time) + (search_time * (double)NTOTAL) / (double)s; \
double no_search = input_time + iter_time + output_time; \
\
printf("+------------------------------------------------------------ \n"); \
printf("TOTAL TIME : %.0lf milliseconds\n", total.result); \
printf("ADJUSTED TIME : %.0lf milliseconds\n", adj_search_time); \
\
printf("+------------------------------------------------------------ \n"); \
printf(" INPUT : %5.2lf%% (%5.2f%%)\n", PC(input_time / total.result), PC(input_time / no_search)); \
printf(" SEARCH : %5.2lf%%\n", PC(search_time / total.result)); \
printf("ITERATION : %5.2lf%% (%5.2f%%)\n", PC(iter_time / total.result), PC(iter_time / no_search)); \
printf(" OUTPUT : %5.2lf%% (%5.2f%%)\n", PC(output_time / total.result), PC(output_time / no_search)); \
printf("+------------------------------------------------------------ \n"); \
\
assert(s1 == NTOTAL && s2 == 0); \
\
printf("+------------------------------------------------------------ %10s\n\n", #NAME); \
printf("+------------------------------------------------------------ \n"); \
\
assert(s1 == NTOTAL && s2 == 0); \
\
printf("+------------------------------------------------------------ %10s\n\n", #NAME); \
}
BENCHMARK(DEQUE, d, deque, d_new(NTOTAL), d_push_back(coll, array[i]), d_pop_back(coll), d_contains(coll, sarray[i], intcmp))
BENCHMARK(HASHMAP, hm, hmap, hm_new(NTOTAL, 0.8, intcmp, inthash), hm_insert(coll, array[i], array[i]), hm_remove(coll, array[i], &r), hm_contains(coll, sarray[i]))
BENCHMARK(HASHSET, hs, hset, hs_new(NTOTAL, 0.8, intcmp, inthash), hs_insert(coll, array[i]), hs_remove(coll, array[i]), hs_contains(coll, sarray[i]))
BENCHMARK(HEAP, h, heap, h_new(NTOTAL, MinHeap, intcmp), h_insert(coll, array[i]), h_remove(coll, &r), h_contains(coll, sarray[i]))
BENCHMARK(LINKEDLIST, ll, linked, ll_new(), ll_push_back(coll, array[i]), ll_pop_back(coll), ll_contains(coll, sarray[i], intcmp))
BENCHMARK(LIST, l, list, l_new(NTOTAL), l_push_back(coll, array[i]), l_pop_back(coll), l_contains(coll, sarray[i], intcmp))
BENCHMARK(QUEUE, q, queue, q_new(NTOTAL), q_enqueue(coll, array[i]), q_dequeue(coll), q_contains(coll, sarray[i], intcmp))
BENCHMARK(STACK, s, stack, s_new(NTOTAL), s_push(coll, array[i]), s_pop(coll), s_contains(coll, sarray[i], intcmp))
BENCHMARK(TREEMAP, tm, tmap, tm_new(intcmp), tm_insert(coll, array[i], array[i]), tm_remove(coll, array[i], &r), tm_contains(coll, sarray[i]))
BENCHMARK(TREESET, ts, tset, ts_new(intcmp), ts_insert(coll, array[i]), ts_remove(coll, array[i]), ts_contains(coll, sarray[i]))
BENCHMARK(DEQUE, d, deque, d_new(NTOTAL, (struct deque_fval *)&int_ftab), d_push_back(coll, array[i]), d_pop_back(coll),
d_contains(coll, sarray[i]))
BENCHMARK(HASHMAP, hm, hashmap, hm_new(NTOTAL, 0.6, (struct hashmap_fkey *)&int_ftab, (struct hashmap_fval *)&int_ftab),
hm_insert(coll, array[i], array[i]), hm_remove(coll, array[i], &r), hm_contains(coll, sarray[i]))
BENCHMARK(HASHSET, hs, hashset, hs_new(NTOTAL, 0.6, (struct hashset_fval *)&int_ftab), hs_insert(coll, array[i]),
hs_remove(coll, array[i]), hs_contains(coll, sarray[i]))
BENCHMARK(HEAP, h, heap, h_new(NTOTAL, CMC_MIN_HEAP, (struct heap_fval *)&int_ftab), h_insert(coll, array[i]),
h_remove(coll), h_contains(coll, sarray[i]))
BENCHMARK(LINKEDLIST, ll, linkedlist, ll_new((struct linkedlist_fval *)&int_ftab), ll_push_back(coll, array[i]),
ll_pop_back(coll), ll_contains(coll, sarray[i]))
BENCHMARK(LIST, l, list, l_new(NTOTAL, (struct list_fval *)&int_ftab), l_push_back(coll, array[i]), l_pop_back(coll),
l_contains(coll, sarray[i]))
BENCHMARK(QUEUE, q, queue, q_new(NTOTAL, (struct queue_fval *)&int_ftab), q_enqueue(coll, array[i]), q_dequeue(coll),
q_contains(coll, sarray[i]))
BENCHMARK(STACK, s, stack, s_new(NTOTAL, (struct stack_fval *)&int_ftab), s_push(coll, array[i]), s_pop(coll),
s_contains(coll, sarray[i]))
BENCHMARK(TREEMAP, tm, treemap, tm_new((struct treemap_fkey *)&int_ftab, (struct treemap_fval *)&int_ftab),
tm_insert(coll, array[i], array[i]), tm_remove(coll, array[i], &r), tm_contains(coll, sarray[i]))
BENCHMARK(TREESET, ts, treeset, ts_new((struct treeset_fval *)&int_ftab), ts_insert(coll, array[i]),
ts_remove(coll, array[i]), ts_contains(coll, sarray[i]))
BENCHMARK(INTERVALHEAP, ih, intervalheap, ih_new(NTOTAL, (struct intervalheap_fval *)&int_ftab),
ih_insert(coll, array[i]), ih_remove_max(coll), ih_contains(coll, sarray[i]))
BENCHMARK(MULTIMAP, hmm, hashmultimap,
hmm_new(NTOTAL, 0.8, (struct hashmultimap_fkey *)&int_ftab, (struct hashmultimap_fval *)&int_ftab),
hmm_insert(coll, array[i], array[i]), hmm_remove(coll, array[i], &r), hmm_contains(coll, sarray[i]))
BENCHMARK(MULTISET, hms, hashmultiset, hms_new(NTOTAL, 0.6, (struct hashmultiset_fval *)&int_ftab),
hms_insert(coll, array[i]), hms_remove(coll, array[i]), hms_contains(coll, sarray[i]))
int main(void)
{
@@ -210,10 +260,14 @@ int main(void)
shuffle(sarray, &st);
printf("\nNote: Adjusted Time refers to if the container had done a search over all %" PRIuMAX " elements.\n\n", NTOTAL);
printf("\nNote: Adjusted Time refers to if the container had done a search over all %" PRIuMAX " elements.\n\n",
NTOTAL);
// Linear containers have to search for NMIN elements and non-linear (hash
// and tree) have to search for all elements.
struct cmc_timer timer;
cmc_timer_start(timer);
DEQUE_io_benchmark(array, sarray, NMIN);
HASHMAP_io_benchmark(array, sarray, NTOTAL);
HASHSET_io_benchmark(array, sarray, NTOTAL);
@@ -225,6 +279,16 @@ int main(void)
TREEMAP_io_benchmark(array, sarray, NTOTAL);
TREESET_io_benchmark(array, sarray, NTOTAL);
// INTERVALHEAP_io_benchmark(array, array, NMIN);
// MULTIMAP_io_benchmark(array, array, NTOTAL);
// MULTISET_io_benchmark(array, array, NTOTAL);
cmc_timer_stop(timer);
printf("+-----------------------------------------------------------+ \n");
printf("| Total Benchmark Running Time : %12.0lf seconds | \n", timer.result / 1000);
printf("+-----------------------------------------------------------+ \n");
free(array);
free(sarray);
+19
View File
@@ -0,0 +1,19 @@
INCLUDE=-I ../../..
CFLAGS=-O3 -Wall -Wextra -Werror -DCOUNT=20000000 -DCMC_NO_CALLBACKS
# Install hyperfine
# https://github.com/sharkdp/hyperfine
run: build
hyperfine --warmup 2 --runs 5 './hashmap.exe'
hyperfine --warmup 2 --runs 5 './hashmultimap.exe'
hyperfine --warmup 2 --runs 5 './unorderedmap.exe'
build:
gcc hashmap.c -o hashmap.exe $(INCLUDE) $(CFLAGS)
gcc hashmultimap.c -o hashmultimap.exe $(INCLUDE) $(CFLAGS)
g++ unorderedmap.cpp $(INCLUDE) -o unorderedmap.exe $(CFLAGS)
clean:
rm *.exe -f
rm *.txt -f
@@ -0,0 +1,55 @@
#ifndef COUNT
#error "Please define COUNT"
#endif
#include "murmurhash.h"
#include "../../util/twister.c"
#define K uint64_t
#define V uint64_t
#define PFX hm
#define SNAME hashmap
#include "cmc/hashmap.h"
int cmp(uint64_t a, uint64_t b)
{
return (a > b) - (a < b);
}
// size_t hash(uint64_t a)
// {
// size_t x = (size_t)a;
// x = ((x >> 16) ^ x) * 0x45d9f3b;
// x = ((x >> 16) ^ x) * 0x45d9f3b;
// x = (x >> 16) ^ x;
// return x;
// }
size_t hash(uint64_t k)
{
static size_t seed = 211106232532969;
return MurMurHash(&k, sizeof(k), seed);
}
struct hashmap_fkey *fkey = &(struct hashmap_fkey){ .cmp = cmp, .hash = hash, NULL };
struct hashmap_fval *fval = &(struct hashmap_fval){ .cmp = cmp, .hash = hash, NULL };
int main(void)
{
mt_state tw;
twist_init(&tw, 50331653);
struct hashmap *map = hm_new(COUNT, 0.6, fkey, fval);
for (uint64_t i = 0; i < COUNT; i++)
{
uint64_t v = twist_uint64(&tw);
hm_insert(map, v, v);
}
hm_free(map);
return 0;
}
@@ -0,0 +1,55 @@
#ifndef COUNT
#error "Please define COUNT"
#endif
#include "murmurhash.h"
#include "../../util/twister.c"
#define K uint64_t
#define V uint64_t
#define PFX hmm
#define SNAME hashmultimap
#include "cmc/hashmultimap.h"
int cmp(uint64_t a, uint64_t b)
{
return (a > b) - (a < b);
}
// size_t hash(uint64_t a)
// {
// size_t x = (size_t)a;
// x = ((x >> 16) ^ x) * 0x45d9f3b;
// x = ((x >> 16) ^ x) * 0x45d9f3b;
// x = (x >> 16) ^ x;
// return x;
// }
size_t hash(uint64_t k)
{
static size_t seed = 211106232532969;
return MurMurHash(&k, sizeof(k), seed);
}
struct hashmultimap_fkey *fkey = &(struct hashmultimap_fkey){ .cmp = cmp, .hash = hash, NULL };
struct hashmultimap_fval *fval = &(struct hashmultimap_fval){ .cmp = cmp, .hash = hash, NULL };
int main(void)
{
mt_state tw;
twist_init(&tw, 50331653);
struct hashmultimap *map = hmm_new(COUNT, 0.6, fkey, fval);
for (uint64_t i = 0; i < COUNT; i++)
{
uint64_t v = twist_uint64(&tw);
hmm_insert(map, v, v);
}
hmm_free(map);
return 0;
}
@@ -0,0 +1,58 @@
// https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/hash_bytes.cc
#ifndef MURMURHASH
#define MURMURHASH
#include <string.h>
inline size_t unaligned_load(const char *p)
{
size_t result;
memcpy(&result, p, sizeof(result));
return result;
}
inline size_t load_bytes(const char *p, int n)
{
size_t result = 0;
--n;
do
{
result = (result << 8) + (unsigned char)(p[n]);
} while (--n >= 0);
return result;
}
inline size_t shift_mix(size_t v)
{
return v ^ (v >> 47);
}
size_t MurMurHash(const void *ptr, size_t len, size_t seed)
{
static const size_t mul = (((size_t)0xc6a4a793UL) << 32UL) + (size_t)0x5bd1e995UL;
const char *const buf = (const char *)(ptr);
// Remove the bytes not divisible by the sizeof(size_t). This
// allows the main loop to process the data as 64-bit integers.
const size_t len_aligned = len & ~(size_t)0x7;
const char *const end = buf + len_aligned;
size_t hash = seed ^ (len * mul);
for (const char *p = buf; p != end; p += 8)
{
const size_t data = shift_mix(unaligned_load(p) * mul) * mul;
hash ^= data;
hash *= mul;
}
if ((len & 0x7) != 0)
{
const size_t data = load_bytes(end, len & 0x7);
hash ^= data;
hash *= mul;
}
hash = shift_mix(hash) * mul;
hash = shift_mix(hash);
return hash;
}
#endif /* MURMURHASH */
@@ -0,0 +1,34 @@
#ifndef COUNT
#error "Please define COUNT"
#endif
#include "murmurhash.h"
#include <unordered_map>
#include "../../util/twister.c"
struct IntHasher
{
std::size_t operator()(const uint64_t &k) const
{
static size_t seed = 211106232532969;
return MurMurHash(&k, sizeof(k), seed);
}
};
int main(void)
{
mt_state tw;
twist_init(&tw, 50331653);
std::unordered_map<uint64_t, uint64_t, IntHasher> map(COUNT);
for (uint64_t i = 0; i < COUNT; i++)
{
uint64_t v = twist_uint64(&tw);
map.insert({ v, v });
}
return 0;
}
-27
View File
@@ -1,27 +0,0 @@
/**
* timer.h
*
* Creation Date: 12/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Simple timer macros.
*/
#include <time.h>
typedef struct timer_s
{
clock_t start;
clock_t stop;
double result;
} timer_t;
#define TIMER_START(timer) \
timer.start = clock();
#define TIMER_STOP(timer) \
timer.stop = clock();
#define TIMER_CALC(timer) \
timer.result = (double)(((timer.stop - timer.start) * 1000.0) / CLOCKS_PER_SEC);
+1 -1
View File
@@ -7,7 +7,7 @@
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Mersenne Twister PRNG utility
*
*
*/
#include <stdio.h>
#include <stdlib.h>
+11
View File
@@ -0,0 +1,11 @@
[book]
authors = ["Leonardo Vencovsky"]
language = "en"
multilingual = false
src = "documentation/"
title = "C Macro Collections"
[build]
build-dir = "docs/"
[preprocessor.index]
+92
View File
@@ -0,0 +1,92 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* bitset.h
*
* Creation Date: 30/04/2020
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* BitSet
*
* A Bit Set is an array where each bit can be individually modified and queried
* by using bitwise operators such as |, &, ^, ~, >> and << (or, and, xor, not,
* right shift, left shift respectively).
*
* Implementation
*
* This BitSet implementation uses an array of type cmc_bitset_word which can be
* typedefed to any unsigned type such as uint8_t, uint16_t, uint32_t, uint64_t,
* size_t, etc. The BitSet does not make use of K or V. Because of that, it also
* doesn't have Functions Tables.
*
* The BitSet is initialized with a custom capacity but, if a bit index accessed
* is greater than the total capacity, the BitSet will resize. This means that
* the BitSet will try to guarantee that every bit index is accessible, as long
* as there is enough memory.
*/
#include "cor/bitset.h"
#include "cor/core.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/bitset/struct.h"
/* Function declaration */
#include "cmc/bitset/header.h"
/* Function implementation */
#include "cmc/bitset/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - bitset iterator
* STR - Print helper functions
*/
#define CMC_EXT_BITSET_PARTS INIT, ITER, STR
/**/
#include "cmc/bitset/ext/struct.h"
/**/
#include "cmc/bitset/ext/header.h"
/**/
#include "cmc/bitset/ext/code.h"
#include "cor/undef.h"
+512
View File
@@ -0,0 +1,512 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
bool CMC_(PFX, _impl_resize)(struct SNAME *_bitset_, size_t n_bits, bool do_resize);
struct SNAME *CMC_(PFX, _new)(size_t n_bits)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(n_bits, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t n_bits, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (n_bits < 1)
return NULL;
if (!alloc)
alloc = &cmc_alloc_node_default;
size_t capacity = cmc_bidx_to_widx(n_bits - 1) + 1;
struct SNAME *_bitset_ = alloc->malloc(sizeof(struct SNAME));
if (!_bitset_)
return NULL;
_bitset_->buffer = alloc->calloc(capacity, sizeof(cmc_bitset_word));
if (!_bitset_->buffer)
{
alloc->free(_bitset_);
return NULL;
}
_bitset_->capacity = capacity;
_bitset_->flag = CMC_FLAG_OK;
_bitset_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_bitset_, callbacks);
return _bitset_;
}
struct SNAME CMC_(PFX, _init)(size_t n_bits)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _init_custom)(n_bits, NULL, NULL);
}
struct SNAME CMC_(PFX, _init_custom)(size_t n_bits, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
struct SNAME _bitset_ = { 0 };
if (n_bits < 1)
return _bitset_;
if (!alloc)
alloc = &cmc_alloc_node_default;
size_t capacity = cmc_bidx_to_widx(n_bits - 1) + 1;
_bitset_.buffer = alloc->calloc(capacity, sizeof(cmc_bitset_word));
if (!_bitset_.buffer)
return _bitset_;
_bitset_.capacity = capacity;
_bitset_.flag = CMC_FLAG_OK;
_bitset_.alloc = alloc;
CMC_CALLBACKS_ASSIGN(&_bitset_, callbacks);
return _bitset_;
}
void CMC_(PFX, _free)(struct SNAME *_bitset_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
free(_bitset_->buffer);
free(_bitset_);
}
void CMC_(PFX, _release)(struct SNAME _bitset_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
free(_bitset_.buffer);
}
void CMC_(PFX, _customize)(struct SNAME *_bitset_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_bitset_->alloc = &cmc_alloc_node_default;
else
_bitset_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_bitset_, callbacks);
_bitset_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _set)(struct SNAME *_bitset_, size_t bit_index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _impl_resize)(_bitset_, bit_index + 1, false))
return false;
/* How many bits in a word */
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
size_t i = cmc_bidx_to_widx(bit_index);
_bitset_->buffer[i] |= ((cmc_bitset_word)1) << (bit_index % bits);
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _set_range)(struct SNAME *_bitset_, size_t from, size_t to)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (to < from)
{
_bitset_->flag = CMC_FLAG_INVALID;
return false;
}
if (!CMC_(PFX, _impl_resize)(_bitset_, to + 1, false))
return false;
size_t start_index = cmc_bidx_to_widx(from);
size_t end_index = cmc_bidx_to_widx(to);
/* How many bits in a word */
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
/* 1111 ... 1111 */
const cmc_bitset_word ones = ~((cmc_bitset_word)0);
cmc_bitset_word shift_start = from % bits;
cmc_bitset_word shift_end = (cmc_bitset_word)(-(to + 1)) % bits;
cmc_bitset_word start_mask = ones << shift_start;
cmc_bitset_word end_mask = ones >> shift_end;
if (start_index == end_index)
{
_bitset_->buffer[end_index] |= (start_mask & end_mask);
}
else
{
_bitset_->buffer[start_index] |= start_mask;
for (size_t i = start_index + 1; i < end_index; i++)
_bitset_->buffer[i] |= ~((cmc_bitset_word)0);
_bitset_->buffer[end_index] |= end_mask;
}
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _clear)(struct SNAME *_bitset_, size_t bit_index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _impl_resize)(_bitset_, bit_index + 1, false))
return false;
/* How many bits in a word */
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
size_t i = cmc_bidx_to_widx(bit_index);
_bitset_->buffer[i] &= ~(((cmc_bitset_word)1) << (bit_index % bits));
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _clear_range)(struct SNAME *_bitset_, size_t from, size_t to)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (to < from)
{
_bitset_->flag = CMC_FLAG_INVALID;
return false;
}
if (!CMC_(PFX, _impl_resize)(_bitset_, to + 1, false))
return false;
size_t start_index = cmc_bidx_to_widx(from);
size_t end_index = cmc_bidx_to_widx(to);
/* How many bits in a word */
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
/* 1111 ... 1111 */
const cmc_bitset_word ones = ~((cmc_bitset_word)0);
cmc_bitset_word shift_start = from % bits;
cmc_bitset_word shift_end = (cmc_bitset_word)(-(to + 1)) % bits;
cmc_bitset_word start_mask = ones << shift_start;
cmc_bitset_word end_mask = ones >> shift_end;
if (start_index == end_index)
{
_bitset_->buffer[end_index] &= ~(start_mask & end_mask);
}
else
{
_bitset_->buffer[start_index] &= ~start_mask;
for (size_t i = start_index + 1; i < end_index; i++)
_bitset_->buffer[i] = 0;
_bitset_->buffer[end_index] &= ~end_mask;
}
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _flip)(struct SNAME *_bitset_, size_t bit_index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _impl_resize)(_bitset_, bit_index + 1, false))
return false;
/* How many bits in a word */
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
size_t i = cmc_bidx_to_widx(bit_index);
_bitset_->buffer[i] ^= ((cmc_bitset_word)1) << (bit_index % bits);
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _flip_range)(struct SNAME *_bitset_, size_t from, size_t to)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (to < from)
{
_bitset_->flag = CMC_FLAG_INVALID;
return false;
}
if (!CMC_(PFX, _impl_resize)(_bitset_, to + 1, false))
return false;
size_t start_index = cmc_bidx_to_widx(from);
size_t end_index = cmc_bidx_to_widx(to);
/* How many bits in a word */
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
/* 1111 ... 1111 */
const cmc_bitset_word ones = ~((cmc_bitset_word)0);
cmc_bitset_word shift_start = from % bits;
cmc_bitset_word shift_end = (cmc_bitset_word)(-(to + 1)) % bits;
cmc_bitset_word start_mask = ones << shift_start;
cmc_bitset_word end_mask = ones >> shift_end;
if (start_index == end_index)
{
_bitset_->buffer[end_index] ^= (start_mask & end_mask);
}
else
{
_bitset_->buffer[start_index] ^= start_mask;
for (size_t i = start_index + 1; i < end_index; i++)
_bitset_->buffer[i] ^= ones;
_bitset_->buffer[end_index] ^= end_mask;
}
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _put)(struct SNAME *_bitset_, size_t bit_index, bool state)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (state)
return CMC_(PFX, _set)(_bitset_, bit_index);
else
return CMC_(PFX, _clear)(_bitset_, bit_index);
}
bool CMC_(PFX, _put_range)(struct SNAME *_bitset_, size_t from, size_t to, bool state)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (state)
return CMC_(PFX, _set_range)(_bitset_, from, to);
else
return CMC_(PFX, _clear_range)(_bitset_, from, to);
}
bool CMC_(PFX, _set_all)(struct SNAME *_bitset_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
for (size_t i = 0; i < _bitset_->capacity; i++)
_bitset_->buffer[i] = ~((cmc_bitset_word)0);
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _clear_all)(struct SNAME *_bitset_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
for (size_t i = 0; i < _bitset_->capacity; i++)
_bitset_->buffer[i] = 0;
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _flip_all)(struct SNAME *_bitset_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
for (size_t i = 0; i < _bitset_->capacity; i++)
_bitset_->buffer[i] ^= ~((cmc_bitset_word)0);
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _get)(struct SNAME *_bitset_, size_t bit_index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* How many bits in a word */
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
cmc_bitset_word w = _bitset_->buffer[cmc_bidx_to_widx(bit_index)];
return w & ((cmc_bitset_word)1 << (bit_index % bits));
}
bool CMC_(PFX, _resize)(struct SNAME *_bitset_, size_t n_bits)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _impl_resize)(_bitset_, n_bits, true);
}
/* When do_resize is false, then we just want to assure that the bitset */
/* can accommodate n_bits */
bool CMC_(PFX, _impl_resize)(struct SNAME *_bitset_, size_t n_bits, bool do_resize)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (n_bits == 0)
{
_bitset_->flag = CMC_FLAG_INVALID;
return false;
}
/* -1 because n_bits is 1-based and we need to pass a 0-based index */
/* +1 to have a 1-based result */
size_t words = cmc_bidx_to_widx(n_bits - 1) + 1;
/* Be sure we are not always shrinking when we just want to make */
/* sure that we have enough size for n_bits */
if (!do_resize && words <= _bitset_->capacity)
return true;
cmc_bitset_word *new_buffer = realloc(_bitset_->buffer, words * sizeof(cmc_bitset_word));
if (!new_buffer)
{
_bitset_->flag = CMC_FLAG_ALLOC;
return false;
}
_bitset_->buffer = new_buffer;
/* Make new bits be all zeroes */
if (_bitset_->capacity < words)
memset(_bitset_->buffer + _bitset_->capacity, 0, (words - _bitset_->capacity) * sizeof(cmc_bitset_word));
_bitset_->capacity = words;
CMC_CALLBACKS_CALL(_bitset_);
_bitset_->flag = CMC_FLAG_OK;
return true;
}
+57
View File
@@ -0,0 +1,57 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Bitset bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Functions */
/* Iterator Initialization */
/* Iterator State */
/* Iterator Movement */
/* Iterator Access */
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
#endif /* CMC_EXT_STR */
+57
View File
@@ -0,0 +1,57 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Bitset bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Functions */
/* Iterator Initialization */
/* Iterator State */
/* Iterator Movement */
/* Iterator Access */
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
#endif /* CMC_EXT_STR */
+45
View File
@@ -0,0 +1,45 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Bitset bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* BitSet Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target bitset */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+49
View File
@@ -0,0 +1,49 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t n_bits);
struct SNAME *CMC_(PFX, _new_custom)(size_t n_bits, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
struct SNAME CMC_(PFX, _init)(size_t n_bits);
struct SNAME CMC_(PFX, _init_custom)(size_t n_bits, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _free)(struct SNAME *_bitset_);
void CMC_(PFX, _release)(struct SNAME _bitset_);
void CMC_(PFX, _customize)(struct SNAME *_bitset_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _set)(struct SNAME *_bitset_, size_t bit_index);
bool CMC_(PFX, _set_range)(struct SNAME *_bitset_, size_t from, size_t to);
bool CMC_(PFX, _clear)(struct SNAME *_bitset_, size_t bit_index);
bool CMC_(PFX, _clear_range)(struct SNAME *_bitset_, size_t from, size_t to);
bool CMC_(PFX, _flip)(struct SNAME *_bitset_, size_t bit_index);
bool CMC_(PFX, _flip_range)(struct SNAME *_bitset_, size_t from, size_t to);
bool CMC_(PFX, _put)(struct SNAME *_bitset_, size_t bit_index, bool state);
bool CMC_(PFX, _put_range)(struct SNAME *_bitset_, size_t from, size_t to, bool state);
bool CMC_(PFX, _set_all)(struct SNAME *_bitset_);
bool CMC_(PFX, _clear_all)(struct SNAME *_bitset_);
bool CMC_(PFX, _flip_all)(struct SNAME *_bitset_);
/* Element Access */
bool CMC_(PFX, _get)(struct SNAME *_bitset_, size_t bit_index);
/* Collection State */
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_bitset_, size_t n_bits);
+42
View File
@@ -0,0 +1,42 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* BitSet Structure */
struct SNAME
{
/* Dynamic Array of Bits */
cmc_bitset_word *buffer;
/* Current array capacity */
size_t capacity;
/* Currently used bits */
/* This should always be true: */
/* capacity - count < sizeof(cmc_bitset_word) * CHAR_BIT */
size_t count;
/* Flags indicating errors or success */
int flag;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
+67
View File
@@ -0,0 +1,67 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* alloc.h
*
* Creation Date: 24/05/2020
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#ifndef CMC_COR_ALLOC_H
#define CMC_COR_ALLOC_H
#ifndef CMC_NO_ALLOC
#ifdef CMC_CAMEL_CASE
#define CMC_ALLOC_NODE_NAME CMCAllocNode
#else
#define CMC_ALLOC_NODE_NAME cmc_alloc_node
#endif
#include "core.h"
/**
* struct cmc_alloc_node
*
* Custom allocation node. Allows collections to use custom allocation
* functions. The cmc_alloc_node_default is the default heap allocator provided
* by the standard library.
*/
#define CMC_ALLOC_TYPE struct CMC_ALLOC_NODE_NAME *
static struct CMC_ALLOC_NODE_NAME
{
void *(*malloc)(size_t);
void *(*calloc)(size_t, size_t);
void *(*realloc)(void *, size_t);
void (*free)(void *);
} CMC_UNUSED cmc_alloc_node_default = { malloc, calloc, realloc, free };
#endif /* CMC_NO_ALLOC */
#endif /* CMC_COR_ALLOC_H */
+68
View File
@@ -0,0 +1,68 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* bitset.h
*
* Creation Date: 20/05/2020
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Things commonly used by bitset collections.
*/
#ifndef CMC_COR_BITSET_H
#define CMC_COR_BITSET_H
#include "core.h"
/* Defines the underlaying data type for the bitset array */
/* Possible values: uint64_t, uint32_t, uint16_t, uint8_t, size_t */
#ifndef CMC_BITSET_WORD_TYPE
#define CMC_BITSET_WORD_TYPE uint32_t
#endif /* CMC_BITSET_WORD_TYPE */
typedef CMC_BITSET_WORD_TYPE cmc_bitset_word;
/**
* cmc_bidx_to_widx
*
* Translates a bit index to a word index
*/
static inline size_t cmc_bidx_to_widx(size_t idx)
{
/* Calculate how many shifts based on the size of cmc_bitset_word */
static const size_t shift = ((sizeof(cmc_bitset_word) * 8) >> 6) > 0 ? 6
: ((sizeof(cmc_bitset_word) * 8) >> 5) > 0 ? 5
: ((sizeof(cmc_bitset_word) * 8) >> 4) > 0 ? 4
: 3;
return idx >> shift;
}
#endif /* CMC_COR_BITSET_H */
+61
View File
@@ -0,0 +1,61 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* callbacks.h
*
* Creation Date: 24/05/2020
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#ifndef CMC_COR_CALLBACKS_H
#define CMC_COR_CALLBACKS_H
typedef void (*cmc_callback)(const char func_name[], void *self);
#define CMC_CALLBACK_TYPE cmc_callback
#ifdef CMC_CALLBACKS
#define CMC_CALLBACKS_DECL cmc_callback callbacks
#define CMC_CALLBACKS_MAYBE_UNUSED(param)
#define CMC_CALLBACKS_GET(ds) (ds)->callbacks
#define CMC_CALLBACKS_ASSIGN(ds, cb) CMC_CALLBACKS_GET(ds) = cb
#define CMC_CALLBACKS_CALL(ds) \
if (CMC_CALLBACKS_GET(ds)) \
CMC_CALLBACKS_GET(ds)(__func__, (void *)ds);
#else
#define CMC_CALLBACKS_DECL
#define CMC_CALLBACKS_MAYBE_UNUSED(param) CMC_UNUSED_PARAM(param) /* Prevent -Wunused-parameter */
#define CMC_CALLBACKS_GET(ds) NULL /* Helps with compatibility */
#define CMC_CALLBACKS_ASSIGN(ds, cb)
#define CMC_CALLBACKS_CALL(ds)
#endif
#endif /* CMC_COR_CALLBACKS_H */
+100
View File
@@ -0,0 +1,100 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* core.h
*
* Creation Date: 17/03/2020
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Core includes and macros for the entire library.
*
* Here you will find:
* - CMC_
* - CMC_TO_STRING
* - CMC_INTERNAL_PREFIX_[ITER|NODE|ENTRY|FKEY|FVAL]
* - CMC_DEF_[ITER|NODE|ENTRY|FKEY|FVAL]
*/
#ifndef CMC_COR_CORE_H
#define CMC_COR_CORE_H
#ifndef CMC_NO_IMPORTS
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif /* CMC_NO_IMPORTS */
#if defined(__GNUC__) || defined(__clang__)
#define CMC_UNUSED __attribute__((__unused__))
#else
#define CMC_UNUSED
#endif
#define CMC_UNUSED_PARAM(param) ((void)param)
#define CMC__(A, B) A##B
#define CMC_(A, B) CMC__(A, B)
#define CMC_TO_STRING_(X) #X
#define CMC_TO_STRING(X) CMC_TO_STRING_(X)
#include "alloc.h"
#include "callbacks.h"
#include "dev.h"
#include "flags.h"
#include "ftable.h"
#if defined(CMC_CAMEL_CASE)
#define CMC_INTERNAL_PREFIX_ITER Iter
#define CMC_INTERNAL_PREFIX_NODE Node
#define CMC_INTERNAL_PREFIX_ENTRY Entry
#define CMC_INTERNAL_PREFIX_FVAL FVal
#define CMC_INTERNAL_PREFIX_FKEY FKey
#else
#define CMC_INTERNAL_PREFIX_ITER _iter
#define CMC_INTERNAL_PREFIX_NODE _node
#define CMC_INTERNAL_PREFIX_ENTRY _entry
#define CMC_INTERNAL_PREFIX_FVAL _fval
#define CMC_INTERNAL_PREFIX_FKEY _fkey
#endif
#define CMC_DEF_ITER(SNAME) CMC_(SNAME, CMC_INTERNAL_PREFIX_ITER)
#define CMC_DEF_NODE(SNAME) CMC_(SNAME, CMC_INTERNAL_PREFIX_NODE)
#define CMC_DEF_ENTRY(SNAME) CMC_(SNAME, CMC_INTERNAL_PREFIX_ENTRY)
#define CMC_DEF_FVAL(SNAME) CMC_(SNAME, CMC_INTERNAL_PREFIX_FVAL)
#define CMC_DEF_FKEY(SNAME) CMC_(SNAME, CMC_INTERNAL_PREFIX_FKEY)
#endif /* CMC_COR_CORE_H */
+46
View File
@@ -0,0 +1,46 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* dev.h
*
* Creation Date: 01/02/2023
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#ifndef CMC_COR_DEV_H
#define CMC_COR_DEV_H
/**
* Macros for tracing and debugging data structures when CMC_DEV is enabled
*/
#ifndef CMC_DEV_FCALL
#define CMC_DEV_FCALL cmc_log_trace("fcall")
#endif
#endif /* CMC_COR_DEV_H */
+72
View File
@@ -0,0 +1,72 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* flags.h
*
* Creation Date: 14/05/2020
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#ifndef CMC_COR_FLAGS_H
#define CMC_COR_FLAGS_H
#include "core.h"
/**
* enum cmc_flags
*
* Defines common error codes used by the entire library.
*/
// clang-format off
enum cmc_flags
{
CMC_FLAG_OK = 0, // No errors
CMC_FLAG_ALLOC = 1, // Allocation failed
CMC_FLAG_EMPTY = 2, // The collection is empty when it should not
CMC_FLAG_NOT_FOUND = 3, // Key or value not found
CMC_FLAG_INVALID = 4, // Invalid argument or operation
CMC_FLAG_RANGE = 5, // Index out of range
CMC_FLAG_DUPLICATE = 6, // Duplicate key or value
CMC_FLAG_ERROR = 7, // Generic error, usually caused by algorithm error
CMC_FLAG_THREAD = 8, // Generic error regarding threads
CMC_FLAG_MUTEX = 9, // Generic error regarding mutexes
CMC_FLAG_FULL = 10, // When a collection that doesn't resize is full
CMC_FLAG_FTABLE = 11, // When a required ftable function is missing
};
// clang-format on
/**
* cmc_flags_to_str
*
* Maps the error codes to their character representation.
*/
CMC_UNUSED static const char *cmc_flags_to_str[12] = {
"OK", "ALLOC", "EMPTY", "NOT_FOUND", "INVALID", "RANGE", "DUPLICATE", "ERROR", "THREAD", "MUTEX", "FULL", "FTABLE"
};
#endif /* CMC_COR_FLAGS_H */
+52
View File
@@ -0,0 +1,52 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ftable.h
*
* Creation Date: 27/05/2020
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Type definitions for Functions Tables.
*/
#ifndef CMC_COR_FTABLE_H
#define CMC_COR_FTABLE_H
/**
* Where T can either be K or V
*/
#define CMC_DEF_FTAB_CMP(T) int (*cmp)(T, T)
#define CMC_DEF_FTAB_CPY(T) T (*cpy)(T)
#define CMC_DEF_FTAB_STR(T) bool (*str)(FILE *, T)
#define CMC_DEF_FTAB_FREE(T) void (*free)(T)
#define CMC_DEF_FTAB_HASH(T) size_t (*hash)(T)
#define CMC_DEF_FTAB_PRI(T) int (*pri)(T, T)
#endif /* CMC_COR_FTABLE_H */
+110
View File
@@ -0,0 +1,110 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* hashtable.h
*
* Creation Date: 17/03/2020
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Things commonly used by hashtable-based collections.
*/
#ifndef CMC_COR_HASHTABLE_H
#define CMC_COR_HASHTABLE_H
#include "core.h"
/**
* CMC_ENTRY_DELETED
*
* Defines a pointer to an entry that has been deleted
*/
#define CMC_ENTRY_DELETED ((void *)1)
/**
* enum cmc_entry_state
*
* Defines the three possible states for a node on a flat hashtable.
*/
enum cmc_entry_state
{
CMC_ES_DELETED = -1,
CMC_ES_EMPTY = 0,
CMC_ES_FILLED = 1
};
/**
* static const size_t cmc_hashtable_primes[59]
*
* Prime numbers used to define a capacity for the hashtables for better
* hashing.
*/
// clang-format off
static const size_t cmc_hashtable_primes[] = {
/* < 1e3 */
53, 97, 191, 383, 769,
/* < 1e4 */
1531, 3067, 6143,
/* < 1e5 */
12289, 24571, 49157, 98299,
/* < 1e6 */
196613, 393209, 786431,
/* < 1e7 */
1572869, 3145721, 6291449,
/* < 1e8 */
12582917, 25165813, 50331653,
/* < 1e9 */
100663291, 201326611, 402653189, 805306357,
/* < 1e10 */
1610612741, 3221225473, 6442450939,
/* < 1e11 */
12884901893, 25769803799, 51539607551,
/* < 1e12 */
103079215111, 206158430209, 412316860441, 824633720831,
/* < 1e13 */
1649267441651, 3298534883309, 6597069766657,
/* < 1e14 */
13194139533299, 26388279066623, 52776558133303,
/* < 1e15 */
105553116266489, 211106232532969, 422212465066001, 844424930131963,
/* < 1e16 */
1688849860263953, 3377699720527861, 6755399441055731,
/* < 1e17 */
13510798882111483, 27021597764222939, 54043195528445957,
/* < 1e18 */
108086391056891903, 216172782113783773, 432345564227567621, 864691128455135207,
/* < 1e19 */
1729382256910270481, 3458764513820540933, 6917529027641081903,
/* < 1e20 */
13835058055282163729llu,
};
// clang-format on
#endif /* CMC_COR_HASHTABLE_H */
+55
View File
@@ -0,0 +1,55 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* heap.h
*
* Creation Date: 01/06/2020
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Things commonly used by heap collections.
*/
#ifndef CMC_COR_HEAP_H
#define CMC_COR_HEAP_H
/**
* enum cmc_heap_order
*
* Defines the two possible heaps:
* - Max Heap has the greatest element at the top
* - Min Heap has the smallest element at the top
*/
enum cmc_heap_order
{
CMC_MAX_HEAP = 1,
CMC_MIN_HEAP = -1
};
#endif /* CMC_COR_HEAP_H */
+67
View File
@@ -0,0 +1,67 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* undef.h
*
* Creation Date: 12/01/2023
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Common undefs
*/
/* You never want these to fallthrough since they should be unique for each collection */
#undef PFX
#undef SNAME
#ifndef CMC_ARGS_FALLTHROUGH
#undef CMC_DEV
#undef CMC_SAC
#ifndef CMC_ARGS_KEY_FALLTHROUGH
#undef K
#endif
#ifndef CMC_ARGS_VAL_FALLTHROUGH
#undef V
#endif
#undef SIZE
#ifndef CMC_EXT_FALLTHROUGH
#undef CMC_EXT_INIT
#undef CMC_EXT_ITER
#undef CMC_EXT_NODE
#undef CMC_EXT_SEQ
#undef CMC_EXT_SETF
#undef CMC_EXT_STR
#endif
#endif
+92
View File
@@ -0,0 +1,92 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* deque.h
*
* Creation Date: 20/03/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Deque
*
* A Deque (double-ended queue) is a linear data structure that is able to add
* or remove elements from both ends. It can also be thought of a double-ended
* stack since you can push and pop elements from two ends. The Deque can also
* be used as a Queue.
*
* There is no random access for a Deque. The only elements accessible are the
* front element and the back.
*
* Implementation
*
* This implementation uses a circular buffer (ring buffer or cyclic buffer) in
* order to operate on O(1) for push and pop on either ends (only case where it
* takes longer than O(1) is when the buffer is reallocated). If it was
* implemented as a regular array, adding or removing elements from the front
* would take O(N) due to the need to shift all elements in the deque.
*/
#include "cor/core.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* V - deque data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/deque/struct.h"
/* Function declaration */
#include "cmc/deque/header.h"
/* Function implementation */
#include "cmc/deque/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - Deque iterator
* STR - Print helper functions
*/
#define CMC_EXT_DEQUE_PARTS INIT, ITER, STR
/**/
#include "cmc/deque/ext/struct.h"
/**/
#include "cmc/deque/ext/header.h"
/**/
#include "cmc/deque/ext/code.h"
#include "cor/undef.h"
+461
View File
@@ -0,0 +1,461 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
/* None */
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(capacity, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity < 1)
return NULL;
if (!f_val)
return NULL;
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_deque_ = alloc->malloc(sizeof(struct SNAME));
if (!_deque_)
return NULL;
_deque_->buffer = alloc->calloc(capacity, sizeof(V));
if (!_deque_->buffer)
{
alloc->free(_deque_);
return NULL;
}
_deque_->capacity = capacity;
_deque_->count = 0;
_deque_->front = 0;
_deque_->back = 0;
_deque_->flag = CMC_FLAG_OK;
_deque_->f_val = f_val;
_deque_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_deque_, callbacks);
return _deque_;
}
void CMC_(PFX, _clear)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_deque_->f_val->free)
{
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
{
_deque_->f_val->free(_deque_->buffer[i]);
i = (i + 1) % _deque_->capacity;
}
}
memset(_deque_->buffer, 0, sizeof(V) * _deque_->capacity);
_deque_->count = 0;
_deque_->front = 0;
_deque_->back = 0;
_deque_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_deque_->f_val->free)
{
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
{
_deque_->f_val->free(_deque_->buffer[i]);
i = (i + 1) % _deque_->capacity;
}
}
_deque_->alloc->free(_deque_->buffer);
_deque_->alloc->free(_deque_);
}
void CMC_(PFX, _customize)(struct SNAME *_deque_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_deque_->alloc = &cmc_alloc_node_default;
else
_deque_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_deque_, callbacks);
_deque_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _push_front)(struct SNAME *_deque_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_deque_))
{
if (!CMC_(PFX, _resize)(_deque_, _deque_->capacity * 2))
return false;
}
_deque_->front = (_deque_->front == 0) ? _deque_->capacity - 1 : _deque_->front - 1;
_deque_->buffer[_deque_->front] = value;
_deque_->count++;
_deque_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_deque_);
return true;
}
bool CMC_(PFX, _push_back)(struct SNAME *_deque_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_deque_))
{
if (!CMC_(PFX, _resize)(_deque_, _deque_->capacity * 2))
return false;
}
_deque_->buffer[_deque_->back] = value;
_deque_->back = (_deque_->back == _deque_->capacity - 1) ? 0 : _deque_->back + 1;
_deque_->count++;
_deque_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_deque_);
return true;
}
bool CMC_(PFX, _pop_front)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_deque_))
{
_deque_->flag = CMC_FLAG_EMPTY;
return false;
}
_deque_->buffer[_deque_->front] = (V){ 0 };
_deque_->front = (_deque_->front == _deque_->capacity - 1) ? 0 : _deque_->front + 1;
_deque_->count--;
_deque_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_deque_);
return true;
}
bool CMC_(PFX, _pop_back)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_deque_))
{
_deque_->flag = CMC_FLAG_EMPTY;
return false;
}
_deque_->back = (_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1;
_deque_->buffer[_deque_->back] = (V){ 0 };
_deque_->count--;
_deque_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_deque_);
return true;
}
V CMC_(PFX, _front)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_deque_))
{
_deque_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
_deque_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_deque_);
return _deque_->buffer[_deque_->front];
}
V CMC_(PFX, _back)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_deque_))
{
_deque_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
_deque_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_deque_);
return _deque_->buffer[(_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1];
}
bool CMC_(PFX, _contains)(struct SNAME *_deque_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_deque_->flag = CMC_FLAG_OK;
bool result = false;
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
{
if (_deque_->f_val->cmp(_deque_->buffer[i], value) == 0)
{
result = true;
break;
}
i = (i + 1) % _deque_->capacity;
}
CMC_CALLBACKS_CALL(_deque_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _deque_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _deque_->count >= _deque_->capacity;
}
size_t CMC_(PFX, _count)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _deque_->count;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _deque_->capacity;
}
int CMC_(PFX, _flag)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _deque_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_deque_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_deque_->flag = CMC_FLAG_OK;
if (_deque_->capacity == capacity)
goto success;
if (capacity < _deque_->count)
{
_deque_->flag = CMC_FLAG_INVALID;
return false;
}
V *new_buffer = _deque_->alloc->malloc(sizeof(V) * capacity);
if (!new_buffer)
{
_deque_->flag = CMC_FLAG_ALLOC;
return false;
}
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
{
new_buffer[j] = _deque_->buffer[i];
i = (i + 1) % _deque_->capacity;
}
_deque_->alloc->free(_deque_->buffer);
_deque_->buffer = new_buffer;
_deque_->capacity = capacity;
_deque_->front = 0;
_deque_->back = _deque_->count;
success:
CMC_CALLBACKS_CALL(_deque_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *result = CMC_(PFX, _new_custom)(_deque_->capacity, _deque_->f_val, _deque_->alloc, NULL);
if (!result)
{
_deque_->flag = CMC_FLAG_ERROR;
return NULL;
}
CMC_CALLBACKS_ASSIGN(result, _deque_->callbacks);
if (_deque_->f_val->cpy)
{
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
{
result->buffer[j] = _deque_->f_val->cpy(_deque_->buffer[i]);
i = (i + 1) % _deque_->capacity;
}
}
else
{
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
{
result->buffer[j] = _deque_->buffer[i];
i = (i + 1) % _deque_->capacity;
}
}
result->count = _deque_->count;
result->front = 0;
result->back = _deque_->count;
_deque_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_deque1_, struct SNAME *_deque2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_deque1_->flag = CMC_FLAG_OK;
_deque2_->flag = CMC_FLAG_OK;
if (_deque1_->count != _deque2_->count)
return false;
size_t i, j, k;
for (i = _deque1_->front, j = _deque2_->front, k = 0; k < _deque1_->count; k++)
{
if (_deque1_->f_val->cmp(_deque1_->buffer[i], _deque2_->buffer[j]) != 0)
return false;
i = (i + 1) % _deque1_->capacity;
j = (j + 1) % _deque2_->capacity;
}
return true;
}
+430
View File
@@ -0,0 +1,430 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
struct SNAME CMC_(PFX, _init)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _init_custom)(capacity, f_val, NULL, NULL);
}
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
struct SNAME _deque_ = { 0 };
if (capacity < 1)
return _deque_;
if (!f_val)
return _deque_;
if (!alloc)
alloc = &cmc_alloc_node_default;
_deque_.buffer = alloc->calloc(capacity, sizeof(V));
if (!_deque_.buffer)
return _deque_;
_deque_.capacity = capacity;
_deque_.count = 0;
_deque_.front = 0;
_deque_.back = 0;
_deque_.flag = CMC_FLAG_OK;
_deque_.f_val = f_val;
_deque_.alloc = alloc;
CMC_CALLBACKS_ASSIGN(&_deque_, callbacks);
return _deque_;
}
void CMC_(PFX, _release)(struct SNAME _deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_deque_.f_val->free)
{
for (size_t i = _deque_.front, j = 0; j < _deque_.count; j++)
{
_deque_.f_val->free(_deque_.buffer[i]);
i = (i + 1) % _deque_.capacity;
}
}
_deque_.alloc->free(_deque_.buffer);
}
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Deque bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = target->front;
iter.index = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
if (!CMC_(PFX, _empty)(target))
{
if (iter.target->back == 0)
iter.cursor = iter.target->capacity - 1;
else
iter.cursor = iter.target->back - 1;
iter.index = iter.target->count - 1;
}
else
{
iter.cursor = 0;
iter.index = 0;
}
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->target->front;
iter->index = 0;
iter->start = true;
iter->end = false;
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
if (iter->target->back == 0)
iter->cursor = iter->target->capacity - 1;
else
iter->cursor = iter->target->back - 1;
iter->index = iter->target->count - 1;
iter->start = false;
iter->end = true;
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
iter->cursor = (iter->cursor + 1) % (iter->target->capacity);
iter->index++;
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1;
iter->index--;
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->index + steps >= iter->target->count)
return false;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->index += steps;
iter->cursor = (iter->cursor + steps) % iter->target->capacity;
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->index < steps)
return false;
iter->end = CMC_(PFX, _empty)(iter->target);
iter->index -= steps;
/* Prevent underflow */
if (iter->cursor < steps)
iter->cursor += iter->target->capacity;
iter->cursor -= steps;
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->index > index)
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
else if (iter->index < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
return true;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->target->buffer[iter->cursor];
}
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return NULL;
return &(iter->target->buffer[iter->cursor]);
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->index;
}
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_deque_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *d_ = _deque_;
return 0 <= fprintf(fptr,
"struct %s<%s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"front:%" PRIuMAX ", "
"back:%" PRIuMAX ", "
"flag:%d, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), d_, d_->buffer, d_->capacity, d_->count, d_->front,
d_->back, d_->flag, d_->f_val, d_->alloc, CMC_CALLBACKS_GET(d_));
}
bool CMC_(PFX, _print)(struct SNAME *_deque_, FILE *fptr, const char *start, const char *separator, const char *end)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
{
if (!_deque_->f_val->str(fptr, _deque_->buffer[i]))
return false;
i = (i + 1) % _deque_->capacity;
if (j + 1 < _deque_->count)
fprintf(fptr, "%s", separator);
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+80
View File
@@ -0,0 +1,80 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
struct SNAME CMC_(PFX, _init)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _release)(struct SNAME _deque_);
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Deque bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
/* Debug prints the struct to fptr */
bool CMC_(PFX, _to_string)(struct SNAME *_deque_, FILE *fptr);
/* Prints each item in the deque as an array */
bool CMC_(PFX, _print)(struct SNAME *_deque_, FILE *fptr, const char *start, const char *separator, const char *end);
#endif /* CMC_EXT_STR */
+47
View File
@@ -0,0 +1,47 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Deque bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Deque Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target deque */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* Keeps track of relative index to the iteration of elements */
size_t index;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+68
View File
@@ -0,0 +1,68 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Value function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_deque_);
void CMC_(PFX, _free)(struct SNAME *_deque_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_deque_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _push_front)(struct SNAME *_deque_, V value);
bool CMC_(PFX, _push_back)(struct SNAME *_deque_, V value);
bool CMC_(PFX, _pop_front)(struct SNAME *_deque_);
bool CMC_(PFX, _pop_back)(struct SNAME *_deque_);
/* Element Access */
V CMC_(PFX, _front)(struct SNAME *_deque_);
V CMC_(PFX, _back)(struct SNAME *_deque_);
/* Collection State */
bool CMC_(PFX, _contains)(struct SNAME *_deque_, V value);
bool CMC_(PFX, _empty)(struct SNAME *_deque_);
bool CMC_(PFX, _full)(struct SNAME *_deque_);
size_t CMC_(PFX, _count)(struct SNAME *_deque_);
size_t CMC_(PFX, _capacity)(struct SNAME *_deque_);
int CMC_(PFX, _flag)(struct SNAME *_deque_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_deque_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_deque_);
bool CMC_(PFX, _equals)(struct SNAME *_deque1_, struct SNAME *_deque2_);
+45
View File
@@ -0,0 +1,45 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
struct SNAME
{
/* Dynamic circular array of elements */
V *buffer;
/* Current circular array capacity */
size_t capacity;
/* Current amount of elements */
size_t count;
/* Index representing the front of the deque */
size_t front;
/* Index representing the back of the deque */
size_t back;
/* Flags indicating errors or success */
int flag;
/* Functions Table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
+89
View File
@@ -0,0 +1,89 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* hashbidimap.h
*
* Creation Date: 26/09/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* HashBidiMap
*
* A bidirectional map is a map that allows you to create a bijection in both
* directions between two sets of elements (K <-> V). It is possible to retrieve
* the value using a key or retrieve a key using a value. The naming (key and
* value) is simply used to differentiate between one set of elements and the
* other set of elements.
*
* Implementation
*
* This implementation uses two arrays of pointers to an entry containing both
* the key and the value.
*/
#include "cor/core.h"
#include "cor/hashtable.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* K - hashbidimap key data type
* V - hashbidimap value data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/hashbidimap/struct.h"
/* Function declaration */
#include "cmc/hashbidimap/header.h"
/* Function implementation */
#include "cmc/hashbidimap/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - Hashbidimap iterator
* STR - Print helper functions
*/
#define CMC_EXT_HASHBIDIMAP_PARTS INIT, ITER, STR
/**/
#include "cmc/hashbidimap/ext/struct.h"
/**/
#include "cmc/hashbidimap/ext/header.h"
/**/
#include "cmc/hashbidimap/ext/code.h"
#include "cor/undef.h"
+961
View File
@@ -0,0 +1,961 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value);
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_key)(struct SNAME *_map_, K key);
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_val)(struct SNAME *_map_, V val);
static struct CMC_DEF_ENTRY(SNAME) *
*CMC_(PFX, _impl_add_entry_to_key)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry);
static struct CMC_DEF_ENTRY(SNAME) *
*CMC_(PFX, _impl_add_entry_to_val)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry);
static size_t CMC_(PFX, _impl_calculate_size)(size_t required);
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(capacity, load, f_key, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity == 0 || load <= 0 || load >= 1)
return NULL;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * load)
return NULL;
if (!f_key || !f_val)
return NULL;
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME));
if (!_map_)
return NULL;
_map_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]));
if (!_map_->buffer)
{
alloc->free(_map_->buffer);
alloc->free(_map_);
return NULL;
}
_map_->count = 0;
_map_->capacity = real_capacity;
_map_->load = load;
_map_->flag = CMC_FLAG_OK;
_map_->f_key = f_key;
_map_->f_val = f_val;
_map_->flag = CMC_FLAG_OK;
_map_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
return _map_;
}
void CMC_(PFX, _clear)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i][0];
if (entry && entry != CMC_ENTRY_DELETED)
{
if (_map_->f_key->free)
_map_->f_key->free(entry->key);
if (_map_->f_val->free)
_map_->f_val->free(entry->value);
_map_->alloc->free(entry);
}
_map_->buffer[i][0] = NULL;
_map_->buffer[i][1] = NULL;
}
_map_->count = 0;
_map_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_(PFX, _clear)(_map_);
_map_->alloc->free(_map_->buffer);
_map_->alloc->free(_map_);
}
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_map_->alloc = &cmc_alloc_node_default;
else
_map_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
_map_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_map_))
{
if (!CMC_(PFX, _resize)(_map_, _map_->capacity + 1))
return false;
}
if (CMC_(PFX, _impl_get_entry_by_key)(_map_, key) != NULL ||
CMC_(PFX, _impl_get_entry_by_val)(_map_, value) != NULL)
{
_map_->flag = CMC_FLAG_DUPLICATE;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_new_entry)(_map_, key, value);
struct CMC_DEF_ENTRY(SNAME) **key_entry = CMC_(PFX, _impl_add_entry_to_key)(_map_, entry);
struct CMC_DEF_ENTRY(SNAME) **val_entry = CMC_(PFX, _impl_add_entry_to_val)(_map_, entry);
if (!key_entry || !val_entry)
{
if (key_entry)
*key_entry = CMC_ENTRY_DELETED;
if (val_entry)
*val_entry = CMC_ENTRY_DELETED;
_map_->alloc->free(entry);
_map_->flag = CMC_FLAG_ERROR;
return false;
}
_map_->count++;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _update_key)(struct SNAME *_map_, V val, K new_key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
val_entry = CMC_(PFX, _impl_get_entry_by_val)(_map_, val);
if (!val_entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
/* The mapping val -> new_key is already true */
if (_map_->f_key->cmp(new_key, (*val_entry)->key) == 0)
goto success;
if (CMC_(PFX, _impl_get_entry_by_key)(_map_, new_key) != NULL)
{
_map_->flag = CMC_FLAG_DUPLICATE;
return false;
}
key_entry = (*val_entry)->ref[0];
if (!key_entry || *key_entry != *val_entry)
{
/* Should never happen */
_map_->flag = CMC_FLAG_ERROR;
return false;
}
/* Remove entry from key buffer and add it again with new key */
struct CMC_DEF_ENTRY(SNAME) *to_add = *key_entry;
K tmp_key = to_add->key;
to_add->key = new_key;
*key_entry = CMC_ENTRY_DELETED;
if (!CMC_(PFX, _impl_add_entry_to_key)(_map_, to_add))
{
/* Revert changes */
to_add->key = tmp_key;
*key_entry = to_add;
_map_->flag = CMC_FLAG_ERROR;
return false;
}
success:
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _update_val)(struct SNAME *_map_, K key, V new_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
key_entry = CMC_(PFX, _impl_get_entry_by_key)(_map_, key);
if (!key_entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
/* The mapping key -> new_val is already true */
if (_map_->f_val->cmp(new_val, (*key_entry)->value) == 0)
goto success;
if (CMC_(PFX, _impl_get_entry_by_val)(_map_, new_val) != NULL)
{
_map_->flag = CMC_FLAG_DUPLICATE;
return false;
}
val_entry = (*key_entry)->ref[1];
if (!val_entry || *val_entry != *key_entry)
{
/* Should never happen */
_map_->flag = CMC_FLAG_ERROR;
return false;
}
/* Remove entry from value buffer and add it again with new value */
struct CMC_DEF_ENTRY(SNAME) *to_add = *val_entry;
V tmp_val = to_add->value;
to_add->value = new_val;
*val_entry = CMC_ENTRY_DELETED;
if (!CMC_(PFX, _impl_add_entry_to_val)(_map_, to_add))
{
/* Revert changes */
to_add->value = tmp_val;
*val_entry = to_add;
_map_->flag = CMC_FLAG_ERROR;
return false;
}
success:
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _remove_by_key)(struct SNAME *_map_, K key, K *out_key, V *out_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
key_entry = CMC_(PFX, _impl_get_entry_by_key)(_map_, key);
if (!key_entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
val_entry = (*key_entry)->ref[1];
if (!val_entry || *val_entry != *key_entry)
{
/* Should never happen */
_map_->flag = CMC_FLAG_ERROR;
return false;
}
if (out_key)
*out_key = (*key_entry)->key;
if (out_val)
*out_val = (*key_entry)->value;
_map_->alloc->free(*key_entry);
*key_entry = CMC_ENTRY_DELETED;
*val_entry = CMC_ENTRY_DELETED;
_map_->count--;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _remove_by_val)(struct SNAME *_map_, V val, K *out_key, V *out_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
val_entry = CMC_(PFX, _impl_get_entry_by_val)(_map_, val);
if (!val_entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
key_entry = (*val_entry)->ref[0];
if (!key_entry || *key_entry != *val_entry)
{
/* Should never happen */
_map_->flag = CMC_FLAG_ERROR;
return false;
}
if (out_key)
*out_key = (*val_entry)->key;
if (out_val)
*out_val = (*val_entry)->value;
_map_->alloc->free(*val_entry);
*key_entry = CMC_ENTRY_DELETED;
*val_entry = CMC_ENTRY_DELETED;
_map_->count--;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
K CMC_(PFX, _get_key)(struct SNAME *_map_, V val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) **entry = CMC_(PFX, _impl_get_entry_by_val)(_map_, val);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return (K){ 0 };
}
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return (*entry)->key;
}
V CMC_(PFX, _get_val)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) **entry = CMC_(PFX, _impl_get_entry_by_key)(_map_, key);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return (V){ 0 };
}
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return (*entry)->value;
}
bool CMC_(PFX, _contains_key)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map_->flag = CMC_FLAG_OK;
bool result = CMC_(PFX, _impl_get_entry_by_key)(_map_, key) != NULL;
CMC_CALLBACKS_CALL(_map_);
return result;
}
bool CMC_(PFX, _contains_val)(struct SNAME *_map_, V val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map_->flag = CMC_FLAG_OK;
bool result = CMC_(PFX, _impl_get_entry_by_val)(_map_, val) != NULL;
CMC_CALLBACKS_CALL(_map_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return (double)_map_->capacity * _map_->load <= (double)_map_->count;
}
size_t CMC_(PFX, _count)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->count;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->capacity;
}
double CMC_(PFX, _load)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->load;
}
int CMC_(PFX, _flag)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map_->flag = CMC_FLAG_OK;
if (_map_->capacity == capacity)
goto success;
if (_map_->capacity > capacity / _map_->load)
goto success;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * _map_->load)
{
_map_->flag = CMC_FLAG_ERROR;
return false;
}
/* Calculate required capacity based on the prime numbers */
size_t new_cap = CMC_(PFX, _impl_calculate_size)(capacity);
/* Not possible to shrink with current available prime numbers */
if (new_cap < _map_->count / _map_->load)
{
_map_->flag = CMC_FLAG_INVALID;
return false;
}
/* No callbacks since _new_map_ is just a temporary hashtable */
struct SNAME *_new_map_ =
CMC_(PFX, _new_custom)(capacity, _map_->load, _map_->f_key, _map_->f_val, _map_->alloc, NULL);
if (!_new_map_)
{
_map_->flag = CMC_FLAG_ALLOC;
return false;
}
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
if (scan && scan != CMC_ENTRY_DELETED)
{
struct CMC_DEF_ENTRY(SNAME) **e1 = CMC_(PFX, _impl_add_entry_to_key)(_new_map_, scan);
struct CMC_DEF_ENTRY(SNAME) **e2 = CMC_(PFX, _impl_add_entry_to_val)(_new_map_, scan);
if (!e1 || !e2)
{
/* Prevent the map from freeing the data */
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ 0 };
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
_map_->alloc->free(_new_map_->buffer);
_map_->alloc->free(_new_map_);
_map_->flag = CMC_FLAG_ERROR;
return false;
}
_new_map_->count++;
}
}
if (_map_->count != _new_map_->count)
{
/* Prevent the map from freeing the data */
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ 0 };
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
_map_->alloc->free(_new_map_->buffer);
_map_->alloc->free(_new_map_);
_map_->flag = CMC_FLAG_ERROR;
return false;
}
struct CMC_DEF_ENTRY(SNAME) * (*tmp_buff)[2] = _map_->buffer;
_map_->buffer = _new_map_->buffer;
_map_->capacity = _new_map_->capacity;
_map_->alloc->free(tmp_buff);
_map_->alloc->free(_new_map_);
success:
CMC_CALLBACKS_CALL(_map_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* TODO this function can be optimized */
struct SNAME *result = CMC_(PFX, _new_custom)(_map_->capacity * _map_->load, _map_->load, _map_->f_key,
_map_->f_val, _map_->alloc, NULL);
if (!result)
{
_map_->flag = CMC_FLAG_ERROR;
return NULL;
}
CMC_CALLBACKS_ASSIGN(result, _map_->callbacks);
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
if (scan && scan != CMC_ENTRY_DELETED)
{
K tmp_key;
V tmp_val;
if (_map_->f_key->cpy)
tmp_key = _map_->f_key->cpy(scan->key);
else
tmp_key = scan->key;
if (_map_->f_val->cpy)
tmp_val = _map_->f_val->cpy(scan->value);
else
tmp_val = scan->value;
/* TODO treat the possible errors */
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_new_entry)(result, tmp_key, tmp_val);
CMC_(PFX, _impl_add_entry_to_key)(result, entry);
CMC_(PFX, _impl_add_entry_to_val)(result, entry);
result->count++;
}
}
_map_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map1_->flag = CMC_FLAG_OK;
_map2_->flag = CMC_FLAG_OK;
if (_map1_->count != _map2_->count)
return false;
struct SNAME *_mapA_;
struct SNAME *_mapB_;
if (_map1_->capacity < _map2_->capacity)
{
_mapA_ = _map1_;
_mapB_ = _map2_;
}
else
{
_mapA_ = _map2_;
_mapB_ = _map1_;
}
for (size_t i = 0; i < _mapA_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _mapA_->buffer[i][0];
if (scan && scan != CMC_ENTRY_DELETED)
{
struct CMC_DEF_ENTRY(SNAME) **entry_B = CMC_(PFX, _impl_get_entry_by_key)(_mapB_, scan->key);
if (!entry_B)
return false;
if (_mapA_->f_val->cmp((*entry_B)->value, scan->value) != 0)
return false;
}
}
return true;
}
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->alloc->malloc(sizeof(struct CMC_DEF_ENTRY(SNAME)));
if (!entry)
return NULL;
entry->key = key;
entry->value = value;
entry->dist[0] = 0;
entry->dist[1] = 0;
entry->ref[0] = NULL;
entry->ref[1] = NULL;
return entry;
}
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_key)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t hash = _map_->f_key->hash(key);
size_t pos = hash % _map_->capacity;
struct CMC_DEF_ENTRY(SNAME) *target = _map_->buffer[pos][0];
while (target != NULL)
{
if (target != CMC_ENTRY_DELETED && _map_->f_key->cmp(target->key, key) == 0)
return &(_map_->buffer[pos % _map_->capacity][0]);
pos++;
target = _map_->buffer[pos % _map_->capacity][0];
}
return NULL;
}
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_val)(struct SNAME *_map_, V val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t hash = _map_->f_val->hash(val);
size_t pos = hash % _map_->capacity;
struct CMC_DEF_ENTRY(SNAME) *target = _map_->buffer[pos][1];
while (target != NULL)
{
if (target != CMC_ENTRY_DELETED && _map_->f_val->cmp(target->value, val) == 0)
return &(_map_->buffer[pos % _map_->capacity][1]);
pos++;
target = _map_->buffer[pos % _map_->capacity][1];
}
return NULL;
}
static struct CMC_DEF_ENTRY(SNAME) *
*CMC_(PFX, _impl_add_entry_to_key)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) **to_return = NULL;
size_t hash = _map_->f_key->hash(entry->key);
size_t original_pos = hash % _map_->capacity;
size_t pos = original_pos;
struct CMC_DEF_ENTRY(SNAME) **scan = &(_map_->buffer[hash % _map_->capacity][0]);
if (*scan == NULL)
{
*scan = entry;
entry->ref[0] = scan;
return scan;
}
else
{
while (true)
{
pos++;
scan = &(_map_->buffer[pos % _map_->capacity][0]);
if (*scan == NULL || *scan == CMC_ENTRY_DELETED)
{
if (!to_return)
to_return = scan;
*scan = entry;
entry->ref[0] = scan;
entry->dist[0] = pos - original_pos;
return to_return;
}
else if ((*scan)->dist[0] < pos - original_pos)
{
if (!to_return)
to_return = scan;
size_t tmp_dist = (*scan)->dist[0];
entry->dist[0] = pos - original_pos;
original_pos = pos - tmp_dist;
entry->ref[0] = scan;
struct CMC_DEF_ENTRY(SNAME) *_tmp_ = *scan;
*scan = entry;
entry = _tmp_;
}
}
}
return NULL;
}
static struct CMC_DEF_ENTRY(SNAME) *
*CMC_(PFX, _impl_add_entry_to_val)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) **to_return = NULL;
size_t hash = _map_->f_val->hash(entry->value);
size_t original_pos = hash % _map_->capacity;
size_t pos = original_pos;
struct CMC_DEF_ENTRY(SNAME) **scan = &(_map_->buffer[hash % _map_->capacity][1]);
if (*scan == NULL)
{
*scan = entry;
entry->ref[1] = scan;
return scan;
}
else
{
while (true)
{
pos++;
scan = &(_map_->buffer[pos % _map_->capacity][1]);
if (*scan == NULL || *scan == CMC_ENTRY_DELETED)
{
if (!to_return)
to_return = scan;
*scan = entry;
entry->ref[1] = scan;
entry->dist[1] = pos - original_pos;
return to_return;
}
else if ((*scan)->dist[1] < pos - original_pos)
{
if (!to_return)
to_return = scan;
size_t tmp_dist = (*scan)->dist[1];
entry->dist[1] = pos - original_pos;
original_pos = pos - tmp_dist;
entry->ref[1] = scan;
struct CMC_DEF_ENTRY(SNAME) *_tmp_ = *scan;
*scan = entry;
entry = _tmp_;
}
}
}
return NULL;
}
static size_t CMC_(PFX, _impl_calculate_size)(size_t required)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
if (cmc_hashtable_primes[count - 1] < required)
return required;
size_t i = 0;
while (cmc_hashtable_primes[i] < required)
i++;
return cmc_hashtable_primes[i];
}
+473
View File
@@ -0,0 +1,473 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _init_custom)(capacity, load, f_key, f_val, NULL, NULL);
}
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
struct SNAME _map_ = { 0 };
if (capacity == 0 || load <= 0 || load >= 1)
return _map_;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * load)
return _map_;
if (!f_key || !f_val)
return _map_;
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
if (!alloc)
alloc = &cmc_alloc_node_default;
_map_.buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]));
if (!_map_.buffer)
return _map_;
_map_.count = 0;
_map_.capacity = real_capacity;
_map_.load = load;
_map_.flag = CMC_FLAG_OK;
_map_.f_key = f_key;
_map_.f_val = f_val;
_map_.flag = CMC_FLAG_OK;
_map_.alloc = alloc;
CMC_CALLBACKS_ASSIGN(&_map_, callbacks);
return _map_;
}
void CMC_(PFX, _release)(struct SNAME _map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_(PFX, _clear)(&_map_);
_map_.alloc->free(_map_.buffer);
}
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Hashbidimap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) * CMC_(PFX, _iter_new)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) *iter = target->alloc->malloc(sizeof(struct CMC_DEF_ITER(SNAME)));
if (!iter)
return NULL;
CMC_(PFX, _iter_init)(iter, target);
return iter;
}
void CMC_(PFX, _iter_free)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
iter->target->alloc->free(iter);
}
void CMC_(PFX, _iter_init)(struct CMC_DEF_ITER(SNAME) * iter, struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
memset(iter, 0, sizeof(struct CMC_DEF_ITER(SNAME)));
iter->target = target;
iter->start = true;
iter->end = CMC_(PFX, _empty)(target);
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i][0];
if (entry && entry != CMC_ENTRY_DELETED)
{
iter->first = i;
break;
}
}
iter->cursor = iter->first;
for (size_t i = target->capacity; i > 0; i--)
{
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i - 1][0];
if (entry && entry != CMC_ENTRY_DELETED)
{
iter->last = i - 1;
break;
}
}
}
}
bool CMC_(PFX, _iter_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
void CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->first;
iter->index = 0;
iter->start = true;
iter->end = false;
}
}
void CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->last;
iter->index = iter->target->count - 1;
iter->start = false;
iter->end = true;
}
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = iter->target->buffer[iter->cursor][0];
iter->index++;
while (1)
{
iter->cursor++;
scan = iter->target->buffer[iter->cursor][0];
if (scan != NULL && scan != CMC_ENTRY_DELETED)
break;
}
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = iter->target->buffer[iter->cursor][0];
iter->index--;
while (1)
{
iter->cursor--;
scan = iter->target->buffer[iter->cursor][0];
if (scan != NULL && scan != CMC_ENTRY_DELETED)
break;
}
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->index + steps >= iter->target->count)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_next)(iter);
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->index < steps)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_prev)(iter);
return true;
}
/* Returns true only if the iterator was able to be positioned at */
/* the given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->index > index)
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
else if (iter->index < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
return true;
}
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
{
iter->target->flag = CMC_FLAG_EMPTY;
return (K){ 0 };
}
return iter->target->buffer[iter->cursor][0]->key;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
{
iter->target->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
return iter->target->buffer[iter->cursor][0]->value;
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->index;
}
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *m_ = _map_;
return 0 <= fprintf(fptr,
"struct %s<%s, %s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"load:%lf, "
"flag:%d, "
"f_key:%p, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(K), CMC_TO_STRING(V), m_, m_->buffer, m_->capacity,
m_->count, m_->load, m_->flag, m_->f_key, m_->f_val, m_->alloc, CMC_CALLBACKS_GET(m_));
}
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *key_val_sep)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
size_t last = 0;
for (size_t i = _map_->capacity; i > 0; i--)
{
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i - 1][0];
if (entry && entry != CMC_ENTRY_DELETED)
{
last = i - 1;
break;
}
}
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i][0];
if (entry && entry != CMC_ENTRY_DELETED)
{
if (!_map_->f_key->str(fptr, entry->key))
return false;
fprintf(fptr, "%s", key_val_sep);
if (!_map_->f_val->str(fptr, entry->value))
return false;
if (i + 1 < last)
fprintf(fptr, "%s", separator);
}
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+86
View File
@@ -0,0 +1,86 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _release)(struct SNAME _map_);
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Hashbidimap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Functions */
/* Iterator Allocation and Deallocation */
struct CMC_DEF_ITER(SNAME) * CMC_(PFX, _iter_new)(struct SNAME *target);
void CMC_(PFX, _iter_free)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Initialization */
void CMC_(PFX, _iter_init)(struct CMC_DEF_ITER(SNAME) * iter, struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
void CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
void CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter);
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
/* Debug prints the struct to fptr */
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr);
/* Prints each item in the hashbidimap as an array */
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *key_val_sep);
#endif /* CMC_EXT_STR */
+51
View File
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Hashbidimap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* HashBidiMap Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target hashbidimap */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* Keeps track of relative index to the iteration of elements */
size_t index;
/* The index of the first element */
size_t first;
/* The index of the last element */
size_t last;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+90
View File
@@ -0,0 +1,90 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Key struct function table */
struct CMC_DEF_FKEY(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(K);
/* Copy function */
CMC_DEF_FTAB_CPY(K);
/* To string function */
CMC_DEF_FTAB_STR(K);
/* Free from memory function */
CMC_DEF_FTAB_FREE(K);
/* Hash function */
CMC_DEF_FTAB_HASH(K);
/* Priority function */
CMC_DEF_FTAB_PRI(K);
};
/* Value struct function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_map_);
void CMC_(PFX, _free)(struct SNAME *_map_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value);
bool CMC_(PFX, _update_key)(struct SNAME *_map_, V val, K new_key);
bool CMC_(PFX, _update_val)(struct SNAME *_map_, K key, V new_val);
bool CMC_(PFX, _remove_by_key)(struct SNAME *_map_, K key, K *out_key, V *out_val);
bool CMC_(PFX, _remove_by_val)(struct SNAME *_map_, V val, K *out_key, V *out_val);
/* Element Access */
K CMC_(PFX, _get_key)(struct SNAME *_map_, V val);
V CMC_(PFX, _get_val)(struct SNAME *_map_, K key);
/* Collection State */
bool CMC_(PFX, _contains_key)(struct SNAME *_map_, K key);
bool CMC_(PFX, _contains_val)(struct SNAME *_map_, V val);
bool CMC_(PFX, _empty)(struct SNAME *_map_);
bool CMC_(PFX, _full)(struct SNAME *_map_);
size_t CMC_(PFX, _count)(struct SNAME *_map_);
size_t CMC_(PFX, _capacity)(struct SNAME *_map_);
double CMC_(PFX, _load)(struct SNAME *_map_);
int CMC_(PFX, _flag)(struct SNAME *_map_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_);
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_);
+69
View File
@@ -0,0 +1,69 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
struct SNAME
{
/* Array 0 is K -> V and array 1 is V -> K */
struct CMC_DEF_ENTRY(SNAME) * (*buffer)[2];
/* Current arrays capacity */
size_t capacity;
/* Current amount of keys */
size_t count;
/* Load factor in range (0.0, 1.0) */
double load;
/* Flags indicating errors or success */
int flag;
/* Key function table */
struct CMC_DEF_FKEY(SNAME) * f_key;
/* Value function table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
/* Methods */
/* Returns an iterator to the start of the hashbidimap */
struct CMC_DEF_ITER(SNAME) (*it_start)(struct SNAME *);
/* Returns an iterator to the end of the hashbidimap */
struct CMC_DEF_ITER(SNAME) (*it_end)(struct SNAME *);
};
/* HashBidiMap Entry */
struct CMC_DEF_ENTRY(SNAME)
{
/* Entry Key */
K key;
/* Entry Value */
V value;
/* The distance of this node to its original position */
/* dist[0] is relative to K -> V */
/* dist[1] is relative to V -> K */
size_t dist[2];
/* References to this node in the hashbidimap buffer. Used to */
/* prevent searching for this node twice for update() and */
/* remove(). Increases memory overhead but reduces execution time */
/* ref[0] is relative to K -> V */
/* ref[1] is relative to V -> K */
struct CMC_DEF_ENTRY(SNAME) * *ref[2];
};
+82
View File
@@ -0,0 +1,82 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* hashmap.h
*
* Creation Date: 03/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* HashMap
*
* A HashMap is an implementation of a Map with unique keys, where every key is
* mapped to a value. The keys are not sorted. It is implemented as a flat
* hashtable with linear probing and robin hood hashing.
*/
#include "cor/core.h"
#include "cor/hashtable.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* K - hashmap key data type
* V - hashmap value data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/hashmap/struct.h"
/* Function declaration */
#include "cmc/hashmap/header.h"
/* Function implementation */
#include "cmc/hashmap/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - hashmap iterator
* STR - Print helper functions
*/
#define CMC_EXT_HASHMAP_PARTS INIT, ITER, STR
/**/
#include "cmc/hashmap/ext/struct.h"
/**/
#include "cmc/hashmap/ext/header.h"
/**/
#include "cmc/hashmap/ext/code.h"
#include "cor/undef.h"
+728
View File
@@ -0,0 +1,728 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key);
static size_t CMC_(PFX, _impl_calculate_size)(size_t required);
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val)
{
return CMC_(PFX, _new_custom)(capacity, load, f_key, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity == 0 || load <= 0 || load >= 1)
return NULL;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * load)
return NULL;
if (!f_key || !f_val)
return NULL;
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME));
if (!_map_)
return NULL;
_map_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME)));
if (!_map_->buffer)
{
alloc->free(_map_);
return NULL;
}
_map_->count = 0;
_map_->capacity = real_capacity;
_map_->load = load;
_map_->flag = CMC_FLAG_OK;
_map_->f_key = f_key;
_map_->f_val = f_val;
_map_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
return _map_;
}
void CMC_(PFX, _clear)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_map_->f_key->free || _map_->f_val->free)
{
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
if (_map_->f_key->free)
_map_->f_key->free(entry->key);
if (_map_->f_val->free)
_map_->f_val->free(entry->value);
}
}
}
memset(_map_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _map_->capacity);
_map_->count = 0;
_map_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_map_->f_key->free || _map_->f_val->free)
{
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
if (_map_->f_key->free)
_map_->f_key->free(entry->key);
if (_map_->f_val->free)
_map_->f_val->free(entry->value);
}
}
}
_map_->alloc->free(_map_->buffer);
_map_->alloc->free(_map_);
}
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_map_->alloc = &cmc_alloc_node_default;
else
_map_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
_map_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_map_))
{
if (!CMC_(PFX, _resize)(_map_, _map_->capacity + 1))
return false;
}
if (CMC_(PFX, _impl_get_entry)(_map_, key) != NULL)
{
_map_->flag = CMC_FLAG_DUPLICATE;
return false;
}
size_t hash = _map_->f_key->hash(key);
size_t original_pos = hash % _map_->capacity;
size_t pos = original_pos;
struct CMC_DEF_ENTRY(SNAME) *target = &(_map_->buffer[pos]);
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
{
target->key = key;
target->value = value;
target->dist = 0;
target->state = CMC_ES_FILLED;
}
else
{
while (true)
{
pos++;
target = &(_map_->buffer[pos % _map_->capacity]);
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
{
target->key = key;
target->value = value;
target->dist = pos - original_pos;
target->state = CMC_ES_FILLED;
break;
}
else if (target->dist < pos - original_pos)
{
K tmp_k = target->key;
V tmp_v = target->value;
size_t tmp_dist = target->dist;
target->key = key;
target->value = value;
target->dist = pos - original_pos;
key = tmp_k;
value = tmp_v;
original_pos = pos - tmp_dist;
}
}
}
_map_->count++;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
if (old_value)
*old_value = entry->value;
entry->value = new_value;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_map_, key);
if (result == NULL)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
if (out_value)
*out_value = result->value;
result->key = (K){ 0 };
result->value = (V){ 0 };
result->dist = 0;
result->state = CMC_ES_DELETED;
_map_->count--;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
K max_key = (K){ 0 };
V max_val = (V){ 0 };
for (size_t i = 0; i < _map_->capacity; i++)
{
if (_map_->buffer[i].state == CMC_ES_FILLED)
{
if (first)
{
max_key = _map_->buffer[i].key;
max_val = _map_->buffer[i].value;
first = false;
}
else if (_map_->f_key->cmp(_map_->buffer[i].key, max_key) > 0)
{
max_key = _map_->buffer[i].key;
max_val = _map_->buffer[i].value;
}
}
}
if (key)
*key = max_key;
if (value)
*value = max_val;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
K min_key = (K){ 0 };
V min_val = (V){ 0 };
for (size_t i = 0; i < _map_->capacity; i++)
{
if (_map_->buffer[i].state == CMC_ES_FILLED)
{
if (first)
{
min_key = _map_->buffer[i].key;
min_val = _map_->buffer[i].value;
first = false;
}
else if (_map_->f_key->cmp(_map_->buffer[i].key, min_key) < 0)
{
min_key = _map_->buffer[i].key;
min_val = _map_->buffer[i].value;
}
}
}
if (key)
*key = min_key;
if (value)
*value = min_val;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
V CMC_(PFX, _get)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return (V){ 0 };
}
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return entry->value;
}
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return NULL;
}
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return NULL;
}
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return &(entry->value);
}
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map_->flag = CMC_FLAG_OK;
bool result = CMC_(PFX, _impl_get_entry)(_map_, key) != NULL;
CMC_CALLBACKS_CALL(_map_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return (double)_map_->capacity * _map_->load <= (double)_map_->count;
}
size_t CMC_(PFX, _count)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->count;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->capacity;
}
double CMC_(PFX, _load)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->load;
}
int CMC_(PFX, _flag)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map_->flag = CMC_FLAG_OK;
if (_map_->capacity == capacity)
goto success;
if (_map_->capacity > capacity / _map_->load)
goto success;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * _map_->load)
{
_map_->flag = CMC_FLAG_ERROR;
return false;
}
/* Calculate required capacity based on the prime numbers */
size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity);
/* Not possible to shrink with current available prime numbers */
if (theoretical_size < _map_->count / _map_->load)
{
_map_->flag = CMC_FLAG_INVALID;
return false;
}
/* No callbacks since _new_map_ is just a temporary hashtable */
struct SNAME *_new_map_ =
CMC_(PFX, _new_custom)(capacity, _map_->load, _map_->f_key, _map_->f_val, _map_->alloc, NULL);
if (!_new_map_)
{
_map_->flag = CMC_FLAG_ALLOC;
return false;
}
for (size_t i = 0; i < _map_->capacity; i++)
{
if (_map_->buffer[i].state == CMC_ES_FILLED)
{
K key = _map_->buffer[i].key;
V value = _map_->buffer[i].value;
/* TODO check this for possible errors */
CMC_(PFX, _insert)(_new_map_, key, value);
}
}
/* Unlikely */
if (_map_->count != _new_map_->count)
{
CMC_(PFX, _free)(_new_map_);
_map_->flag = CMC_FLAG_ERROR;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *tmp_b = _map_->buffer;
_map_->buffer = _new_map_->buffer;
_new_map_->buffer = tmp_b;
size_t tmp_c = _map_->capacity;
_map_->capacity = _new_map_->capacity;
_new_map_->capacity = tmp_c;
/* Prevent the map from freeing the data */
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ 0 };
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
CMC_(PFX, _free)(_new_map_);
success:
CMC_CALLBACKS_CALL(_map_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *result = CMC_(PFX, _new_custom)(_map_->capacity * _map_->load, _map_->load, _map_->f_key,
_map_->f_val, _map_->alloc, NULL);
if (!result)
{
_map_->flag = CMC_FLAG_ERROR;
return NULL;
}
CMC_CALLBACKS_ASSIGN(result, _map_->callbacks);
if (_map_->f_key->cpy || _map_->f_val->cpy)
{
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = &(_map_->buffer[i]);
if (scan->state != CMC_ES_EMPTY)
{
struct CMC_DEF_ENTRY(SNAME) *target = &(result->buffer[i]);
if (scan->state == CMC_ES_DELETED)
target->state = CMC_ES_DELETED;
else
{
target->state = scan->state;
target->dist = scan->dist;
if (_map_->f_key->cpy)
target->key = _map_->f_key->cpy(scan->key);
else
target->key = scan->key;
if (_map_->f_val->cpy)
target->value = _map_->f_val->cpy(scan->value);
else
target->value = scan->value;
}
}
}
}
else
memcpy(result->buffer, _map_->buffer, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _map_->capacity);
result->count = _map_->count;
_map_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map1_->flag = CMC_FLAG_OK;
_map2_->flag = CMC_FLAG_OK;
if (_map1_->count != _map2_->count)
return false;
/* Optimize loop using the smallest hashtable */
struct SNAME *_map_a_;
struct SNAME *_map_b_;
_map_a_ = _map1_->capacity < _map2_->capacity ? _map1_ : _map2_;
_map_b_ = _map_a_ == _map1_ ? _map2_ : _map1_;
for (size_t i = 0; i < _map_a_->capacity; i++)
{
if (_map_a_->buffer[i].state == CMC_ES_FILLED)
{
struct CMC_DEF_ENTRY(SNAME) *entry_a = &(_map_a_->buffer[i]);
struct CMC_DEF_ENTRY(SNAME) *entry_b = CMC_(PFX, _impl_get_entry)(_map_b_, entry_a->key);
if (!entry_b)
return false;
if (_map_a_->f_val->cmp(entry_a->value, entry_b->value) != 0)
return false;
}
}
return true;
}
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t hash = _map_->f_key->hash(key);
size_t pos = hash % _map_->capacity;
struct CMC_DEF_ENTRY(SNAME) *target = &(_map_->buffer[pos]);
while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED)
{
if (target->state != CMC_ES_DELETED && _map_->f_key->cmp(target->key, key) == 0)
return target;
pos++;
target = &(_map_->buffer[pos % _map_->capacity]);
}
return NULL;
}
static size_t CMC_(PFX, _impl_calculate_size)(size_t required)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
if (cmc_hashtable_primes[count - 1] < required)
return required;
size_t i = 0;
while (cmc_hashtable_primes[i] < required)
i++;
return cmc_hashtable_primes[i];
}
+514
View File
@@ -0,0 +1,514 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _init_custom)(capacity, load, f_key, f_val, NULL, NULL);
}
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
struct SNAME _map_ = { 0 };
if (capacity == 0 || load <= 0 || load >= 1)
return _map_;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * load)
return _map_;
if (!f_key || !f_val)
return _map_;
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
if (!alloc)
alloc = &cmc_alloc_node_default;
_map_.buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME)));
if (!_map_.buffer)
return _map_;
_map_.count = 0;
_map_.capacity = real_capacity;
_map_.load = load;
_map_.flag = CMC_FLAG_OK;
_map_.f_key = f_key;
_map_.f_val = f_val;
_map_.alloc = alloc;
CMC_CALLBACKS_ASSIGN(&_map_, callbacks);
return _map_;
}
void CMC_(PFX, _release)(struct SNAME _map_)
{
if (_map_.f_key->free || _map_.f_val->free)
{
for (size_t i = 0; i < _map_.capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_.buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
if (_map_.f_key->free)
_map_.f_key->free(entry->key);
if (_map_.f_val->free)
_map_.f_val->free(entry->value);
}
}
}
_map_.alloc->free(_map_.buffer);
}
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Hashmap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == CMC_ES_FILLED)
{
iter.first = i;
break;
}
}
iter.cursor = iter.first;
for (size_t i = target->capacity; i > 0; i--)
{
if (target->buffer[i - 1].state == CMC_ES_FILLED)
{
iter.last = i - 1;
break;
}
}
}
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == CMC_ES_FILLED)
{
iter.first = i;
break;
}
}
for (size_t i = target->capacity; i > 0; i--)
{
if (target->buffer[i - 1].state == CMC_ES_FILLED)
{
iter.last = i - 1;
break;
}
}
iter.cursor = iter.last;
iter.index = target->count - 1;
}
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->first;
iter->index = 0;
iter->start = true;
iter->end = CMC_(PFX, _empty)(iter->target);
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->last;
iter->index = iter->target->count - 1;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->end = true;
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
iter->index++;
while (1)
{
iter->cursor++;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == CMC_ES_FILLED)
break;
}
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
iter->index--;
while (1)
{
iter->cursor--;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == CMC_ES_FILLED)
break;
}
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->index + steps >= iter->target->count)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_next)(iter);
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->index < steps)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_prev)(iter);
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->index > index)
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
else if (iter->index < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
return true;
}
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (K){ 0 };
return iter->target->buffer[iter->cursor].key;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->target->buffer[iter->cursor].value;
}
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return NULL;
return &(iter->target->buffer[iter->cursor].value);
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->index;
}
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *m_ = _map_;
return 0 <= fprintf(fptr,
"struct %s<%s, %s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"load:%lf, "
"flag:%d, "
"f_key:%p, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(K), CMC_TO_STRING(V), m_, m_->buffer, m_->capacity,
m_->count, m_->load, m_->flag, m_->f_key, m_->f_val, m_->alloc, CMC_CALLBACKS_GET(m_));
}
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *key_val_sep)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
size_t last = 0;
for (size_t i = _map_->capacity; i > 0; i--)
{
if ((_map_->buffer[i - 1]).state == CMC_ES_FILLED)
{
last = i - 1;
break;
}
}
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
if (!_map_->f_key->str(fptr, entry->key))
return false;
fprintf(fptr, "%s", key_val_sep);
if (!_map_->f_val->str(fptr, entry->value))
return false;
if (i + 1 < last)
fprintf(fptr, "%s", separator);
}
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+82
View File
@@ -0,0 +1,82 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _release)(struct SNAME _map_);
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Hashmap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter);
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr);
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *key_val_sep);
#endif /* CMC_EXT_STR */
+51
View File
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Hashmap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* HashMap Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target hashmap */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* Keeps track of relative index to the iteration of elements */
size_t index;
/* The index of the first element */
size_t first;
/* The index of the last element */
size_t last;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+89
View File
@@ -0,0 +1,89 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Key struct function table */
struct CMC_DEF_FKEY(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(K);
/* Copy function */
CMC_DEF_FTAB_CPY(K);
/* To string function */
CMC_DEF_FTAB_STR(K);
/* Free from memory function */
CMC_DEF_FTAB_FREE(K);
/* Hash function */
CMC_DEF_FTAB_HASH(K);
/* Priority function */
CMC_DEF_FTAB_PRI(K);
};
/* Value struct function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_map_);
void CMC_(PFX, _free)(struct SNAME *_map_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value);
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value);
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value);
/* Element Access */
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value);
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value);
V CMC_(PFX, _get)(struct SNAME *_map_, K key);
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key);
/* Collection State */
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key);
bool CMC_(PFX, _empty)(struct SNAME *_map_);
bool CMC_(PFX, _full)(struct SNAME *_map_);
size_t CMC_(PFX, _count)(struct SNAME *_map_);
size_t CMC_(PFX, _capacity)(struct SNAME *_map_);
double CMC_(PFX, _load)(struct SNAME *_map_);
int CMC_(PFX, _flag)(struct SNAME *_map_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_);
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_);
+60
View File
@@ -0,0 +1,60 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* HashMap Structure */
struct SNAME
{
/* Array of Entries */
struct CMC_DEF_ENTRY(SNAME) * buffer;
/* Current array capacity */
size_t capacity;
/* Current amount of keys */
size_t count;
/* Load factor in range (0.0, 1.0) */
double load;
/* Flags indicating errors or success */
int flag;
/* Key function table */
struct CMC_DEF_FKEY(SNAME) * f_key;
/* Value function table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
/* HashMap Entry */
struct CMC_DEF_ENTRY(SNAME)
{
/* Entry Key */
K key;
/* Entry Value */
V value;
/* The distance of this node to its original position, used by */
/* robin-hood hashing */
size_t dist;
/* The sate of this node (DELETED, EMPTY, FILLED) */
enum cmc_entry_state state;
};
+107
View File
@@ -0,0 +1,107 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* hashmultimap.h
*
* Creation Date: 26/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* HashMultiMap
*
* The HashMultiMap is a Map that allows for multiple keys. This is a data
* structure that has a very narrow usage. A Map (either TreeMap or HashMap) can
* also work like a HashMultiMap if a certain key is mapped to another
* collection.
*
* Map<K = int, V = List<int>> maps an integer to a list of integer.
* HashMultiMap<K = int, V = int> maps many integer keys to integer values.
*
* The difference is that in a HashMultiMap you can store keys that are the same
* but might be different instances of the same value. This is also relevant if
* your data type is more complex like a struct where its ID is the same but
* some other members of this data type are different.
*
* Implementation
*
* The map uses separate chaining and robin hood hashing. Its internal buffer
* is made of a pair of pointers to entries that represent a linked list. So
* accessing map->buffer[0] would give the first pair of pointers. Each entry
* has both a pointer to a previous entry and a next entry. This design choice
* was made so that every collection in this library has a two-way iterator
* with a very few exceptions.
*
* Each entry is composed of a Key and a Value. Entries with the same key should
* always hash to the same linked list. Also, keys that hash to the same bucket
* will also be in the same linked list.
*
* The order of inserting and removing the same keys will behave like a FIFO. So
* the first key added will be the first to be removed.
*/
#include "cor/core.h"
#include "cor/hashtable.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* K - hashmultimap key data type
* V - hashmultimap value data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/hashmultimap/struct.h"
/* Function declaration */
#include "cmc/hashmultimap/header.h"
/* Function implementation */
#include "cmc/hashmultimap/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - hashmultimap iterator
* STR - Print helper functions
*/
#define CMC_EXT_HASHMULTIMAP_PARTS INIT, ITER, STR
/**/
#include "cmc/hashmultimap/ext/struct.h"
/**/
#include "cmc/hashmultimap/ext/header.h"
/**/
#include "cmc/hashmultimap/ext/code.h"
#include "cor/undef.h"
+986
View File
@@ -0,0 +1,986 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value);
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key);
size_t CMC_(PFX, _impl_key_count)(struct SNAME *_map_, K key);
size_t CMC_(PFX, _impl_calculate_size)(size_t required);
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(capacity, load, f_key, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity == 0 || load <= 0)
return NULL;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * load)
return NULL;
if (!f_key || !f_val)
return NULL;
if (!alloc)
alloc = &cmc_alloc_node_default;
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME));
if (!_map_)
return NULL;
_map_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]));
if (!_map_->buffer)
{
alloc->free(_map_);
return NULL;
}
_map_->count = 0;
_map_->capacity = real_capacity;
_map_->load = load;
_map_->flag = CMC_FLAG_OK;
_map_->f_key = f_key;
_map_->f_val = f_val;
_map_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
return _map_;
}
void CMC_(PFX, _clear)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
while (scan)
{
struct CMC_DEF_ENTRY(SNAME) *next = scan->next;
if (_map_->f_key->free)
_map_->f_key->free(scan->key);
if (_map_->f_val->free)
_map_->f_val->free(scan->value);
_map_->alloc->free(scan);
scan = next;
}
}
memset(_map_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]) * _map_->capacity);
_map_->count = 0;
_map_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t index = 0;
while (index < _map_->capacity)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[index][0];
if (scan)
{
if (scan->next == NULL && scan->prev == NULL)
{
if (_map_->f_key->free)
_map_->f_key->free(scan->key);
if (_map_->f_val->free)
_map_->f_val->free(scan->value);
_map_->alloc->free(scan);
}
else
{
while (scan)
{
struct CMC_DEF_ENTRY(SNAME) *tmp = scan;
scan = scan->next;
if (_map_->f_key->free)
_map_->f_key->free(tmp->key);
if (_map_->f_val->free)
_map_->f_val->free(tmp->value);
_map_->alloc->free(tmp);
}
}
}
index++;
}
_map_->alloc->free(_map_->buffer);
_map_->alloc->free(_map_);
}
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_map_->alloc = &cmc_alloc_node_default;
else
_map_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
_map_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_map_))
{
if (!CMC_(PFX, _resize)(_map_, _map_->capacity + 1))
return false;
}
size_t hash = _map_->f_key->hash(key);
size_t pos = hash % _map_->capacity;
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_new_entry)(_map_, key, value);
if (_map_->buffer[pos][0] == NULL)
{
_map_->buffer[pos][0] = entry;
_map_->buffer[pos][1] = entry;
}
else
{
entry->prev = _map_->buffer[pos][1];
_map_->buffer[pos][1]->next = entry;
_map_->buffer[pos][1] = entry;
}
_map_->count++;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
if (old_value)
*old_value = entry->value;
entry->value = new_value;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
size_t CMC_(PFX, _update_all)(struct SNAME *_map_, K key, V new_value, V **old_values)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return 0;
}
size_t hash = _map_->f_key->hash(key);
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[hash % _map_->capacity][0];
if (entry == NULL)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return 0;
}
if (old_values)
{
size_t total = CMC_(PFX, _impl_key_count)(_map_, key);
if (total == 0)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return 0;
}
*old_values = _map_->alloc->malloc(sizeof(V) * total);
if (!(*old_values))
{
_map_->flag = CMC_FLAG_ALLOC;
return 0;
}
}
size_t index = 0;
while (entry)
{
if (_map_->f_key->cmp(entry->key, key) == 0)
{
if (old_values)
(*old_values)[index] = entry->value;
index++;
entry->value = new_value;
}
entry = entry->next;
}
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return index;
}
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
size_t hash = _map_->f_key->hash(key);
struct CMC_DEF_ENTRY(SNAME) **head = &(_map_->buffer[hash % _map_->capacity][0]);
struct CMC_DEF_ENTRY(SNAME) **tail = &(_map_->buffer[hash % _map_->capacity][1]);
if (*head == NULL)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *entry = *head;
if (entry->next == NULL && entry->prev == NULL)
{
if (_map_->f_key->cmp(entry->key, key) == 0)
{
*head = NULL;
*tail = NULL;
if (out_value)
*out_value = entry->value;
}
else
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
}
else
{
bool found = false;
while (entry)
{
if (_map_->f_key->cmp(entry->key, key) == 0)
{
if (*head == entry)
*head = entry->next;
if (*tail == entry)
*tail = entry->prev;
if (entry->prev)
entry->prev->next = entry->next;
if (entry->next)
entry->next->prev = entry->prev;
if (out_value)
*out_value = entry->value;
found = true;
break;
}
else
entry = entry->next;
}
if (!found)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
}
_map_->alloc->free(entry);
_map_->count--;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
size_t CMC_(PFX, _remove_all)(struct SNAME *_map_, K key, V **out_values)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
size_t hash = _map_->f_key->hash(key);
struct CMC_DEF_ENTRY(SNAME) **head = &(_map_->buffer[hash % _map_->capacity][0]);
struct CMC_DEF_ENTRY(SNAME) **tail = &(_map_->buffer[hash % _map_->capacity][1]);
if (*head == NULL)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return 0;
}
if (out_values)
{
size_t total = CMC_(PFX, _impl_key_count)(_map_, key);
if (total == 0)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return 0;
}
*out_values = _map_->alloc->malloc(sizeof(V) * total);
if (!(*out_values))
{
_map_->flag = CMC_FLAG_ALLOC;
return 0;
}
}
size_t index = 0;
struct CMC_DEF_ENTRY(SNAME) *entry = *head;
if (entry->next == NULL)
{
*head = NULL;
*tail = NULL;
if (out_values)
(*out_values)[index] = entry->value;
index++;
_map_->alloc->free(entry);
}
else
{
while (entry)
{
if (_map_->f_key->cmp(entry->key, key) == 0)
{
if (*head == entry)
*head = entry->next;
if (*tail == entry)
*tail = entry->prev;
struct CMC_DEF_ENTRY(SNAME) *next = entry->next;
if (entry->prev)
entry->prev->next = entry->next;
if (entry->next)
entry->next->prev = entry->prev;
if (out_values)
(*out_values)[index] = entry->value;
index++;
_map_->alloc->free(entry);
entry = next;
}
else
entry = entry->next;
}
}
_map_->count -= index;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return index;
}
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
K max_key = (K){ 0 };
V max_val = (V){ 0 };
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
while (scan)
{
if (first)
{
max_key = scan->key;
max_val = scan->value;
first = false;
}
else if (_map_->f_key->cmp(scan->key, max_key) > 0)
{
max_key = scan->key;
max_val = scan->value;
}
scan = scan->next;
}
}
if (key)
*key = max_key;
if (value)
*value = max_val;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
K min_key = (K){ 0 };
V min_val = (V){ 0 };
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
while (scan)
{
if (first)
{
min_key = scan->key;
min_val = scan->value;
first = false;
}
else if (_map_->f_key->cmp(scan->key, min_key) < 0)
{
min_key = scan->key;
min_val = scan->value;
}
scan = scan->next;
}
}
if (key)
*key = min_key;
if (value)
*value = min_val;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
V CMC_(PFX, _get)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return (V){ 0 };
}
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return entry->value;
}
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return NULL;
}
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return NULL;
}
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return &(entry->value);
}
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map_->flag = CMC_FLAG_OK;
bool result = CMC_(PFX, _impl_get_entry)(_map_, key) != NULL;
CMC_CALLBACKS_CALL(_map_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return (double)_map_->capacity * _map_->load <= (double)_map_->count;
}
size_t CMC_(PFX, _count)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->count;
}
size_t CMC_(PFX, _key_count)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _impl_key_count)(_map_, key);
}
size_t CMC_(PFX, _capacity)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->capacity;
}
double CMC_(PFX, _load)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->load;
}
int CMC_(PFX, _flag)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map_->flag = CMC_FLAG_OK;
if (_map_->capacity == capacity)
goto success;
if (_map_->capacity > capacity / _map_->load)
goto success;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * _map_->load)
{
_map_->flag = CMC_FLAG_ERROR;
return false;
}
/* Calculate required capacity based on the prime numbers */
size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity);
/* Not possible to shrink with current available prime numbers */
if (theoretical_size < _map_->count / _map_->load)
{
_map_->flag = CMC_FLAG_INVALID;
return false;
}
/* No callbacks since _new_map_ is just a temporary hashtable */
struct SNAME *_new_map_ =
CMC_(PFX, _new_custom)(capacity, _map_->load, _map_->f_key, _map_->f_val, _map_->alloc, NULL);
if (!_new_map_)
{
_map_->flag = CMC_FLAG_ALLOC;
return false;
}
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
while (scan)
{
/* TODO check for errors */
CMC_(PFX, _insert)(_new_map_, scan->key, scan->value);
scan = scan->next;
}
}
if (_map_->count != _new_map_->count)
{
CMC_(PFX, _free)(_new_map_);
_map_->flag = CMC_FLAG_ERROR;
return false;
}
struct CMC_DEF_ENTRY(SNAME) * (*tmp_b)[2] = _map_->buffer;
_map_->buffer = _new_map_->buffer;
_new_map_->buffer = tmp_b;
size_t tmp_c = _map_->capacity;
_map_->capacity = _new_map_->capacity;
_new_map_->capacity = tmp_c;
/* Prevent the map from freeing the data */
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ 0 };
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
CMC_(PFX, _free)(_new_map_);
success:
CMC_CALLBACKS_CALL(_map_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callback will be added later */
struct SNAME *result = CMC_(PFX, _new_custom)(_map_->capacity * _map_->load, _map_->load, _map_->f_key,
_map_->f_val, _map_->alloc, NULL);
if (!result)
{
_map_->flag = CMC_FLAG_ERROR;
return NULL;
}
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
while (scan)
{
K key;
V value;
if (_map_->f_key->cpy)
key = _map_->f_key->cpy(scan->key);
else
key = scan->key;
if (_map_->f_val->cpy)
value = _map_->f_val->cpy(scan->value);
else
value = scan->value;
/* TODO check for errors */
CMC_(PFX, _insert)(result, key, value);
scan = scan->next;
}
}
CMC_CALLBACKS_ASSIGN(result, _map_->callbacks);
_map_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map1_->flag = CMC_FLAG_OK;
_map2_->flag = CMC_FLAG_OK;
if (_map1_->count != _map2_->count)
return false;
/* Optimize loop using the smallest hashtable */
struct SNAME *_map_a_;
struct SNAME *_map_b_;
_map_a_ = _map1_->capacity < _map2_->capacity ? _map1_ : _map2_;
_map_b_ = _map_a_ == _map1_ ? _map2_ : _map1_;
for (size_t i = 0; i < _map_a_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_a_->buffer[i][0];
while (scan)
{
/* OPTIMIZE - This is calling key_count for repeating keys */
if (CMC_(PFX, _impl_key_count)(_map_a_, scan->key) != CMC_(PFX, _impl_key_count)(_map_b_, scan->key))
return false;
scan = scan->next;
}
}
return true;
}
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->alloc->malloc(sizeof(struct CMC_DEF_ENTRY(SNAME)));
if (!entry)
return NULL;
entry->key = key;
entry->value = value;
entry->next = NULL;
entry->prev = NULL;
return entry;
}
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t hash = _map_->f_key->hash(key);
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[hash % _map_->capacity][0];
while (entry)
{
if (_map_->f_key->cmp(entry->key, key) == 0)
return entry;
entry = entry->next;
}
return NULL;
}
size_t CMC_(PFX, _impl_key_count)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t hash = _map_->f_key->hash(key);
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[hash % _map_->capacity][0];
size_t total_count = 0;
if (!entry)
return total_count;
while (entry)
{
if (_map_->f_key->cmp(entry->key, key) == 0)
total_count++;
entry = entry->next;
}
return total_count;
}
size_t CMC_(PFX, _impl_calculate_size)(size_t required)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
if (cmc_hashtable_primes[count - 1] < required)
return required;
size_t i = 0;
while (cmc_hashtable_primes[i] < required)
i++;
return cmc_hashtable_primes[i];
}
+465
View File
@@ -0,0 +1,465 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* List bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.curr_entry = NULL;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i][0];
if (entry && entry != CMC_ENTRY_DELETED)
{
iter.curr_entry = target->buffer[i][0];
iter.first = i;
break;
}
}
iter.cursor = iter.first;
for (size_t i = target->capacity; i > 0; i--)
{
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i - 1][1];
if (entry && entry != CMC_ENTRY_DELETED)
{
iter.last = i - 1;
break;
}
}
}
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.curr_entry = NULL;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i][0];
if (entry && entry != CMC_ENTRY_DELETED)
{
iter.first = i;
break;
}
}
for (size_t i = target->capacity; i > 0; i--)
{
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i - 1][1];
if (entry && entry != CMC_ENTRY_DELETED)
{
iter.curr_entry = target->buffer[i - 1][1];
iter.last = i - 1;
break;
}
}
iter.cursor = iter.last;
iter.index = target->count - 1;
}
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->first;
iter->index = 0;
iter->start = true;
iter->end = CMC_(PFX, _empty)(iter->target);
iter->curr_entry = iter->target->buffer[iter->first][0];
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->last;
iter->index = iter->target->count - 1;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->end = true;
iter->curr_entry = iter->target->buffer[iter->last][1];
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->curr_entry->next != NULL)
{
iter->curr_entry = iter->curr_entry->next;
iter->index++;
}
else
{
if (iter->cursor == iter->last)
{
iter->end = true;
return false;
}
iter->cursor++;
while (iter->target->buffer[iter->cursor][0] == NULL)
iter->cursor++;
iter->curr_entry = iter->target->buffer[iter->cursor][0];
iter->index++;
}
iter->start = CMC_(PFX, _empty)(iter->target);
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->curr_entry->prev != NULL)
{
iter->curr_entry = iter->curr_entry->prev;
iter->index--;
}
else
{
if (iter->cursor == iter->first)
{
iter->start = true;
return false;
}
iter->cursor--;
while (iter->target->buffer[iter->cursor][1] == NULL)
iter->cursor--;
iter->curr_entry = iter->target->buffer[iter->cursor][1];
iter->index--;
}
iter->end = CMC_(PFX, _empty)(iter->target);
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->index + steps >= iter->target->count)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_next)(iter);
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->index < steps)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_prev)(iter);
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->index > index)
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
else if (iter->index < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
return true;
}
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (K){ 0 };
return iter->curr_entry->key;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->curr_entry->value;
}
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return NULL;
return &(iter->curr_entry->value);
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->index;
}
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *m_ = _map_;
return 0 <= fprintf(fptr,
"struct %s<%s, %s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"load:%lf, "
"flag:%d, "
"f_key:%p, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(K), CMC_TO_STRING(V), m_, m_->buffer, m_->capacity,
m_->count, m_->load, m_->flag, m_->f_key, m_->f_val, m_->alloc, CMC_CALLBACKS_GET(m_));
}
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *key_val_sep)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
size_t last = 0;
for (size_t i = _map_->capacity; i > 0; i--)
{
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i - 1][1];
if (entry && entry != CMC_ENTRY_DELETED)
{
last = i - 1;
break;
}
}
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
while (scan != NULL)
{
if (!_map_->f_key->str(fptr, scan->key))
return false;
fprintf(fptr, "%s", key_val_sep);
if (!_map_->f_val->str(fptr, scan->value))
return false;
scan = scan->next;
if (i + 1 < last)
fprintf(fptr, "%s", separator);
}
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+75
View File
@@ -0,0 +1,75 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Hashmultimap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter);
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr);
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *key_val_sep);
#endif /* CMC_EXT_STR */
+53
View File
@@ -0,0 +1,53 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Hashmultimap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* HashMultiMap Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target hashmultimap */
struct SNAME *target;
/* Current entry */
struct CMC_DEF_ENTRY(SNAME) * curr_entry;
/* Cursor`s position (index) */
size_t cursor;
/* Keeps track of relative index to the iteration of elements */
size_t index;
/* The index of the first element */
size_t first;
/* The index of the last element */
size_t last;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+92
View File
@@ -0,0 +1,92 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Key struct function table */
struct CMC_DEF_FKEY(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(K);
/* Copy function */
CMC_DEF_FTAB_CPY(K);
/* To string function */
CMC_DEF_FTAB_STR(K);
/* Free from memory function */
CMC_DEF_FTAB_FREE(K);
/* Hash function */
CMC_DEF_FTAB_HASH(K);
/* Priority function */
CMC_DEF_FTAB_PRI(K);
};
/* Value struct function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_map_);
void CMC_(PFX, _free)(struct SNAME *_map_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value);
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value);
size_t CMC_(PFX, _update_all)(struct SNAME *_map_, K key, V new_value, V **old_values);
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value);
size_t CMC_(PFX, _remove_all)(struct SNAME *_map_, K key, V **out_values);
/* Element Access */
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value);
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value);
V CMC_(PFX, _get)(struct SNAME *_map_, K key);
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key);
/* Collection State */
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key);
bool CMC_(PFX, _empty)(struct SNAME *_map_);
bool CMC_(PFX, _full)(struct SNAME *_map_);
size_t CMC_(PFX, _count)(struct SNAME *_map_);
size_t CMC_(PFX, _key_count)(struct SNAME *_map_, K key);
size_t CMC_(PFX, _capacity)(struct SNAME *_map_);
double CMC_(PFX, _load)(struct SNAME *_map_);
int CMC_(PFX, _flag)(struct SNAME *_map_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_);
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_);
+59
View File
@@ -0,0 +1,59 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* HashMultimap Structure */
struct SNAME
{
/* Array of linked list to entries */
struct CMC_DEF_ENTRY(SNAME) * (*buffer)[2];
/* Current array capacity */
size_t capacity;
/* Current amount of keys */
size_t count;
/* Load factor in range (0.0, infinity) */
double load;
/* Flags indicating errors or success */
int flag;
/* Key function table */
struct CMC_DEF_FKEY(SNAME) * f_key;
/* Value function table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
/* HashMultimap Entry */
struct CMC_DEF_ENTRY(SNAME)
{
/* Entry Key */
K key;
/* Entry Value */
V value;
/* Next entry on the linked list */
struct CMC_DEF_ENTRY(SNAME) * next;
/* Previous entry on the linked list */
struct CMC_DEF_ENTRY(SNAME) * prev;
};
+88
View File
@@ -0,0 +1,88 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* hashmultiset.h
*
* Creation Date: 10/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* HashMultiSet
*
* In mathematics, a multiset is a modification of the concept of a set that,
* unlike a set, allows for multiple instances for each of its elements. The
* positive integer number of instances, given for each element is called the
* multiplicity of this element in the multiset. A multiSet also has a
* cardinality which equals the sum of the multiplicities of its elements.
*
* Implementation
*
* In this implementation, the values are stored in a flat hashtable and are
* mapped to their multiplicity.
*/
#include "cor/core.h"
#include "cor/hashtable.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* V - hashmultiset value data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/hashmultiset/struct.h"
/* Function declaration */
#include "cmc/hashmultiset/header.h"
/* Function implementation */
#include "cmc/hashmultiset/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - hashmultiset iterator
* STR - Print helper functions
*/
#define CMC_EXT_HASHMULTISET_PARTS INIT, ITER, SETF, STR
/**/
#include "cmc/hashmultiset/ext/struct.h"
/**/
#include "cmc/hashmultiset/ext/header.h"
/**/
#include "cmc/hashmultiset/ext/code.h"
#include "cor/undef.h"
+825
View File
@@ -0,0 +1,825 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_insert_and_return)(struct SNAME *_set_, V value, bool *new_node);
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value);
static size_t CMC_(PFX, _impl_calculate_size)(size_t required);
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(capacity, load, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val,
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity == 0 || load <= 0 || load >= 1)
return NULL;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * load)
return NULL;
if (!f_val)
return NULL;
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME));
if (!_set_)
return NULL;
_set_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME)));
if (!_set_->buffer)
{
alloc->free(_set_);
return NULL;
}
_set_->count = 0;
_set_->cardinality = 0;
_set_->capacity = real_capacity;
_set_->load = load;
_set_->flag = CMC_FLAG_OK;
_set_->f_val = f_val;
_set_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_set_, callbacks);
return _set_;
}
void CMC_(PFX, _clear)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_set_->f_val->free)
{
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
_set_->f_val->free(entry->value);
}
}
}
memset(_set_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity);
_set_->count = 0;
_set_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_set_->f_val->free)
{
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
_set_->f_val->free(entry->value);
}
}
}
_set_->alloc->free(_set_->buffer);
_set_->alloc->free(_set_);
}
void CMC_(PFX, _customize)(struct SNAME *_set_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_set_->alloc = &cmc_alloc_node_default;
else
_set_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_set_, callbacks);
_set_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _insert)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
bool new_node;
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_set_, value, &new_node);
if (!entry)
{
_set_->flag = CMC_FLAG_ERROR;
return false;
}
if (!new_node)
entry->multiplicity++;
_set_->cardinality++;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _insert_many)(struct SNAME *_set_, V value, size_t count)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (count == 0)
goto success;
bool new_node;
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_set_, value, &new_node);
if (!entry)
{
_set_->flag = CMC_FLAG_ERROR;
return false;
}
if (new_node)
entry->multiplicity = count;
else
entry->multiplicity += count;
_set_->cardinality += count;
success:
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _update)(struct SNAME *_set_, V value, size_t multiplicity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (multiplicity == 0)
{
/* Effectively delete the entry */
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value);
if (!result)
/* If no entry was found then its multiplicity is already 0 */
goto success;
_set_->count--;
_set_->cardinality -= result->multiplicity;
result->value = (V){ 0 };
result->multiplicity = 0;
result->dist = 0;
result->state = CMC_ES_DELETED;
goto success;
}
bool new_node;
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_set_, value, &new_node);
if (!entry)
return false;
if (new_node)
_set_->cardinality++;
_set_->cardinality = (_set_->cardinality - entry->multiplicity) + multiplicity;
entry->multiplicity = multiplicity;
success:
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _remove)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set_))
{
_set_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value);
if (!result)
{
_set_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
if (result->multiplicity > 1)
result->multiplicity--;
else
{
result->value = (V){ 0 };
result->multiplicity = 0;
result->dist = 0;
result->state = CMC_ES_DELETED;
_set_->count--;
}
_set_->cardinality--;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
size_t CMC_(PFX, _remove_all)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set_))
{
_set_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value);
if (!result)
{
_set_->flag = CMC_FLAG_NOT_FOUND;
return 0;
}
size_t removed = result->multiplicity;
result->value = (V){ 0 };
result->multiplicity = 0;
result->dist = 0;
result->state = CMC_ES_DELETED;
_set_->count--;
_set_->cardinality -= removed;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return removed;
}
bool CMC_(PFX, _max)(struct SNAME *_set_, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set_))
{
_set_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
V max_val = (V){ 0 };
for (size_t i = 0; i < _set_->capacity; i++)
{
if (_set_->buffer[i].state == CMC_ES_FILLED)
{
if (first)
{
max_val = _set_->buffer[i].value;
first = false;
}
else if (_set_->f_val->cmp(_set_->buffer[i].value, max_val) > 0)
{
max_val = _set_->buffer[i].value;
}
}
}
if (value)
*value = max_val;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _min)(struct SNAME *_set_, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set_))
{
_set_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
V min_val = (V){ 0 };
for (size_t i = 0; i < _set_->capacity; i++)
{
if (_set_->buffer[i].state == CMC_ES_FILLED)
{
if (first)
{
min_val = _set_->buffer[i].value;
first = false;
}
else if (_set_->f_val->cmp(_set_->buffer[i].value, min_val) < 0)
{
min_val = _set_->buffer[i].value;
}
}
}
if (value)
*value = min_val;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
size_t CMC_(PFX, _multiplicity_of)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_set_, value);
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
if (!entry)
return 0;
return entry->multiplicity;
}
bool CMC_(PFX, _contains)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set_->flag = CMC_FLAG_OK;
bool result = CMC_(PFX, _impl_get_entry)(_set_, value) != NULL;
CMC_CALLBACKS_CALL(_set_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return (double)_set_->capacity * _set_->load <= (double)_set_->count;
}
size_t CMC_(PFX, _count)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->count;
}
size_t CMC_(PFX, _cardinality)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->cardinality;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->capacity;
}
double CMC_(PFX, _load)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->load;
}
int CMC_(PFX, _flag)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set_->flag = CMC_FLAG_OK;
if (_set_->capacity == capacity)
goto success;
if (_set_->capacity > capacity / _set_->load)
goto success;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * _set_->load)
{
_set_->flag = CMC_FLAG_ERROR;
return false;
}
/* Calculate required capacity based on the prime numbers */
size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity);
/* Not possible to shrink with current available prime numbers */
if (theoretical_size < _set_->count / _set_->load)
{
_set_->flag = CMC_FLAG_INVALID;
return false;
}
/* No callbacks since _new_set_ is just a temporary hashtable */
struct SNAME *_new_set_ = CMC_(PFX, _new_custom)(capacity, _set_->load, _set_->f_val, _set_->alloc, NULL);
if (!_new_set_)
{
_set_->flag = CMC_FLAG_ERROR;
return false;
}
for (size_t i = 0; i < _set_->capacity; i++)
{
if (_set_->buffer[i].state == CMC_ES_FILLED)
{
V value = _set_->buffer[i].value;
size_t multiplicity = _set_->buffer[i].multiplicity;
/* TODO check this for possible errors where entry == NULL */
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_new_set_, value, NULL);
entry->multiplicity = multiplicity;
/* Setting cardinality not required, _new_set_ is temporary */
}
}
if (_set_->count != _new_set_->count)
{
CMC_(PFX, _free)(_new_set_);
_set_->flag = CMC_FLAG_ERROR;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *tmp_b = _set_->buffer;
_set_->buffer = _new_set_->buffer;
_new_set_->buffer = tmp_b;
size_t tmp_c = _set_->capacity;
_set_->capacity = _new_set_->capacity;
_new_set_->capacity = tmp_c;
/* Prevent the set from freeing the data */
_new_set_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
CMC_(PFX, _free)(_new_set_);
success:
CMC_CALLBACKS_CALL(_set_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *result =
CMC_(PFX, _new_custom)(_set_->capacity * _set_->load, _set_->load, _set_->f_val, _set_->alloc, NULL);
if (!result)
{
_set_->flag = CMC_FLAG_ERROR;
return NULL;
}
CMC_CALLBACKS_ASSIGN(result, _set_->callbacks);
if (_set_->f_val->cpy)
{
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = &(_set_->buffer[i]);
if (scan->state != CMC_ES_EMPTY)
{
struct CMC_DEF_ENTRY(SNAME) *target = &(result->buffer[i]);
if (scan->state == CMC_ES_DELETED)
target->state = CMC_ES_DELETED;
else
{
target->state = scan->state;
target->dist = scan->dist;
target->multiplicity = scan->multiplicity;
target->value = _set_->f_val->cpy(scan->value);
}
}
}
}
else
memcpy(result->buffer, _set_->buffer, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity);
result->count = _set_->count;
result->cardinality = _set_->cardinality;
_set_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set1_->flag = CMC_FLAG_OK;
_set2_->flag = CMC_FLAG_OK;
if (_set1_->count != _set2_->count)
return false;
if (_set1_->cardinality != _set2_->cardinality)
return false;
if (_set1_->count == 0)
return true;
/* Optimize loop using the smallest hashtable */
struct SNAME *_set_a_;
struct SNAME *_set_b_;
_set_a_ = _set1_->capacity < _set2_->capacity ? _set1_ : _set2_;
_set_b_ = _set_a_ == _set1_ ? _set2_ : _set1_;
for (size_t i = 0; i < _set_a_->capacity; i++)
{
if (_set_a_->buffer[i].state == CMC_ES_FILLED)
{
struct CMC_DEF_ENTRY(SNAME) *entry_a = &(_set_a_->buffer[i]);
struct CMC_DEF_ENTRY(SNAME) *entry_b = CMC_(PFX, _impl_get_entry)(_set_b_, entry_a->value);
if (!entry_b)
return false;
if (entry_a->multiplicity != entry_b->multiplicity)
return false;
}
}
return true;
}
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_insert_and_return)(struct SNAME *_set_, V value, bool *new_node)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* If the entry already exists simply return it as we might do */
/* something with it. This function only guarantees that there is */
/* a valid entry for a given value */
if (new_node)
*new_node = false;
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_set_, value);
if (entry != NULL)
return entry;
if (new_node)
*new_node = true;
if (CMC_(PFX, _full)(_set_))
{
if (!CMC_(PFX, _resize)(_set_, _set_->capacity + 1))
return NULL;
}
size_t hash = _set_->f_val->hash(value);
size_t original_pos = hash % _set_->capacity;
size_t pos = original_pos;
/* Current multiplicity. Might change due to robin hood hashing */
size_t curr_mul = 1;
struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]);
struct CMC_DEF_ENTRY(SNAME) *to_return = NULL;
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
{
target->value = value;
target->multiplicity = curr_mul;
target->dist = pos - original_pos;
target->state = CMC_ES_FILLED;
to_return = target;
}
else
{
while (true)
{
pos++;
target = &(_set_->buffer[pos % _set_->capacity]);
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
{
target->value = value;
target->multiplicity = curr_mul;
target->dist = pos - original_pos;
target->state = CMC_ES_FILLED;
if (!to_return)
to_return = target;
break;
}
else if (target->dist < pos - original_pos)
{
/* Swap everything */
V tmp = target->value;
size_t tmp_dist = target->dist;
size_t tmp_mul = target->multiplicity;
target->value = value;
target->dist = pos - original_pos;
target->multiplicity = curr_mul;
value = tmp;
original_pos = pos - tmp_dist;
curr_mul = tmp_mul;
if (!to_return)
to_return = target;
}
}
}
_set_->count++;
return to_return;
}
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t hash = _set_->f_val->hash(value);
size_t pos = hash % _set_->capacity;
struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]);
while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED)
{
if (target->state != CMC_ES_DELETED && _set_->f_val->cmp(target->value, value) == 0)
return target;
pos++;
target = &(_set_->buffer[pos % _set_->capacity]);
}
return NULL;
}
static size_t CMC_(PFX, _impl_calculate_size)(size_t required)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
if (cmc_hashtable_primes[count - 1] < required)
return required;
size_t i = 0;
while (cmc_hashtable_primes[i] < required)
i++;
return cmc_hashtable_primes[i];
}
+742
View File
@@ -0,0 +1,742 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* List bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == CMC_ES_FILLED)
{
iter.first = i;
break;
}
}
iter.cursor = iter.first;
for (size_t i = target->capacity; i > 0; i--)
{
if (target->buffer[i - 1].state == CMC_ES_FILLED)
{
iter.last = i - 1;
break;
}
}
}
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == CMC_ES_FILLED)
{
iter.first = i;
break;
}
}
for (size_t i = target->capacity; i > 0; i--)
{
if (target->buffer[i - 1].state == CMC_ES_FILLED)
{
iter.last = i - 1;
break;
}
}
iter.cursor = iter.last;
iter.index = target->count - 1;
}
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->first;
iter->index = 0;
iter->start = true;
iter->end = CMC_(PFX, _empty)(iter->target);
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->last;
iter->index = iter->target->count - 1;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->end = true;
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
iter->index++;
while (1)
{
iter->cursor++;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == CMC_ES_FILLED)
break;
}
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
iter->index--;
while (1)
{
iter->cursor--;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == CMC_ES_FILLED)
break;
}
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->index + steps >= iter->target->count)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_next)(iter);
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->index < steps)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_prev)(iter);
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->index > index)
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
else if (iter->index < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
return true;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->target->buffer[iter->cursor].value;
}
size_t CMC_(PFX, _iter_multiplicity)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return 0;
return iter->target->buffer[iter->cursor].multiplicity;
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->index;
}
#endif /* CMC_EXT_ITER */
/**
* SETF
*
* Set functions
*/
#ifdef CMC_EXT_SETF
/* Implementation detail function */
static size_t CMC_(PFX, _impl_multiplicity_of)(struct SNAME *_set_, V value);
struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
return NULL;
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
{
V value = CMC_(PFX, _iter_value)(&iter1);
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter1);
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
size_t max_ = m1 > m2 ? m1 : m2;
CMC_(PFX, _update)(_set_r_, value, max_);
}
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
{
V value = CMC_(PFX, _iter_value)(&iter2);
size_t m1 = CMC_(PFX, _impl_multiplicity_of)(_set1_, value);
size_t m2 = CMC_(PFX, _iter_multiplicity)(&iter2);
size_t max_ = m1 > m2 ? m1 : m2;
CMC_(PFX, _update)(_set_r_, value, max_);
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
return NULL;
struct SNAME *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_;
struct SNAME *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_;
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set_A_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter);
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set_B_, value);
size_t max_ = m1 < m2 ? m1 : m2;
CMC_(PFX, _update)(_set_r_, value, max_);
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
return NULL;
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter);
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
if (m1 > m2)
CMC_(PFX, _update)(_set_r_, value, m1 - m2);
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
struct SNAME *CMC_(PFX, _summation)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
return NULL;
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
{
CMC_(PFX, _insert_many)
(_set_r_, CMC_(PFX, _iter_value)(&iter1), CMC_(PFX, _iter_multiplicity)(&iter1));
}
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
{
CMC_(PFX, _insert_many)
(_set_r_, CMC_(PFX, _iter_value)(&iter2), CMC_(PFX, _iter_multiplicity)(&iter2));
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
return NULL;
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
{
V value = CMC_(PFX, _iter_value)(&iter1);
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter1);
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
if (m1 != m2)
{
if (m1 > m2)
CMC_(PFX, _update)(_set_r_, value, m1 - m2);
else
CMC_(PFX, _update)(_set_r_, value, m2 - m1);
}
}
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
{
V value = CMC_(PFX, _iter_value)(&iter2);
size_t m1 = CMC_(PFX, _impl_multiplicity_of)(_set1_, value);
size_t m2 = CMC_(PFX, _iter_multiplicity)(&iter2);
if (m1 != m2)
{
if (m1 > m2)
CMC_(PFX, _update)(_set_r_, value, m1 - m2);
else
CMC_(PFX, _update)(_set_r_, value, m2 - m1);
}
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_set1_->count > _set2_->count)
return false;
if (CMC_(PFX, _empty)(_set1_))
return true;
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter);
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
if (m1 > m2)
return false;
}
return true;
}
bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _is_subset)(_set2_, _set1_);
}
bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_set1_->count >= _set2_->count)
return false;
if (CMC_(PFX, _empty)(_set1_))
{
if (!CMC_(PFX, _empty)(_set2_))
return true;
else
return false;
}
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter);
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
if (m1 >= m2)
return false;
}
return true;
}
bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _is_proper_subset)(_set2_, _set1_);
}
bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set1_))
return true;
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
if (CMC_(PFX, _impl_get_entry)(_set2_, value) != NULL)
return false;
}
return true;
}
static size_t CMC_(PFX, _impl_multiplicity_of)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_set_, value);
if (!entry)
return 0;
return entry->multiplicity;
}
#endif /* CMC_EXT_SETF */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *s_ = _set_;
return 0 <= fprintf(fptr,
"struct %s<%s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"cardinality:%" PRIuMAX ", "
"load:%lf, "
"flag:%d, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), s_, s_->buffer, s_->capacity, s_->count,
s_->cardinality, s_->load, s_->flag, s_->f_val, s_->alloc, CMC_CALLBACKS_GET(s_));
}
bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *val_mul_sep)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
size_t last = 0;
for (size_t i = _set_->capacity; i > 0; i--)
{
if ((_set_->buffer[i - 1]).state == CMC_ES_FILLED)
{
last = i - 1;
break;
}
}
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
if (!_set_->f_val->str(fptr, entry->value))
return false;
fprintf(fptr, "%s", val_mul_sep);
if (fprintf(fptr, "%" PRIuMAX "", entry->multiplicity) < 0)
return false;
if (i + 1 < last)
fprintf(fptr, "%s", separator);
}
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+95
View File
@@ -0,0 +1,95 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* List bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_multiplicity)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* SETF
*
* Set functions
*/
#ifdef CMC_EXT_SETF
/* Set Operations */
struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_);
struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_);
struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_);
struct SNAME *CMC_(PFX, _summation)(struct SNAME *_set1_, struct SNAME *_set2_);
struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_);
#endif /* CMC_EXT_SETF */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr);
bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *key_val_sep);
#endif /* CMC_EXT_STR */
+57
View File
@@ -0,0 +1,57 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Hashmultiset bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* HashMultiSet Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target HashMultiset */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* Keeps track of relative index to the iteration of elements */
size_t index;
/* The index of the first element */
size_t first;
/* The index of the last element */
size_t last;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+72
View File
@@ -0,0 +1,72 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Value struct function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val,
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_set_);
void CMC_(PFX, _free)(struct SNAME *_set_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_set_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _insert)(struct SNAME *_set_, V value);
bool CMC_(PFX, _insert_many)(struct SNAME *_set_, V value, size_t count);
bool CMC_(PFX, _update)(struct SNAME *_set_, V value, size_t multiplicity);
bool CMC_(PFX, _remove)(struct SNAME *_set_, V value);
size_t CMC_(PFX, _remove_all)(struct SNAME *_set_, V value);
/* Element Access */
bool CMC_(PFX, _max)(struct SNAME *_set_, V *value);
bool CMC_(PFX, _min)(struct SNAME *_set_, V *value);
size_t CMC_(PFX, _multiplicity_of)(struct SNAME *_set_, V value);
/* Collection State */
bool CMC_(PFX, _contains)(struct SNAME *_set_, V value);
bool CMC_(PFX, _empty)(struct SNAME *_set_);
bool CMC_(PFX, _full)(struct SNAME *_set_);
size_t CMC_(PFX, _count)(struct SNAME *_set_);
size_t CMC_(PFX, _cardinality)(struct SNAME *_set_);
size_t CMC_(PFX, _capacity)(struct SNAME *_set_);
double CMC_(PFX, _load)(struct SNAME *_set_);
int CMC_(PFX, _flag)(struct SNAME *_set_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_);
bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_);
+58
View File
@@ -0,0 +1,58 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
struct SNAME
{
/* Array of Entries */
struct CMC_DEF_ENTRY(SNAME) * buffer;
/* Current Array Capcity */
size_t capacity;
/* Current amount of unique elements */
size_t count;
/* Total amount of elements taking into account their multiplicity */
size_t cardinality;
/* Load factor in range (0.0, 1.0) */
double load;
/* Flags indicating errors or success */
int flag;
/* Key function table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
struct CMC_DEF_ENTRY(SNAME)
{
/* Entry element */
V value;
/* The element's multiplicity */
size_t multiplicity;
/* The distance of this node to its original position, used by */
/* robin-hood hashing */
size_t dist;
/* The sate of this node (DELETED, EMPTY, FILLED) */
enum cmc_entry_state state;
};
+81
View File
@@ -0,0 +1,81 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* hashset.h
*
* Creation Date: 01/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* HashSet
*
* A HashSet is an implementation of a Set with unique keys. The keys are not
* sorted. It is implemented as a flat hashtable with linear probing and robin
* hood hashing.
*/
#include "cor/core.h"
#include "cor/hashtable.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* V - hashset value data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/hashset/struct.h"
/* Function declaration */
#include "cmc/hashset/header.h"
/* Function implementation */
#include "cmc/hashset/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - hashset iterator
* STR - Print helper functions
*/
#define CMC_EXT_HASHSET_PARTS ITER, SETF, STR
/**/
#include "cmc/hashset/ext/struct.h"
/**/
#include "cmc/hashset/ext/header.h"
/**/
#include "cmc/hashset/ext/code.h"
#include "cor/undef.h"
+602
View File
@@ -0,0 +1,602 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value);
static size_t CMC_(PFX, _impl_calculate_size)(size_t required);
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(capacity, load, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val,
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity == 0 || load <= 0 || load >= 1)
return NULL;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * load)
return NULL;
if (!f_val)
return NULL;
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME));
if (!_set_)
return NULL;
_set_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME)));
if (!_set_->buffer)
{
alloc->free(_set_);
return NULL;
}
_set_->count = 0;
_set_->capacity = real_capacity;
_set_->load = load;
_set_->flag = CMC_FLAG_OK;
_set_->f_val = f_val;
_set_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_set_, callbacks);
return _set_;
}
void CMC_(PFX, _clear)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_set_->f_val->free)
{
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
_set_->f_val->free(entry->value);
}
}
}
memset(_set_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity);
_set_->count = 0;
_set_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_set_->f_val->free)
{
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
_set_->f_val->free(entry->value);
}
}
}
_set_->alloc->free(_set_->buffer);
_set_->alloc->free(_set_);
}
void CMC_(PFX, _customize)(struct SNAME *_set_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_set_->alloc = &cmc_alloc_node_default;
else
_set_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_set_, callbacks);
_set_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _insert)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_set_))
{
if (!CMC_(PFX, _resize)(_set_, _set_->capacity + 1))
return false;
}
if (CMC_(PFX, _impl_get_entry)(_set_, value) != NULL)
{
_set_->flag = CMC_FLAG_DUPLICATE;
return false;
}
size_t hash = _set_->f_val->hash(value);
size_t original_pos = hash % _set_->capacity;
size_t pos = original_pos;
struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]);
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
{
target->value = value;
target->dist = 0;
target->state = CMC_ES_FILLED;
}
else
{
while (true)
{
pos++;
target = &(_set_->buffer[pos % _set_->capacity]);
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
{
target->value = value;
target->dist = pos - original_pos;
target->state = CMC_ES_FILLED;
break;
}
else if (target->dist < pos - original_pos)
{
V tmp = target->value;
size_t tmp_dist = target->dist;
target->value = value;
target->dist = pos - original_pos;
value = tmp;
original_pos = pos - tmp_dist;
}
}
}
_set_->count++;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _remove)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set_))
{
_set_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value);
if (result == NULL)
{
_set_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
result->value = (V){ 0 };
result->dist = 0;
result->state = CMC_ES_DELETED;
_set_->count--;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _max)(struct SNAME *_set_, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set_))
{
_set_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
V max_val = (V){ 0 };
for (size_t i = 0; i < _set_->capacity; i++)
{
if (_set_->buffer[i].state == CMC_ES_FILLED)
{
if (first)
{
max_val = _set_->buffer[i].value;
first = false;
}
else if (_set_->f_val->cmp(_set_->buffer[i].value, max_val) > 0)
{
max_val = _set_->buffer[i].value;
}
}
}
if (value)
*value = max_val;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _min)(struct SNAME *_set_, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set_))
{
_set_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
V min_val = (V){ 0 };
for (size_t i = 0; i < _set_->capacity; i++)
{
if (_set_->buffer[i].state == CMC_ES_FILLED)
{
if (first)
{
min_val = _set_->buffer[i].value;
first = false;
}
else if (_set_->f_val->cmp(_set_->buffer[i].value, min_val) < 0)
{
min_val = _set_->buffer[i].value;
}
}
}
if (value)
*value = min_val;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _contains)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set_->flag = CMC_FLAG_OK;
bool result = CMC_(PFX, _impl_get_entry)(_set_, value) != NULL;
CMC_CALLBACKS_CALL(_set_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return (double)_set_->capacity * _set_->load <= (double)_set_->count;
}
size_t CMC_(PFX, _count)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->count;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->capacity;
}
double CMC_(PFX, _load)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->load;
}
int CMC_(PFX, _flag)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set_->flag = CMC_FLAG_OK;
if (_set_->capacity == capacity)
goto success;
if (_set_->capacity > capacity / _set_->load)
goto success;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * _set_->load)
{
_set_->flag = CMC_FLAG_ERROR;
return false;
}
/* Calculate required capacity based on the prime numbers */
size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity);
/* Not possible to shrink with current available prime numbers */
if (theoretical_size < _set_->count / _set_->load)
{
_set_->flag = CMC_FLAG_INVALID;
return false;
}
/* No callbacks since _new_set_ is just a temporary hashtable */
struct SNAME *_new_set_ = CMC_(PFX, _new_custom)(capacity, _set_->load, _set_->f_val, _set_->alloc, NULL);
if (!_new_set_)
{
_set_->flag = CMC_FLAG_ALLOC;
return false;
}
for (size_t i = 0; i < _set_->capacity; i++)
{
if (_set_->buffer[i].state == CMC_ES_FILLED)
{
V value = _set_->buffer[i].value;
/* TODO check this for possible errors */
CMC_(PFX, _insert)(_new_set_, value);
}
}
/* Unlikely */
if (_set_->count != _new_set_->count)
{
CMC_(PFX, _free)(_new_set_);
_set_->flag = CMC_FLAG_ERROR;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *tmp_b = _set_->buffer;
_set_->buffer = _new_set_->buffer;
_new_set_->buffer = tmp_b;
size_t tmp_c = _set_->capacity;
_set_->capacity = _new_set_->capacity;
_new_set_->capacity = tmp_c;
/* Prevent the set from freeing the data */
_new_set_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
CMC_(PFX, _free)(_new_set_);
success:
CMC_CALLBACKS_CALL(_set_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *result =
CMC_(PFX, _new_custom)(_set_->capacity * _set_->load, _set_->load, _set_->f_val, _set_->alloc, NULL);
if (!result)
{
_set_->flag = CMC_FLAG_ERROR;
return NULL;
}
CMC_CALLBACKS_ASSIGN(result, _set_->callbacks);
if (_set_->f_val->cpy)
{
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = &(_set_->buffer[i]);
if (scan->state != CMC_ES_EMPTY)
{
struct CMC_DEF_ENTRY(SNAME) *target = &(result->buffer[i]);
if (scan->state == CMC_ES_DELETED)
target->state = CMC_ES_DELETED;
else
{
target->state = scan->state;
target->dist = scan->dist;
target->value = _set_->f_val->cpy(scan->value);
}
}
}
}
else
memcpy(result->buffer, _set_->buffer, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity);
result->count = _set_->count;
_set_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set1_->flag = CMC_FLAG_OK;
_set2_->flag = CMC_FLAG_OK;
if (_set1_->count != _set2_->count)
return false;
/* Optimize loop using the smallest hashtable */
struct SNAME *_set_a_;
struct SNAME *_set_b_;
_set_a_ = _set1_->capacity < _set2_->capacity ? _set1_ : _set2_;
_set_b_ = _set_a_ == _set1_ ? _set2_ : _set1_;
for (size_t i = 0; i < _set_a_->capacity; i++)
{
if (_set_a_->buffer[i].state == CMC_ES_FILLED)
{
if (!CMC_(PFX, _impl_get_entry)(_set_b_, _set_a_->buffer[i].value))
return false;
}
}
return true;
}
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t hash = _set_->f_val->hash(value);
size_t pos = hash % _set_->capacity;
struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]);
while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED)
{
if (target->state != CMC_ES_DELETED && _set_->f_val->cmp(target->value, value) == 0)
return target;
pos++;
target = &(_set_->buffer[pos % _set_->capacity]);
}
return NULL;
}
static size_t CMC_(PFX, _impl_calculate_size)(size_t required)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
if (cmc_hashtable_primes[count - 1] < required)
return required;
size_t i = 0;
while (cmc_hashtable_primes[i] < required)
i++;
return cmc_hashtable_primes[i];
}
+687
View File
@@ -0,0 +1,687 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Hashset bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == CMC_ES_FILLED)
{
iter.first = i;
break;
}
}
iter.cursor = iter.first;
for (size_t i = target->capacity; i > 0; i--)
{
if (target->buffer[i - 1].state == CMC_ES_FILLED)
{
iter.last = i - 1;
break;
}
}
}
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == CMC_ES_FILLED)
{
iter.first = i;
break;
}
}
for (size_t i = target->capacity; i > 0; i--)
{
if (target->buffer[i - 1].state == CMC_ES_FILLED)
{
iter.last = i - 1;
break;
}
}
iter.cursor = iter.last;
iter.index = target->count - 1;
}
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->first;
iter->index = 0;
iter->start = true;
iter->end = CMC_(PFX, _empty)(iter->target);
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->last;
iter->index = iter->target->count - 1;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->end = true;
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
iter->index++;
while (1)
{
iter->cursor++;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == CMC_ES_FILLED)
break;
}
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
iter->index--;
while (1)
{
iter->cursor--;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == CMC_ES_FILLED)
break;
}
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->index + steps >= iter->target->count)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_next)(iter);
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->index < steps)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_prev)(iter);
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->index > index)
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
else if (iter->index < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
return true;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->target->buffer[iter->cursor].value;
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->index;
}
#endif /* CMC_EXT_ITER */
/**
* SETF
*
* Set functions
*/
#ifdef CMC_EXT_SETF
struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
{
_set1_->flag = CMC_FLAG_ALLOC;
_set2_->flag = CMC_FLAG_ALLOC;
return NULL;
}
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
/* TODO turn this into a normal loop and check for errors */
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
{
CMC_(PFX, _insert)(_set_r_, CMC_(PFX, _iter_value)(&iter1));
}
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
{
CMC_(PFX, _insert)(_set_r_, CMC_(PFX, _iter_value)(&iter2));
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
{
_set1_->flag = CMC_FLAG_ALLOC;
_set2_->flag = CMC_FLAG_ALLOC;
return NULL;
}
struct SNAME *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_;
struct SNAME *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_;
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set_A_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
if (CMC_(PFX, _impl_get_entry)(_set_B_, value) != NULL)
CMC_(PFX, _insert)(_set_r_, value);
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
{
_set1_->flag = CMC_FLAG_ALLOC;
_set2_->flag = CMC_FLAG_ALLOC;
return NULL;
}
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL)
CMC_(PFX, _insert)(_set_r_, value);
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
{
_set1_->flag = CMC_FLAG_ALLOC;
_set2_->flag = CMC_FLAG_ALLOC;
return NULL;
}
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
{
V value = CMC_(PFX, _iter_value)(&iter1);
if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL)
CMC_(PFX, _insert)(_set_r_, value);
}
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
{
V value = CMC_(PFX, _iter_value)(&iter2);
if (CMC_(PFX, _impl_get_entry)(_set1_, value) == NULL)
CMC_(PFX, _insert)(_set_r_, value);
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
/* Is _set1_ a subset of _set2_ ? */
/* A set X is a subset of a set Y when: X <= Y */
/* If X is a subset of Y, then Y is a superset of X */
bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set1_->flag = CMC_FLAG_OK;
_set2_->flag = CMC_FLAG_OK;
/* If the cardinality of _set1_ is greater than that of _set2_, */
/* then it is safe to say that _set1_ can't be a subset of _set2_ */
if (_set1_->count > _set2_->count)
return false;
/* The empty set is a subset of all sets */
if (CMC_(PFX, _empty)(_set1_))
return true;
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL)
return false;
}
return true;
}
/* Is _set1_ a superset of _set2_ ? */
/* A set X is a superset of a set Y when: X >= Y */
/* If X is a superset of Y, then Y is a subset of X */
bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _is_subset)(_set2_, _set1_);
}
/* Is _set1_ a proper subset of _set2_ ? */
/* A set X is a proper subset of a set Y when: X < Y */
/* If X is a proper subset of Y, then Y is a proper superset of X */
bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set1_->flag = CMC_FLAG_OK;
_set2_->flag = CMC_FLAG_OK;
/* If the cardinality of _set1_ is greater than or equal to that of */
/* _set2_, then it is safe to say that _set1_ can't be a proper */
/* subset of _set2_ */
if (_set1_->count >= _set2_->count)
return false;
if (CMC_(PFX, _empty)(_set1_))
{
/* The empty set is a proper subset of all non-empty sets */
if (!CMC_(PFX, _empty)(_set2_))
return true;
/* The empty set is not a proper subset of itself (this is true */
/* for any set) */
else
return false;
}
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL)
return false;
}
return true;
}
/* Is _set1_ a proper superset of _set2_ ? */
/* A set X is a proper superset of a set Y when: X > Y */
/* If X is a proper superset of Y, then Y is a proper subset of X */
bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _is_proper_subset)(_set2_, _set1_);
}
/* Is _set1_ a disjointset of _set2_ ? */
/* A set X is a disjointset of a set Y if their intersection is empty, */
/* that is, if there are no elements in common between the two */
bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set1_->flag = CMC_FLAG_OK;
_set2_->flag = CMC_FLAG_OK;
/* The intersection of an empty set with any other set will result */
/* in an empty set */
if (CMC_(PFX, _empty)(_set1_))
return true;
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
if (CMC_(PFX, _impl_get_entry)(_set2_, value) != NULL)
return false;
}
return true;
}
#endif /* CMC_EXT_SETF */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *s_ = _set_;
return 0 <= fprintf(fptr,
"struct %s<%s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"load:%lf, "
"flag:%d, "
"f_val:%p, "
"alloc:%p, "
"callbacks: %p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), s_, s_->buffer, s_->capacity, s_->count, s_->load,
s_->flag, s_->f_val, s_->alloc, CMC_CALLBACKS_GET(s_));
}
bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
size_t last = 0;
for (size_t i = _set_->capacity; i > 0; i--)
{
if ((_set_->buffer[i - 1]).state == CMC_ES_FILLED)
{
last = i - 1;
break;
}
}
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
if (!_set_->f_val->str(fptr, entry->value))
return false;
if (i + 1 < last)
fprintf(fptr, "%s", separator);
}
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+92
View File
@@ -0,0 +1,92 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* List bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* SETF
*
* Set functions
*/
#ifdef CMC_EXT_SETF
/* Set Operations */
struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_);
struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_);
struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_);
struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_);
#endif /* CMC_EXT_SETF */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr);
bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end);
#endif /* CMC_EXT_STR */
+51
View File
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Hashset bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* HashSet Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target HashSet */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* Keeps track of relative index to the iteration of elements */
size_t index;
/* The index of the first element */
size_t first;
/* The index of the last element */
size_t last;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+67
View File
@@ -0,0 +1,67 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Value struct function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val,
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_set_);
void CMC_(PFX, _free)(struct SNAME *_set_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_set_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _insert)(struct SNAME *_set_, V value);
bool CMC_(PFX, _remove)(struct SNAME *_set_, V value);
/* Element Access */
bool CMC_(PFX, _max)(struct SNAME *_set_, V *value);
bool CMC_(PFX, _min)(struct SNAME *_set_, V *value);
/* Collection State */
bool CMC_(PFX, _contains)(struct SNAME *_set_, V value);
bool CMC_(PFX, _empty)(struct SNAME *_set_);
bool CMC_(PFX, _full)(struct SNAME *_set_);
size_t CMC_(PFX, _count)(struct SNAME *_set_);
size_t CMC_(PFX, _capacity)(struct SNAME *_set_);
double CMC_(PFX, _load)(struct SNAME *_set_);
int CMC_(PFX, _flag)(struct SNAME *_set_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_);
bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_);
+55
View File
@@ -0,0 +1,55 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Hashset Structure */
struct SNAME
{
/* Array of Entries */
struct CMC_DEF_ENTRY(SNAME) * buffer;
/* Current Array Capcity */
size_t capacity;
/* Current amount of elements */
size_t count;
/* Load factor in range (0.0, 1.0) */
double load;
/* Flags indicating errors or success */
int flag;
/* Value function table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
struct CMC_DEF_ENTRY(SNAME)
{
/* Entry value */
V value;
/* The distance of this node to its original position, used by */
/* robin-hood hashing */
size_t dist;
/* The sate of this node (DELETED, EMPTY, FILLED) */
enum cmc_entry_state state;
};
+92
View File
@@ -0,0 +1,92 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* heap.h
*
* Creation Date: 25/03/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Heap
*
* The Heap is a specialized tree-based data structure which is essentially a
* complete tree that satisfies the heap property:
* - MaxHeap:
* - The root node is the greatest element of the unique set of keys.
* - A node key is always greater than or equal to its children keys.
* - Minheap:
* - The root node is the smallest element of the unique set of keys.
* - A node Key is always greater than or equal to its children keys.
*
* The heap is mostly used to implement priority queues. Sometimes it can also
* be used to sort elements. There are three main functions:
* - insert : Adds an element to the heap
* - remove_(min/max): Removes the min/max element from the heap
* - min/max : Accesses the min/max element from the heap
*/
#include "cor/core.h"
#include "cor/heap.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* V - heap value data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/heap/struct.h"
/* Function declaration */
#include "cmc/heap/header.h"
/* Function implementation */
#include "cmc/heap/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - heap iterator
* STR - Print helper functions
*/
#define CMC_EXT_HEAP_PARTS ITER, SETF, STR
/**/
#include "cmc/heap/ext/struct.h"
/**/
#include "cmc/heap/ext/header.h"
/**/
#include "cmc/heap/ext/code.h"
#include "cor/undef.h"
+437
View File
@@ -0,0 +1,437 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
static void CMC_(PFX, _impl_float_up)(struct SNAME *_heap_, size_t index);
static void CMC_(PFX, _impl_float_down)(struct SNAME *_heap_, size_t index);
struct SNAME *CMC_(PFX, _new)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(capacity, HO, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val,
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity < 1)
return NULL;
if (HO != CMC_MIN_HEAP && HO != CMC_MAX_HEAP)
return NULL;
if (!f_val)
return NULL;
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_heap_ = alloc->malloc(sizeof(struct SNAME));
if (!_heap_)
return NULL;
_heap_->buffer = alloc->calloc(capacity, sizeof(V));
if (!_heap_->buffer)
{
alloc->free(_heap_);
return NULL;
}
_heap_->capacity = capacity;
_heap_->count = 0;
_heap_->HO = HO;
_heap_->flag = CMC_FLAG_OK;
_heap_->f_val = f_val;
_heap_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_heap_, callbacks);
return _heap_;
}
void CMC_(PFX, _clear)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_heap_->f_val->free)
{
for (size_t i = 0; i < _heap_->count; i++)
{
_heap_->f_val->free(_heap_->buffer[i]);
}
}
memset(_heap_->buffer, 0, sizeof(V) * _heap_->capacity);
_heap_->count = 0;
_heap_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_heap_->f_val->free)
{
for (size_t i = 0; i < _heap_->count; i++)
{
_heap_->f_val->free(_heap_->buffer[i]);
}
}
_heap_->alloc->free(_heap_->buffer);
_heap_->alloc->free(_heap_);
}
void CMC_(PFX, _customize)(struct SNAME *_heap_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_heap_->alloc = &cmc_alloc_node_default;
else
_heap_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_heap_, callbacks);
_heap_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_heap_))
{
if (!CMC_(PFX, _resize)(_heap_, _heap_->count * 2))
return false;
}
_heap_->buffer[_heap_->count++] = value;
if (_heap_->count > 1)
{
CMC_(PFX, _impl_float_up)(_heap_, _heap_->count - 1);
}
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return true;
}
bool CMC_(PFX, _remove)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return false;
}
_heap_->buffer[0] = _heap_->buffer[_heap_->count - 1];
_heap_->buffer[_heap_->count - 1] = (V){ 0 };
_heap_->count--;
CMC_(PFX, _impl_float_down)(_heap_, 0);
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return true;
}
V CMC_(PFX, _peek)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return _heap_->buffer[0];
}
bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_heap_->flag = CMC_FLAG_OK;
bool result = false;
for (size_t i = 0; i < _heap_->count; i++)
{
if (_heap_->f_val->cmp(_heap_->buffer[i], value) == 0)
{
result = true;
break;
}
}
CMC_CALLBACKS_CALL(_heap_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->count >= _heap_->capacity;
}
size_t CMC_(PFX, _count)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->count;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->capacity;
}
int CMC_(PFX, _flag)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_heap_->flag = CMC_FLAG_OK;
if (_heap_->capacity == capacity)
goto success;
if (capacity < _heap_->count)
{
_heap_->flag = CMC_FLAG_INVALID;
return false;
}
V *new_buffer = _heap_->alloc->realloc(_heap_->buffer, sizeof(V) * capacity);
if (!new_buffer)
{
_heap_->flag = CMC_FLAG_ALLOC;
return false;
}
/* TODO zero out new slots */
_heap_->buffer = new_buffer;
_heap_->capacity = capacity;
success:
CMC_CALLBACKS_CALL(_heap_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *result = CMC_(PFX, _new_custom)(_heap_->capacity, _heap_->HO, _heap_->f_val, _heap_->alloc, NULL);
if (!result)
{
_heap_->flag = CMC_FLAG_ERROR;
return NULL;
}
CMC_CALLBACKS_ASSIGN(result, _heap_->callbacks);
if (_heap_->f_val->cpy)
{
for (size_t i = 0; i < _heap_->count; i++)
result->buffer[i] = _heap_->f_val->cpy(_heap_->buffer[i]);
}
else
memcpy(result->buffer, _heap_->buffer, sizeof(V) * _heap_->count);
result->count = _heap_->count;
_heap_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_heap1_->flag = CMC_FLAG_OK;
_heap2_->flag = CMC_FLAG_OK;
if (_heap1_->count != _heap2_->count)
return false;
for (size_t i = 0; i < _heap1_->count; i++)
{
if (_heap1_->f_val->cmp(_heap1_->buffer[i], _heap2_->buffer[i]) != 0)
return false;
}
return true;
}
static void CMC_(PFX, _impl_float_up)(struct SNAME *_heap_, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Current index */
size_t C = index;
V child = _heap_->buffer[C];
V parent = _heap_->buffer[(index - 1) / 2];
int mod = _heap_->HO;
while (C > 0 && _heap_->f_val->cmp(child, parent) * mod > 0)
{
/* Swap between C (current element) and its parent */
V tmp = _heap_->buffer[C];
_heap_->buffer[C] = _heap_->buffer[(C - 1) / 2];
_heap_->buffer[(C - 1) / 2] = tmp;
/* Go to parent */
C = (C - 1) / 2;
/* Prevent the two lines below from accessing a negative index */
if (C == 0)
break;
child = _heap_->buffer[C];
parent = _heap_->buffer[(C - 1) / 2];
}
}
static void CMC_(PFX, _impl_float_down)(struct SNAME *_heap_, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
int mod = _heap_->HO;
while (index < _heap_->count)
{
size_t L = 2 * index + 1;
size_t R = 2 * index + 2;
size_t C = index;
/* Determine if we swap with the left or right element */
if (L < _heap_->count && _heap_->f_val->cmp(_heap_->buffer[L], _heap_->buffer[C]) * mod > 0)
{
C = L;
}
if (R < _heap_->count && _heap_->f_val->cmp(_heap_->buffer[R], _heap_->buffer[C]) * mod > 0)
{
C = R;
}
/* Swap only if either left or right was picked, otherwise done */
if (C != index)
{
V tmp = _heap_->buffer[index];
_heap_->buffer[index] = _heap_->buffer[C];
_heap_->buffer[C] = tmp;
index = C;
}
else
break;
}
}
+325
View File
@@ -0,0 +1,325 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Heap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
if (!CMC_(PFX, _empty)(target))
iter.cursor = target->count - 1;
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = 0;
iter->start = true;
iter->end = CMC_(PFX, _empty)(iter->target);
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->target->count - 1;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->end = true;
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->cursor + 1 == iter->target->count)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
iter->cursor++;
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->cursor == 0)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
iter->cursor--;
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->cursor + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->cursor + steps >= iter->target->count)
return false;
if (iter->end)
return false;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->cursor += steps;
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->cursor == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->cursor < steps)
return false;
iter->end = CMC_(PFX, _empty)(iter->target);
iter->cursor -= steps;
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->cursor > index)
return CMC_(PFX, _iter_rewind)(iter, iter->cursor - index);
else if (iter->cursor < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->cursor);
return true;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->target->buffer[iter->cursor];
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->cursor;
}
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *h_ = _heap_;
const char *t = h_->HO == 1 ? "MaxHeap" : "MinHeap";
return 0 <= fprintf(fptr,
"struct %s<%s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"type:%s, "
"flag:%d, "
"f_val:%p, "
"alloc:%p, "
"callbacks: %p}",
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), h_, h_->buffer, h_->capacity, h_->count, t, h_->flag,
h_->f_val, h_->alloc, CMC_CALLBACKS_GET(h_));
}
bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
for (size_t i = 0; i < _heap_->count; i++)
{
if (!_heap_->f_val->str(fptr, _heap_->buffer[i]))
return false;
if (i + 1 < _heap_->count)
fprintf(fptr, "%s", separator);
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+72
View File
@@ -0,0 +1,72 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Heap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr);
bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end);
#endif /* CMC_EXT_STR */
+45
View File
@@ -0,0 +1,45 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Heap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Heap Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target heap */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+65
View File
@@ -0,0 +1,65 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Value struct function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val,
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_heap_);
void CMC_(PFX, _free)(struct SNAME *_heap_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_heap_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value);
bool CMC_(PFX, _remove)(struct SNAME *_heap_);
/* Element Access */
V CMC_(PFX, _peek)(struct SNAME *_heap_);
/* Collection State */
bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value);
bool CMC_(PFX, _empty)(struct SNAME *_heap_);
bool CMC_(PFX, _full)(struct SNAME *_heap_);
size_t CMC_(PFX, _count)(struct SNAME *_heap_);
size_t CMC_(PFX, _capacity)(struct SNAME *_heap_);
int CMC_(PFX, _flag)(struct SNAME *_heap_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_);
bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_);
+43
View File
@@ -0,0 +1,43 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
struct SNAME
{
/* Dynamic array of elements */
V *buffer;
/* Current array capacity */
size_t capacity;
/* Current amount of elements in the heap */
size_t count;
/* Heap order (MaxHeap or MinHeap) */
enum cmc_heap_order HO;
/* Flags indicating errors or success */
int flag;
/* Value function table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
+84
View File
@@ -0,0 +1,84 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* intervalheap.h
*
* Creation Date: 06/07/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Interval Heap
*
* An interval heap is a specialized heap with:
*
* - O(1) - Find Min
* - O(1) - Find Max
* - O(log n) - Insert
* - O(log n) - Remove Min
* - O(log n) - Remove Max
*/
#include "cor/core.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* V - intervalheap value data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/intervalheap/struct.h"
/* Function declaration */
#include "cmc/intervalheap/header.h"
/* Function implementation */
#include "cmc/intervalheap/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - intervalheap iterator
* STR - Print helper functions
*/
#define CMC_EXT_HEAP_PARTS ITER, SETF, STR
/**/
#include "cmc/intervalheap/ext/struct.h"
/**/
#include "cmc/intervalheap/ext/header.h"
/**/
#include "cmc/intervalheap/ext/code.h"
#include "cor/undef.h"
+860
View File
@@ -0,0 +1,860 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
static void CMC_(PFX, _impl_float_up_max)(struct SNAME *_heap_);
static void CMC_(PFX, _impl_float_up_min)(struct SNAME *_heap_);
static void CMC_(PFX, _impl_float_down_max)(struct SNAME *_heap_);
static void CMC_(PFX, _impl_float_down_min)(struct SNAME *_heap_);
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(capacity, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity == 0 || capacity == UINTMAX_MAX)
return NULL;
if (!f_val)
return NULL;
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_heap_ = alloc->malloc(sizeof(struct SNAME));
if (!_heap_)
return NULL;
capacity = (capacity + capacity % 2) / 2;
_heap_->buffer = alloc->calloc(capacity, sizeof(V[2]));
if (!_heap_->buffer)
{
alloc->free(_heap_);
return NULL;
}
_heap_->capacity = capacity;
_heap_->size = 0;
_heap_->count = 0;
_heap_->flag = CMC_FLAG_OK;
_heap_->f_val = f_val;
_heap_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_heap_, callbacks);
return _heap_;
}
void CMC_(PFX, _clear)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_heap_->f_val->free)
{
for (size_t i = 0; i < _heap_->count; i++)
{
_heap_->f_val->free(_heap_->buffer[i / 2][i % 2]);
}
}
memset(_heap_->buffer, 0, sizeof(V[2]) * _heap_->capacity);
_heap_->size = 0;
_heap_->count = 0;
_heap_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_heap_->f_val->free)
{
for (size_t i = 0; i < _heap_->count; i++)
{
_heap_->f_val->free(_heap_->buffer[i / 2][i % 2]);
}
}
_heap_->alloc->free(_heap_->buffer);
_heap_->alloc->free(_heap_);
}
void CMC_(PFX, _customize)(struct SNAME *_heap_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_heap_->alloc = &cmc_alloc_node_default;
else
_heap_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_heap_, callbacks);
_heap_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_heap_))
{
if (!CMC_(PFX, _resize)(_heap_, _heap_->capacity * 4))
return false;
}
if (_heap_->count % 2 == 0)
{
/* Occupying a new node */
_heap_->buffer[_heap_->size][0] = value;
_heap_->buffer[_heap_->size][1] = (V){ 0 };
_heap_->size++;
}
else
{
V(*node)[2] = &(_heap_->buffer[_heap_->size - 1]);
/* Decide if the new element goes into the MinHeap or MaxHeap */
if (_heap_->f_val->cmp((*node)[0], value) > 0)
{
/* Swap current value and add new element to the MinHeap */
(*node)[1] = (*node)[0];
(*node)[0] = value;
}
else
{
/* No need to swap and add the new element to the MaxHeap */
(*node)[1] = value;
}
}
_heap_->count++;
_heap_->flag = CMC_FLAG_OK;
if (_heap_->count > 2)
{
/* Determine wheather to do a MaxHeap insert or a MinHeap */
/* insert. For any integer this index calculation results in */
/* an even number representing the parent of the last value */
V(*parent)[2] = &(_heap_->buffer[(_heap_->size - 2) / 2]);
if (_heap_->f_val->cmp((*parent)[0], value) > 0)
CMC_(PFX, _impl_float_up_min)(_heap_);
else if (_heap_->f_val->cmp((*parent)[1], value) < 0)
CMC_(PFX, _impl_float_up_max)(_heap_);
/* else no float up required */
}
CMC_CALLBACKS_CALL(_heap_);
return true;
}
bool CMC_(PFX, _remove_max)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return false;
}
if (_heap_->count == 1)
{
_heap_->buffer[0][0] = (V){ 0 };
_heap_->count--;
_heap_->size--;
goto success;
}
/* Swap the result with the last element in the MaxHeap and float */
/* it down */
V(*last_node)[2] = &(_heap_->buffer[_heap_->size - 1]);
if (_heap_->count % 2 == 1)
{
/* Grab from MinHeap and discard last node */
_heap_->buffer[0][1] = (*last_node)[0];
(*last_node)[0] = (V){ 0 };
_heap_->size--;
}
else
{
_heap_->buffer[0][1] = (*last_node)[1];
(*last_node)[1] = (V){ 0 };
}
_heap_->count--;
/* FLoat Down on the MaxHeap */
CMC_(PFX, _impl_float_down_max)(_heap_);
success:
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return true;
}
bool CMC_(PFX, _remove_min)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return false;
}
if (_heap_->count == 1)
{
_heap_->buffer[0][0] = (V){ 0 };
_heap_->count--;
_heap_->size--;
goto success;
}
/* Swap the result with the last element in the MinHeap and float */
/* it down */
V(*last_node)[2] = &(_heap_->buffer[_heap_->size - 1]);
_heap_->buffer[0][0] = (*last_node)[0];
if (_heap_->count % 2 == 1)
{
/* Discard last node */
(*last_node)[0] = (V){ 0 };
_heap_->size--;
}
else
{
/* Place the MaxHeap value in the MinHeap value spot */
(*last_node)[0] = (*last_node)[1];
(*last_node)[1] = (V){ 0 };
}
_heap_->count--;
/* FLoat Down on the MinHeap */
CMC_(PFX, _impl_float_down_min)(_heap_);
success:
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return true;
}
bool CMC_(PFX, _update_max)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return false;
}
if (_heap_->count == 1)
{
_heap_->buffer[0][0] = value;
}
else if (_heap_->f_val->cmp(value, _heap_->buffer[0][0]) < 0)
{
/* Corner case: we are updating the Max value but it is less */
/* than the Min value */
_heap_->buffer[0][1] = _heap_->buffer[0][0];
_heap_->buffer[0][0] = value;
CMC_(PFX, _impl_float_down_max)(_heap_);
}
else
{
/* Update Max element and float it down */
_heap_->buffer[0][1] = value;
CMC_(PFX, _impl_float_down_max)(_heap_);
}
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return true;
}
bool CMC_(PFX, _update_min)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return false;
}
if (_heap_->count == 1)
{
_heap_->buffer[0][0] = value;
}
else if (_heap_->f_val->cmp(value, _heap_->buffer[0][1]) > 0)
{
/* Corner case: we are updating the Min value but it is greater */
/* than the Max value. */
_heap_->buffer[0][0] = _heap_->buffer[0][1];
_heap_->buffer[0][1] = value;
CMC_(PFX, _impl_float_down_min)(_heap_);
}
else
{
/* Update Min element and float it down */
_heap_->buffer[0][0] = value;
CMC_(PFX, _impl_float_down_min)(_heap_);
}
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return true;
}
V CMC_(PFX, _max)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
/* If there is only one element, then the maximum element is the */
/* same as the one in the MinHeap */
if (_heap_->count == 1)
return _heap_->buffer[0][0];
return _heap_->buffer[0][1];
}
V CMC_(PFX, _min)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return _heap_->buffer[0][0];
}
bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_heap_->flag = CMC_FLAG_OK;
bool result = false;
for (size_t i = 0; i < _heap_->count; i++)
{
if (_heap_->f_val->cmp(_heap_->buffer[i / 2][i % 2], value) == 0)
{
result = true;
break;
}
}
CMC_CALLBACKS_CALL(_heap_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* The heap is full if all nodes are completely filled */
return _heap_->size >= _heap_->capacity && _heap_->count % 2 == 0;
}
size_t CMC_(PFX, _count)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->count;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->capacity;
}
int CMC_(PFX, _flag)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_heap_->capacity == capacity)
goto success;
if (capacity < _heap_->count)
{
_heap_->flag = CMC_FLAG_INVALID;
return false;
}
/* Prevent overflow */
if (capacity == UINTMAX_MAX)
{
_heap_->flag = CMC_FLAG_ERROR;
return false;
}
capacity += capacity % 2;
V(*new_buffer)[2] = _heap_->alloc->realloc(_heap_->buffer, sizeof(V[2]) * capacity);
if (!new_buffer)
{
_heap_->flag = CMC_FLAG_ALLOC;
return false;
}
if (capacity > _heap_->capacity)
{
memset(new_buffer + _heap_->capacity, 0, sizeof(V[2]) * (capacity - _heap_->capacity));
}
_heap_->buffer = new_buffer;
_heap_->capacity = capacity;
success:
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *result = _heap_->alloc->malloc(sizeof(struct SNAME));
if (!result)
{
_heap_->flag = CMC_FLAG_ALLOC;
return NULL;
}
memcpy(result, _heap_, sizeof(struct SNAME));
result->buffer = _heap_->alloc->malloc(sizeof(V[2]) * _heap_->capacity);
if (!result->buffer)
{
_heap_->alloc->free(result);
_heap_->flag = CMC_FLAG_ALLOC;
return NULL;
}
if (_heap_->f_val->cpy)
{
for (size_t i = 0; i < _heap_->count; i++)
result->buffer[i / 2][i % 2] = _heap_->f_val->cpy(_heap_->buffer[i / 2][i % 2]);
}
else
memcpy(result->buffer, _heap_->buffer, sizeof(V[2]) * _heap_->capacity);
result->capacity = _heap_->capacity;
result->size = _heap_->size;
result->count = _heap_->count;
result->flag = CMC_FLAG_OK;
result->f_val = _heap_->f_val;
result->alloc = _heap_->alloc;
CMC_CALLBACKS_ASSIGN(result, _heap_->callbacks);
_heap_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_heap1_->flag = CMC_FLAG_OK;
_heap2_->flag = CMC_FLAG_OK;
if (_heap1_->count != _heap2_->count)
return false;
for (size_t i = 0; i < _heap1_->count; i++)
{
V value1 = _heap1_->buffer[i / 2][i % 2];
V value2 = _heap2_->buffer[i / 2][i % 2];
if (_heap1_->f_val->cmp(value1, value2) != 0)
return false;
}
return true;
}
static void CMC_(PFX, _impl_float_up_max)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t index = _heap_->size - 1;
V(*curr_node)[2] = &(_heap_->buffer[index]);
/* FLoat Up on the MaxHeap */
while (index > 0)
{
/* Parent index */
size_t P_index = (index - 1) / 2;
V(*parent)[2] = &(_heap_->buffer[P_index]);
if (index == _heap_->size - 1 && _heap_->count % 2 != 0)
{
/* In this case, the current node has no MaxHeap value so */
/* we instead compare with the MinHeap value */
if (_heap_->f_val->cmp((*curr_node)[0], (*parent)[1]) < 0)
break;
/* Since the comparison above passed now we need to swap */
/* the current node with the parent but it will have to be */
/* done with the node's MinHeap value since the MaxHeap */
/* value doesn't exist */
V tmp = (*curr_node)[0];
(*curr_node)[0] = (*parent)[1];
(*parent)[1] = tmp;
}
else
{
/* Usual case, just compare both MaxHeap values */
if (_heap_->f_val->cmp((*curr_node)[1], (*parent)[1]) < 0)
break;
/* Swap with parent and repeat */
V tmp = (*curr_node)[1];
(*curr_node)[1] = (*parent)[1];
(*parent)[1] = tmp;
}
/* Update indexe and node */
index = P_index;
curr_node = parent;
}
}
static void CMC_(PFX, _impl_float_up_min)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t index = _heap_->size - 1;
V(*curr_node)[2] = &(_heap_->buffer[index]);
/* FLoat Up on the MinHeap */
while (index > 0)
{
/* Parent index */
size_t P_index = (index - 1) / 2;
V(*parent)[2] = &(_heap_->buffer[P_index]);
if (_heap_->f_val->cmp((*curr_node)[0], (*parent)[0]) >= 0)
break;
/* Swap with parent and repeat */
V tmp = (*curr_node)[0];
(*curr_node)[0] = (*parent)[0];
(*parent)[0] = tmp;
/* Update indexe and node */
index = P_index;
curr_node = parent;
}
}
static void CMC_(PFX, _impl_float_down_max)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Floats Down from the MaxHeap */
size_t index = 0;
V(*curr_node)[2] = &(_heap_->buffer[index]);
while (true)
{
/* If there are no children it is done */
if (2 * index + 1 >= _heap_->size)
break;
/* Child index to be compared with current value */
size_t child;
size_t L_index = index * 2 + 1;
size_t R_index = index * 2 + 2;
/* If there are two children, pick the smallest one */
if (R_index < _heap_->size)
{
V(*L)[2] = &(_heap_->buffer[L_index]);
V(*R)[2] = &(_heap_->buffer[R_index]);
/* If the right child is the last node and there is no */
/* MaxHeap value */
/* then do the comparison with the MinHeap value */
if (R_index == _heap_->size - 1 && _heap_->count % 2 != 0)
child = _heap_->f_val->cmp((*L)[1], (*R)[0]) > 0 ? L_index : R_index;
else
child = _heap_->f_val->cmp((*L)[1], (*R)[1]) > 0 ? L_index : R_index;
}
/* Pick the only one available */
else
child = L_index;
V(*child_node)[2] = &(_heap_->buffer[child]);
/* Again, check if the child node is the last one and has no */
/* MaxHeap value */
if (child == _heap_->size - 1 && _heap_->count % 2 != 0)
{
/* Odd case, compare with MinHeap value */
/* If current value is not less than the child node's */
/* value it is done */
if (_heap_->f_val->cmp((*curr_node)[1], (*child_node)[0]) >= 0)
break;
/* Otherwise swap and continue */
V tmp = (*child_node)[0];
(*child_node)[0] = (*curr_node)[1];
(*curr_node)[1] = tmp;
}
else
{
/* If current value is not less than the child node's */
/* value it is done */
if (_heap_->f_val->cmp((*curr_node)[1], (*child_node)[1]) >= 0)
break;
/* Otherwise swap and continue */
V tmp = (*child_node)[1];
(*child_node)[1] = (*curr_node)[1];
(*curr_node)[1] = tmp;
/* Check if the MinHeap and MaxHeap values need to be */
/* swapped */
if (_heap_->f_val->cmp((*child_node)[0], (*child_node)[1]) > 0)
{
/* Swap because the MinHeap value is greater than the */
/* MaxHeap value */
tmp = (*child_node)[0];
(*child_node)[0] = (*child_node)[1];
(*child_node)[1] = tmp;
}
}
/* Update index and node */
index = child;
curr_node = child_node;
}
}
static void CMC_(PFX, _impl_float_down_min)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Floats Down from the MinHeap */
size_t index = 0;
V(*curr_node)[2] = &(_heap_->buffer[index]);
while (true)
{
/* If there are no children it is done */
if (2 * index + 1 >= _heap_->size)
break;
/* Child index to be compared with current value */
size_t child;
size_t L_index = index * 2 + 1;
size_t R_index = index * 2 + 2;
/* If there are two children, pick the smallest one */
if (R_index < _heap_->size)
{
V(*L)[2] = &(_heap_->buffer[L_index]);
V(*R)[2] = &(_heap_->buffer[R_index]);
child = _heap_->f_val->cmp((*L)[0], (*R)[0]) < 0 ? L_index : R_index;
}
/* Pick the only one available */
else
child = L_index;
V(*child_node)[2] = &(_heap_->buffer[child]);
/* If current value is smaller than the child node's value, it */
/* is done */
if (_heap_->f_val->cmp((*curr_node)[0], (*child_node)[0]) < 0)
break;
/* Otherwise swap and continue */
V tmp = (*child_node)[0];
(*child_node)[0] = (*curr_node)[0];
(*curr_node)[0] = tmp;
/* If the child node is the last node check if the MinHeap and */
/* MaxHeap values need to be swapped */
if (child != _heap_->size - 1 || _heap_->count % 2 == 0)
{
if (_heap_->f_val->cmp((*child_node)[0], (*child_node)[1]) > 0)
{
/* Swap because the MinHeap value is greater than the */
/* MaxHeap value */
tmp = (*child_node)[0];
(*child_node)[0] = (*child_node)[1];
(*child_node)[1] = tmp;
}
}
/* Update index and node */
index = child;
curr_node = child_node;
}
}
+326
View File
@@ -0,0 +1,326 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Intervalheap bi-directional iterator.
*
* TODO allow creation of iterators exclusively for min or max heap
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
if (!CMC_(PFX, _empty)(target))
iter.cursor = target->count - 1;
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = 0;
iter->start = true;
iter->end = CMC_(PFX, _empty)(iter->target);
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->target->count - 1;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->end = true;
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->cursor + 1 == iter->target->count)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
iter->cursor++;
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->cursor == 0)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
iter->cursor--;
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->cursor + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->cursor + steps >= iter->target->count)
return false;
if (iter->end)
return false;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->cursor += steps;
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->cursor == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->cursor < steps)
return false;
iter->end = CMC_(PFX, _empty)(iter->target);
iter->cursor -= steps;
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->cursor > index)
return CMC_(PFX, _iter_rewind)(iter, iter->cursor - index);
else if (iter->cursor < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->cursor);
return true;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->target->buffer[iter->cursor / 2][iter->cursor % 2];
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->cursor;
}
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *h_ = _heap_;
return 0 <= fprintf(fptr,
"struct %s<%s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"size:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"flag:%d, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), h_, h_->buffer, h_->capacity, h_->size, h_->count,
h_->flag, h_->f_val, h_->alloc, CMC_CALLBACKS_GET(h_));
}
bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
for (size_t i = 0; i < _heap_->count; i++)
{
if (!_heap_->f_val->str(fptr, _heap_->buffer[i / 2][i % 2]))
return false;
if (i + 1 < _heap_->count)
fprintf(fptr, "%s", separator);
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+88
View File
@@ -0,0 +1,88 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* List bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* IntervalHeap Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target IntervalHeap */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr);
bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end);
#endif /* CMC_EXT_STR */
+23
View File
@@ -0,0 +1,23 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+71
View File
@@ -0,0 +1,71 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Value struct function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Functions */
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_heap_);
void CMC_(PFX, _free)(struct SNAME *_heap_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_heap_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value);
bool CMC_(PFX, _remove_max)(struct SNAME *_heap_);
bool CMC_(PFX, _remove_min)(struct SNAME *_heap_);
/* Collection Update */
bool CMC_(PFX, _update_max)(struct SNAME *_heap_, V value);
bool CMC_(PFX, _update_min)(struct SNAME *_heap_, V value);
/* Element Access */
V CMC_(PFX, _max)(struct SNAME *_heap_);
V CMC_(PFX, _min)(struct SNAME *_heap_);
/* Collection State */
bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value);
bool CMC_(PFX, _empty)(struct SNAME *_heap_);
bool CMC_(PFX, _full)(struct SNAME *_heap_);
size_t CMC_(PFX, _count)(struct SNAME *_heap_);
size_t CMC_(PFX, _capacity)(struct SNAME *_heap_);
int CMC_(PFX, _flag)(struct SNAME *_heap_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_);
bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_);
+44
View File
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
struct SNAME
{
/* Dynamic array of elements */
/* buffer[n][0] is MinHeap and buffer[n][1] is MaxHeap */
V (*buffer)[2];
/* Current array capacity */
size_t capacity;
/* Current amount of pairs of values in the array */
size_t size;
/* Current amount of elements in the heap */
size_t count;
/* Flags indicating errors or success */
int flag;
/* Value function table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
+90
View File
@@ -0,0 +1,90 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* linkedlist.h
*
* Creation Date: 22/03/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* LinkedList
*
* A LinkedList is a linear collection of elements, whose order is not given by
* their physical placement in memory. Instead, each element points to the next
* (singly-linked list) and to a previous one (doubly-linked list). It consists
* of nodes connected by these next or previous pointers. Unlike an array, the
* LinkedList can indefinitely grow.
*
* Implementation
*
* The LinkedList is implemented as a doubly-linked list and allows insertions
* and removals at both ends in O(1) and in a given index in O(N). The list has
* a head and tail pointer. The head points to the first element in the sequence
* and tail points to the last.
*/
#include "cor/core.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* V - linkedlist data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/linkedlist/struct.h"
/* Function declaration */
#include "cmc/linkedlist/header.h"
/* Function implementation */
#include "cmc/linkedlist/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - List iterator
* NODE - Operations relative to a linkedlist node
* STR - Print helper functions
*/
#define CMC_EXT_LINKEDLIST_PARTS INIT, ITER, NODE, STR
/**/
#include "cmc/linkedlist/ext/struct.h"
/**/
#include "cmc/linkedlist/ext/header.h"
/**/
#include "cmc/linkedlist/ext/code.h"
#include "cor/undef.h"
+619
View File
@@ -0,0 +1,619 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _impl_get_node)(struct SNAME *_list_, size_t index);
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _impl_new_node)(struct SNAME *_list_, V value);
struct SNAME *CMC_(PFX, _new)(struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!f_val)
return NULL;
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME));
if (!_list_)
return NULL;
_list_->count = 0;
_list_->head = NULL;
_list_->tail = NULL;
_list_->flag = CMC_FLAG_OK;
_list_->f_val = f_val;
_list_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_list_, callbacks);
return _list_;
}
void CMC_(PFX, _clear)(struct SNAME *_list_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_NODE(SNAME) *scan = _list_->head;
while (_list_->head != NULL)
{
_list_->head = _list_->head->next;
if (_list_->f_val->free)
{
_list_->f_val->free(scan->value);
}
_list_->alloc->free(scan);
scan = _list_->head;
}
_list_->count = 0;
_list_->head = NULL;
_list_->tail = NULL;
_list_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_list_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_(PFX, _clear)(_list_);
_list_->alloc->free(_list_);
}
void CMC_(PFX, _customize)(struct SNAME *_list_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_list_->alloc = &cmc_alloc_node_default;
else
_list_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_list_, callbacks);
_list_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _push_front)(struct SNAME *_list_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_NODE(SNAME) *_node_ = CMC_(PFX, _impl_new_node)(_list_, value);
if (!_node_)
return false;
if (CMC_(PFX, _empty)(_list_))
{
_list_->head = _node_;
_list_->tail = _node_;
}
else
{
_node_->next = _list_->head;
_list_->head->prev = _node_;
_list_->head = _node_;
}
_list_->count++;
_list_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_list_);
return true;
}
bool CMC_(PFX, _push_at)(struct SNAME *_list_, V value, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index > _list_->count)
{
_list_->flag = CMC_FLAG_RANGE;
return false;
}
if (index == 0)
{
return CMC_(PFX, _push_front)(_list_, value);
}
else if (index == _list_->count)
{
return CMC_(PFX, _push_back)(_list_, value);
}
struct CMC_DEF_NODE(SNAME) *_node_ = CMC_(PFX, _impl_new_node)(_list_, value);
if (!_node_)
return false;
struct CMC_DEF_NODE(SNAME) *scan = CMC_(PFX, _impl_get_node)(_list_, index - 1);
_node_->next = scan->next;
_node_->prev = scan;
_node_->next->prev = _node_;
_node_->prev->next = _node_;
_list_->count++;
_list_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_list_);
return true;
}
bool CMC_(PFX, _push_back)(struct SNAME *_list_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_NODE(SNAME) *_node_ = CMC_(PFX, _impl_new_node)(_list_, value);
if (!_node_)
return false;
if (CMC_(PFX, _empty)(_list_))
{
_list_->head = _node_;
_list_->tail = _node_;
}
else
{
_node_->prev = _list_->tail;
_list_->tail->next = _node_;
_list_->tail = _node_;
}
_list_->count++;
_list_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_list_);
return true;
}
bool CMC_(PFX, _pop_front)(struct SNAME *_list_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_list_))
{
_list_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_NODE(SNAME) *_node_ = _list_->head;
_list_->head = _list_->head->next;
_list_->alloc->free(_node_);
if (_list_->head == NULL)
_list_->tail = NULL;
else
_list_->head->prev = NULL;
_list_->count--;
_list_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_list_);
return true;
}
bool CMC_(PFX, _pop_at)(struct SNAME *_list_, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_list_))
{
_list_->flag = CMC_FLAG_EMPTY;
return false;
}
if (index >= _list_->count)
{
_list_->flag = CMC_FLAG_RANGE;
return false;
}
if (index == 0)
{
return CMC_(PFX, _pop_front)(_list_);
}
else if (index == _list_->count - 1)
{
return CMC_(PFX, _pop_back)(_list_);
}
struct CMC_DEF_NODE(SNAME) *_node_ = CMC_(PFX, _impl_get_node)(_list_, index);
if (!_node_)
return false;
_node_->next->prev = _node_->prev;
_node_->prev->next = _node_->next;
_list_->alloc->free(_node_);
_list_->count--;
_list_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_list_);
return true;
}
bool CMC_(PFX, _pop_back)(struct SNAME *_list_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_list_))
{
_list_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_NODE(SNAME) *_node_ = _list_->tail;
_list_->tail = _list_->tail->prev;
_list_->alloc->free(_node_);
if (_list_->tail == NULL)
_list_->head = NULL;
else
_list_->tail->next = NULL;
_list_->count--;
_list_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_list_);
return true;
}
V CMC_(PFX, _front)(struct SNAME *_list_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_list_))
{
_list_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
_list_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_list_);
return _list_->head->value;
}
V CMC_(PFX, _get)(struct SNAME *_list_, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_list_))
{
_list_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
if (index >= _list_->count)
{
_list_->flag = CMC_FLAG_RANGE;
return (V){ 0 };
}
struct CMC_DEF_NODE(SNAME) *scan = CMC_(PFX, _impl_get_node)(_list_, index);
if (scan == NULL)
return (V){ 0 };
CMC_CALLBACKS_CALL(_list_);
return scan->value;
}
V *CMC_(PFX, _get_ref)(struct SNAME *_list_, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_list_))
{
_list_->flag = CMC_FLAG_EMPTY;
return NULL;
}
if (index >= _list_->count)
{
_list_->flag = CMC_FLAG_RANGE;
return NULL;
}
struct CMC_DEF_NODE(SNAME) *scan = CMC_(PFX, _impl_get_node)(_list_, index);
if (scan == NULL)
return NULL;
CMC_CALLBACKS_CALL(_list_);
return &(scan->value);
}
V CMC_(PFX, _back)(struct SNAME *_list_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_list_))
{
_list_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
_list_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_list_);
return _list_->tail->value;
}
bool CMC_(PFX, _contains)(struct SNAME *_list_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_list_->flag = CMC_FLAG_OK;
bool result = false;
struct CMC_DEF_NODE(SNAME) *scan = _list_->head;
while (scan != NULL)
{
if (_list_->f_val->cmp(scan->value, value) == 0)
{
result = true;
break;
}
scan = scan->next;
}
CMC_CALLBACKS_CALL(_list_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_list_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _list_->count == 0;
}
size_t CMC_(PFX, _count)(struct SNAME *_list_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _list_->count;
}
int CMC_(PFX, _flag)(struct SNAME *_list_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _list_->flag;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_list_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *result = CMC_(PFX, _new_custom)(_list_->f_val, _list_->alloc, NULL);
if (!result)
return NULL;
CMC_CALLBACKS_ASSIGN(result, _list_->callbacks);
struct CMC_DEF_NODE(SNAME) *scan = _list_->head;
while (scan != NULL)
{
/* This allocation should never fail since it might not be */
/* possible to recover from it. That is why it isn't checked */
struct CMC_DEF_NODE(SNAME) * new_node;
if (_list_->f_val->cpy)
new_node = CMC_(PFX, _impl_new_node)(_list_, _list_->f_val->cpy(scan->value));
else
new_node = CMC_(PFX, _impl_new_node)(_list_, scan->value);
if (!result->head)
{
result->head = new_node;
result->tail = new_node;
}
else
{
new_node->prev = result->tail;
result->tail->next = new_node;
result->tail = new_node;
}
scan = scan->next;
}
result->count = _list_->count;
_list_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_list1_, struct SNAME *_list2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_list1_->flag = CMC_FLAG_OK;
_list2_->flag = CMC_FLAG_OK;
if (_list1_->count != _list2_->count)
return false;
struct CMC_DEF_NODE(SNAME) *scan1 = _list1_->head;
struct CMC_DEF_NODE(SNAME) *scan2 = _list2_->head;
while (scan1 != NULL && scan2 != NULL)
{
if (_list1_->f_val->cmp(scan1->value, scan2->value) != 0)
return false;
scan1 = scan1->next;
scan2 = scan2->next;
}
return true;
}
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _impl_new_node)(struct SNAME *_list_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_NODE(SNAME) *_node_ = _list_->alloc->malloc(sizeof(struct CMC_DEF_NODE(SNAME)));
if (!_node_)
{
_list_->flag = CMC_FLAG_ALLOC;
return NULL;
}
_node_->value = value;
_node_->next = NULL;
_node_->prev = NULL;
return _node_;
}
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _impl_get_node)(struct SNAME *_list_, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_list_))
{
_list_->flag = CMC_FLAG_EMPTY;
return NULL;
}
if (index >= _list_->count)
{
_list_->flag = CMC_FLAG_RANGE;
return NULL;
}
struct CMC_DEF_NODE(SNAME) *_node_ = NULL;
if (index <= _list_->count / 2)
{
_node_ = _list_->head;
for (size_t i = 0; i < index; i++)
{
_node_ = _node_->next;
}
}
else
{
_node_ = _list_->tail;
for (size_t i = _list_->count - 1; i > index; i--)
{
_node_ = _node_->prev;
}
}
_list_->flag = CMC_FLAG_OK;
return _node_;
}
+610
View File
@@ -0,0 +1,610 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* List bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = target->head;
iter.index = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = target->tail;
iter.index = 0;
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
if (!CMC_(PFX, _empty)(target))
iter.index = target->count - 1;
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->target->head;
iter->index = 0;
iter->start = true;
iter->end = CMC_(PFX, _empty)(iter->target);
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->target->tail;
iter->index = iter->target->count - 1;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->end = true;
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->cursor->next == NULL)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
iter->cursor = iter->cursor->next;
iter->index++;
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->cursor->prev == NULL)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
iter->cursor = iter->cursor->prev;
iter->index--;
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->cursor->next == NULL)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->index + steps >= iter->target->count)
return false;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->index += steps;
for (size_t i = 0; i < steps; i++)
iter->cursor = iter->cursor->next;
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->cursor->prev == NULL)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->index < steps)
return false;
iter->end = CMC_(PFX, _empty)(iter->target);
iter->index -= steps;
for (size_t i = 0; i < steps; i++)
iter->cursor = iter->cursor->prev;
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->index > index)
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
else if (iter->index < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
return true;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->cursor->value;
}
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return NULL;
return &(iter->cursor->value);
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->index;
}
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _iter_node)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->cursor;
}
#endif /* CMC_EXT_ITER */
/**
* NODE
*
* Operations relative to a linkedlist node
*/
#ifdef CMC_EXT_NODE
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _new_node)(struct SNAME *_list_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_NODE(SNAME) *_node_ = _list_->alloc->malloc(sizeof(struct CMC_DEF_NODE(SNAME)));
if (!_node_)
{
_list_->flag = CMC_FLAG_ALLOC;
return NULL;
}
_node_->value = value;
_node_->next = NULL;
_node_->prev = NULL;
return _node_;
}
void CMC_(PFX, _free_node)(struct SNAME *_list_, struct CMC_DEF_NODE(SNAME) * _node_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_list_->alloc->free(_node_);
}
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _head)(struct SNAME *_list_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _list_->head;
}
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _get_node)(struct SNAME *_list_, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_list_))
{
_list_->flag = CMC_FLAG_EMPTY;
return NULL;
}
if (index >= _list_->count)
{
_list_->flag = CMC_FLAG_RANGE;
return NULL;
}
struct CMC_DEF_NODE(SNAME) *_node_ = NULL;
if (index <= _list_->count / 2)
{
_node_ = _list_->head;
for (size_t i = 0; i < index; i++)
{
_node_ = _node_->next;
}
}
else
{
_node_ = _list_->tail;
for (size_t i = _list_->count - 1; i > index; i--)
{
_node_ = _node_->prev;
}
}
_list_->flag = CMC_FLAG_OK;
return _node_;
}
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _tail)(struct SNAME *_list_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _list_->tail;
}
bool CMC_(PFX, _add_next)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_NODE(SNAME) *new_node = CMC_(PFX, _new_node)(_owner_, value);
if (!new_node)
return false;
new_node->next = _node_->next;
if (_node_->next != NULL)
_node_->next->prev = new_node;
else
_owner_->tail = new_node;
new_node->prev = _node_;
_node_->next = new_node;
_owner_->count++;
_owner_->flag = CMC_FLAG_OK;
return true;
}
bool CMC_(PFX, _add_prev)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_NODE(SNAME) *new_node = CMC_(PFX, _new_node)(_owner_, value);
if (!new_node)
return false;
new_node->prev = _node_->prev;
if (_node_->prev != NULL)
_node_->prev->next = new_node;
else
_owner_->head = new_node;
new_node->next = _node_;
_node_->prev = new_node;
_owner_->count++;
_owner_->flag = CMC_FLAG_OK;
return true;
}
bool CMC_(PFX, _del_next)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_node_->next == NULL)
{
_owner_->flag = CMC_FLAG_INVALID;
return false;
}
struct CMC_DEF_NODE(SNAME) *tmp = _node_->next;
_node_->next = _node_->next->next;
if (tmp->next != NULL)
tmp->next->prev = _node_;
else
_owner_->tail = _node_;
_owner_->alloc->free(tmp);
_owner_->count--;
_owner_->flag = CMC_FLAG_OK;
return true;
}
bool CMC_(PFX, _del_curr)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_node_->prev != NULL)
_node_->prev->next = _node_->next;
else
_owner_->head = _node_->next;
if (_node_->next != NULL)
_node_->next->prev = _node_->prev;
else
_owner_->tail = _node_->prev;
_owner_->alloc->free(_node_);
_owner_->count--;
_owner_->flag = CMC_FLAG_OK;
return true;
}
bool CMC_(PFX, _del_prev)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_node_->prev == NULL)
{
_owner_->flag = CMC_FLAG_INVALID;
return false;
}
struct CMC_DEF_NODE(SNAME) *tmp = _node_->prev;
_node_->prev = _node_->prev->prev;
if (tmp->prev != NULL)
tmp->prev->next = _node_;
else
_owner_->head = _node_;
_owner_->alloc->free(tmp);
_owner_->count--;
_owner_->flag = CMC_FLAG_OK;
return true;
}
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _next_node)(struct CMC_DEF_NODE(SNAME) * _node_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _node_->next;
}
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _prev_node)(struct CMC_DEF_NODE(SNAME) * _node_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _node_->prev;
}
#endif /* CMC_EXT_NODE */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_list_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *l_ = _list_;
return 0 <= fprintf(fptr,
"struct %s<%s> "
"at %p { "
"count:%" PRIuMAX ", "
"head:%p, "
"tail:%p, "
"flag:%d, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), l_, l_->count, l_->head, l_->tail, l_->flag, l_->f_val,
l_->alloc, CMC_CALLBACKS_GET(l_));
}
bool CMC_(PFX, _print)(struct SNAME *_list_, FILE *fptr, const char *start, const char *separator, const char *end)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
struct CMC_DEF_NODE(SNAME) *scan = _list_->head;
while (scan != NULL)
{
if (!_list_->f_val->str(fptr, scan->value))
return false;
scan = scan->next;
if (scan)
fprintf(fptr, "%s", separator);
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+115
View File
@@ -0,0 +1,115 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* List bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* LinkedList Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target Linked List */
struct SNAME *target;
/* Cursor's current node */
struct CMC_DEF_NODE(SNAME) * cursor;
/* Keeps track of relative index to the iteration of elements */
size_t index;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _iter_node)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* NODE
*
* Operations relative to a linkedlist node
*/
#ifdef CMC_EXT_NODE
/* Node Allocation and Deallocation */
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _new_node)(struct SNAME *_list_, V value);
void CMC_(PFX, _free_node)(struct SNAME *_list_, struct CMC_DEF_NODE(SNAME) * _node_);
/* Node Access Relative to a Linked List */
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _head)(struct SNAME *_list_);
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _get_node)(struct SNAME *_list_, size_t index);
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _tail)(struct SNAME *_list_);
/* Input and Output Relative to a Node */
bool CMC_(PFX, _add_next)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_, V value);
bool CMC_(PFX, _add_prev)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_, V value);
bool CMC_(PFX, _del_next)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_);
bool CMC_(PFX, _del_curr)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_);
bool CMC_(PFX, _del_prev)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_);
/* Node Access Relative to a Linked List Node */
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _next_node)(struct CMC_DEF_NODE(SNAME) * _node_);
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _prev_node)(struct CMC_DEF_NODE(SNAME) * _node_);
#endif /* CMC_EXT_NODE */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_list_, FILE *fptr);
bool CMC_(PFX, _print)(struct SNAME *_list_, FILE *fptr, const char *start, const char *separator, const char *end);
#endif /* CMC_EXT_STR */
Loaded 100 of 394 files, more files were not shown because too many files have changed in this diff. Show more