190 Commits
Author SHA1 Message Date
Leonardo Vencovsky 99f08e2b6e Add clangd to project 2024-06-26 22:50:15 +02:00
Leonardo Vencovsky 47ece66520 Move everything out of src folder 2023-12-13 15:14:46 +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
494 changed files with 55722 additions and 62667 deletions

No files matched your search

+2 -2
View File
@@ -1,13 +1,13 @@
# clang-format 9.0.0
Language: Cpp
BasedOnStyle: LLVM
AlignEscapedNewlines: Left
AlignEscapedNewlines: DontAlign
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
BreakBeforeBraces: Allman
BreakStringLiterals: false
ColumnLimit: 80
ColumnLimit: 120
Cpp11BracedListStyle: false
ForEachMacros: ["CMC_FOREACH", "CMC_FOREACH_REV"]
IndentCaseLabels: true
+2
View File
@@ -0,0 +1,2 @@
CompileFlags:
CompilationDatabase: "cmake"
+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
+8
View File
@@ -56,3 +56,11 @@ dkms.conf
# Experimental folder
experimental/
# Test / Code Coverage build folder
build
tests/coverage
tests/out
cmake
-19
View File
@@ -1,19 +0,0 @@
dist: trusty
os: linux
language: c
compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-7
- cmake
script:
- sudo ln -s /usr/bin/gcc-6 /usr/local/bin/gcc
- export CC=gcc-7
# - make -C ./tests/
- make -C ./tests/main/
- make -C ./tests/codecov/
after_success:
- bash <(curl -s https://codecov.io/bash)
+77 -29
View File
@@ -1,6 +1,54 @@
# RELEASE.MAJOR.MINOR
1.8.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
@@ -14,13 +62,13 @@
Removed ./utl/cmc_string.h
Replaced CMC_FOR_EACH and CMC_FOR_EACH_REV by CMC_FOREACH and CMC_FOREACH_REV
1.7.3
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
1.7.2 (0.20.0)
Added resize function to array based collections
Added the following functions to hashtable based collections:
- load
@@ -31,18 +79,18 @@
Removed unnecessary conditional input and output functions
Minor fixes throughout the library
1.7.1
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
1.7.0 (0.18.0)
Removed FMOD (function modifier)
Added CMC prefix to all macros defined within the library
1.6.3
1.6.3 (0.17.0)
Added iterator functions to all collections:
- iter_advance
- iter_rewind
@@ -50,7 +98,7 @@
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
1.6.2 (0.16.0)
Added new functions to all collections:
- copy_of
- equals
@@ -58,11 +106,11 @@
Fixed some collections and some improvements to the hashtables
Unified the functions set and update from the map implementations
1.6.1
1.6.1 (0.15.0)
Removed ./ext/linkedqueue.h
Added a deallocator parameter to all _free and _clear functions
1.6.0
1.6.0 (0.14.0)
Added ./ext/intervalheap.h
Added ./ext/multimap.h
Added ./ext/multiset.h
@@ -72,12 +120,12 @@
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
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
1.5.2 (0.12.0)
Added ./utl/test.h
Added ./utl/assert.h
Added ./tests/list.c - UnitTest for LIST
@@ -85,13 +133,13 @@
Removed ./utl/log.h functions that were unnecessary
Added the CMC namespace to CONCATC and CONCATH at macro_collections.h
1.5.1
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
1.5.0 (0.10.0)
Changed tests compilation and execution to a single Makefile
Changed project structure
./src/
@@ -105,7 +153,7 @@
Added ./ext/linkedqueue.h - A singly-linked list based queue
Added ./sac/stack.h - A Stack purely allocated on the stack
1.4.3
1.4.3 (0.9.0)
Fixed some functions names
Added set functions for both Tree and Hash Set
- is_subset
@@ -114,7 +162,7 @@
- is_proper_subset
- is_disjointset
1.4.2
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
@@ -122,12 +170,12 @@
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
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
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
@@ -139,48 +187,48 @@
Changed pointertype test to be a pointer to struct instead of pointer to char
Added CHANGELOG and TODO
1.3.0
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
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
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
1.2.2 (0.3.2)
Removed unnecessary modulo operation in hashtable functions
1.2.1
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
1.2.0 (0.3.0)
'contains' functions added to all collections
'contains' tests and benchmark
Unified Benchmark
Updated examples
1.1.3
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
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
1.1.1 (0.2.1)
Reordering functions (implementation details are now at the end of each file)
1.1.0
1.1.0 (0.2.0)
Added new list functions:
- new_from
- prepend
@@ -189,10 +237,10 @@
- remove
- fits
1.0.1
1.0.1 (0.1.1)
Fixed hashset logic in robin-hood hashing
1.0.0
1.0.0 (0.1.0)
First stable version
Includes the following collections:
- deque
+18
View File
@@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.8)
project(cmc)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
file(GLOB_RECURSE sources
"./tests/main.c"
)
add_definitions(-DCMC_CALLBACKS)
add_executable(cmc ${sources})
target_include_directories(cmc PUBLIC
"./"
)
+30 -14
View File
@@ -1,22 +1,38 @@
# This file is useful to format all the source files and header in this library using clang-format
.PHONY: all cmc dev sac utl tests FORCE
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
all: cmc dev sac utl tests
tests:
make -C ./tests
cmc: FORCE
clang-format --style=file -i ./src/cmc/*.h
tests_dev:
make -C ./tests dev
dev: FORCE
clang-format --style=file -i ./src/dev/*.h
format:
- find ./ -name *.h -type f | xargs clang-format --style=file --verbose -i
sac: FORCE
clang-format --style=file -i ./src/sac/*.h
bench:
make -C ./benchmarks benchmark
utl: FORCE
clang-format --style=file -i ./src/utl/*.h
docbuild:
mdbook build -d ../docs documentation
tests: FORCE
clang-format --style=file -i ./tests/main/unt/*.c ./tests/*.c
docserve:
mdbook serve documentation
FORCE:
install_dev_deps:
sudo apt install gcc make valgrind lcov clang-format hyperfine clangd cmake
cargo install mdbook
build_clangd:
cmake -S . -G "Unix Makefiles" -B cmake
.PHONY: tests tests_dev format bench docbuild docserve install_dev_deps
+179 -157
View File
@@ -1,94 +1,194 @@
# C Macro Collections
<p align="center">
<img src="https://leoven.github.io/C-Macro-Collections/images/logo.png" alt="C Macro Collections Logo" width="300"/>
<img src="https://leoven.github.io/C-Macro-Collections/img/logo.png" alt="C Macro Collections Logo" width="300"/>
</p>
<p align="center">Header only, macro generated, generic and type-safe Collections in C.</p>
<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-lightgrey.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-5A5A5A.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHN0eWxlPSIiPjxyZWN0IGlkPSJiYWNrZ3JvdW5kcmVjdCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgeD0iMCIgeT0iMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJub25lIi8%2BPHRpdGxlPmljbi9kb2MtdGV4dDwvdGl0bGU%2BPGcgY2xhc3M9ImN1cnJlbnRMYXllciIgc3R5bGU9IiI%2BPHRpdGxlPkxheWVyIDE8L3RpdGxlPjxwYXRoIGQ9Ik01IDFoNC4yNDRhMiAyIDAgMCAxIDEuNDM0LjYwNmwyLjc1NiAyLjgzNEEyIDIgMCAwIDEgMTQgNS44MzVWMTJhMyAzIDAgMCAxLTMgM0g1YTMgMyAwIDAgMS0zLTNWNGEzIDMgMCAwIDEgMy0zem0wIDJhMSAxIDAgMCAwLTEgMXY4YTEgMSAwIDAgMCAxIDFoNmExIDEgMCAwIDAgMS0xVjUuODM1TDkuMjQ0IDNINXptMS41IDdoM2EuNS41IDAgMSAxIDAgMWgtM2EuNS41IDAgMSAxIDAtMXptMC0yaDJhLjUuNSAwIDAgMSAwIDFoLTJhLjUuNSAwIDAgMSAwLTF6TTggMmwzIDEuOTk1TDEzIDdIOWExIDEgMCAwIDEtMS0xVjJ6IiBpZD0iYSIgY2xhc3M9IiIgZmlsbD0iI2ZmZmZmZiIgZmlsbC1vcGFjaXR5PSIxIi8%2BPC9nPjwvc3ZnPg%3D%3D" alt="LinkToDocs"/></a>
<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="#"><img src="https://img.shields.io/badge/Version-v1.8.0-orange.svg" alt="Version"/></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
* Project Structure
* Available Collections
* Features
* Overall To-Do
* Design Decisions
* What to use
* How to use
* [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 [Slate](https://github.com/slatedocs/slate)
* __documentation__ - Backup folder of the markdowns and custom styles used in [Slate](https://github.com/slatedocs/slate)
* __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
* __cmc__ - The main C Macro Collections Library
* __cor__ - Core includes in the C Macro Collections Library
* __dev__ - The main C Macro Collections Library for development (containing logging)
* __sac__ - Statically Allocated Collections
* __utl__ - Utility like ForEach macros, logging, etc
* __macro\_collections.h__ - Master header containing all collections and utilities
* __tests__ - Where all tests are hosted
## Available Collections
* Linear Collections
* List, LinkedList, Deque, Stack, Queue, SortedList
* Sets
* HashSet, TreeSet, MultiSet
* Maps
* BidiMap, HashMap, TreeMap, MultiMap
* Heaps
* Heap, IntervalHeap
__The following table is an overview of all the currently available or upcoming data structures__:
| Collection <img width=250/> | Abstract Data Type <img width=250/> | Data Structure <img width=250/> | Details |
| :--------------------------------: | :---------------------------------: | :-----------------------------: | :-----------------------------------: |
| BidiMap <br> _bidimap.h_ | Bidirectional Map | Two Hashtables | A bijection between two sets of unique keys and unique values `K <-> V` using two hashtables |
| 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 |
| HashMap <br> _hashmap.h_ | Map | 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 |
| HashSet <br> _hashset.h_ | Set | 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 |
| MultiMap <br> _multimap.h_ | Multimap | Custom Hashtable | A mapping of multiple keys with one node per key using a hashtable with separate chaining |
| Multiset <br> _multiset.h_ | Multiset | Hashtable | A mapping of a value and its multiplicity using a hashtable with open addressing and robin hood hashing |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
## Features
## Other Features
### Two-way iterators
These are some features within the library that are implemented by all collections.
## Two-way iterators
All collections come with a two-way iterator. You can go back and forwards in constant time and access elements in constant time.
### Custom Allocation
## Custom Allocation
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`.
### Callbacks
## Callbacks
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.
### Functions Table
## Functions Table
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 to a collection to operate. They are:
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:
#### CMP
@@ -124,41 +224,32 @@ A priority function works much like the comparator function except that it compa
The following table shows which functions are required, optional or never used for each Collection:
| Collection | CMP | CPY | STR | FREE | HASH | PRI |
| ---------- | :-: | :-: | :-: | :--: | :--: | :-: |
| BidiMap | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| Deque | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| HashMap | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| HashSet | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| Heap | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) |
| IntervalHeap | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) |
| List | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| LinkedList | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| MultiMap | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| MultiSet | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| Queue | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| SortedList | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| Stack | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| TreeMap | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| TreeSet | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| 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=+) |
| Color | Label |
| :---: | ----- |
| ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | Required for basic functionality. |
| ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | Required for specific functions. |
| ![#497edd](https://placehold.it/20/497edd/000000?text=+) | Required for non-core specific functions. |
| ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | Optional. |
| ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | Not Used. |
## Overall To-Do
In the long term, these are the steps left for the completion of this library:
* Complete the implementation of all the functions in the scope of the TODO file for the main collections;
* Reorganize and complete all tests for the `cmc` collections;
* Make an exact copy of all collections to `dev` with many logging utility, for them to be used under development;
* Port all of these collections to be statically allocated and be part of the `sac` library;
* Complete all tests for `sac`.
| 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. |
## Design Decisions
@@ -184,76 +275,7 @@ You can use them as Stacks, Queues and Deques, but with modern memory hierarchy
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).
## What to use
## Special Macros
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).
* **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.
![DataStructuresDiagram](https://i.imgur.com/hFqBSlC.png)
![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)
## How to use
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 the entire C-Macro-Collections library.
### Macros
> Note here that `SNAME` represents the uppercase name of the collection.
Every collection is separated by two parts:
* `HEADER` - Contains all struct definitions and function definitions.
* `SOURCE` - Contains all function implementations.
All collections have three main macros:
* `CMC_GENERATE_SNAME` - Generates `CMC_GENERATE_SNAME_HEADER` and `CMC_GENERATE_SNAME_SOURCE`.
Or you can generate each part individually:
* `CMC_GENERATE_SNAME_HEADER` - Generates all struct definitions and function definitions.
* `CMC_GENERATE_SNAME_SOURCE` - Generates all function implementations.
### Parameters
When including `macro_collections.h` in your source code you gain access to a macro called `CMC_COLLECTION_GENERATE` with the following parameters:
* __C__ - Container name in uppercase (*BIDIMAP*, *DEQUE*, *HASHMAP*, *HASHSET*, *HEAP*, *INTERVALHEAP*, *LINKEDLIST*, *LIST*, *MULTIMAP*, *MULTISET*, *QUEUE*, *SORTEDLIST*, *STACK*, *TREEMAP*, *TREESET*).
* __PFX__ - Functions prefix or namespace.
* __SNAME__ - Structure name (`struct SNAME`).
* __K__ - Key type. Only used in *HASHMAP*, *TREEMAP*, *MULTIMAP* and *BIDIMAP*; ignored by others.
* __V__ - Value type. Primary type for most collections, or value to be mapped by *HASHMAP*, *TREEMAP*, *MULTIMAP* and *BIDIMAP*.
**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.
### For Each
There are 2 for-each macros:
* `CMC_FOREACH` - Starts at the start of the collection towards the end.
* `CMC_FOREACH_REV` - Starts at the end of the collection towards the start.
* __PFX__ - Functions prefix or namespace.
* __SNAME__ - Structure name.
* __TARGET__ - The variable name of the collection you wish to iterate over.
* __ITERNAME__ - Iterator variable name.
For `CMC_FOREACH` and `CMC_FOREACH_REV` you will be able to name the iterator variable through the __ITERNAME__ parameter.
<hr>
Check out some code reviews that covers some parts the project:
| About | Link |
|-------|--------|
| Unit Test *./utl/test.h* | [![Code Review](http://www.zomis.net/codereview/shield/?qid=222954)](http://codereview.stackexchange.com/q/222954/178948) |
| Interval Heap *./cmc/intervalheap.h* | [![Code Review](http://www.zomis.net/codereview/shield/?qid=223595)](http://codereview.stackexchange.com/q/223595/178948) |
| Hash Set *./cmc/hashset.h* | [![Code Review](http://www.zomis.net/codereview/shield/?qid=217333)](http://codereview.stackexchange.com/q/217333/178948) |
| Linked List *./cmc/linkedlist.h* | [![Code Review](http://www.zomis.net/codereview/shield/?qid=216737)](http://codereview.stackexchange.com/q/216737/178948) |
| Others | [![Code Review](http://www.zomis.net/codereview/shield/?qid=213553)](http://codereview.stackexchange.com/q/213553/178948) |
* `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"`
+52 -12
View File
@@ -1,19 +1,53 @@
TODO
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
#!! High Priority ----------------------------------------------------------------------------------
[/] Tests
[/] Documentation
#!! Next Patch -----------------------------------------------------------------
#!! Medium Priority --------------------------------------------------------------------------------
#!! 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
#!! Being Considered -------------------------------------------------------------------------------
[ ] Serialization
[ ] save {all}
[ ] load {all}
@@ -22,13 +56,14 @@ TODO
[ ] Zip Iterators
[ ] Consumer Iterators
#!! Optimizations ----------------------------------------------------------------------------------
[ ] Use binary search to find optimum hashtable prime size inside impl_calculate_size
[ ] Optimize certain loops that use iterators that can simply use a normal loop
[ ] Replace IntervalHeap node by a simple buffer of two pointers (V (*buffer)[2])
#!! Optimizations --------------------------------------------------------------
#!! Done -------------------------------------------------------------------------------------------
[ ] Use binary search to find optimum hashtable prime size inside
impl_calculate_size
#!! Done -----------------------------------------------------------------------
[X] Remove PUBLIC and PRIVATE
[X] Utility
@@ -62,3 +97,8 @@ TODO
[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
+191 -148
View File
@@ -12,13 +12,19 @@
* - Iteration
* - Output
*/
#include "macro_collections.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)
@@ -26,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);
@@ -59,136 +48,190 @@ void shuffle(int *array, mt_state_ptr st)
}
}
CMC_COLLECTION_GENERATE(DEQUE, d, deque, /* K */, int)
CMC_COLLECTION_GENERATE(HASHMAP, hm, hmap, int, int)
CMC_COLLECTION_GENERATE(HASHSET, hs, hset, /* K */, int)
CMC_COLLECTION_GENERATE(HEAP, h, heap, /* K */, int)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll, linked, /* K */, int)
CMC_COLLECTION_GENERATE(LIST, l, list, /* K */, int)
CMC_COLLECTION_GENERATE(QUEUE, q, queue, /* K */, int)
CMC_COLLECTION_GENERATE(STACK, s, stack, /* K */, int)
CMC_COLLECTION_GENERATE(TREEMAP, tm, tmap, int, int)
CMC_COLLECTION_GENERATE(TREESET, ts, tset, /* K */, 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 };
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih, iheap, /* k */, int)
CMC_COLLECTION_GENERATE(MULTIMAP, mm, mmap, int, int)
CMC_COLLECTION_GENERATE(MULTISET, ms, mset, /* K */, int)
#define CMC_ARGS_FALLTHROUGH
#define V int
#define K int
#define CMC_EXT_ITER
#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; \
int r, k, v; \
size_t j; \
\
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); \
\
cmc_timer_calc(timer); \
\
size_t s1 = PFX##_count(coll); \
\
#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; \
\
cmc_timer_start(timer); \
\
for (size_t i = 0; i < s; i++) \
{ \
searchbody; \
} \
\
cmc_timer_stop(timer); \
\
cmc_timer_calc(timer); \
\
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
\
double search_time = timer.result; \
\
struct sname##_iter iter; \
\
cmc_timer_start(timer); \
\
for (PFX##_iter_init(&iter, coll); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
{ \
} \
\
cmc_timer_stop(timer); \
\
cmc_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; \
\
cmc_timer_start(timer); \
\
for (size_t i = 0; i < NTOTAL; i++) \
{ \
removebody; \
} \
\
cmc_timer_stop(timer); \
\
cmc_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; \
\
cmc_timer_stop(total); \
cmc_timer_calc(total); \
\
PFX##_free(coll, NULL); \
\
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.6, 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.6, intcmp, inthash), 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, 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, iheap, ih_new(NTOTAL, intcmp), ih_insert(coll, array[i]), ih_remove_max(coll, &r), ih_contains(coll, sarray[i]))
BENCHMARK(MULTIMAP, mm, mmap, mm_new(NTOTAL, 0.8, intcmp, inthash), mm_insert(coll, array[i], array[i]), mm_remove(coll, array[i], &r), mm_contains(coll, sarray[i]))
BENCHMARK(MULTISET, ms, mset, ms_new(NTOTAL, 0.6, intcmp, inthash), ms_insert(coll, array[i]), ms_remove(coll, array[i]), ms_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)
{
@@ -217,7 +260,8 @@ 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.
@@ -235,12 +279,11 @@ 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);
// INTERVALHEAP_io_benchmark(array, array, NMIN);
// MULTIMAP_io_benchmark(array, array, NTOTAL);
// MULTISET_io_benchmark(array, array, NTOTAL);
cmc_timer_stop(timer);
cmc_timer_calc(timer);
printf("+-----------------------------------------------------------+ \n");
printf("| Total Benchmark Running Time : %12.0lf seconds | \n", timer.result / 1000);
+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;
}
-2
View File
@@ -1,2 +0,0 @@
main:
gcc compile_time.c -c -O3 -ftime-report -I ../../src
-178
View File
@@ -1,178 +0,0 @@
/* Compilation time for over 90 collections */
#include <macro_collections.h>
struct imaginary
{
double real;
double imag;
};
enum app_state
{
TRACE = 1,
DEBUG = 2,
INFO = 3,
WARN = 4,
ERROR = 5,
FATAL = 6
};
CMC_COLLECTION_GENERATE(BIDIMAP, bd0, bidimap0, struct imaginary, struct imaginary)
CMC_COLLECTION_GENERATE(DEQUE, d0, deque0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(HASHMAP, hm0, hmap0, struct imaginary, struct imaginary)
CMC_COLLECTION_GENERATE(HASHSET, hs0, hset0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(HEAP, h0, heap0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih0, iheap0, struct imaginary, struct imaginary)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll0, linked0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(LIST, l0, list0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(MULTIMAP, mm0, mmap0, struct imaginary, struct imaginary)
CMC_COLLECTION_GENERATE(MULTISET, ms0, mset0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(STACK, s0, stack0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl0, sotredlist0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(QUEUE, q0, queue0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(TREESET, ts0, tset0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(TREEMAP, tm0, tmap0, struct imaginary, struct imaginary)
CMC_COLLECTION_GENERATE(BIDIMAP, bd1, bidimap1, int, int)
CMC_COLLECTION_GENERATE(DEQUE, d1, deque1, /* K */, int)
CMC_COLLECTION_GENERATE(HASHMAP, hm1, hmap1, int, int)
CMC_COLLECTION_GENERATE(HASHSET, hs1, hset1, /* K */, int)
CMC_COLLECTION_GENERATE(HEAP, h1, heap1, /* K */, int)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih1, iheap1, int, int)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll1, linked1, /* K */, int)
CMC_COLLECTION_GENERATE(LIST, l1, list1, /* K */, int)
CMC_COLLECTION_GENERATE(MULTIMAP, mm1, mmap1, int, int)
CMC_COLLECTION_GENERATE(MULTISET, ms1, mset1, /* K */, int)
CMC_COLLECTION_GENERATE(STACK, s1, stack1, /* K */, int)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl1, sotredlist1, /* K */, int)
CMC_COLLECTION_GENERATE(QUEUE, q1, queue1, /* K */, int)
CMC_COLLECTION_GENERATE(TREESET, ts1, tset1, /* K */, int)
CMC_COLLECTION_GENERATE(TREEMAP, tm1, tmap1, int, int)
CMC_COLLECTION_GENERATE(BIDIMAP, bd2, bidimap2, double, double)
CMC_COLLECTION_GENERATE(DEQUE, d2, deque2, /* K */, double)
CMC_COLLECTION_GENERATE(HASHMAP, hm2, hmap2, double, double)
CMC_COLLECTION_GENERATE(HASHSET, hs2, hset2, /* K */, double)
CMC_COLLECTION_GENERATE(HEAP, h2, heap2, /* K */, double)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih2, iheap2, double, double)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll2, linked2, /* K */, double)
CMC_COLLECTION_GENERATE(LIST, l2, list2, /* K */, double)
CMC_COLLECTION_GENERATE(MULTIMAP, mm2, mmap2, double, double)
CMC_COLLECTION_GENERATE(MULTISET, ms2, mset2, /* K */, double)
CMC_COLLECTION_GENERATE(STACK, s2, stack2, /* K */, double)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl2, sotredlist2, /* K */, double)
CMC_COLLECTION_GENERATE(QUEUE, q2, queue2, /* K */, double)
CMC_COLLECTION_GENERATE(TREESET, ts2, tset2, /* K */, double)
CMC_COLLECTION_GENERATE(TREEMAP, tm2, tmap2, double, double)
CMC_COLLECTION_GENERATE(BIDIMAP, bd3, bidimap3, size_t, size_t)
CMC_COLLECTION_GENERATE(DEQUE, d3, deque3, /* K */, size_t)
CMC_COLLECTION_GENERATE(HASHMAP, hm3, hmap3, size_t, size_t)
CMC_COLLECTION_GENERATE(HASHSET, hs3, hset3, /* K */, size_t)
CMC_COLLECTION_GENERATE(HEAP, h3, heap3, /* K */, size_t)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih3, iheap3, size_t, size_t)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll3, linked3, /* K */, size_t)
CMC_COLLECTION_GENERATE(LIST, l3, list3, /* K */, size_t)
CMC_COLLECTION_GENERATE(MULTIMAP, mm3, mmap3, size_t, size_t)
CMC_COLLECTION_GENERATE(MULTISET, ms3, mset3, /* K */, size_t)
CMC_COLLECTION_GENERATE(STACK, s3, stack3, /* K */, size_t)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl3, sotredlist3, /* K */, size_t)
CMC_COLLECTION_GENERATE(QUEUE, q3, queue3, /* K */, size_t)
CMC_COLLECTION_GENERATE(TREESET, ts3, tset3, /* K */, size_t)
CMC_COLLECTION_GENERATE(TREEMAP, tm3, tmap3, size_t, size_t)
CMC_COLLECTION_GENERATE(BIDIMAP, bd4, bidimap4, enum app_state, enum app_state)
CMC_COLLECTION_GENERATE(DEQUE, d4, deque4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(HASHMAP, hm4, hmap4, enum app_state, enum app_state)
CMC_COLLECTION_GENERATE(HASHSET, hs4, hset4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(HEAP, h4, heap4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih4, iheap4, enum app_state, enum app_state)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll4, linked4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(LIST, l4, list4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(MULTIMAP, mm4, mmap4, enum app_state, enum app_state)
CMC_COLLECTION_GENERATE(MULTISET, ms4, mset4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(STACK, s4, stack4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl4, sotredlist4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(QUEUE, q4, queue4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(TREESET, ts4, tset4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(TREEMAP, tm4, tmap4, enum app_state, enum app_state)
CMC_COLLECTION_GENERATE(BIDIMAP, bd5, bidimap5, void *, void *)
CMC_COLLECTION_GENERATE(DEQUE, d5, deque5, /* K */, void *)
CMC_COLLECTION_GENERATE(HASHMAP, hm5, hmap5, void *, void *)
CMC_COLLECTION_GENERATE(HASHSET, hs5, hset5, /* K */, void *)
CMC_COLLECTION_GENERATE(HEAP, h5, heap5, /* K */, void *)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih5, iheap5, void *, void *)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll5, linked5, /* K */, void *)
CMC_COLLECTION_GENERATE(LIST, l5, list5, /* K */, void *)
CMC_COLLECTION_GENERATE(MULTIMAP, mm5, mmap5, void *, void *)
CMC_COLLECTION_GENERATE(MULTISET, ms5, mset5, /* K */, void *)
CMC_COLLECTION_GENERATE(STACK, s5, stack5, /* K */, void *)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl5, sotredlist5, /* K */, void *)
CMC_COLLECTION_GENERATE(QUEUE, q5, queue5, /* K */, void *)
CMC_COLLECTION_GENERATE(TREESET, ts5, tset5, /* K */, void *)
CMC_COLLECTION_GENERATE(TREEMAP, tm5, tmap5, void *, void *)
CMC_COLLECTION_GENERATE(BIDIMAP, bd6, bidimap6, int *, int *)
CMC_COLLECTION_GENERATE(DEQUE, d6, deque6, /* K */, int *)
CMC_COLLECTION_GENERATE(HASHMAP, hm6, hmap6, int *, int *)
CMC_COLLECTION_GENERATE(HASHSET, hs6, hset6, /* K */, int *)
CMC_COLLECTION_GENERATE(HEAP, h6, heap6, /* K */, int *)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih6, iheap6, int *, int *)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll6, linked6, /* K */, int *)
CMC_COLLECTION_GENERATE(LIST, l6, list6, /* K */, int *)
CMC_COLLECTION_GENERATE(MULTIMAP, mm6, mmap6, int *, int *)
CMC_COLLECTION_GENERATE(MULTISET, ms6, mset6, /* K */, int *)
CMC_COLLECTION_GENERATE(STACK, s6, stack6, /* K */, int *)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl6, sotredlist6, /* K */, int *)
CMC_COLLECTION_GENERATE(QUEUE, q6, queue6, /* K */, int *)
CMC_COLLECTION_GENERATE(TREESET, ts6, tset6, /* K */, int *)
CMC_COLLECTION_GENERATE(TREEMAP, tm6, tmap6, int *, int *)
CMC_COLLECTION_GENERATE(BIDIMAP, bd7, bidimap7, struct imaginary *, struct imaginary *)
CMC_COLLECTION_GENERATE(DEQUE, d7, deque7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(HASHMAP, hm7, hmap7, struct imaginary *, struct imaginary *)
CMC_COLLECTION_GENERATE(HASHSET, hs7, hset7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(HEAP, h7, heap7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih7, iheap7, struct imaginary *, struct imaginary *)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll7, linked7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(LIST, l7, list7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(MULTIMAP, mm7, mmap7, struct imaginary *, struct imaginary *)
CMC_COLLECTION_GENERATE(MULTISET, ms7, mset7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(STACK, s7, stack7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl7, sotredlist7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(QUEUE, q7, queue7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(TREESET, ts7, tset7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(TREEMAP, tm7, tmap7, struct imaginary *, struct imaginary *)
CMC_COLLECTION_GENERATE(BIDIMAP, bd8, bidimap8, double *, double *)
CMC_COLLECTION_GENERATE(DEQUE, d8, deque8, /* K */, double *)
CMC_COLLECTION_GENERATE(HASHMAP, hm8, hmap8, double *, double *)
CMC_COLLECTION_GENERATE(HASHSET, hs8, hset8, /* K */, double *)
CMC_COLLECTION_GENERATE(HEAP, h8, heap8, /* K */, double *)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih8, iheap8, double *, double *)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll8, linked8, /* K */, double *)
CMC_COLLECTION_GENERATE(LIST, l8, list8, /* K */, double *)
CMC_COLLECTION_GENERATE(MULTIMAP, mm8, mmap8, double *, double *)
CMC_COLLECTION_GENERATE(MULTISET, ms8, mset8, /* K */, double *)
CMC_COLLECTION_GENERATE(STACK, s8, stack8, /* K */, double *)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl8, sotredlist8, /* K */, double *)
CMC_COLLECTION_GENERATE(QUEUE, q8, queue8, /* K */, double *)
CMC_COLLECTION_GENERATE(TREESET, ts8, tset8, /* K */, double *)
CMC_COLLECTION_GENERATE(TREEMAP, tm8, tmap8, double *, double *)
CMC_COLLECTION_GENERATE(BIDIMAP, bd9, bidimap9, enum app_state *, enum app_state *)
CMC_COLLECTION_GENERATE(DEQUE, d9, deque9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(HASHMAP, hm9, hmap9, enum app_state *, enum app_state *)
CMC_COLLECTION_GENERATE(HASHSET, hs9, hset9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(HEAP, h9, heap9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih9, iheap9, enum app_state *, enum app_state *)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll9, linked9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(LIST, l9, list9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(MULTIMAP, mm9, mmap9, enum app_state *, enum app_state *)
CMC_COLLECTION_GENERATE(MULTISET, ms9, mset9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(STACK, s9, stack9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl9, sotredlist9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(QUEUE, q9, queue9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(TREESET, ts9, tset9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(TREEMAP, tm9, tmap9, enum app_state *, enum app_state *)
-433
View File
@@ -1,433 +0,0 @@
#include <macro_collections.h>
/**
* HashMap, MultiMap and BidiMap use hashtables with different strategies. This
* benchmark is aimed to explore the pros and cons of each implementation.
*
* HashMap - A plain hashtable with no indirection using linear probing and
* robin hood hashing.
* Expectations:
* - Constant memory usage which leads to high memory usage per element
* ratio when the hashtable has few elements but the ratio is
* somewhat good as it starts to fill up;
* - Faster lookup due to no indirection and good caching;
* - Faster insertion and removal due to no calls to free or malloc.
*
* MultiMap - A hashtable using separate chaining where each bucket is a doubly
* linked list.
* Expectations:
* - High memory usage per element ratio due to the double linked
* lists;
* - Pointer indirection might lead to slower lookup and poor caching
* due to using nodes to store the key and the value;
* - A bit slower insertion and removal as calls to free and malloc are
* needed.
*
* BidiMap - Two arrays, one representing the key set and one the value set.
* Each array is made of pointers to an entry. This way one entry can
* be referenced by both the key set and the value set using only one
* node. Uses robin hood hashing to adjust the pointers.
* Expectations:
* - Overrall low memory usage compared to other implementations;
* - Pointer indirection might lead to slower lookupand poor caching
* due to using nodes to store the key and the value;
* - Very slow insertion and removal as a node needs to be added or
* removed on both arrays.
*/
/* Generate Code */
CMC_COLLECTION_GENERATE(HASHMAP, hmap, hmap, int, int)
CMC_COLLECTION_GENERATE(MULTIMAP, mmap, mmap, int, int)
CMC_COLLECTION_GENERATE(BIDIMAP, bmap, bmap, int, int)
/* Forward declaration of benchmarks */
void benchmark_bidimap(const char *collection, int total_elements,
double load_factor);
void benchmark_hashmap(const char *collection, int total_elements,
double load_factor);
void benchmark_multimap(const char *collection, int total_elements,
double load_factor);
/* Comparator and Hash function */
int cmp(int a, int b)
{
return a - b;
}
size_t hash(int a)
{
size_t x = (size_t)a;
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = (x >> 16) ^ x;
return x;
}
/* Custom allocators to count memory usage */
size_t total_memory = 0;
/* Report Functions */
void print_overview(const char *collection, int total_elements,
double load_factor)
{
printf("Overview\n"
" Collection : %s\n"
" Total Elements : %d\n"
" Load Factor : %.4lf\n\n",
collection, total_elements, load_factor);
}
void print_time(const char *collection, double C, double R, double U, double D)
{
/* C - Create, R - Read, U - Update, D - Delete */
printf("Time [%s]: \n"
" Total : %8.0lf milliseconds \n"
" Create : %8.0lf milliseconds\n"
" Read : %8.0lf milliseconds\n"
" Update : %8.0lf milliseconds\n"
" Delete : %8.0lf milliseconds\n\n",
collection, C + R + U + D, C, R, U, D);
}
void print_memory(const char *s, size_t memory[11], int partition_size)
{
printf("Each Partition : %d elements\n\n", partition_size);
for (size_t i = 0; i < 11; i++)
{
printf(" %3" PRIuMAX "%% : %12" PRIuMAX " B | %10" PRIuMAX " kB | %8" PRIuMAX " MB (+ %2.0lf%%)\n",
i * 10, memory[i], memory[i] / 1000, memory[i] / 1000000, (1 - ((double)memory[0] / (double)memory[i])) * 100.0);
}
}
/* Custom allocation functions */
void *my_malloc(size_t size)
{
void *result = malloc(size);
if (result)
total_memory += size;
return result;
}
void *my_calloc(size_t count, size_t size)
{
void *result = calloc(count, size);
if (result)
total_memory += count * size;
return result;
}
void *my_realloc(void *buffer, size_t size)
{
/* This assumes that this benchmark never uses realloc */
return realloc(buffer, size);
}
void my_free(void *block)
{
free(block);
}
/* Default custom allocation node */
struct cmc_alloc_node alloc_default = { .malloc = my_malloc,
.calloc = my_calloc,
.realloc = my_realloc,
.free = my_free };
int main(int argc, char const *argv[])
{
if (argc != 4)
{
fprintf(
stderr,
"Usage:\n"
" %s collection_name total_elements load_factor\n"
"\nOPTIONS\n"
" - collection_name : (BIDIMAP|HASHMAP|MULTIMAP|ALL)\n"
" - total_elements : Total elements to be added to the hashtable (int > 0)\n"
" - load_factor : The hashtable's load factor (0 < l < 1.0)\n",
argv[0]);
return 1;
}
int total_elements = atoi(argv[2]);
double load_factor = atof(argv[3]);
bool error = false;
if (total_elements < 1)
{
error = true;
fprintf(stderr, "Invalid value for total_elements: %s\n", argv[2]);
}
if (load_factor <= 0.0 || load_factor >= 1.0)
{
error = true;
fprintf(stderr, "Invalid value for load_factor: %s\n", argv[3]);
}
if (error)
return 1;
const char *collection = argv[1];
if (strcmp(collection, "BIDIMAP") == 0)
{
benchmark_bidimap(collection, total_elements, load_factor);
}
else if (strcmp(collection, "HASHMAP") == 0)
{
benchmark_hashmap(collection, total_elements, load_factor);
}
else if (strcmp(collection, "MULTIMAP") == 0)
{
benchmark_multimap(collection, total_elements, load_factor);
}
else if (strcmp(collection, "ALL") == 0)
{
benchmark_bidimap("BIDIMAP", total_elements, load_factor);
benchmark_hashmap("HASHMAP", total_elements, load_factor);
benchmark_multimap("MULTIMAP", total_elements, load_factor);
}
else
{
fprintf(stderr, "Unknown parameter collection_name = %s\n", collection);
return 1;
}
return 0;
}
void benchmark_bidimap(const char *collection, int total_elements,
double load_factor)
{
printf("--------------------------------------------------------------------------------\n");
total_memory = 0;
/* Normalize total_elements to be a multiple of 10 and calculate partition size */
total_elements = total_elements % 10 == 0 ? total_elements : total_elements + (10 - total_elements % 10);
int partition = total_elements / 10;
print_overview(collection, total_elements, load_factor);
struct bmap *map = bmap_new_custom(total_elements, load_factor, cmp, hash,
cmp, hash, &alloc_default, NULL);
/* Create, Read, Update, Delete */
struct cmc_timer timers[4] = { 0 };
/* Memory Usage 0%, 10%, 20%, ... 100% */
size_t memory[11] = {0};
memory[0] = total_memory;
/* Create */
cmc_timer_start(timers[0]);
for (int i = 0; i < 10; i++)
{
for (int j = partition * i; j < partition * (i + 1); j++)
{
bmap_insert(map, j, j);
}
memory[i + 1] = total_memory;
}
cmc_timer_stop(timers[0]);
cmc_timer_calc(timers[0]);
/* Create End */
/* Read */
cmc_timer_start(timers[1]);
for (int i = 0; i < total_elements; i++)
bmap_contains_key(map, i);
cmc_timer_stop(timers[1]);
cmc_timer_calc(timers[1]);
/* Read End */
/* Update */
cmc_timer_start(timers[2]);
for (int i = 0; i < total_elements; i++)
bmap_update_val_by_key(map, i, total_elements - i - 1);
cmc_timer_stop(timers[2]);
cmc_timer_calc(timers[2]);
/* Update End */
/* Delete */
cmc_timer_start(timers[3]);
for (int i = 0; i < total_elements; i++)
bmap_remove_by_key(map, i, NULL, NULL);
cmc_timer_stop(timers[3]);
cmc_timer_calc(timers[3]);
/* Delete End */
print_time(collection, timers[0].result, timers[1].result, timers[2].result,
timers[3].result);
print_memory(collection, memory, partition);
bmap_free(map, NULL);
printf("--------------------------------------------------------------------------------\n");
}
void benchmark_hashmap(const char *collection, int total_elements,
double load_factor)
{
printf("--------------------------------------------------------------------------------\n");
total_memory = 0;
/* Normalize total_elements to be a multiple of 10 and calculate partition size */
total_elements = total_elements % 10 == 0 ? total_elements : total_elements + (10 - total_elements % 10);
int partition = total_elements / 10;
print_overview(collection, total_elements, load_factor);
struct hmap *map = hmap_new_custom(total_elements, load_factor, cmp, hash, &alloc_default, NULL);
/* Create, Read, Update, Delete */
struct cmc_timer timers[4] = { 0 };
/* Memory Usage 0%, 10%, 20%, ... 100% */
size_t memory[11] = {0};
memory[0] = total_memory;
/* Create */
cmc_timer_start(timers[0]);
for (int i = 0; i < 10; i++)
{
for (int j = partition * i; j < partition * (i + 1); j++)
{
hmap_insert(map, j, j);
}
memory[i + 1] = total_memory;
}
cmc_timer_stop(timers[0]);
cmc_timer_calc(timers[0]);
/* Create End */
/* Read */
cmc_timer_start(timers[1]);
for (int i = 0; i < total_elements; i++)
hmap_contains(map, i);
cmc_timer_stop(timers[1]);
cmc_timer_calc(timers[1]);
/* Read End */
/* Update */
cmc_timer_start(timers[2]);
for (int i = 0; i < total_elements; i++)
hmap_update(map, i, total_elements - i - 1, NULL);
cmc_timer_stop(timers[2]);
cmc_timer_calc(timers[2]);
/* Update End */
/* Delete */
cmc_timer_start(timers[3]);
for (int i = 0; i < total_elements; i++)
hmap_remove(map, i, NULL);
cmc_timer_stop(timers[3]);
cmc_timer_calc(timers[3]);
/* Delete End */
print_time(collection, timers[0].result, timers[1].result, timers[2].result,
timers[3].result);
print_memory(collection, memory, partition);
hmap_free(map, NULL);
printf("--------------------------------------------------------------------------------\n");
}
void benchmark_multimap(const char *collection, int total_elements,
double load_factor)
{
printf("--------------------------------------------------------------------------------\n");
total_memory = 0;
/* Normalize total_elements to be a multiple of 10 and calculate partition size */
total_elements = total_elements % 10 == 0 ? total_elements : total_elements + (10 - total_elements % 10);
int partition = total_elements / 10;
print_overview(collection, total_elements, load_factor);
struct mmap *map = mmap_new_custom(total_elements, load_factor, cmp, hash, &alloc_default, NULL);
/* Create, Read, Update, Delete */
struct cmc_timer timers[4] = { 0 };
/* Memory Usage 0%, 10%, 20%, ... 100% */
size_t memory[11] = {0};
memory[0] = total_memory;
/* Create */
cmc_timer_start(timers[0]);
for (int i = 0; i < 10; i++)
{
for (int j = partition * i; j < partition * (i + 1); j++)
{
mmap_insert(map, j, j);
}
memory[i + 1] = total_memory;
}
cmc_timer_stop(timers[0]);
cmc_timer_calc(timers[0]);
/* Create End */
/* Read */
cmc_timer_start(timers[1]);
for (int i = 0; i < total_elements; i++)
mmap_contains(map, i);
cmc_timer_stop(timers[1]);
cmc_timer_calc(timers[1]);
/* Read End */
/* Update */
cmc_timer_start(timers[2]);
for (int i = 0; i < total_elements; i++)
mmap_update(map, i, total_elements - i - 1, NULL);
cmc_timer_stop(timers[2]);
cmc_timer_calc(timers[2]);
/* Update End */
/* Delete */
cmc_timer_start(timers[3]);
for (int i = 0; i < total_elements; i++)
mmap_remove(map, i, NULL);
cmc_timer_stop(timers[3]);
cmc_timer_calc(timers[3]);
/* Delete End */
print_time(collection, timers[0].result, timers[1].result, timers[2].result,
timers[3].result);
print_memory(collection, memory, partition);
mmap_free(map, NULL);
printf("--------------------------------------------------------------------------------\n");
}
-8
View File
@@ -1,8 +0,0 @@
CFLAGS = -Wall -Wextra
INCLUDE = ../../src
main:
gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DCMC_QUEUE
a.exe
gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DSAC_QUEUE
a.exe
-76
View File
@@ -1,76 +0,0 @@
/**
* queue.c
*
* Creation Date: 24/06/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/* Showing off how different queue implementations affect runtime cost */
#include "utl/timer.h"
#include <stdio.h>
#include <inttypes.h>
#define MAX 200000
#if defined(CMC_QUEUE)
#include "cmc/queue.h"
CMC_GENERATE_QUEUE(q, queue, int)
#define TARGET "QUEUE"
#elif defined(SAC_QUEUE)
#include "sac/queue.h"
SAC_QUEUE_GENERATE(q, queue, , int, MAX)
#define TARGET "SAC QUEUE"
#else
#error Please define either CMC_QUEUE, SAC_QUEUE or EXT_QUEUE
#endif
int main(void)
{
#if defined(CMC_QUEUE)
struct queue *q = q_new(MAX);
#elif defined(SAC_QUEUE)
queue _q = q_new();
queue_ptr q = &_q;
#endif
size_t sum = 0;
int i = 0;
struct cmc_timer timer;
cmc_timer_start(timer);
while (q_count(q) != MAX)
{
q_enqueue(q, i++);
if (i % 10 == 0)
{
for (size_t i = 0; i < 9; i++)
{
sum += q_peek(q);
q_dequeue(q);
}
}
}
cmc_timer_stop(timer);
cmc_timer_calc(timer);
printf("----------------------------------------\n");
printf("%s\n", TARGET);
printf("Execution time: %.0lf milliseconds\n", timer.result);
printf("SUM: %" PRIuMAX "\n", sum);
printf("----------------------------------------\n");
#if defined(CMC_QUEUE)
q_free(q, NULL);
#endif
return 0;
}
+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 */
+29 -4
View File
@@ -1,3 +1,27 @@
/**
* 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
*
@@ -12,8 +36,8 @@
* Things commonly used by hashtable-based collections.
*/
#ifndef CMC_IMPL_HASHTABLE_H
#define CMC_IMPL_HASHTABLE_H
#ifndef CMC_COR_HASHTABLE_H
#define CMC_COR_HASHTABLE_H
#include "core.h"
@@ -39,7 +63,8 @@ enum cmc_entry_state
/**
* static const size_t cmc_hashtable_primes[59]
*
* Prime numbers used to define a capacity for the hashtables for better hashing.
* Prime numbers used to define a capacity for the hashtables for better
* hashing.
*/
// clang-format off
static const size_t cmc_hashtable_primes[] = {
@@ -82,4 +107,4 @@ static const size_t cmc_hashtable_primes[] = {
};
// clang-format on
#endif /* CMC_IMPL_HASHTABLE_H */
#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 */
Loaded 100 of 494 files, more files were not shown because too many files have changed in this diff. Show more