189 Commits
Author SHA1 Message Date
Leonardo de744f5822 v1.7.2 2019-10-18 11:15:52 -03:00
Leonardo 5583ca38b3 Changed default_type functions to compound literals 2019-10-17 01:37:55 -03:00
Leonardo 2d3b441d74 Added resize to multimap, multiset and sortedlist 2019-10-16 21:34:30 -03:00
Leonardo 99cd01ba1e Added intervalheap resize 2019-10-15 23:52:09 -03:00
Leonardo 1f11b6d2da Added preview of bidimap 2019-10-14 22:37:39 -03:00
Leonardo e41fe14502 Refactoring multiset code to be at most 100 characters per line 2019-10-12 00:27:38 -03:00
Leonardo 63d0453341 Finally releasing sortedlist 2019-10-11 02:14:33 -03:00
Leonardo 5e1a26b72e Added queue and stack resize 2019-10-10 15:10:37 -03:00
Leonardo e06e795ed8 hashmap quickfix 2019-10-09 00:53:40 -03:00
Leonardo b9b507bf07 Added heap and list resize function and refactored some tests and added some more 2019-10-08 13:57:58 -03:00
Leonardo 9f8671f75f Added resize function to hashmap and hashset 2019-10-07 19:57:20 -03:00
Leonardo f0b7b125b9 Added deque.h resize and added more deque and hashmap tests 2019-10-05 00:31:29 -03:00
Leonardo 8483eda701 Added two working examples, hanoi and printer 2019-10-04 01:19:18 -03:00
Leonardo b870649627 Refactoring tests 2019-10-03 11:29:35 -03:00
Leonardo 93ac623ffe Update README and benchmark 2019-10-02 00:11:08 -03:00
Leonardo 5997302a8c Fixed deque and queue bug and added more tests 2019-10-01 00:48:09 -03:00
Leonardo f52a9ff702 Refactoring tests and added sortedlist test 2019-09-30 18:27:19 -03:00
Leonardo 376c0ad4e7 Minor optimization to list.h and added finished more TODOs from sortedlist.h 2019-09-30 18:26:31 -03:00
Leonardo 34e649d82a Removed all conditional IO 2019-09-29 15:49:10 -03:00
Leonardo bfb8426183 Fixing travis 2019-09-28 15:01:02 -03:00
Leonardo 4f755f0915 Redone tests
./codecov is a stalled version for code coverage. It will be merged with main when the library is done with breaking changes
2019-09-28 14:58:10 -03:00
Leonardo dea77b5ca2 A minor fix to intervalheap.h 2019-09-27 00:06:26 -03:00
Leonardo b300c889f3 Added cmc prefix to timer 2019-09-27 00:05:22 -03:00
Leonardo 2126da3f25 Removed unnecessary typedefs for log.h and test.h and fixed the latter 2019-09-26 01:17:18 -03:00
Leonardo fb7854ef5d Update assert.h and removed
Added 3 new assertion macros:

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

The list prepend, append and insert - seq_push_front, seq_push_back, seq_push_at
2019-09-21 00:37:56 -03:00
Leonardo 2c84c35264 Adding sortedlist skeleton
Some functions are already working but there is still too much to be optimized
2019-09-18 02:29:11 -03:00
Leonardo c27edd53f6 Added cmc_assert_sorted 2019-09-18 02:28:20 -03:00
Leonardo a0db76b50d Update README.md
Trying to fix the shield's icon
2019-09-17 12:00:40 -03:00
Leonardo bb3efd75ff Update README and TODO 2019-09-17 00:37:12 -03:00
Leonardo 3d7e218195 Move the string format to each collection files and quick fix on deque
Now the format to print them is only declared if you actually include the header
2019-09-16 23:50:06 -03:00
Leonardo 191c47fc7c v1.7.0 2019-09-16 14:47:54 -03:00
Leonardo f2f806612f Moving documentation to the docs folder 2019-09-16 14:47:42 -03:00
Leonardo 5e2e001265 Merge branch 'master' of https://github.com/LeoVen/C-Macro-Containers 2019-09-16 14:45:45 -03:00
Leonardo 2ca2210a77 Added CMC prefix to all macros and removed FMOD 2019-09-16 14:45:24 -03:00
Leonardo Vencovsky 747aa8cb4e Merge pull request #4 from LeoVen/dev
Merge pull request #2 from LeoVen/master
2019-09-16 14:35:55 -03:00
Leonardo 4fe4e96811 v1.6.3 2019-09-14 00:38:45 -03:00
Leonardo 0df0ebbdeb Update TODO, quick fixes in a makefile and in assert.h 2019-09-14 00:38:13 -03:00
Leonardo e834aaee81 Added iter_advance, iter_rewind and iter_go_to to all collections
Also reworked many iterator functions that could cause strange behavior
2019-09-13 18:46:00 -03:00
Leonardo 1928fdd6d5 Reworked assert.h and test.h and added the cmc prefix to the logging utility
Integrated the assert utility with the test utility. Now any assertion that fails inside the unit test will trigger failure and is no longer needed to manually pass or fail a test.
Also reworked makefiles.
2019-09-06 12:17:11 -03:00
Leonardo abdbfa2018 v1.6.2 2019-09-05 01:48:51 -03:00
Leonardo a1a940399a Unified _set and _update functions
Also _remove now accepts an optional parameter if to retrieve or not the removed value. _update also has the same optional parameter that retrieves the old value.
The multimap will allocate an array based on the amount of keys and add all the values to that array.
2019-09-05 01:33:54 -03:00
Leonardo 855e085996 Fixed benchmark 2019-09-05 01:09:06 -03:00
Leonardo e95379bdd7 Updated tests 2019-09-03 17:07:34 -03:00
Leonardo 762b95db26 Some fixes and improvements to hashmap, hashset and multimap 2019-09-03 17:07:15 -03:00
Leonardo 396066f289 Update README.md 2019-09-03 16:54:21 -03:00
Leonardo f070d274f4 Added _equals function to all collections and fixed some issues with multimap 2019-08-29 23:25:32 -03:00
Leonardo 1f50add1bb Added _copy_of functions to all collections 2019-08-28 16:34:15 -03:00
Leonardo e68b8a8e0e Fixing main unit test 2019-08-27 01:38:34 -03:00
Leonardo 5ee7bfa23a v1.6.1 2019-08-27 01:36:06 -03:00
Leonardo 8ec768d30e removed linkedqueue and now _free and _clear have a deallocator parameter 2019-08-27 01:33:58 -03:00
Leonardo Vencovsky 35d27ffb39 Merge pull request #2 from LeoVen/master
Fast forward dev
2019-08-08 15:43:04 -03:00
Leonardo 613392ae76 Changed how _update works and added _set
_update: retrieves old value
_set: ignores old value
2019-08-05 23:28:12 -03:00
Leonardo f74ce7519a Added update function for hashmap, treemap and multimap and added update_all for multimap 2019-08-03 01:55:36 -03:00
Leonardo 01d0b42e1a v1.6.0 2019-08-02 01:03:28 -03:00
Leonardo e470021d13 Added to_string to intervalheap and multimap 2019-08-02 00:53:35 -03:00
Leonardo 7de3ce5c0c Updating examples readme and added multiset to benchmark 2019-08-02 00:36:54 -03:00
Leonardo 976965bcfa Fixed integer overflow with hashtables when calculating their capacity 2019-08-02 00:18:22 -03:00
Leonardo 1254e657c5 Complete remake of multiset 2019-08-01 23:52:50 -03:00
Leonardo 90ee6a424d heap hotfix 2019-07-31 23:08:51 -03:00
Leonardo bf79616e7e Adding Code Review shields 2019-07-18 22:58:41 -03:00
Leonardo 09ebb1eae8 Thank you Code Review for your awesome community! 2019-07-17 13:57:13 -03:00
Leonardo ba6d8edde1 Update .travis.yml 2019-07-17 00:05:54 -03:00
Leonardo 2f76ad4b6f Update README.md 2019-07-16 23:59:38 -03:00
Leonardo 407141661a Fixing test 2019-07-16 23:58:02 -03:00
Leonardo 38620ba457 Added to_string methods to cmc, ./utl/cmc_string.h, fixed some variable names and fixed includes 2019-07-16 23:55:30 -03:00
Leonardo f8f704f432 Added intervalheap and multimap to benchmark 2019-07-14 22:33:30 -03:00
Leonardo 8ae83acd1a Update stack unit test 2019-07-13 00:17:31 -03:00
Leonardo af26f6c081 More fixes to ./cmc/stack.h 2019-07-13 00:17:01 -03:00
Leonardo d82be005da Fixing stack iter_init 2019-07-12 23:34:16 -03:00
Leonardo e37b54fc62 Added bool type assert 2019-07-12 23:33:35 -03:00
Leonardo 9eb8d5f682 Fixing tests and added linkedqueue tests 2019-07-10 17:26:31 -03:00
Leonardo 7ecb2e90fd Update TODO 2019-07-10 16:57:54 -03:00
Leonardo 354cd538f8 Added cmc prefixes to enums used by heap and hashtables and fixed return type on treeset and hashset 2019-07-10 16:57:46 -03:00
Leonardo 0c883b0a74 Multimap tests 2019-07-09 23:51:01 -03:00
Leonardo 9c23c3ca77 Update multimap to new standards 2019-07-08 19:55:48 -03:00
Leonardo d0244a0513 Update TODO 2019-07-06 01:24:07 -03:00
Leonardo 875678d7a9 Added intervalheap, simplified heap and moved multimap and multiset to the ext folder 2019-07-06 00:26:54 -03:00
Leonardo 65f2b79157 Merge branch 'dev' 2019-07-05 16:46:12 -03:00
LeoVen c60ee10185 Changing timer_t to cmc_timer to not generate conflicts 2019-07-05 13:30:07 -03:00
LeoVen f7a598efc8 Word Counter example using the pthread library 2019-07-05 00:52:03 -03:00
Leonardo e8142f96b1 v1.5.3 2019-07-04 15:49:56 -03:00
Leonardo 97d50bc3d9 Fixing and adding more tests 2019-07-04 15:34:25 -03:00
Leonardo 8c457eeb12 Fixing missing return statements 2019-07-04 14:55:17 -03:00
Leonardo 846d0bbba6 More tests 2019-07-04 02:18:05 -03:00
Leonardo a9314ee8f7 Update assert.h 2019-07-04 02:13:41 -03:00
Leonardo 9bff706bba test quickfix 2019-07-02 01:49:19 -03:00
Leonardo 31c871c4c2 Fixing CI shield 2019-07-02 01:38:08 -03:00
Leonardo 82b374ec83 Revert "Fixing CI shield and trying to fix code coverage through codecov.yml"
This reverts commit 940552d6cd.
2019-07-02 01:36:46 -03:00
Leonardo 940552d6cd Fixing CI shield and trying to fix code coverage through codecov.yml 2019-07-02 01:30:03 -03:00
Leonardo 6a2cb70fb5 Tests update 2019-07-02 01:05:16 -03:00
Leonardo 78cfc0c335 Create .gitattributes 2019-07-01 17:20:04 -03:00
Leonardo f454934b07 Reorganizing tests 2019-07-01 17:10:28 -03:00
Leonardo 5504f82052 Added codecov shield 2019-06-28 01:48:31 -03:00
Leonardo d01997b7cb v1.5.2 2019-06-28 01:08:55 -03:00
Leonardo 7b349ea426 Many minor fixes, changes and first attempt of codecov
Changes on assert.h, foreach.h, test.h and timer.h
Updated benchmarks, examples and tests
Updated tests/Makefile for future
Added list.c test
Added CMC namespace to CONCATC and CONCATH on macro_collections.h
2019-06-28 00:52:23 -03:00
Leonardo 1edb12a83c Added assert macros utility 2019-06-27 23:55:10 -03:00
Leonardo 176bbc66ad Added UnitTest utility and removed unnecessary logging functions 2019-06-26 01:32:44 -03:00
Leonardo 41eebe546a v1.5.1 2019-06-24 02:11:28 -03:00
Leonardo afaecb2dde Update TODO, CHANGELOG and headers 2019-06-24 02:11:10 -03:00
Leonardo 9062415322 Added sac/queue.h, moved timer.h to utl folder, new queue benchmark 2019-06-24 02:09:02 -03:00
Leonardo 6213b42d5a v1.5.0 2019-06-21 16:17:11 -03:00
Leonardo 8010cce8c7 Restructuring project
View CHANGELOG on v1.5.0 for more information
2019-06-21 16:07:03 -03:00
Leonardo dad9b7a81f Update README.md and Documentation.md 2019-06-19 01:23:18 -03:00
Leonardo 21a2bea746 Fixing previous commit 2019-06-13 00:44:41 -03:00
Leonardo b0a2e42cfe Minor fixes all around
Changed some input parameter names
Updated TODO
Changed how hashtables initialization works. Now the given initial capacity will be guaranteed to be reached before the hashtable rehashes (load is now considered in the calculation).
2019-06-13 00:40:55 -03:00
Leonardo b6cbadd8e2 v1.4.3 2019-06-11 00:44:10 -03:00
Leonardo 870cfe302d Added more set functions
Added is_subset, is_superset, is_proper_subset, is_proper_superset, is_disjointset
2019-06-11 00:42:11 -03:00
Leonardo ea04c7ddaa Quickfix function name 2019-06-09 23:53:34 -03:00
Leonardo a86140094c Update .travis.yml 2019-06-07 01:48:25 -03:00
Leonardo 85c49a92fd v1.4.2 2019-06-07 01:45:10 -03:00
Leonardo aac07a645c Now collections accept plain struct
Also fixed impl prefixes and function modifiers
Added new test for all possible data types
Fixed some READMEs
2019-06-07 01:44:15 -03:00
Leonardo efdb1c80a3 Changed TreeSet max and min to be compatible with the TreeMap and the hash collections 2019-06-06 23:42:14 -03:00
Leonardo a9c7439d15 Update .travis.yml 2019-05-30 21:29:41 -03:00
Leonardo 26555bc10a v1.4.1 2019-05-30 21:27:18 -03:00
Leonardo 0f84d65656 Removed PUBLIC and PRIVATE, corrected some examples and new test 2019-05-30 21:23:37 -03:00
Leonardo a9b775419d Update Documentation.md 2019-05-30 16:54:40 -03:00
Leonardo a384a8b180 Update .gitignore 2019-05-27 17:13:09 -03:00
Leonardo 424582f969 Update documentation and TODO 2019-05-23 23:08:03 -03:00
Leonardo 6044e92262 Update CONTRIBUTING.md 2019-05-17 23:41:31 -03:00
Leonardo ee96bcbc55 Update CHANGELOG
reversed changelog ~duh
2019-05-16 17:07:03 -03:00
Leonardo 5b39676d79 v1.4.0 2019-05-16 14:58:31 -03:00
Leonardo 5e2b841e9e Added CHANGELOG and TODO 2019-05-16 14:49:50 -03:00
Leonardo 3ec32bd57b changed pointertype test to be a pointer to a struct not a char 2019-05-16 14:25:28 -03:00
Leonardo Vencovsky 9531f7b5da Merge pull request #1 from LeoVen/iter
Merge iter to master
2019-05-16 13:44:48 -03:00
Leonardo 5f39eb011c Final update - fixed foreach, tests and benchmark 2019-05-16 13:41:35 -03:00
Leonardo 22e84db11a Tenth update on iterators - TREESET 2019-05-16 01:18:26 -03:00
Leonardo 8410111eab Ninth update on iterators - TREEMAP 2019-05-16 00:04:54 -03:00
Leonardo 490936bddd Eighth update on iterators - STACK 2019-05-15 20:42:28 -03:00
Leonardo f956094178 Seventh update on iterators - QUEUE 2019-05-15 19:57:35 -03:00
Leonardo 812d0240e3 Sixth update on iterators - LINKEDLIST 2019-05-15 18:49:40 -03:00
Leonardo 918b73ad51 Fifth update on iterators - HEAP 2019-05-15 15:22:59 -03:00
Leonardo ae5241a6fb Fourth update on iterators - HASHSET 2019-05-14 23:22:52 -03:00
Leonardo d3e7d64d2a Third update on iterators - HASHMAP 2019-05-14 00:52:20 -03:00
Leonardo 226e4ec817 Update Documentation.md 2019-05-13 23:06:30 -03:00
Leonardo 221c55cf2a Second update on iterators - DEQUE 2019-05-13 23:01:27 -03:00
Leonardo 444f597a98 First update on iterators - LIST 2019-05-11 00:24:48 -03:00
Leonardo 8843a8fb7a Update Documentation.md 2019-05-10 00:05:03 -03:00
Leonardo bc350611fc Update benchmark
Added Mersenne Twister utility as the function rand() was not random enough
2019-05-09 16:40:04 -03:00
Leonardo c61ac2e347 Changed iter_new to inter_init and added new iter_new that allocates the iterator on the heap 2019-05-08 11:47:00 -03:00
Leonardo 6002650f06 v1.3.0 2019-05-07 17:35:02 -03:00
Leonardo 21ab3eeb07 Changed linkedlist IO relative to a node 2019-05-07 17:20:01 -03:00
Leonardo 2f767f7623 v1.2.4 2019-05-04 00:12:28 -03:00
Leonardo d89972c621 Fixing hashset and hashmap error with a pointer data type and adding a test to address that 2019-05-04 00:06:27 -03:00
Leonardo f0b763afba Hashmap example 2019-05-03 23:57:58 -03:00
Leonardo 661455abe4 TreeSet documentation 2019-04-29 23:24:24 -03:00
Leonardo 71fb0a52c5 v1.2.3 2019-04-26 23:36:16 -03:00
Leonardo d715ea70a8 Added treemap example 2019-04-26 23:35:28 -03:00
Leonardo a37207e9d7 Added get_ref
Gets the reference of a value. Useful for primitive values like int, char, double, size_t, etc.
The only collections with this function are associative collections (when getting the value) and lists (working as an update method).
Other collections have not received this function because they are either sorted by the values so changing it would break the structure or because removing and adding back again the element is done instantaneously.
2019-04-26 23:35:09 -03:00
Leonardo 37bfcbb9c4 Added multimap 2019-04-26 20:48:46 -03:00
Leonardo be9c5af7cb v1.2.2 2019-04-24 17:21:29 -03:00
Leonardo 73171f5068 Removing unnecessary modulo in hashtable functions 2019-04-24 17:20:56 -03:00
Leonardo f07efbd828 Update Documentation.md 2019-04-23 16:53:08 -03:00
Leonardo 8cc5ef1f90 Update Documentation.md 2019-04-17 22:56:13 -03:00
Leonardo fbf020c784 v1.2.1 2019-04-16 23:46:08 -03:00
Leonardo b6d0424bb4 Update Documentation.md 2019-04-16 23:42:43 -03:00
Leonardo e2916aedb4 Update example 2019-04-16 23:42:38 -03:00
Leonardo 8966cd5e7d List optimization and indexof function
Replaced all for loops with memcpy, memmove and memset.
2019-04-16 23:41:51 -03:00
Leonardo 58bb89086e Update Documentation.md 2019-04-15 21:44:23 -03:00
Leonardo 763ea5dbd5 v1.2.0 2019-04-14 23:22:48 -03:00
Leonardo 0413da5c12 Update .travis.yml 2019-04-14 23:03:13 -03:00
Leonardo fe57443433 Added contains test and benchmark and updated example and tests 2019-04-14 20:29:48 -03:00
Leonardo e4d5687907 Added contains functions to all collections 2019-04-14 18:12:58 -03:00
Leonardo ae5c745ef8 Unified Benchmark 2019-04-13 00:03:42 -03:00
Leonardo e8cfd9131b v1.1.3 2019-04-12 00:42:35 -03:00
Leonardo 8625a6a411 Revamped benchmarks and sorted alphabetically foreach tests 2019-04-12 00:42:01 -03:00
Leonardo bd8d745d7d Renaming deque's rear to back to be consistent with function names 2019-04-12 00:33:02 -03:00
Leonardo 469cddb515 Example quickfix 2019-04-11 14:59:39 -03:00
Leonardo 00fe35810b v.1.1.2 2019-04-11 14:58:04 -03:00
Leonardo 9b632895b1 Update .travis.yml 2019-04-11 14:46:17 -03:00
Leonardo 032d34a6bd Revamped iterator test and added examples 2019-04-11 14:45:23 -03:00
Leonardo bddb9252f3 Fixing iterators 2019-04-11 14:43:28 -03:00
Leonardo d2692a8dbe Added multiset 2019-04-10 17:23:37 -03:00
Leonardo 213fa25a3a Removed all Complexity sections from documentation 2019-04-10 16:18:35 -03:00
Leonardo a208b4d41b v1.1.1 2019-04-09 23:52:17 -03:00
Leonardo 1741e77c33 Reordering functions
All implementation detail functions are at the end of source their source file
2019-04-09 23:52:02 -03:00
Leonardo ad93db4203 v1.1.0 2019-04-08 18:35:25 -03:00
Leonardo bc46ace086 Added more list functions and examples 2019-04-08 18:34:52 -03:00
Leonardo 964ececf0b v1.0.1 2019-04-07 19:41:56 -03:00
Leonardo c449025e52 Minor fix in hashset 2019-04-06 23:55:05 -03:00
Leonardo 44a29874eb Update Documentation.md 2019-04-05 23:24:48 -03:00
Leonardo 2b18531478 Update README, CONTRIBUTING and templates 2019-04-04 18:35:00 -03:00
Leonardo 2d533c2db5 Update .travis.yml 2019-04-04 17:22:47 -03:00
Leonardo 0b07829041 Update .travis.yml 2019-04-04 17:17:42 -03:00
186 changed files with 37990 additions and 7692 deletions

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
# Auto detect text files and perform LF normalization
* text=auto
*.h linguist-language=C
*.c linguist-language=C
+1 -1
View File
@@ -4,7 +4,7 @@
A clear and concise description of what the bug is.
### To Reproduce
### How to Reproduce
Steps to reproduce the behavior:
+6
View File
@@ -1,5 +1,11 @@
# 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 [...]
+4 -1
View File
@@ -52,4 +52,7 @@ Mkfile.old
dkms.conf
# vscode folder
.vscode
.vscode
# Experimental folder
experimental/
+4 -3
View File
@@ -8,11 +8,12 @@ addons:
- ubuntu-toolchain-r-test
packages:
- gcc-7
- cmake
script:
- sudo ln -s /usr/bin/gcc-6 /usr/local/bin/gcc
- export CC=gcc-7
- cd ./C-Macro-Containers/tests
- gcc foreach.c -Wall -Wextra -o foreach
- ./foreach
- make -C ./tests/
- make -C ./tests/main/
- make -C ./tests/codecov/
after_success:
- bash <(curl -s https://codecov.io/bash)
+192
View File
@@ -0,0 +1,192 @@
# RELEASE.MAJOR.MINOR
1.7.2
- Added resize function to array based collections
- Added the following functions to hashtable based collections:
- load
- full
- Added more assert macros utility
- Added plenty more tests
- Substituted impl_default_value / key by compound literals
- Removed unnecessary conditional input and output functions
- Minor fixes throughout the library
1.7.1
- 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
- Removed FMOD (function modifier)
- Added CMC prefix to all macros defined within the library
1.6.3
- Added iterator functions to all collections:
- iter_advance
- iter_rewind
- iter_go_to
- Added cmc prefix to the logging utility
- Integrated the assert utility with the test utility. Now any assertion that fails inside the unit test will trigger failure and is no longer needed to manually pass or fail tests.
1.6.2
Added new functions to all collections:
- copy_of
- equals
Added the new collections to the tests
Fixed some collections and some improvements to the hashtables
Unified the functions set and update from the map implementations
1.6.1
Removed ./ext/linkedqueue.h
Added a deallocator parameter to all _free and _clear functions
1.6.0
Added ./ext/intervalheap.h
Added ./ext/multimap.h
Added ./ext/multiset.h
Added to_string function to most collections
Added the cmc prefix to the enum entry_state used by hashtables and to the enum heap_type used by the heap
Fixed return type on some functions from ./cmc/hashset.h and ./cmc/treeset.h
Fixed hashtables integer overflow when the capacity is divided by the load factor
Changed timer.h struct name from timer_t to cmc_timer to prevent name collisions on linux
1.5.3
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
Added ./utl/test.h
Added ./utl/assert.h
Added ./tests/list.c - UnitTest for LIST
Small fixes on ./utl/foreach.h, ./utl/test.h and redone ./utl/timer.h
Removed ./utl/log.h functions that were unnecessary
Added the CMC namespace to CONCATC and CONCATH at macro_collections.h
1.5.1
New queue benchmark
Added ./sac/queue.h
Added ./utl/timer.h
Fixing descriptions and other minor fixes
1.5.0
Changed tests compilation and execution to a single Makefile
Changed project structure
./src/
./cmc/ - Main C Macro Collections Library
./dev/ - A copy of ./cmc/ used for development (logging utility)
./ext/ - Extra collections
./sac/ - Stack Allocated Collections
./utl/ - Utility like ForEach, logging, etc
Added ./utl/log.h a logging utility
Added ./dev/deque.h - A mirror of ./cmc/deque.h but with logging utility
Added ./ext/linkedqueue.h - A singly-linked list based queue
Added ./sac/stack.h - A Stack purely allocated on the stack
1.4.3
Fixed some functions names
Added set functions for both Tree and Hash Set
- is_subset
- is_proper_subset
- is_superset
- is_proper_subset
- is_disjointset
1.4.2
Adapted code so that plain struct type is accepted
Changed TreeSet max and min to be compatible with the TreeMap and the hash collections
Changed function modifier of all implementation detail to static
Fixed some implementation detail functions that were not prefixed with impl
Added types.c to test if it is possible to compile all the collections' generated code accepting all C data types
Removed pointertype.c (replaced by types.c)
1.4.1
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
New way on how iterators work to all collections
Added iter_init to work with stack allocated iterators
Added iter_new and iter_free to work with heap allocated iterators
Added two pointers to functions (it_start and it_end) that allow you to access iterators to both start and end of the target collection easily
iter_next and iter_prev now only move the iterator
To access the key, value and index, use a separate function
Removed FOR_EACH_MAP as it is no longer necessary since FOR_EACH also works to associative containers now
Updated benchmark, examples and tests to work on these new iterators
Changed pointertype test to be a pointer to struct instead of pointer to char
Added CHANGELOG and TODO
1.3.0
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
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
Added get_ref functions to all collections that support it (only included in hashmap, linkedlist, list and treemap)
1.2.2
Removed unnecessary modulo operation in hashtable functions
1.2.1
Optimized list - now using 'string.h' functions to shift elements around instead of for-loops:
- memset
- memcpy
- memmove
1.2.0
'contains' functions added to all collections
'contains' tests and benchmark
Unified Benchmark
Updated examples
1.1.3
Renamed deque's 'rear' struct member to 'back' to be more consistent with other collections
Better benchmark and foreach tests are alphabetically ordered
1.1.2
Fixing iterators for when they are initialized with an empty target
Better iterator tests
More examples
1.1.1
Reordering functions (implementation details are now at the end of each file)
1.1.0
Added new list functions:
- new_from
- prepend
- insert
- append
- remove
- fits
1.0.1
Fixed hashset logic in robin-hood hashing
1.0.0
First stable version
Includes the following collections:
- deque
- hashmap
- hashset
- heap
- linkedlist
- list
- queue
- stack
- treemap
- treeset
Two-way iterators
Benchmarks
Tests:
- foreach
- iterator
+8 -2
View File
@@ -2,13 +2,19 @@
Two simple steps:
* Fork this repository
* Fork this repository to your github account
* Clone it to your machine
Now you can start working on the project.
## Open Issues
Check out `bug_report.md` and `feature_request.md` templates in the `.github` folder to know how to make a bug report or feature request.
## Here are things you could work on:
> You can check out the TODO file to see what I've planned on doing, in case you want to work on any of those topics
1. New features, new functions, new stuff!
* Before adding anything new, please, first create an issue for it to be discussed;
* Write tests to anything new you make.
@@ -34,7 +40,7 @@ Now you can start working on the project.
4. All source files (`.c`, `.h`, etc) must contain a header with the following template:
* Complete file name.
* First commit date in `dd/mm/yyyy`.
* Authors name with (optional) github link to his page.
* Authors name with (optional) link to github page.
```
/**
-1482
View File
File diff suppressed because it is too large. Load diff
+149 -142
View File
@@ -1,170 +1,115 @@
# C-Macro-Collections
# C Macro Collections
Generate Simple Data Structures of any type in C for you to use in your projects.
<p align="center">
<img src="https://leoven.github.io/C-Macro-Collections/images/logo.png" alt="C Macro Collections Logo" width="300"/>
</p>
![License](https://img.shields.io/badge/License-MIT-blue.svg)
![Version](https://img.shields.io/badge/Version-v1.0.0-orange.svg)
![Build](https://travis-ci.org/LeoVen/C-Macro-Collections.svg?branch=master)
<p align="center">Header only, macro generated, generic and type-safe Collections 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>
</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.7.2-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>
</p>
## Table of Contents
* Project Structure
* Available Collections
* Overall To-Do
* Design Decisions
* What to use
* How to use
## Project Structure
* __benchmarks__ - Where all benchmarks are hosted
* __examples__ - Examples separated by collections
* __src__ - All headers part of the C Macro Collections Library
* __cmc__ - The main C Macro Collections Library
* __dev__ - The main C Macro Collections Library for development (containing logging)
* __ext__ - Extra collections
* __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
* List
* LinkedList
* Stack
* Queue
* Deque
* Heap
* TreeSet
* TreeMap
* HashSet
* HashMap
* Linear Collections
* List, LinkedList, Deque, Stack, Queue
* Sets
* HashSet, TreeSet, MultiSet
* Maps
* HashMap, TreeMap, MultiMap
* Heaps
* Heap, IntervalHeap
* Coming Soon
* BidiMap, SortedList
Check out **Documentation.md** for more information about each data structure.
| 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 |
## How to use
## Overall To-Do
To generate the data structures, all you need to do is to include the necessary header files. You can include the containers you want to use individually or you can include the master header, `macro_collections.h`, that comes with all collections and other functionalities like the `FOR_EACH` macro.
In the long term, these are the steps left for the completion of this library:
There are three C standard headers that all collections use:
* Complete the implementation of all the functions in the scope of the TODO file for the main collections (all those included in `cmc` and `ext`);
* Reorganize and complete all tests for `cmc` and `ext`;
* 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`.
* `<stdlib.h>`
* `<stdbool.h>`
* `<string.h>`
## Design Decisions
With the last one being used only by array based containers. These headers are already included by default.
### Stack vs Heap Allocation
### Macros
Currently all collections need to be allocated on the heap. Iterators have both options but it is encouraged to allocate them on the stack since they don't require dynamic memory.
> Note here that `SNAME` represents the uppercase name of the data structure.
### Some collections overlap others in terms of functionality
Every collection is separated by three parts:
Yes, you can use a Deque as a Queue or a List as a Stack without any major cost, but the idea is to have the least amount of code to fulfill the needs of a collection.
* `STRUCT` - Contains all structure definitions.
* `HEADER` - Contains all functions definitions.
* `SOURCE` - Contains all functions implementations.
Take for example the Stack. It is simple, small and doesn't have many functions. If you generate a List to be used (only) as a Stack (which is one of the bulkiest collections) you'll end up with a lot of code generated and compiled for nothing.
All collections have five main macros:
The Deque versus Queue situation is a little less problematic, but again, you need to be careful when generating a lot of code as compilation times might go up to 15 seconds even with modern ultra-fast compilers.
* PUBLIC
* `SNAME_GENERATE_HEADER_PUBLIC` - Generates both `STRUCT` and `HEADER`
* `SNAME_GENERATE_SOURCE_PUBLIC` - Generates `SOURCE`
* PRIVATE
* `SNAME_GENERATE_HEADER_PRIVATE` - Generates `HEADER`
* `SNAME_GENERATE_SOURCE_PRIVATE` - Generates both `STRUCT` and `SOURCE`
* Standalone
* `SNAME_GENERATE` - Generates `STRUCT`, `HEADER` and `SOURCE`.
Another example is using a HashMap/TreeMap as a HashSet/TreeSet (with a dummy value that is never used), but I just think that this is a bad thing to do and you would be wasting some memory. Also, the sets generate a lot of code related to set theory, whereas maps don't.
Or you can generate each part individually:
### But what about the LinkedList ?
* `SNAME_GENERATE_STRUCT` - Generates all structure definitions.
* `SNAME_GENERATE_HEADER` - Generates all functions definitions.
* `SNAME_GENERATE_SOURCE` - Generates all functions implementations.
You can use them as Stacks, Queues and Deques, but with modern memory hierarchy models, array-based data structures have a significantly faster runtime due to caching, so I didn't bother to have specific implementations of those aforementioned collections.
### For Each
### You can't structurally modify a collection when iterating over it
There are 4 for-each macros:
* `FOR_EACH` - Starts at the start of the data structure towards the end.
* `FOR_EACH_REV` - Starts at the end of the data structure towards the start.
* `FOR_EACH_MAP` - Like `FOR_EACH` but for associative data structures like *TREEMAP* and *HASHMAP*.
* `FOR_EACH_MAP_REV` - Like `FOR_EACH_REV` but for associative data structures like *TREEMAP* and *HASHMAP*.
Check out the **Documentation.md** to know exactly what represents the *end* and the *start* of each data structure.
### Parameters
When including `macro_collections.h` in your source code you gain access to a macro called `COLLECTION_GENERATE` with the following parameters:
* \*__C__ - Container name in uppercase (*LIST*, *LINKEDLIST*, *STACK*, *QUEUE*, *DEQUE*, *HEAP*, *TREESET*, *TREEMAP*, *HASHSET*, *HASHMAP*).
* \*__P__ - Permission (PRIVATE, PUBLIC). Only matters when header and source are declared in separate files.
* *PRIVATE* - Members of a struct are hidden in source file and only accessible through functions.
* *PUBLIC* - Members of a struct are visible.
* \*__PFX__ - Functions prefix or namespace.
* \*__SNAME__ - Structure name (`typedef struct SNAME##_s SNAME`).
* __FMOD__ - Function modifier (`static` or empty).
* \*\*__K__ - Key type. Only used in *HASHMAP* and *TREEMAP*; ignored by others.
* \*__V__ - Value type. Primary type for most data structures, or value to be mapped by *HASHMAP* and *TREEMAP*.
\* Required parameters
\*\* Required only by *HASHMAP* and *TREEMAP*
**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.
When including `foreach.h` in your source code you gain access to all for-each macros with the following parameters:
* __PFX__ - Functions prefix or namespace.
* __SNAME__ - Structure name.
* __V__ - Value type.
* \*__K__ - Key type.
* __TARGET__ - The variable name of the data structure you wish to iterate over.
* __BODY__ - Block of code.
\* Only available for `FOR_EACH_MAP` and `FOR_EACH_MAP_REV`.
Inside body you will have access to three new variables:
* `iter` - Represents the iterator.
* \*`key` - Represents the resulting key on each iteration.
* `value` - Represents the resulting value on each iteration.
\* Only available in `FOR_EACH_MAP` and `FOR_EACH_MAP_REV`.
### Separate Header and Source
Below is an example of how to hide the struct members when using a separate source file.
**header.h**
```c
#include "macro_collection.h"
COLLECTION_GENERATE_HEADER(LIST, PRIVATE, l, list, , , int)
```
**source.c**
```c
#include "header.h"
COLLECTION_GENERATE_SOURCE(LIST, PRIVATE, l, list, , , int)
```
**main.c**
```c
#include "header.h"
int main(void)
{
list *my_list = l_new(100);
// Valid code
size_t len1 = l_count(my_list);
// Invalid code
size_t len2 = my_list->count;
l_free(my_list);
}
```
**Compilation process**
```
gcc -c source.c -I ./path/to/source
gcc -c main.c -I ./path/to/source
gcc source.o main.o
```
The container members won't be visible to the file `main.c`. For this to work, all parameters must be identical, with the only difference being the macro name.
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
The following table shows how each data structure is implemented and how well they do when using as common [abstract data types](https://en.wikipedia.org/wiki/Abstract_data_type).
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 data structure implements correctly the 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.
@@ -173,3 +118,65 @@ The following table shows how each data structure is implemented and how well th
![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 (*LIST*, *LINKEDLIST*, *STACK*, *QUEUE*, *DEQUE*, *HEAP*, *TREESET*, *TREEMAP*, *HASHSET*, *HASHMAP*).
* __PFX__ - Functions prefix or namespace.
* __SNAME__ - Structure name (`typedef struct SNAME##_s 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_FOR_EACH` - Starts at the start of the collection towards the end.
* `CMC_FOR_EACH_REV` - Starts at the end of the collection towards the start.
When including `foreach.h` in your source code you gain access to all for-each macros with the following parameters:
* __PFX__ - Functions prefix or namespace.
* __SNAME__ - Structure name.
* __TARGET__ - The variable name of the collection you wish to iterate over.
* __BODY__ - Block of code.
Inside body you will have access to the iterator variable `iter`. With it you can use functions to access the key, value or index from the iterator. Checkout the documentation for more details.
<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 *./ext/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) |
+67
View File
@@ -0,0 +1,67 @@
TODO
[/] - In Progress
[X] - Finished
[~] - Needs to be reviewed
[/] Documentation
[/] Tests
[X] Remove PUBLIC and PRIVATE
[X] Extra Collections
[X] Add MultiSet
[X] Add MultiMap
[X] Add IntervalHeap
[/] Add SortedList
[/] Add BiDiMap
[/] Add functions
[X] update {hashmap, treemap, multimap}
[X] set {hashmap, treemap, multimap}
[X] to_string {all}
[X] iter_advance {all} (iterators)
[X] iter_rewind {all} (iterators)
[X] iter_go_to {all} (iterators)
[ ] from_array {all}
[ ] to_array {all}
[X] equals {all}
[X] copy_of {all}
[X] resize {array based collections}
[ ] Serialization
[ ] save {all}
[ ] load {all}
[ ] serialize {all}
[ ] deserialize {all}
[ ] Callback utility
[ ] Zip Iterators
[ ] Statically Allocated Collections
[ ] Deque
[ ] HashMap
[ ] HashSet
[ ] Heap
[ ] LinkedList
[ ] List
[~] Queue
[~] Stack
[ ] TreeMap
[ ] TreeSet
[ ] Dev Collections
[~] Deque
[ ] HashMap
[ ] HashSet
[ ] Heap
[ ] LinkedList
[ ] List
[ ] Queue
[ ] Stack
[ ] TreeMap
[ ] TreeSet
[X] Utility
[X] assert.h
[X] foreach.h
[X] log.h
[X] test.h
[X] timer.h
[ ] Optimizations
[ ] Hashtable insertion can avoid a call to impl_get_entry to check if a key already exists
[ ] Use binary search to find optimum hashtable prime size inside impl_calculate_size
+253
View File
@@ -0,0 +1,253 @@
/**
* benchmark.c
*
* Creation Date: 13/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Benchmarks:
* - Input
* - Search
* - 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>
#define NTOTAL UINT64_C(10000000)
#define NMIN UINT64_C(100)
// 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);
}
void shuffle(int *array, mt_state_ptr st)
{
for (size_t i = 0; i < NTOTAL; i++)
{
size_t j = randsize(0, NTOTAL - 1, st);
int tmp = array[j];
array[j] = array[i];
array[i] = tmp;
}
}
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)
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 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"); \
cmc_timer timer, total; \
int r, k, v; \
size_t j; \
\
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); \
\
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; \
\
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); \
\
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); \
\
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)); \
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); \
}
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(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]))
int main(void)
{
// Using the Mersenne Twister to generate random numbers. This seed
// guarantees that everytime this program runs it will generate the same
// random numbers. The random numbers influence on the shuffling of the
// array.
mt_state st;
twist_init(&st, UINT64_C(12604951237));
int *array = malloc(NTOTAL * sizeof(int));
int *sarray = malloc(NTOTAL * sizeof(int));
if (!array)
{
printf("Allocation failed\n");
return 1;
}
for (int i = -5000000; i < 5000000; i++)
array[i + 5000000] = i;
shuffle(array, &st);
memcpy(sarray, array, NTOTAL * sizeof(int));
shuffle(sarray, &st);
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.
cmc_timer timer;
cmc_timer_start(timer);
DEQUE_io_benchmark(array, sarray, NMIN);
HASHMAP_io_benchmark(array, sarray, NTOTAL);
HASHSET_io_benchmark(array, sarray, NTOTAL);
HEAP_io_benchmark(array, sarray, NMIN);
LINKEDLIST_io_benchmark(array, sarray, NMIN);
LIST_io_benchmark(array, sarray, NMIN);
QUEUE_io_benchmark(array, sarray, NMIN);
STACK_io_benchmark(array, sarray, NMIN);
TREEMAP_io_benchmark(array, sarray, NTOTAL);
TREESET_io_benchmark(array, sarray, NTOTAL);
INTERVALHEAP_io_benchmark(array, array, NMIN);
MULTIMAP_io_benchmark(array, array, NTOTAL);
MULTISET_io_benchmark(array, array, NTOTAL);
cmc_timer_stop(timer);
cmc_timer_calc(timer);
printf("+-----------------------------------------------------------+ \n");
printf("| Total Benchmark Running Time : %12.0lf seconds | \n", timer.result / 1000);
printf("+-----------------------------------------------------------+ \n");
free(array);
free(sarray);
return 0;
}
-44
View File
@@ -1,44 +0,0 @@
#include <stdio.h>
#include "../src/macro_collections.h"
int intcmp(int a, int b)
{
return a - b;
}
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;
}
COLLECTION_GENERATE(HASHSET, PUBLIC, set, hash_set, static, , int)
int main(int argc, char const *argv[])
{
hash_set *set = set_new(50000, 0.9, intcmp, inthash);
//hash_set *set = set_new(intcmp);
for (int i = -1000000; i <= 1000000; i++)
set_insert(set, i);
hash_set_iter iter;
size_t index;
int result, total_sum = 0;
for (set_iter_new(&iter, set); !set_iter_end(&iter);)
{
set_iter_next(&iter, &result, &index);
total_sum += result;
}
set_free(set);
return 0;
}
+10
View File
@@ -0,0 +1,10 @@
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
gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DEXT_QUEUE
a.exe
+82
View File
@@ -0,0 +1,82 @@
/**
* 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"
QUEUE_GENERATE(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"
#elif defined(EXT_QUEUE)
#include "ext/linkedqueue.h"
LINKEDQUEUE_GENERATE(q, queue, , int)
#define TARGET "LINKED QUEUE"
#else
#error Please define either CMC_QUEUE, SAC_QUEUE or EXT_QUEUE
#endif
int main(void)
{
#if defined(CMC_QUEUE)
queue *q = q_new(MAX);
#elif defined(SAC_QUEUE)
queue _q = q_new();
queue_ptr q = &_q;
#elif defined(EXT_QUEUE)
queue *q = q_new();
#endif
size_t sum = 0;
int i = 0;
timer_t timer;
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);
}
}
}
TIMER_STOP(timer);
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) || defined(EXT_QUEUE)
q_free(q);
#endif
return 0;
}
-44
View File
@@ -1,44 +0,0 @@
#include <stdio.h>
#include "../src/macro_collections.h"
int intcmp(int a, int b)
{
return a - b;
}
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;
}
COLLECTION_GENERATE(TREESET, PUBLIC, set, hash_set, static, , int)
int main(int argc, char const *argv[])
{
//hash_set *set = set_new(50000, 0.9, intcmp, inthash);
hash_set *set = set_new(intcmp);
for (int i = -1000000; i <= 1000000; i++)
set_insert(set, i);
hash_set_iter iter;
size_t index;
int result, total_sum = 0;
for (set_iter_new(&iter, set); !set_iter_end(&iter);)
{
set_iter_next(&iter, &result, &index);
total_sum += result;
}
set_free(set);
return 0;
}
+102
View File
@@ -0,0 +1,102 @@
/**
* twister.c
*
* Creation Date: 09/05/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Mersenne Twister PRNG utility
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define NN 312
#define MM 156
#define MATRIX_A UINT64_C(0xB5026F5AA96619E9)
#define UM UINT64_C(0xFFFFFFFF80000000) // Most significant 33 bits
#define LM UINT64_C(0x7FFFFFFF) // Least significant 31 bits
// State vector
typedef struct mt_state_s
{
uint64_t mt[NN];
int mti;
} mt_state, *mt_state_ptr;
// Initializes mt[NN] with a seed
void twist_init(mt_state_ptr st, uint64_t seed);
// Generates a random uint64_t in [0, 2^64-1] interval
uint64_t twist_uint64(mt_state_ptr st);
// Generates a double in [0, 1) interval
double twist_real(mt_state_ptr st);
//
// Implementation
//
// Initialize a state mt[NN] with a seed
void twist_init(mt_state_ptr st, uint64_t seed)
{
st->mti = NN + 1;
st->mt[0] = seed;
for (st->mti = 1; st->mti < NN; st->mti++)
{
st->mt[st->mti] = (UINT64_C(6364136223846793005) * (st->mt[st->mti - 1] ^ (st->mt[st->mti - 1] >> 62)) + st->mti);
}
}
// Generates a random uint64_t in [0, 2^64-1] interval
uint64_t twist_uint64(mt_state_ptr st)
{
int i;
uint64_t x;
static uint64_t mag01[2] = {UINT64_C(0), MATRIX_A};
if (st->mti >= NN)
{
// Generate NN words at one time if twist_init() has not been called
// A default initial seed is used
if (st->mti == NN + 1)
twist_init(st, UINT64_C(5489));
for (i = 0; i < NN - MM; i++)
{
x = (st->mt[i] & UM) | (st->mt[i + 1] & LM);
st->mt[i] = st->mt[i + MM] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
}
for (; i < NN - 1; i++)
{
x = (st->mt[i] & UM) | (st->mt[i + 1] & LM);
st->mt[i] = st->mt[i + (MM - NN)] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
}
x = (st->mt[NN - 1] & UM) | (st->mt[0] & LM);
st->mt[NN - 1] = st->mt[MM - 1] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
st->mti = 0;
}
x = st->mt[st->mti++];
x ^= (x >> 29) & UINT64_C(0x5555555555555555);
x ^= (x << 17) & UINT64_C(0x71D67FFFEDA60000);
x ^= (x << 37) & UINT64_C(0xFFF7EEE000000000);
x ^= (x >> 43);
return x;
}
// Generates a double in [0, 1) interval
double twist_real(mt_state_ptr st)
{
return (twist_uint64(st) >> 11) * (1.0 / 9007199254740992.0);
}
File diff suppressed because it is too large. Load diff
+247
View File
@@ -0,0 +1,247 @@
THIS IS A SAFE COPY OF THE MARKDOWN FOR THE DOCUMENTATION LOCATED AT https://leoven.github.io/C-Macro-Collections/
---
title: CMC Documentation
toc_footers:
- <a href='https://github.com/lord/slate'>Documentation Powered by Slate</a>
language_tabs:
- C
search: true
---
# Introduction
[![github](https://img.shields.io/badge/GitHub-C%20Macro%20Collections-lightgrey.svg?logo=github)](https://github.com/LeoVen/C-Macro-Collections)
![License](https://img.shields.io/badge/License-MIT-blue.svg)
![Version](https://img.shields.io/badge/Version-v1.6.2-orange.svg)
[![Build](https://travis-ci.org/LeoVen/C-Macro-Collections.svg?branch=master)](https://travis-ci.org/LeoVen/C-Macro-Collections)
[![codecov](https://codecov.io/gh/LeoVen/C-Macro-Collections/branch/master/graph/badge.svg)](https://codecov.io/gh/LeoVen/C-Macro-Collections)
The C Macro Collections Library is a compilation of macros that can be used to generate common data structures for any desired type. These data structures are [type safe](https://en.wikipedia.org/wiki/Type_safety).
The documentation is currently being written in hopes that in the future it can be used to help you get to know better this amazing C library.
## Why this library
C is a low level language and lacks all the data structures that we commonly use. Many high level languages already come with these collections so that we don't have to implement everything ourselves. This is why the C Macro Collections Library was created.
The library currently provides many data structures, such as:
* Linear Collections
* List, LinkedList, Deque, Stack, Queue
* Sets
* HashSet, TreeSet, MultiSet
* Maps
* HashMap, TreeMap, MultiMap
* Heaps
* Heap, IntervalHeap
All with the following features:
* __Type-safe__ - No `void *` pointers are used. A collection of type `int` will only accept integers;
* __Customization__ - Custom struct name and function namespace;
* __Bidirectional Iterators__ - Full support for iterators;
* __Nesting__ - Collections can be nested (List of Lists, HashSet of Stacks, etc).
## Library Structure
The `src` folder is subdivided in 5 other folders and one file:
> The `dev` folder is an exact copy of `cmc` but it is filled with logging information regarding the code execution and debugging.
> The `sac` library contains fixed-length collections with an internal C array.
* __cmc__ - The main C Macro Collections Library
* __dev__ - The main C Macro Collections Library for development
* __ext__ - Extra collections
* __sac__ - Statically Allocated Collections
* __utl__ - Utility like ForEach macros, logging, etc
* __macro\_collections.h__ - Master header containing all collections and utilities
## How to install
> Include header files like this
```c
#include <cmc/list.h>
#include <dev/deque.h>
#include <utl/assert.h>
```
> Not like this
```c
#include <list.h>
#include <deque.h> // dev or cmc?
#include <assert.h> // this will import from the standard library
```
No installation is required. All you have to do is include the appropriate header files, generate any collections that you desire and then compile your program. It is recommended that you include the headers relative to the `src` folder and include it with `-I path/to/library/src` as shown in the following example.
The library has no external dependencies other than the C standard library.
## Minimal Example
Lets create a list of type `int`, add some elements to it and get the sum of all the elements printed on the screen.
### Include headers
```c
#include <cmc/list.h>
```
First you need to include only the necessary headers. It is not recommended that you include everything with `macro_collections.h`, only in cases where you might be using almost all features from the library.
### Generating a list
```c
// CMC_GENERATE_LIST(PFX, SNAME, V)
CMC_GENERATE_LIST(il, int_list, int)
```
The List is also known as `vector`, `ArrayList` and dynamic array. In fact the latter is the best description for this collection. It is a dynamic array that can grow and shrink as needed. To generate it we can simply call the macro `CMC_GENERATE_LIST` after our includes. It has three parameters:
| Parameter name | Purpose |
| :------------: | ------- |
| __PFX__ | Functions prefix (namespace) |
| __SNAME__ | Struct name |
| __V__ | The list value type (can be any valid data type) |
<aside class="notice">
All collections can be generated by using the macro CMC_GENERATE_ and then the name of the include (in this case list.h) but in uppercase without the `.h`.
</aside>
### Initializing and adding elements
```c
// Allocate an int_list with an initial capacity of 100
int_list *list = il_new(100);
// Adding elements to the back of the list
for (int i = 0; i <= 1000; i++)
{
if (!il_push_back(list, i))
{
// Something went wrong (check out documentation)
}
}
```
To initialize any collection we call a function `_new`. Since the `PFX` parameter is set to `il` all functions related to our list of integer will be prefixed by `il`, so `_new` becomes `il_new`.
The list name is `int_list` as defined by `SNAME`. This type is a typedef like:
`typedef struct SNAME##_s SNAME;`
Which expands to:
`typedef struct int_list_s int_list`
To add elements to the back of a list we can use `il_push_back`. This function will first check if the list has enough space for a new element. If not, reallocate the internal buffer with doubled size and then add the new element.
### Iteration
> It is recommended that the iterator is allocated on the stack
```c
// Resulting sum will be stored here
int sum = 0;
// Declare our iterator (allocating it on the stack)
int_list_iter it;
// Loop for each element
for (il_iter_init(&it, list); !il_iter_end(&it); il_iter_next(&it))
{
// Accessing the value
int elem = il_iter_value(&it);
sum += elem;
}
printf("%d\n", sum);
```
There are 6 (2 optional) steps to iterate over the elements of any collection:
| Step | Description | Function |
| :--: | ----------- | -------- |
| 1 | Allocate the iterator (optional) | `il_iter_new` |
| 2 | Initialize the iterator given a target list | `il_iter_init` |
| 3 | Access the iterator's elements (value, index, etc) | `il_iter_value` |
| 4 | Go to the next element | `il_iter_next` |
| 5 | Check if we haven't reached the end of the list | `il_iter_end` |
| 6 | Free the iterator if it was allocated on the heap | `il_iter_free` |
Note that all iterator functions are prefixed by the user defined prefix and then by `iter` (`il + iter = il_iter`). Also, the steps __1__ and __6__ are optional so `il_iter_new` and `il_iter_free` are not used in the example.
By the end of the example we have the variable `sum` with the sum of all integers inside our list. We can then print it and this example is almost done.
### Freeing resources
```c
// void il_free(int_list *_list_, void(*deallocator)(int))
il_free(list, NULL);
```
The list is currently allocated in memory. To deallocate it we call `il_free`. This function takes a pointer to the allocated list and a pointer to a `deallocator` function that will be responsible for deallocating each element in the list. This last parameter is optional and we won't be using it since our data type `int` is not allocated in the heap. This optional parameter can be set to `NULL` to be ignored by the `il_free` function.
### Compile and run
> source.c
```c
#include <cmc/list.h>
CMC_GENERATE_LIST(il, int_list, int)
int main(void)
{
int_list *list = il_new(100);
for (int i = 0; i <= 1000; i++)
{
if (!il_push_back(list, i))
{
// Something went wrong (check out documentation)
}
}
int sum = 0;
int_list_iter it;
for (il_iter_init(&it, list); !il_iter_end(&it); il_iter_next(&it))
{
int elem = il_iter_value(&it);
sum += elem;
}
printf("%d\n", sum);
il_free(list, NULL);
}
```
If the source file is `source.c`, all you have to do is to include the `src` folder to the include path and compile. The following example uses `gcc`:
`gcc source.c -I path/to/library/src`
### Conclusion
The C Macro Collections Library is prepared to accept any data type and is highly customizable. It is also very easy to integrate and no previous compilation is required. The library also comes with many utilities in the `utl` folder that are designed to work well with all collections.
# Upcoming
This documentation is still being written. Here is some of the things you will be able to find here:
* Full explanation about data structures
* Full documentation about all current collections and others to come
* Fully explained examples
* Benchmark examples
+16
View File
@@ -0,0 +1,16 @@
# Examples
* deque - DEQUE collection examples
* hashmap - HASHMAP collection examples
* hashset - HASHSET collection examples
* heap - HEAP collection examples
* iterators - Examples of using the collection's iterators
* linkedlist - LINKEDLIST collection examples
* list - LIST collection examples
* multimap - MULTIMAP collection examples
* multiset - MULTISET collection examples
* others - Other examples, generally more robust and using multiple collections
* queue - QUEUE collection examples
* stack - STACK collection examples
* treemap - TREEMAP collection examples
* treeset - TREESET collection examples
+1
View File
@@ -1,3 +1,4 @@
# Deque examples
* even_odd.c - separates odd numbers to one end of the deque and even number to the other. Sum only half of it to give the total sum of even numbers.
* iterator.c - A complete example of the deque iterator
+5 -4
View File
@@ -7,10 +7,10 @@
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/deque.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "deque.h"
DEQUE_GENERATE(d, deque, /* static */, size_t)
@@ -29,13 +29,14 @@ int main(int argc, char const *argv[])
}
deque_iter iter;
d_iter_new(&iter, numbers);
d_iter_init(&iter, numbers);
size_t result, index, sum = 0;
for (d_iter_toend(&iter); !d_iter_start(&iter);)
for (d_iter_to_end(&iter); !d_iter_start(&iter); d_iter_prev(&iter))
{
d_iter_prev(&iter, &result, &index);
result = d_iter_value(&iter);
index = d_iter_index(&iter);
if ((double)index < (double)d_count(numbers) / 2.0)
break;
+199
View File
@@ -0,0 +1,199 @@
/**
* iterator.c
*
* Creation Date: 13/05/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Iterator Example
*/
#include "cmc/deque.h"
#include <stdio.h>
#include <inttypes.h>
// Creates a deque of integers
DEQUE_GENERATE(d, deque, /* FMOD */, int)
int main(int argc, char const *argv[])
{
// Create a new deque with an initial capacity of 100
deque *my_deque = d_new(100);
// Add elements to the deque
for (int i = 0; i < 20; i++)
{
// Add odd numbers to the front
d_push_front_if(my_deque, i, !(i % 2 == 0));
// And even numbers to the back
d_push_back_if(my_deque, i, i % 2 == 0);
}
// Iterate from the start (front index) to the end (rear index) of the deque
for (deque_iter it = my_deque->it_start(my_deque); // Initialize iterator 'it' to the start of the deque
!d_iter_end(&it); // Conditional stop (until it is not at the end)
d_iter_next(&it)) // Iterator goes one position forward
{
// Access the current element
int e = d_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = d_iter_index(&it);
// Print deque
// Index is useful in situations like this
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == d_count(my_deque) - 1)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// Index can also be used to iterate over a certain portion of a collection
size_t limit = d_count(my_deque) / 2;
for (deque_iter it = my_deque->it_start(my_deque); !d_iter_end(&it); d_iter_next(&it))
{
// Access the current element
int e = d_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = d_iter_index(&it);
// Print deque up until limit
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == limit - 1) // -1 because index is 0 based and we want half of the deque
{
printf("%d ]\n", e);
break;
}
// For elements at the middle
else
printf("%d, ", e);
}
// Going backwards
for (deque_iter it = my_deque->it_end(my_deque); // Initialize iterator 'it' to the end of the deque
!d_iter_start(&it); // Conditional stop (until it is not at the start)
d_iter_prev(&it)) // Iterator goes one position backwards
{
// Access the current element
int e = d_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = d_iter_index(&it);
// Print deque
// Note how the conditions for the first and last elements are simply swapped
// Because iterating backwards make the first element be the index count - 1
// and the last one be the index 0
// If it is the first element
if (i == d_count(my_deque) - 1)
printf("[ %d, ", e);
// If it is the last element
else if (i == 0)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// You can also use iterators in a while loop
// But to do so you must declare the iterator struct outside the loop first
deque_iter it;
// You have three options:
// - Initialize it using the functions provided by the deque [ my_deque->it_start() and my_deque->it_end() ]
// - Initialize it using the init() function (when the iterator is already allocated)
// - Initialize it using the new() function (allocates on the heap, pointers only)
it = my_deque->it_start(my_deque);
it = my_deque->it_end(my_deque);
// This is equivalent to it_start()
d_iter_init(&it, my_deque);
// For pointers
// Also equivalent to it_start()
deque_iter *iter = d_iter_new(my_deque);
// The actual while loop
while (!d_iter_end(iter))
{
// Accessing elements
int e = d_iter_value(iter);
size_t i = d_iter_index(iter);
// Print index and element
printf("deque[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator forwards
d_iter_next(iter);
}
// Send the iterator to the start of the deque
d_iter_to_start(iter);
// Send the iterator to the end of the deque
d_iter_to_end(iter);
// Backwards loop
while (!d_iter_start(iter))
{
// Accessing elements
int e = d_iter_value(iter);
size_t i = d_iter_index(iter);
// Print index and element
printf("deque[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator backwards
d_iter_prev(iter);
}
// Certain iterators also allow you to modify the contents it is iterating over
// Exceptions are collections that depend of the current state of the element
// like tree-based collections and heap (collections that have some kind of ordering).
// You also can't change the keys of an associative collection
// Change every element that is divisible by 3 to the number 7
for (d_iter_to_start(&it); !d_iter_end(&it); d_iter_next(&it))
{
// Get a reference to the current value
int *r = d_iter_rvalue(&it);
if (r != NULL && *r % 3 == 0)
*r = 7;
}
// Now print it to see the difference
for (deque_iter it = my_deque->it_start(my_deque); !d_iter_end(&it); d_iter_next(&it))
{
int e = d_iter_value(&it);
size_t i = d_iter_index(&it);
if (i == 0)
printf("[ %d, ", e);
else if (i == d_count(my_deque) - 1)
printf("%d ]\n", e);
else
printf("%d, ", e);
}
// Dispose the iterator called by d_iter_new()
d_iter_free(iter);
// Dispose the deque created
d_free(my_deque);
return 0;
}
+73
View File
@@ -0,0 +1,73 @@
#include <cmc/stack.h>
#include <utl/log.h>
CMC_GENERATE_STACK(stk, stack, int)
struct
{
stack *from;
stack *aux;
stack *to;
} print_aux = {NULL};
void print_stacks()
{
for (int i = 9; i >= 0; i--)
{
int ia = print_aux.from->buffer[i];
int ib = print_aux.aux->buffer[i];
int ic = print_aux.to->buffer[i];
printf("| %c | %c | %c |\n",
ia == 0 ? 32 : ia + 48,
ib == 0 ? 32 : ib + 48,
ic == 0 ? 32 : ic + 48);
}
printf("+---+---+---+\n\n");
}
void move(stack *from, stack *to)
{
stk_push(to, stk_top(from));
stk_pop(from);
}
void hanoi(int n, stack *from, stack *aux, stack *to)
{
if (n == 0)
return;
hanoi(n - 1, from, to, aux);
move(from, to);
print_stacks();
hanoi(n - 1, aux, from, to);
}
int main(int argc, char const *argv[])
{
stack *from = stk_new(10);
stack *to = stk_new(10);
stack *aux = stk_new(10);
for (int i = 4; i >= 1; i--)
stk_push(from, i);
print_aux.from = from;
print_aux.aux = aux;
print_aux.to = to;
print_stacks();
hanoi(stk_count(from), from, aux, to);
stk_free(from, NULL);
stk_free(to, NULL);
stk_free(aux, NULL);
return 0;
}
+3 -1
View File
@@ -1,3 +1,5 @@
# Hashmap examples
Currently none
* countries - Uses a hashmap to map the country name to its population
* foreach.c - ForEach macro example
* iterator.c - A complete example of the hashmap iterator
+216
View File
@@ -0,0 +1,216 @@
Afghanistan,34656032
Albania,2876101
Algeria,40606052
American Samoa,55599
Andorra,77281
Angola,28813463
Antigua and Barbuda,100963
Argentina,43847430
Armenia,2924816
Aruba,104822
Australia,24127159
Austria,8747358
Azerbaijan,9762274
Bahamas; The,391232
Bahrain,1425171
Bangladesh,162951560
Barbados,284996
Belarus,9507120
Belgium,11348159
Belize,366954
Benin,10872298
Bermuda,65331
Bhutan,797765
Bolivia,10887882
Bosnia and Herzegovina,3516816
Botswana,2250260
Brazil,207652865
British Virgin Islands,30661
Brunei Darussalam,423196
Bulgaria,7127822
Burkina Faso,18646433
Burundi,10524117
Cabo Verde,539560
Cambodia,15762370
Cameroon,23439189
Canada,36286425
Cayman Islands,60765
Central African Republic,4594621
Chad,14452543
Channel Islands,164541
Chile,17909754
China,1378665000
Colombia,48653419
Comoros,795601
Congo; Dem. Rep.,78736153
Congo; Rep.,5125821
Costa Rica,4857274
Cote d'Ivoire,23695919
Croatia,4170600
Cuba,11475982
Curacao,159999
Cyprus,1170125
Czech Republic,10561633
Denmark,5731118
Djibouti,942333
Dominica,73543
Dominican Republic,10648791
Ecuador,16385068
Egypt; Arab Rep.,95688681
El Salvador,6344722
Equatorial Guinea,1221490
Estonia,1316481
Ethiopia,102403196
Faroe Islands,49117
Fiji,898760
Finland,5495096
France,66896109
French Polynesia,280208
Gabon,1979786
Gambia; The,2038501
Georgia,3719300
Germany,82667685
Ghana,28206728
Gibraltar,34408
Greece,10746740
Greenland,56186
Grenada,107317
Guam,162896
Guatemala,16582469
Guinea,12395924
Guinea-Bissau,1815698
Guyana,773303
Haiti,10847334
Honduras,9112867
Hong Kong SAR; China,7346700
Hungary,9817958
Iceland,334252
India,1324171354
Indonesia,261115456
Iran; Islamic Rep.,80277428
Iraq,37202572
Ireland,4773095
Isle of Man,83737
Israel,8547100
Italy,60600590
Jamaica,2881355
Japan,126994511
Jordan,9455802
Kazakhstan,17797032
Kenya,48461567
Kiribati,114395
Korea; Dem. People’s Rep.,25368620
Korea; Rep.,51245707
Kosovo,1816200
Kuwait,4052584
Kyrgyz Republic,6082700
Lao PDR,6758353
Latvia,1960424
Lebanon,6006668
Lesotho,2203821
Liberia,4613823
Libya,6293253
Liechtenstein,37666
Lithuania,2872298
Luxembourg,582972
Macao SAR; China,612167
Macedonia; FYR,2081206
Madagascar,24894551
Malawi,18091575
Malaysia,31187265
Maldives,417492
Mali,17994837
Malta,436947
Marshall Islands,53066
Mauritania,4301018
Mauritius,1263473
Mexico,127540423
Micronesia; Fed. Sts.,104937
Moldova,3552000
Monaco,38499
Mongolia,3027398
Montenegro,622781
Morocco,35276786
Mozambique,28829476
Myanmar,52885223
Namibia,2479713
Nauru,13049
Nepal,28982771
Netherlands,17018408
New Caledonia,278000
New Zealand,4692700
Nicaragua,6149928
Niger,20672987
Nigeria,185989640
Northern Mariana Islands,55023
Norway,5232929
Oman,4424762
Pakistan,193203476
Palau,21503
Panama,4034119
Papua New Guinea,8084991
Paraguay,6725308
Peru,31773839
Philippines,103320222
Poland,37948016
Portugal,10324611
Puerto Rico,3411307
Qatar,2569804
Romania,19705301
Russian Federation,144342396
Rwanda,11917508
Samoa,195125
San Marino,33203
Sao Tome and Principe,199910
Saudi Arabia,32275687
Senegal,15411614
Serbia,7057412
Seychelles,94677
Sierra Leone,7396190
Singapore,5607283
Sint Maarten (Dutch part),40005
Slovak Republic,5428704
Slovenia,2064845
Solomon Islands,599419
Somalia,14317996
South Africa,55908865
South Sudan,12230730
Spain,46443959
Sri Lanka,21203000
St. Kitts and Nevis,54821
St. Lucia,178015
St. Martin (French part),31949
St. Vincent and the Grenadines,109643
Sudan,39578828
Suriname,558368
Swaziland,1343098
Sweden,9903122
Switzerland,8372098
Syrian Arab Republic,18430453
Tajikistan,8734951
Tanzania,55572201
Thailand,68863514
Timor-Leste,1268671
Togo,7606374
Tonga,107122
Trinidad and Tobago,1364962
Tunisia,11403248
Turkey,79512426
Turkmenistan,5662544
Turks and Caicos Islands,34900
Tuvalu,11097
Uganda,41487965
Ukraine,45004645
United Arab Emirates,9269612
United Kingdom,65637239
United States,323127513
Uruguay,3444006
Uzbekistan,31848200
Vanuatu,270402
Venezuela; RB,31568179
Vietnam,92701100
Virgin Islands (U.S.),102951
West Bank and Gaza,4551566
Yemen; Rep.,27584213
Zambia,16591390
Zimbabwe,16150362
1 Afghanistan 34656032
2 Albania 2876101
3 Algeria 40606052
4 American Samoa 55599
5 Andorra 77281
6 Angola 28813463
7 Antigua and Barbuda 100963
8 Argentina 43847430
9 Armenia 2924816
10 Aruba 104822
11 Australia 24127159
12 Austria 8747358
13 Azerbaijan 9762274
14 Bahamas; The 391232
15 Bahrain 1425171
16 Bangladesh 162951560
17 Barbados 284996
18 Belarus 9507120
19 Belgium 11348159
20 Belize 366954
21 Benin 10872298
22 Bermuda 65331
23 Bhutan 797765
24 Bolivia 10887882
25 Bosnia and Herzegovina 3516816
26 Botswana 2250260
27 Brazil 207652865
28 British Virgin Islands 30661
29 Brunei Darussalam 423196
30 Bulgaria 7127822
31 Burkina Faso 18646433
32 Burundi 10524117
33 Cabo Verde 539560
34 Cambodia 15762370
35 Cameroon 23439189
36 Canada 36286425
37 Cayman Islands 60765
38 Central African Republic 4594621
39 Chad 14452543
40 Channel Islands 164541
41 Chile 17909754
42 China 1378665000
43 Colombia 48653419
44 Comoros 795601
45 Congo; Dem. Rep. 78736153
46 Congo; Rep. 5125821
47 Costa Rica 4857274
48 Cote d'Ivoire 23695919
49 Croatia 4170600
50 Cuba 11475982
51 Curacao 159999
52 Cyprus 1170125
53 Czech Republic 10561633
54 Denmark 5731118
55 Djibouti 942333
56 Dominica 73543
57 Dominican Republic 10648791
58 Ecuador 16385068
59 Egypt; Arab Rep. 95688681
60 El Salvador 6344722
61 Equatorial Guinea 1221490
62 Estonia 1316481
63 Ethiopia 102403196
64 Faroe Islands 49117
65 Fiji 898760
66 Finland 5495096
67 France 66896109
68 French Polynesia 280208
69 Gabon 1979786
70 Gambia; The 2038501
71 Georgia 3719300
72 Germany 82667685
73 Ghana 28206728
74 Gibraltar 34408
75 Greece 10746740
76 Greenland 56186
77 Grenada 107317
78 Guam 162896
79 Guatemala 16582469
80 Guinea 12395924
81 Guinea-Bissau 1815698
82 Guyana 773303
83 Haiti 10847334
84 Honduras 9112867
85 Hong Kong SAR; China 7346700
86 Hungary 9817958
87 Iceland 334252
88 India 1324171354
89 Indonesia 261115456
90 Iran; Islamic Rep. 80277428
91 Iraq 37202572
92 Ireland 4773095
93 Isle of Man 83737
94 Israel 8547100
95 Italy 60600590
96 Jamaica 2881355
97 Japan 126994511
98 Jordan 9455802
99 Kazakhstan 17797032
100 Kenya 48461567
101 Kiribati 114395
102 Korea; Dem. People’s Rep. 25368620
103 Korea; Rep. 51245707
104 Kosovo 1816200
105 Kuwait 4052584
106 Kyrgyz Republic 6082700
107 Lao PDR 6758353
108 Latvia 1960424
109 Lebanon 6006668
110 Lesotho 2203821
111 Liberia 4613823
112 Libya 6293253
113 Liechtenstein 37666
114 Lithuania 2872298
115 Luxembourg 582972
116 Macao SAR; China 612167
117 Macedonia; FYR 2081206
118 Madagascar 24894551
119 Malawi 18091575
120 Malaysia 31187265
121 Maldives 417492
122 Mali 17994837
123 Malta 436947
124 Marshall Islands 53066
125 Mauritania 4301018
126 Mauritius 1263473
127 Mexico 127540423
128 Micronesia; Fed. Sts. 104937
129 Moldova 3552000
130 Monaco 38499
131 Mongolia 3027398
132 Montenegro 622781
133 Morocco 35276786
134 Mozambique 28829476
135 Myanmar 52885223
136 Namibia 2479713
137 Nauru 13049
138 Nepal 28982771
139 Netherlands 17018408
140 New Caledonia 278000
141 New Zealand 4692700
142 Nicaragua 6149928
143 Niger 20672987
144 Nigeria 185989640
145 Northern Mariana Islands 55023
146 Norway 5232929
147 Oman 4424762
148 Pakistan 193203476
149 Palau 21503
150 Panama 4034119
151 Papua New Guinea 8084991
152 Paraguay 6725308
153 Peru 31773839
154 Philippines 103320222
155 Poland 37948016
156 Portugal 10324611
157 Puerto Rico 3411307
158 Qatar 2569804
159 Romania 19705301
160 Russian Federation 144342396
161 Rwanda 11917508
162 Samoa 195125
163 San Marino 33203
164 Sao Tome and Principe 199910
165 Saudi Arabia 32275687
166 Senegal 15411614
167 Serbia 7057412
168 Seychelles 94677
169 Sierra Leone 7396190
170 Singapore 5607283
171 Sint Maarten (Dutch part) 40005
172 Slovak Republic 5428704
173 Slovenia 2064845
174 Solomon Islands 599419
175 Somalia 14317996
176 South Africa 55908865
177 South Sudan 12230730
178 Spain 46443959
179 Sri Lanka 21203000
180 St. Kitts and Nevis 54821
181 St. Lucia 178015
182 St. Martin (French part) 31949
183 St. Vincent and the Grenadines 109643
184 Sudan 39578828
185 Suriname 558368
186 Swaziland 1343098
187 Sweden 9903122
188 Switzerland 8372098
189 Syrian Arab Republic 18430453
190 Tajikistan 8734951
191 Tanzania 55572201
192 Thailand 68863514
193 Timor-Leste 1268671
194 Togo 7606374
195 Tonga 107122
196 Trinidad and Tobago 1364962
197 Tunisia 11403248
198 Turkey 79512426
199 Turkmenistan 5662544
200 Turks and Caicos Islands 34900
201 Tuvalu 11097
202 Uganda 41487965
203 Ukraine 45004645
204 United Arab Emirates 9269612
205 United Kingdom 65637239
206 United States 323127513
207 Uruguay 3444006
208 Uzbekistan 31848200
209 Vanuatu 270402
210 Venezuela; RB 31568179
211 Vietnam 92701100
212 Virgin Islands (U.S.) 102951
213 West Bank and Gaza 4551566
214 Yemen; Rep. 27584213
215 Zambia 16591390
216 Zimbabwe 16150362
+90
View File
@@ -0,0 +1,90 @@
#include "cmc/hashmap.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <inttypes.h>
#include "util.c"
HASHMAP_GENERATE(hm, hmap, , char *, size_t)
hmap *load(const char *fname);
int main(int argc, char const *argv[])
{
hmap *map = load("data.csv");
if (!map)
return 1;
printf("+--------------------------------------------------+\n");
printf("| Search Country Population by Country Name |\n");
printf("| |\n");
printf("| - Type 'exit' to exit |\n");
printf("| - Type country name to search its population |\n");
printf("+--------------------------------------------------+\n\n");
// If you wish to list all items
// char *key;
// size_t value, index;
// hmap_iter iter;
// for (hm_iter_new(&iter, map); !hm_iter_end(&iter);)
// {
// hm_iter_next(&iter, &key, &value, &index);
// printf("%30s : %" PRIuMAX "\n", key, value);
// free(key);
// }
char sbuffer[1000];
while (1)
{
printf("Query > ");
fflush(stdin);
scanf("%[^\n]s", sbuffer);
if (strcmp(sbuffer, "exit") == 0)
break;
size_t *result = hm_get_ref(map, sbuffer);
if (result == NULL)
printf("Result > %s Not Found\n", sbuffer);
else
printf("Result > %" PRIuMAX "\n", *result);
}
hm_free(map);
return 0;
}
hmap *load(const char *fname)
{
FILE *fptr = fopen(fname, "r");
if (!fptr)
return NULL;
hmap *map = hm_new(10000, 0.7, chrcmp, chrhash);
char buff[400];
size_t value;
while (fscanf(fptr, "%[^,],%" PRIuMAX "\n", buff, &value) != EOF)
{
char *name = strdup(buff);
if (!hm_insert(map, name, value))
{
printf("\n\n\nERROR\n");
printf("%s : %" PRIuMAX "", name, value);
exit(2);
}
}
return map;
}
+17
View File
@@ -0,0 +1,17 @@
#include <stdlib.h>
int chrcmp(char *a, char *b)
{
return strcmp(a, b);
}
size_t chrhash(char *str)
{
size_t hash = 5381;
int c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
+65
View File
@@ -0,0 +1,65 @@
/**
* iterator.c
*
* Creation Date: 23/05/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Foreach macro example
*/
#include "cmc/hashmap.h"
#include "utl/foreach.h"
#include <stdio.h>
// Int hash function
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;
}
// Int compare function
int intcmp(int a, int b)
{
return (a > b) - (a < b);
}
// Generate all the code for the hashmap
HASHMAP_GENERATE(hm, hashmap, /* FMOD */, int, double)
int main(void)
{
// Create a new hashmap with custom hash function
// The comparison function is only required to know if the key looked for was found
hashmap *map = hm_new(1000, 0.6, intcmp, inthash);
// Add keys mapped to a value
for (int i = 0; i < 5000; i++)
{
hm_insert(map, i, (double)i / 1000.0);
}
// Iterate over the HashMap without the FOR_EACH macro
for (hashmap_iter iter = map->it_start(map); !hm_iter_end(&iter); hm_iter_next(&iter))
{
printf("MAP[%4d] = %.3lf\n", hm_iter_key(&iter), hm_iter_value(&iter));
}
// Iterate over the HashMap using FOR_EACH macro
FOR_EACH(hm, hashmap, map, {
// Inside, the variable 'iter' will be available and from it you can access
// the key, value or index.
printf("MAP[%4d] = %.3lf\n", hm_iter_key(&iter), hm_iter_value(&iter));
});
hm_free(map);
return 0;
}
+230
View File
@@ -0,0 +1,230 @@
/**
* iterator.c
*
* Creation Date: 14/05/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Iterator Example
*/
#include "cmc/hashmap.h"
#include <stdio.h>
#include <inttypes.h>
// Int hash function
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;
}
// Int compare function
int intcmp(int a, int b)
{
return a - b;
}
// Creates a hashmap of integers
HASHMAP_GENERATE(hm, hashmap, /* FMOD */, int, double)
int main(int argc, char const *argv[])
{
// Create a new hashmap with an initial capacity of 100 and load factor of 0.6
hashmap *my_map = hm_new(100, 0.6, intcmp, inthash);
// Add pairs to the hashmap
for (int i = 0; i < 20; i++)
{
// Map integers to doubles
hm_insert(my_map, i, (double)i / 10.0);
}
// Iterate from the start (index 0) to the end (index count - 1) of the hashmap
for (hashmap_iter it = my_map->it_start(my_map); // Initialize iterator 'it' to the start of the hashmap
!hm_iter_end(&it); // Conditional stop (until it is not at the end)
hm_iter_next(&it)) // Iterator goes one position forward
{
// Access the current key
int k = hm_iter_key(&it);
// Access the current value
double v = hm_iter_value(&it);
// Access the current index (index is relative to all the pairs in the iteration)
size_t i = hm_iter_index(&it);
// Print hashmap
// Index is useful in situations like this
// If it is the first pair
if (i == 0)
printf("[ {%d:%.2lf}, ", k, v);
// If it is the last pair
else if (i == hm_count(my_map) - 1)
printf("{%d:%.2lf} ]\n", k, v);
// For pairs at the middle
else
printf("{%d:%.2lf}, ", k, v);
}
// Index can also be used to iterate over a certain portion of a collection
size_t limit = hm_count(my_map) / 2;
for (hashmap_iter it = my_map->it_start(my_map); !hm_iter_end(&it); hm_iter_next(&it))
{
// Access the current key
int k = hm_iter_key(&it);
// Access the current value
double v = hm_iter_value(&it);
// Access the current index (index is relative to all the pairs in the iteration)
size_t i = hm_iter_index(&it);
// Print hashmap up until limit
// If it is the first pair
if (i == 0)
printf("[ {%d:%.2lf}, ", k, v);
// If it is the last pair
else if (i == limit - 1) // -1 because index is 0 based and we want half of the hashmap
{
printf("{%d:%.2lf} ]\n", k, v);
break;
}
// For pairs at the middle
else
printf("{%d:%.2lf}, ", k, v);
}
// Going backwards
for (hashmap_iter it = my_map->it_end(my_map); // Initialize iterator 'it' to the end of the hashmap
!hm_iter_start(&it); // Conditional stop (until it is not at the start)
hm_iter_prev(&it)) // Iterator goes one position backwards
{
// Access the current key
int k = hm_iter_key(&it);
// Access the current value
double v = hm_iter_value(&it);
// Access the current index (index is relative to all the pairs in the iteration)
size_t i = hm_iter_index(&it);
// Print hashmap
// Note how the conditions for the first and last pairs are simply swapped
// Because iterating backwards make the first pair be the index count - 1
// and the last one be the index 0
// If it is the first pair
if (i == hm_count(my_map) - 1)
printf("[ {%d:%.2lf}, ", k, v);
// If it is the last pair
else if (i == 0)
printf("{%d:%.2lf} ]\n", k, v);
// For pairs at the middle
else
printf("{%d:%.2lf}, ", k, v);
}
// You can also use iterators in a while loop
// But to do so you must declare the iterator struct outside the loop first
hashmap_iter it;
// You have three options:
// - Initialize it using the functions provided by the hashmap [ my_map->it_start() and my_map->it_end() ]
// - Initialize it using the init() function (when the iterator is already allocated)
// - Initialize it using the new() function (allocates on the heap, pointers only)
it = my_map->it_start(my_map);
it = my_map->it_end(my_map);
// This is equivalent to it_start()
hm_iter_init(&it, my_map);
// For pointers
// Also equivalent to it_start()
hashmap_iter *iter = hm_iter_new(my_map);
// The actual while loop
while (!hm_iter_end(iter))
{
// Accessing pairs
int k = hm_iter_key(iter);
double v = hm_iter_value(iter);
size_t i = hm_iter_index(iter);
// Print index and key value pair
printf("hashmap[%2" PRIuMAX "] = { %2d : %.2lf }\n", i, k, v);
// Move iterator forwards
hm_iter_next(iter);
}
// Send the iterator to the start of the hashmap
hm_iter_to_start(iter);
// Send the iterator to the end of the hashmap
hm_iter_to_end(iter);
// Backwards loop
while (!hm_iter_start(iter))
{
// Accessing pairs
int k = hm_iter_key(iter);
double v = hm_iter_value(iter);
size_t i = hm_iter_index(iter);
// Print index and the key value pair
printf("hashmap[%2" PRIuMAX "] = { %2d : %.2lf }\n", i, k, v);
// Move iterator backwards
hm_iter_prev(iter);
}
// Certain iterators also allow you to modify the contents it is iterating over
// Exceptions are collections that depend of the current state of the pair
// like tree-based collections and heap (collections that have some kind of ordering).
// You also can't change the keys of an associative collection
// Change every value where its key is divisible by 3 to the number 7
for (hm_iter_to_start(&it); !hm_iter_end(&it); hm_iter_next(&it))
{
// Get current key
int k = hm_iter_key(&it);
// Get a reference to the current value
double *v = hm_iter_rvalue(&it);
if (k % 3 == 0)
*v = 7;
}
// Now print it to see the difference
for (hashmap_iter it = my_map->it_start(my_map); !hm_iter_end(&it); hm_iter_next(&it))
{
int k = hm_iter_key(&it);
double v = hm_iter_value(&it);
size_t i = hm_iter_index(&it);
if (i == 0)
printf("[ {%d:%.2lf}, ", k, v);
else if (i == hm_count(my_map) - 1)
printf("{%d:%.2lf} ]\n", k, v);
else
printf("{%d:%.2lf}, ", k, v);
}
// Dispose the iterator called by hm_iter_new()
hm_iter_free(iter);
// Dispose the hashmap created
hm_free(my_map);
return 0;
}
+1
View File
@@ -1,3 +1,4 @@
# Hashset examples
* iterator.c - A complete example of the hashset iterator
* set_ops.c - Demonstrates common set operations like *union*, *intersection*, *difference* and *symmetric difference*.
+194
View File
@@ -0,0 +1,194 @@
/**
* iterator.c
*
* Creation Date: 15/05/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Iterator Example
*/
#include "cmc/hashset.h"
#include <stdio.h>
#include <inttypes.h>
// Int hash function
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;
}
// Int compare function
int intcmp(int a, int b)
{
return a - b;
}
// Creates a hashset of integers
HASHSET_GENERATE(hs, hashset, /* FMOD */, int)
int main(int argc, char const *argv[])
{
// Create a new hashset with an initial capacity of 100 and load factor of 0.6
hashset *my_hashset = hs_new(100, 0.6, intcmp, inthash);
// Add elements to the hashset
for (int i = 0; i < 20; i++)
{
hs_insert(my_hashset, i);
}
// Iterate from the start (index 0) to the end (index count - 1) of the hashset
for (hashset_iter it = my_hashset->it_start(my_hashset); // Initialize iterator 'it' to the start of the hashset
!hs_iter_end(&it); // Conditional stop (until it is not at the end)
hs_iter_next(&it)) // Iterator goes one position forward
{
// Access the current element
int e = hs_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = hs_iter_index(&it);
// Print hashset
// Index is useful in situations like this
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == hs_count(my_hashset) - 1)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// Index can also be used to iterate over a certain portion of a collection
size_t limit = hs_count(my_hashset) / 2;
for (hashset_iter it = my_hashset->it_start(my_hashset); !hs_iter_end(&it); hs_iter_next(&it))
{
// Access the current element
int e = hs_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = hs_iter_index(&it);
// Print hashset up until limit
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == limit - 1) // -1 because index is 0 based and we want half of the hashset
{
printf("%d ]\n", e);
break;
}
// For elements at the middle
else
printf("%d, ", e);
}
// Going backwards
for (hashset_iter it = my_hashset->it_end(my_hashset); // Initialize iterator 'it' to the end of the hashset
!hs_iter_start(&it); // Conditional stop (until it is not at the start)
hs_iter_prev(&it)) // Iterator goes one position backwards
{
// Access the current element
int e = hs_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = hs_iter_index(&it);
// Print hashset
// Note how the conditions for the first and last elements are simply swapped
// Because iterating backwards make the first element be the index count - 1
// and the last one be the index 0
// If it is the first element
if (i == hs_count(my_hashset) - 1)
printf("[ %d, ", e);
// If it is the last element
else if (i == 0)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// You can also use iterators in a while loop
// But to do so you must declare the iterator struct outside the loop first
hashset_iter it;
// You have three options:
// - Initialize it using the functions provided by the hashset [ my_hashset->it_start() and my_hashset->it_end() ]
// - Initialize it using the init() function (when the iterator is already allocated)
// - Initialize it using the new() function (allocates on the heap, pointers only)
it = my_hashset->it_start(my_hashset);
it = my_hashset->it_end(my_hashset);
// This is equivalent to it_start()
hs_iter_init(&it, my_hashset);
// For pointers
// Also equivalent to it_start()
hashset_iter *iter = hs_iter_new(my_hashset);
// The actual while loop
while (!hs_iter_end(iter))
{
// Accessing elements
int e = hs_iter_value(iter);
size_t i = hs_iter_index(iter);
// Print index and element
printf("hashset[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator forwards
hs_iter_next(iter);
}
// Send the iterator to the start of the hashset
hs_iter_to_start(iter);
// Send the iterator to the end of the hashset
hs_iter_to_end(iter);
// Backwards loop
while (!hs_iter_start(iter))
{
// Accessing elements
int e = hs_iter_value(iter);
size_t i = hs_iter_index(iter);
// Print index and element
printf("hashset[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator backwards
hs_iter_prev(iter);
}
// Certain iterators also allow you to modify the contents it is iterating over
// Exceptions are collections that depend of the current state of the element
// like tree-based collections and heap (collections that have some kind of ordering).
// You also can't change the keys of an associative collection
// In the case of a hashset or any set, this is not possible because the
// values of a set are its keys. Changing the elements could cause the set
// to be in an invalid state.
// Dispose the iterator called by hs_iter_new()
hs_iter_free(iter);
// Dispose the hashset created
hs_free(my_hashset);
return 0;
}
+6 -7
View File
@@ -14,22 +14,21 @@
// - Difference
// - Symmetric Difference
#include "cmc/hashset.h"
#include <stdio.h>
#include <stdlib.h>
#include "hashset.h"
// change to hashset to have the same effects
HASHSET_GENERATE(set, set, /* static */, int)
void print_set(set *s)
{
size_t index;
int result;
set_iter iter;
set_iter_new(&iter, s);
for (set_iter_tostart(&iter); !set_iter_end(&iter);)
set_iter_init(&iter, s);
for (set_iter_to_start(&iter); !set_iter_end(&iter); set_iter_next(&iter))
{
set_iter_next(&iter, &result, &index);
int result = set_iter_value(&iter);
size_t index = set_iter_index(&iter);
if (index == 0)
printf("[ %2d, ", result);
else if (index == s->count - 1)
+1
View File
@@ -1,3 +1,4 @@
# Heap examples
* heapsort.c - Uses the heap to sort the elements in a given array.
* iterator.c - A complete example of the heap iterator
+2 -2
View File
@@ -7,8 +7,8 @@
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/heap.h"
#include <stdio.h>
#include "heap.h"
static int intcmp(int a, int b)
{
@@ -19,7 +19,7 @@ HEAP_GENERATE(h, heap, static, int)
int main(int argc, char const *argv[])
{
heap *h = h_new(32, MaxHeap, intcmp);
heap *h = h_new(32, cmc_max_heap, intcmp);
for (int i = 1; i < 101; i++)
{
+181
View File
@@ -0,0 +1,181 @@
/**
* iterator.c
*
* Creation Date: 15/05/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Iterator Example
*/
#include "cmc/heap.h"
#include <stdio.h>
#include <inttypes.h>
// Int compare function
int intcmp(int a, int b)
{
return a - b;
}
// Creates a heap of integers
HEAP_GENERATE(h, heap, /* FMOD */, int)
int main(int argc, char const *argv[])
{
// Create a new max heap with an initial capacity of 100
heap *my_heap = h_new(100, cmc_max_heap, intcmp);
// Add elements to the heap
for (int i = 0; i < 20; i++)
{
h_insert(my_heap, i);
}
// Iterate from the start (index 0) to the end (index count - 1) of the heap
for (heap_iter it = my_heap->it_start(my_heap); // Initialize iterator 'it' to the start of the heap
!h_iter_end(&it); // Conditional stop (until it is not at the end)
h_iter_next(&it)) // Iterator goes one position forward
{
// Access the current element
int e = h_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = h_iter_index(&it);
// Print heap
// Index is useful in situations like this
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == h_count(my_heap) - 1)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// Index can also be used to iterate over a certain portion of a collection
size_t limit = h_count(my_heap) / 2;
for (heap_iter it = my_heap->it_start(my_heap); !h_iter_end(&it); h_iter_next(&it))
{
// Access the current element
int e = h_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = h_iter_index(&it);
// Print heap up until limit
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == limit - 1) // -1 because index is 0 based and we want half of the heap
{
printf("%d ]\n", e);
break;
}
// For elements at the middle
else
printf("%d, ", e);
}
// Going backwards
for (heap_iter it = my_heap->it_end(my_heap); // Initialize iterator 'it' to the end of the heap
!h_iter_start(&it); // Conditional stop (until it is not at the start)
h_iter_prev(&it)) // Iterator goes one position backwards
{
// Access the current element
int e = h_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = h_iter_index(&it);
// Print heap
// Note how the conditions for the first and last elements are simply swapped
// Because iterating backwards make the first element be the index count - 1
// and the last one be the index 0
// If it is the first element
if (i == h_count(my_heap) - 1)
printf("[ %d, ", e);
// If it is the last element
else if (i == 0)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// You can also use iterators in a while loop
// But to do so you must declare the iterator struct outside the loop first
heap_iter it;
// You have three options:
// - Initialize it using the functions provided by the heap [ my_heap->it_start() and my_heap->it_end() ]
// - Initialize it using the init() function (when the iterator is already allocated)
// - Initialize it using the new() function (allocates on the heap, pointers only)
it = my_heap->it_start(my_heap);
it = my_heap->it_end(my_heap);
// This is equivalent to it_start()
h_iter_init(&it, my_heap);
// For pointers
// Also equivalent to it_start()
heap_iter *iter = h_iter_new(my_heap);
// The actual while loop
while (!h_iter_end(iter))
{
// Accessing elements
int e = h_iter_value(iter);
size_t i = h_iter_index(iter);
// Print index and element
printf("heap[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator forwards
h_iter_next(iter);
}
// Send the iterator to the start of the heap
h_iter_to_start(iter);
// Send the iterator to the end of the heap
h_iter_to_end(iter);
// Backwards loop
while (!h_iter_start(iter))
{
// Accessing elements
int e = h_iter_value(iter);
size_t i = h_iter_index(iter);
// Print index and element
printf("heap[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator backwards
h_iter_prev(iter);
}
// Certain iterators also allow you to modify the contents it is iterating over
// Exceptions are collections that depend of the current state of the element
// like tree-based collections and heap (collections that have some kind of ordering).
// You also can't change the keys of an associative collection
// In the case of a heap this is not possible because the heap have its
// elements ordered. Changing them could cause the heap to be in an invalid
// state.
// Dispose the iterator called by h_iter_new()
h_iter_free(iter);
// Dispose the heap created
h_free(my_heap);
return 0;
}
+60
View File
@@ -0,0 +1,60 @@
/**
* deque.c
*
* Creation Date: 11/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/deque.h"
#include <stdio.h>
DEQUE_GENERATE(d, deque, static, int)
int main(int argc, char const *argv[])
{
// Initialize deque and add some elements
deque *d = d_new(10);
for (int i = 0; i < 10; i++)
{
i % 2 == 0 ? d_push_back(d, i) : d_push_front(d, i);
}
// Initialize iterator
deque_iter iter;
d_iter_init(&iter, d);
// Make the iterator go back and forward
for (int j = 0; j < 4; j++)
{
while (!d_iter_end(&iter))
{
printf("C[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter));
d_iter_next(&iter);
}
printf("\n");
while (!d_iter_start(&iter))
{
printf("C[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter));
d_iter_prev(&iter);
}
printf("\n\n");
}
for (d_iter_to_start(&iter); !d_iter_end(&iter); d_iter_next(&iter))
{
printf("D[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter));
}
printf("\n");
for (d_iter_to_end(&iter); !d_iter_start(&iter); d_iter_prev(&iter))
{
printf("D[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter));
}
d_free(d);
return 0;
}
+76
View File
@@ -0,0 +1,76 @@
/**
* hashmap.c
*
* Creation Date: 11/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/hashmap.h"
#include <stdio.h>
HASHMAP_GENERATE(hm, hmap, static, int, double)
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;
}
int intcmp(int a, int b)
{
return (a > b) - (a < b);
}
int main(int argc, char const *argv[])
{
double varr[10] = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9};
// Initialize hashmap and add some element
hmap *hm = hm_new(50, 0.9, intcmp, inthash);
for (int i = 0; i < 10; i++)
hm_insert(hm, i, varr[i]);
// Initialize iterator
hmap_iter iter;
hm_iter_init(&iter, hm);
for (int j = 0; j < 4; j++)
{
while (!hm_iter_end(&iter))
{
printf("C[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter));
hm_iter_next(&iter);
}
printf("\n");
while (!hm_iter_start(&iter))
{
printf("C[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter));
hm_iter_prev(&iter);
}
printf("\n\n");
}
for (hm_iter_to_start(&iter); !hm_iter_end(&iter); hm_iter_next(&iter))
{
printf("HM[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter));
}
printf("\n");
for (hm_iter_to_end(&iter); !hm_iter_start(&iter); hm_iter_prev(&iter))
{
printf("HM[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter));
}
hm_free(hm);
return 0;
}
+75
View File
@@ -0,0 +1,75 @@
/**
* hashset.c
*
* Creation Date: 11/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/hashset.h"
#include <stdio.h>
HASHSET_GENERATE(hs, hset, static, int)
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;
}
int intcmp(int a, int b)
{
return (a > b) - (a < b);
}
int main(int argc, char const *argv[])
{
// Initialize hashset and add some elements
hset *hs = hs_new(10, 0.9, intcmp, inthash);
for (int i = 0; i < 10; i++)
hs_insert(hs, i);
// Initialize iterator
hset_iter iter;
hs_iter_init(&iter, hs);
// Make the iterator go back and forward
for (int j = 0; j < 4; j++)
{
while (!hs_iter_end(&iter))
{
printf("C[%2d] = %2d\n", hs_iter_index(&iter), hs_iter_value(&iter));
hs_iter_next(&iter);
}
printf("\n");
while (!hs_iter_start(&iter))
{
printf("C[%2d] = %2d\n", hs_iter_index(&iter), hs_iter_value(&iter));
hs_iter_prev(&iter);
}
printf("\n\n");
}
for (hs_iter_to_start(&iter); !hs_iter_end(&iter); hs_iter_next(&iter))
{
printf("HS[%2d] = %2d\n", hs_iter_index(&iter), hs_iter_value(&iter));
}
printf("\n");
for (hs_iter_to_end(&iter); !hs_iter_start(&iter); hs_iter_prev(&iter))
{
printf("HS[%2d] = %2d\n", hs_iter_index(&iter), hs_iter_value(&iter));
}
hs_free(hs);
return 0;
}
+63
View File
@@ -0,0 +1,63 @@
/**
* heap.c
*
* Creation Date: 11/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/heap.h"
#include <stdio.h>
int intcmp(int a, int b)
{
return (a > b) - (a < b);
}
HEAP_GENERATE(h, heap, static, int)
int main(int argc, char const *argv[])
{
// Initialize heap and add some elements
heap *h = h_new(10, MaxHeap, intcmp);
for (int i = 0; i < 10; i++)
h_insert(h, i);
// Initialize iterator
heap_iter iter;
h_iter_init(&iter, h);
// Make the iterator go back and forward
for (int j = 0; j < 4; j++)
{
while (!h_iter_end(&iter))
{
printf("C[%2d] = %2d\n", h_iter_index(&iter), h_iter_value(&iter));
h_iter_next(&iter);
}
printf("\n");
while (!h_iter_start(&iter))
{
printf("C[%2d] = %2d\n", h_iter_index(&iter), h_iter_value(&iter));
h_iter_prev(&iter);
}
printf("\n\n");
}
for (h_iter_to_start(&iter); !h_iter_end(&iter); h_iter_next(&iter))
{
printf("H[%2d] = %2d\n", h_iter_index(&iter), h_iter_value(&iter));
}
printf("\n");
for (h_iter_to_end(&iter); !h_iter_start(&iter); h_iter_prev(&iter))
{
printf("H[%2d] = %2d\n", h_iter_index(&iter), h_iter_value(&iter));
}
h_free(h);
return 0;
}
+58
View File
@@ -0,0 +1,58 @@
/**
* linkedlist.c
*
* Creation Date: 11/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/linkedlist.h"
#include <stdio.h>
LINKEDLIST_GENERATE(ll, linkedlist, static, int)
int main(int argc, char const *argv[])
{
// Initialize linkedlist and add some elements
linkedlist *ll = ll_new();
for (int i = 0; i < 10; i++)
ll_push_back(ll, i);
// Initialize iterator
linkedlist_iter iter;
ll_iter_init(&iter, ll);
// Make the iterator go back and forward
for (int j = 0; j < 4; j++)
{
while (!ll_iter_end(&iter))
{
printf("C[%2d] = %2d\n", ll_iter_index(&iter), ll_iter_value(&iter));
ll_iter_next(&iter);
}
printf("\n");
while (!ll_iter_start(&iter))
{
printf("C[%2d] = %2d\n", ll_iter_index(&iter), ll_iter_value(&iter));
ll_iter_prev(&iter);
}
printf("\n\n");
}
for (ll_iter_to_start(&iter); !ll_iter_end(&iter); ll_iter_next(&iter))
{
printf("LL[%2d] = %2d\n", ll_iter_index(&iter), ll_iter_value(&iter));
}
printf("\n");
for (ll_iter_to_end(&iter); !ll_iter_start(&iter); ll_iter_prev(&iter))
{
printf("LL[%2d] = %2d\n", ll_iter_index(&iter), ll_iter_value(&iter));
}
ll_free(ll);
return 0;
}
+58
View File
@@ -0,0 +1,58 @@
/**
* list.c
*
* Creation Date: 11/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/list.h"
#include <stdio.h>
LIST_GENERATE(l, list, static, int)
int main(int argc, char const *argv[])
{
// Initialize list and add some elements
list *l = l_new(10);
for (int i = 0; i < 10; i++)
l_push_back(l, i);
// Initialize iterator
list_iter iter;
l_iter_init(&iter, l);
// Make the iterator go back and forward
for (int j = 0; j < 4; j++)
{
while (!l_iter_end(&iter))
{
printf("C[%2d] = %2d\n", l_iter_index(&iter), l_iter_value(&iter));
l_iter_next(&iter);
}
printf("\n");
while (!l_iter_start(&iter))
{
printf("C[%2d] = %2d\n", l_iter_index(&iter), l_iter_value(&iter));
l_iter_prev(&iter);
}
printf("\n\n");
}
for (l_iter_to_start(&iter); !l_iter_end(&iter); l_iter_next(&iter))
{
printf("L[%2d] = %2d\n", l_iter_index(&iter), l_iter_value(&iter));
}
printf("\n");
for (l_iter_to_end(&iter); !l_iter_start(&iter); l_iter_prev(&iter))
{
printf("L[%2d] = %2d\n", l_iter_index(&iter), l_iter_value(&iter));
}
l_free(l);
return 0;
}
+58
View File
@@ -0,0 +1,58 @@
/**
* queue.c
*
* Creation Date: 11/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/queue.h"
#include <stdio.h>
QUEUE_GENERATE(q, queue, static, int)
int main(int argc, char const *argv[])
{
// Initialize queue and add some elements
queue *q = q_new(10);
for (int i = 0; i < 10; i++)
q_enqueue(q, i);
// Initialize iterator
queue_iter iter;
q_iter_init(&iter, q);
// Make the iterator go back and forward
for (int j = 0; j < 4; j++)
{
while (!q_iter_end(&iter))
{
printf("C[%2d] = %2d\n", q_iter_index(&iter), q_iter_value(&iter));
q_iter_next(&iter);
}
printf("\n");
while (!q_iter_start(&iter))
{
printf("C[%2d] = %2d\n", q_iter_index(&iter), q_iter_value(&iter));
q_iter_prev(&iter);
}
printf("\n\n");
}
for (q_iter_to_start(&iter); !q_iter_end(&iter); q_iter_next(&iter))
{
printf("Q[%2d] = %2d\n", q_iter_index(&iter), q_iter_value(&iter));
}
printf("\n");
for (q_iter_to_end(&iter); !q_iter_start(&iter); q_iter_prev(&iter))
{
printf("Q[%2d] = %2d\n", q_iter_index(&iter), q_iter_value(&iter));
}
q_free(q);
return 0;
}
+58
View File
@@ -0,0 +1,58 @@
/**
* stack.c
*
* Creation Date: 11/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/stack.h"
#include <stdio.h>
STACK_GENERATE(s, stack, static, int)
int main(int argc, char const *argv[])
{
// Initialize stack and add some elements
stack *s = s_new(10);
for (int i = 0; i < 10; i++)
s_push(s, i);
// Initialize iterator
stack_iter iter;
s_iter_init(&iter, s);
// Make the iterator go back and forward
for (int j = 0; j < 4; j++)
{
while (!s_iter_end(&iter))
{
printf("C[%2d] = %2d\n", s_iter_index(&iter), s_iter_value(&iter));
s_iter_next(&iter);
}
printf("\n");
while (!s_iter_start(&iter))
{
printf("C[%2d] = %2d\n", s_iter_index(&iter), s_iter_value(&iter));
s_iter_prev(&iter);
}
printf("\n\n");
}
for (s_iter_to_start(&iter); !s_iter_end(&iter); s_iter_next(&iter))
{
printf("S[%2d] = %2d\n", s_iter_index(&iter), s_iter_value(&iter));
}
printf("\n");
for (s_iter_to_end(&iter); !s_iter_start(&iter); s_iter_prev(&iter))
{
printf("S[%2d] = %2d\n", s_iter_index(&iter), s_iter_value(&iter));
}
s_free(s);
return 0;
}
+64
View File
@@ -0,0 +1,64 @@
/**
* treemap.c
*
* Creation Date: 11/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/treemap.h"
#include <stdio.h>
int intcmp(int a, int b)
{
return (a > b) - (a < b);
}
TREEMAP_GENERATE(tm, tmap, static, int, double)
int main(int argc, char const *argv[])
{
double varr[10] = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9};
// Initialize treemap and add some element
tmap *hm = tm_new(intcmp);
for (int i = 0; i < 10; i++)
tm_insert(hm, i, varr[i]);
// Initialize iterator
tmap_iter iter;
tm_iter_init(&iter, hm);
for (int j = 0; j < 4; j++)
{
while (!tm_iter_end(&iter))
{
printf("C[%2d] = { %2d : %2.2lf }\n", tm_iter_index(&iter), tm_iter_key(&iter), tm_iter_value(&iter));
tm_iter_next(&iter);
}
printf("\n");
while (!tm_iter_start(&iter))
{
printf("C[%2d] = { %2d : %2.2lf }\n", tm_iter_index(&iter), tm_iter_key(&iter), tm_iter_value(&iter));
tm_iter_prev(&iter);
}
printf("\n\n");
}
for (tm_iter_to_start(&iter); !tm_iter_end(&iter); tm_iter_next(&iter))
{
printf("TM[%2d] = { %2d : %2.2lf }\n", tm_iter_index(&iter), tm_iter_key(&iter), tm_iter_value(&iter));
}
printf("\n");
for (tm_iter_to_end(&iter); !tm_iter_start(&iter); tm_iter_prev(&iter))
{
printf("TM[%2d] = { %2d : %2.2lf }\n", tm_iter_index(&iter), tm_iter_key(&iter), tm_iter_value(&iter));
}
tm_free(hm);
return 0;
}
+63
View File
@@ -0,0 +1,63 @@
/**
* treeset.c
*
* Creation Date: 11/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/treeset.h"
#include <stdio.h>
int intcmp(int a, int b)
{
return (a > b) - (a < b);
}
TREESET_GENERATE(ts, tset, static, int)
int main(int argc, char const *argv[])
{
// Initialize treeset and add some elements
tset *ts = ts_new(intcmp);
for (int i = 0; i < 10; i++)
ts_insert(ts, i);
// Initialize iterator
tset_iter iter;
ts_iter_init(&iter, ts);
// Make the iterator go back and forward
for (int j = 0; j < 4; j++)
{
while (!ts_iter_end(&iter))
{
printf("C[%2d] = %2d\n", ts_iter_index(&iter), ts_iter_value(&iter));
ts_iter_next(&iter);
}
printf("\n");
while (!ts_iter_start(&iter))
{
printf("C[%2d] = %2d\n", ts_iter_index(&iter), ts_iter_value(&iter));
ts_iter_prev(&iter);
}
printf("\n\n");
}
for (ts_iter_to_start(&iter); !ts_iter_end(&iter); ts_iter_next(&iter))
{
printf("TS[%2d] = %2d\n", ts_iter_index(&iter), ts_iter_value(&iter));
}
printf("\n");
for (ts_iter_to_end(&iter); !ts_iter_start(&iter); ts_iter_prev(&iter))
{
printf("TS[%2d] = %2d\n", ts_iter_index(&iter), ts_iter_value(&iter));
}
ts_free(ts);
return 0;
}
+1 -1
View File
@@ -1,4 +1,4 @@
# Linkedlist examples
* iterator.c - Example of using a linked list iterator.
* iterator.c - A complete example of the linked list iterator
* linked_list_node.c - Example of using functions that add or remove elements relative to a node.
+172 -23
View File
@@ -1,46 +1,195 @@
/**
* iterator.c
*
* Creation Date: 22/03/2019
* Creation Date: 10/05/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Iterator Example
*/
#include "cmc/linkedlist.h"
#include <stdio.h>
#include "linkedlist.h"
#include <inttypes.h>
LINKEDLIST_GENERATE(ll, linked, static, int)
// Creates a linkedlist of integers
LINKEDLIST_GENERATE(ll, linkedlist, /* FMOD */, int)
int main(int argc, char const *argv[])
{
size_t i;
int r;
// Create a new linkedlist
linkedlist *my_linkedlist = ll_new();
// Initliazie linked list and add some elements
linked *ll = ll_new();
// Add elements to the linkedlist
for (int i = 0; i < 20; i++)
ll_push_back(ll, i);
{
ll_push_back(my_linkedlist, i);
}
// Initialize iterator
linked_iter iter;
ll_iter_new(&iter, ll);
// Iterate from the start (index 0) to the end (index count - 1) of the linkedlist
for (linkedlist_iter it = my_linkedlist->it_start(my_linkedlist); // Initialize iterator 'it' to the start of the linkedlist
!ll_iter_end(&it); // Conditional stop (until it is not at the end)
ll_iter_next(&it)) // Iterator goes one position forward
{
// Access the current element
int e = ll_iter_value(&it);
// Move cursor to the end of the list
ll_iter_toend(&iter);
// While there is a previous element on the list
while (ll_iter_prev(&iter, &r, &i))
printf("list[%2d] = %2d\n", i, r);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = ll_iter_index(&it);
printf("\n");
// Print linkedlist
// Move cursor to the start of the list
ll_iter_tostart(&iter);
// While there is a next element on the list
while (ll_iter_next(&iter, &r, &i))
printf("list[%2d] = %2d\n", i, r);
// Index is useful in situations like this
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == ll_count(my_linkedlist) - 1)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
ll_free(ll);
// Index can also be used to iterate over a certain portion of a collection
size_t limit = ll_count(my_linkedlist) / 2;
for (linkedlist_iter it = my_linkedlist->it_start(my_linkedlist); !ll_iter_end(&it); ll_iter_next(&it))
{
// Access the current element
int e = ll_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = ll_iter_index(&it);
// Print linkedlist up until limit
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == limit - 1) // -1 because index is 0 based and we want half of the linkedlist
{
printf("%d ]\n", e);
break;
}
// For elements at the middle
else
printf("%d, ", e);
}
// Going backwards
for (linkedlist_iter it = my_linkedlist->it_end(my_linkedlist); // Initialize iterator 'it' to the end of the linkedlist
!ll_iter_start(&it); // Conditional stop (until it is not at the start)
ll_iter_prev(&it)) // Iterator goes one position backwards
{
// Access the current element
int e = ll_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = ll_iter_index(&it);
// Print linkedlist
// Note how the conditions for the first and last elements are simply swapped
// Because iterating backwards make the first element be the index count - 1
// and the last one be the index 0
// If it is the first element
if (i == ll_count(my_linkedlist) - 1)
printf("[ %d, ", e);
// If it is the last element
else if (i == 0)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// You can also use iterators in a while loop
// But to do so you must declare the iterator struct outside the loop first
linkedlist_iter it;
// You have three options:
// - Initialize it using the functions provided by the linkedlist [ my_linkedlist->it_start() and my_linkedlist->it_end() ]
// - Initialize it using the init() function (when the iterator is already allocated)
// - Initialize it using the new() function (allocates on the heap, pointers only)
it = my_linkedlist->it_start(my_linkedlist);
it = my_linkedlist->it_end(my_linkedlist);
// This is equivalent to it_start()
ll_iter_init(&it, my_linkedlist);
// For pointers
// Also equivalent to it_start()
linkedlist_iter *iter = ll_iter_new(my_linkedlist);
// The actual while loop
while (!ll_iter_end(iter))
{
// Accessing elements
int e = ll_iter_value(iter);
size_t i = ll_iter_index(iter);
// Print index and element
printf("linkedlist[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator forwards
ll_iter_next(iter);
}
// Send the iterator to the start of the linkedlist
ll_iter_to_start(iter);
// Send the iterator to the end of the linkedlist
ll_iter_to_end(iter);
// Backwards loop
while (!ll_iter_start(iter))
{
// Accessing elements
int e = ll_iter_value(iter);
size_t i = ll_iter_index(iter);
// Print index and element
printf("linkedlist[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator backwards
ll_iter_prev(iter);
}
// Certain iterators also allow you to modify the contents it is iterating over
// Exceptions are collections that depend of the current state of the element
// like tree-based collections and heap (collections that have some kind of ordering).
// You also can't change the keys of an associative collection
// Change every element that is divisible by 2 to the number 7
for (ll_iter_to_start(&it); !ll_iter_end(&it); ll_iter_next(&it))
{
// Get a reference to the current value
int *r = ll_iter_rvalue(&it);
if (r != NULL && *r % 2 == 0)
*r = 7;
}
// Now print it to see the difference
for (linkedlist_iter it = my_linkedlist->it_start(my_linkedlist); !ll_iter_end(&it); ll_iter_next(&it))
{
int e = ll_iter_value(&it);
size_t i = ll_iter_index(&it);
if (i == 0)
printf("[ %d, ", e);
else if (i == ll_count(my_linkedlist) - 1)
printf("%d ]\n", e);
else
printf("%d, ", e);
}
// Dispose the iterator called by ll_iter_new()
ll_iter_free(iter);
// Dispose the linkedlist created
ll_free(my_linkedlist);
return 0;
}
+22 -6
View File
@@ -7,13 +7,14 @@
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/linkedlist.h"
#include <stdio.h>
#include <assert.h>
#include "linkedlist.h"
#include <inttypes.h>
LINKEDLIST_GENERATE(l, list, /* static */, int)
int main(int argc, char const *argv[])
int main(void)
{
list *l = l_new();
@@ -25,14 +26,14 @@ int main(int argc, char const *argv[])
{
if (node->data % 3 == 0)
{
l_insert_prv(node, 33);
l_insert_nxt(node, 99);
l_insert_before(l, node, 33);
l_insert_after(l, node, 99);
node = node->next; // skip 99
}
}
size_t s = 0;
for (list_node *node = l_front_node(l); node != NULL; node = l_next_node(node), s++)
for (list_node *node = l_head(l); node != NULL; node = l_next_node(node), s++)
{
if (node->prev == NULL)
printf("[ %d, ", node->data);
@@ -42,7 +43,22 @@ int main(int argc, char const *argv[])
printf("%d, ", node->data);
}
printf("List Head: %d\nList Tail: %d\nList Count: %d\n", l->head->data, l->tail->data, l->count);
printf("\n\n");
s = 0;
for (list_node *node = l_tail(l); node != NULL; node = l_prev_node(node), s++)
{
if (node->next == NULL)
printf("[ %d, ", node->data);
else if (node->prev == NULL)
printf("%d ]\n", node->data);
else
printf("%d, ", node->data);
}
printf("\n\n");
printf("List Head: %d\nList Tail: %d\nList Count: %" PRIuMAX "\n", l->head->data, l->tail->data, l->count);
assert(s == l->count);
+3 -1
View File
@@ -1,3 +1,5 @@
# List examples
Currently none
* iterator.c - A complete example of the list iterator
* list.c - Example of using a list and its iterator.
* string.c - How to treat a list as a mutable string.
+195
View File
@@ -0,0 +1,195 @@
/**
* iterator.c
*
* Creation Date: 10/05/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Iterator Example
*/
#include "cmc/list.h"
#include <stdio.h>
#include <inttypes.h>
// Creates a list of integers
LIST_GENERATE(l, list, /* FMOD */, int)
int main(int argc, char const *argv[])
{
// Create a new list with an initial capacity of 100
list *my_list = l_new(100);
// Add elements to the list
for (int i = 0; i < 20; i++)
{
l_push_back(my_list, i);
}
// Iterate from the start (index 0) to the end (index count - 1) of the list
for (list_iter it = my_list->it_start(my_list); // Initialize iterator 'it' to the start of the list
!l_iter_end(&it); // Conditional stop (until it is not at the end)
l_iter_next(&it)) // Iterator goes one position forward
{
// Access the current element
int e = l_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = l_iter_index(&it);
// Print list
// Index is useful in situations like this
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == l_count(my_list) - 1)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// Index can also be used to iterate over a certain portion of a collection
size_t limit = l_count(my_list) / 2;
for (list_iter it = my_list->it_start(my_list); !l_iter_end(&it); l_iter_next(&it))
{
// Access the current element
int e = l_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = l_iter_index(&it);
// Print list up until limit
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == limit - 1) // -1 because index is 0 based and we want half of the list
{
printf("%d ]\n", e);
break;
}
// For elements at the middle
else
printf("%d, ", e);
}
// Going backwards
for (list_iter it = my_list->it_end(my_list); // Initialize iterator 'it' to the end of the list
!l_iter_start(&it); // Conditional stop (until it is not at the start)
l_iter_prev(&it)) // Iterator goes one position backwards
{
// Access the current element
int e = l_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = l_iter_index(&it);
// Print list
// Note how the conditions for the first and last elements are simply swapped
// Because iterating backwards make the first element be the index count - 1
// and the last one be the index 0
// If it is the first element
if (i == l_count(my_list) - 1)
printf("[ %d, ", e);
// If it is the last element
else if (i == 0)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// You can also use iterators in a while loop
// But to do so you must declare the iterator struct outside the loop first
list_iter it;
// You have three options:
// - Initialize it using the functions provided by the list [ my_list->it_start() and my_list->it_end() ]
// - Initialize it using the init() function (when the iterator is already allocated)
// - Initialize it using the new() function (allocates on the heap, pointers only)
it = my_list->it_start(my_list);
it = my_list->it_end(my_list);
// This is equivalent to it_start()
l_iter_init(&it, my_list);
// For pointers
// Also equivalent to it_start()
list_iter *iter = l_iter_new(my_list);
// The actual while loop
while (!l_iter_end(iter))
{
// Accessing elements
int e = l_iter_value(iter);
size_t i = l_iter_index(iter);
// Print index and element
printf("list[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator forwards
l_iter_next(iter);
}
// Send the iterator to the start of the list
l_iter_to_start(iter);
// Send the iterator to the end of the list
l_iter_to_end(iter);
// Backwards loop
while (!l_iter_start(iter))
{
// Accessing elements
int e = l_iter_value(iter);
size_t i = l_iter_index(iter);
// Print index and element
printf("list[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator backwards
l_iter_prev(iter);
}
// Certain iterators also allow you to modify the contents it is iterating over
// Exceptions are collections that depend of the current state of the element
// like tree-based collections and heap (collections that have some kind of ordering).
// You also can't change the keys of an associative collection
// Change every element that is divisible by 2 to the number 7
for (l_iter_to_start(&it); !l_iter_end(&it); l_iter_next(&it))
{
// Get a reference to the current value
int *r = l_iter_rvalue(&it);
if (r != NULL && *r % 2 == 0)
*r = 7;
}
// Now print it to see the difference
for (list_iter it = my_list->it_start(my_list); !l_iter_end(&it); l_iter_next(&it))
{
int e = l_iter_value(&it);
size_t i = l_iter_index(&it);
if (i == 0)
printf("[ %d, ", e);
else if (i == l_count(my_list) - 1)
printf("%d ]\n", e);
else
printf("%d, ", e);
}
// Dispose the iterator called by l_iter_new()
l_iter_free(iter);
// Dispose the list created
l_free(my_list);
return 0;
}
+75
View File
@@ -0,0 +1,75 @@
/**
* list.c
*
* Creation Date: 08/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/list.h"
#include <stdio.h>
LIST_GENERATE(l, list, /* FMOD */, int)
int main(int argc, char const *argv[])
{
// Create a list with internal capacity of 100
list *my_list = l_new(100);
// - push_front (index: 0) [Complexity: O(N)]
// - push (index: give) [Complexity: O(N)*]
// - push_back (index: count) [Complexity: O(1)]
//
// - pop_front (index: 0) [Complexity: O(N)]
// - pop (index: given) [Complexity: O(N)*]
// - push_back (index: count - 1) [Complexity: O(1)]
//
// *average
//
// Average list Input/Output: O(N)
for (int i = 0; i < 200; i++)
{
// Add elements to the list
l_push_back(my_list, i);
}
// Erase all values from the list
l_clear(my_list);
// Now that list is empty, add only even numbers
for (int i = 0; i < 200; i++)
{
// Add even numbers to a given index. In this case they are being added
// to the end of the list (count index == push_back). With a condition
// of being even (i % 2 == 0)
bool added = l_push_if(my_list, i, l_count(my_list), i % 2 == 0);
// If added is true, the element was added to the list
}
// Iterator
list_iter iter;
int result, sum = 0;
size_t index;
// Iterate over each element starting from the start (iter_new positions
// the iterator to the start of the list) until the end of the list.
for (l_iter_init(&iter, my_list); !l_iter_end(&iter); l_iter_next(&iter))
{
// Here index corresponds to the position of the result relative to all
// other elements in the iteration. It is only a coincidence that the
// index here is the same as the result's position in the list.
index = l_iter_index(&iter);
result = l_iter_value(&iter);
// Do whatever you want with result and index, e.g.
sum += result * index;
}
// Release resources
l_free(my_list);
return 0;
}
+163
View File
@@ -0,0 +1,163 @@
/**
* string.c
*
* Creation Date: 08/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/list.h"
#include <stdio.h>
#include <string.h>
LIST_GENERATE(str, string, /* FMOD */, char)
// Comparison function
int chrcmp(char a, char b)
{
return (a > b) - (a < b);
}
void print_str(string *str)
{
// If the buffer is not completely filled, there will be at least one null
// byte in the end of the list's contents. This printf is possible but very
// dangerous as you might end up printing something else from memory until
// a null byte.
printf("%s\n", str->buffer);
printf("Size: %llu\n", str_count(str));
}
int main(int argc, char const *argv[])
{
// How to treat a list as a mutable string without \0 at the end
char *example1 = "Lorem ipsum";
char *example2 = "dolor sit amet";
char *example3 = "consectetur";
string *my_str = str_new_from(example2, strlen(example2));
// Add a single character to the front of the list
str_push_front(my_str, ' ');
// Add a sequence of characters to the front of the list
str_prepend(my_str, example1, strlen(example1));
// Add a charater to the back of the list
str_push_back(my_str, ' ');
// Add a sequence of characters to the back of the list
str_append(my_str, example3, strlen(example3));
// Iterate through each letter and print it
string_iter iter;
str_iter_init(&iter, my_str);
size_t index;
char result;
// Printing each character
for (str_iter_to_start(&iter); !str_iter_end(&iter); str_iter_next(&iter))
{
putchar(str_iter_value(&iter));
}
printf("\n\n");
// You can also print it reversed
for (str_iter_to_end(&iter); !str_iter_start(&iter); str_iter_prev(&iter))
{
putchar(str_iter_value(&iter));
}
printf("\n\n");
// Now remove the first letter supposing we don't know where it starts
index = str_indexof(my_str, ' ', chrcmp, true);
if (index == str_count(my_str))
{
// char not found...
// Treat error
}
// Now that we know where the first word is, remove it, including the
// extra space. [from, to] are inclusive.
str_remove(my_str, 0, index);
// Print it once again
for (str_iter_to_start(&iter); !str_iter_end(&iter); str_iter_next(&iter))
{
putchar(str_iter_value(&iter));
}
printf("\nString length: %lu\n\n", str_count(my_str));
print_str(my_str);
// Removing last word.
// Finding last white space:
index = str_indexof(my_str, ' ', chrcmp, false);
// Extract last word including white space
string *str_out = str_extract(my_str, index, str_count(my_str) - 1);
if (!str_out)
printf("Could not extract string\n");
else
{
// Pop white space
str_pop_front(str_out);
for (str_iter_init(&iter, my_str); !str_iter_end(&iter); str_iter_next(&iter))
{
putchar(str_iter_value(&iter));
}
printf("\nString length: %lu\n\n", str_count(my_str));
for (str_iter_init(&iter, str_out); !str_iter_end(&iter); str_iter_next(&iter))
{
putchar(str_iter_value(&iter));
}
printf("\nString length: %lu\n", str_count(str_out));
}
// Free strings
str_free(my_str);
str_free(str_out);
printf("\n----------------------------------------\n\n");
// Another example follows
// Using prepend, insert, append, remove and extract functions
string *str = str_new(100);
str_prepend(str, "Hello World!", 12);
print_str(str);
str_insert(str, "Awesome ", 8, 6);
print_str(str);
str_append(str, " Indigo.", 8);
print_str(str);
str_remove(str, 14, 20);
print_str(str);
string *str_res = str_extract(str, 5, 12);
print_str(str);
print_str(str_res);
str_free(str);
str_free(str_res);
return 0;
}
+3
View File
@@ -0,0 +1,3 @@
# Multimap examples
* multimap.c - Basic examples of a multimap.
+77
View File
@@ -0,0 +1,77 @@
#include "multimap.h"
#include "foreach.h"
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int intcmp(int a, int b)
{
return (a > b) - (a < b);
}
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;
}
MULTIMAP_GENERATE(mm, multi_map, , int, int)
int main(int argc, char const *argv[])
{
const int min = 1, max = 201;
multi_map *map = mm_new(50, 0.8, intcmp, inthash);
printf("Multimap actual capacity: %" PRIu64 "\n", map->capacity);
printf("Adding items from %d to %d twice\n", min, max);
for (int i = min; i < max; i++)
if (!mm_insert(map, i, i))
printf("ERROR with %d:%d\n", i, i);
for (int i = min; i < max; i++)
if (!mm_insert(map, i, i))
printf("ERROR with %d:%d\n", i, i);
printf("Multimap count : %" PRIu64 "\n", map->count);
printf("Multimap capacity : %" PRIu64 "\n", map->capacity);
printf("Multimap load : %lf\n", (double)map->count / (double)map->capacity);
int64_t sum = 0;
for (int i = min; i < max; i++)
sum += mm_get(map, i);
printf("Sum (unique): %" PRId64 "\n", sum);
FOR_EACH_MAP(mm, multi_map, int, int, map, {
printf("[%3" PRIu64 "] = { %3d : %3d }\n", index, key, value);
})
printf("Removing all items\n");
for (int i = min; i < max; i++)
if (!mm_remove_all(map, i))
printf("ERROR with %d:%d\n", i, i);
sum = 0;
for (int i = min; i < max; i++)
sum += mm_get(map, i);
printf("Sum: %" PRId64 "\n", sum);
FOR_EACH_MAP(mm, multi_map, int, int, map, {
printf("[%2" PRIu64 "] = { %2d : %5d }\n", index, key, value);
})
mm_free(map);
return 0;
}
+3
View File
@@ -0,0 +1,3 @@
# Multiset examples
* multiset_operations.c - Demonstrates common multiset operations.
+119
View File
@@ -0,0 +1,119 @@
/**
* multiset_operations.c
*
* Creation Date: 01/08/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include <ext/multiset.h>
#include <utl/assert.h>
#include <inttypes.h>
#include <stdio.h>
MULTISET_GENERATE(ms, multiset, , char)
struct pair
{
char value;
size_t mul;
};
int charcmp(char a, char b)
{
return (a > b) - (a < b);
}
size_t charhash(char a)
{
return a;
}
void print_set(multiset *M)
{
cmc_assert_not_equals(ptr, NULL, M);
size_t S = ms_count(M);
printf("%s : ", ms_to_string(M).s);
if (S == 0)
{
printf("{ EMPTY SET }\n");
return;
}
for (multiset_iter it = M->it_start(M); !ms_iter_end(&it); ms_iter_next(&it))
{
size_t index = ms_iter_index(&it);
char value = ms_iter_value(&it);
size_t mul = ms_iter_multiplicity(&it);
if (index == 0)
printf("{ %c:%" PRIuMAX ", ", value, mul);
else if (index == S - 1)
printf("%c:%" PRIuMAX " }\n", value, mul);
else
printf("%c:%" PRIuMAX ", ", value, mul);
}
}
int main(int argc, char const *argv[])
{
struct pair mset1[4] = {{'a', 2}, {'b', 1}, {'c', 3}, {'d', 1}};
struct pair mset2[4] = {{'c', 1}, {'d', 3}, {'e', 1}, {'f', 2}};
multiset *A = ms_new(20, 0.6, charcmp, charhash);
multiset *B = ms_new(20, 0.6, charcmp, charhash);
for (int i = 0; i < 4; i++)
{
cmc_assert(ms_insert_many(A, mset1[i].value, mset1[i].mul));
cmc_assert(ms_insert_many(B, mset2[i].value, mset2[i].mul));
}
printf("Given two sets A and B:\n");
print_set(A);
print_set(B);
multiset *U = ms_union(A, B);
printf("\nA UNION B:\n");
print_set(U);
multiset *I = ms_intersection(A, B);
printf("\nA INTERSECTION B:\n");
print_set(I);
multiset *DA = ms_difference(A, B);
multiset *DB = ms_difference(B, A);
printf("\nA - B:\n");
print_set(DA);
printf("\nB - A:\n");
print_set(DB);
multiset *AB = ms_summation(A, B);
printf("\nA + B:\n");
print_set(AB);
multiset *BA = ms_summation(B, A);
printf("\nB + A:\n");
print_set(BA);
multiset *SD = ms_symmetric_difference(A, B);
printf("\nA SYM DIFF B:\n");
print_set(SD);
ms_free(A);
ms_free(B);
ms_free(U);
ms_free(I);
ms_free(DA);
ms_free(DB);
ms_free(AB);
ms_free(BA);
ms_free(SD);
return 0;
}
+2 -2
View File
@@ -1,5 +1,5 @@
# Other examples
* book_store - A book store where its books are loaded onto a list from a csv file. The newly added ones go to a queue of featured books where old ones are removed to give place to new ones. You can find a book by looking up its ISBN using a treemap or traversing the treemap and find all ISBNs of a corresponding title.
* separate_header_source - Example of how to used `PUBLIC` and `PRIVATE` parameters.
* for_each.c - Using the `FOR_EACH`.
* separate_header_source - Example of how to compile the header and source separately.
* for_each.c - Using the `FOR_EACH` macro.
+28 -18
View File
@@ -9,11 +9,11 @@
#include "book.c"
#include "random.c"
COLLECTION_GENERATE(LIST, PUBLIC, l, list, , , book *)
COLLECTION_GENERATE(LIST, PUBLIC, il, intlist, , , int)
COLLECTION_GENERATE(QUEUE, PUBLIC, q, queue, , , book *)
COLLECTION_GENERATE(TREEMAP, PUBLIC, map, map, , int, char *)
COLLECTION_GENERATE(TREESET, PUBLIC, set, set, , , char *)
COLLECTION_GENERATE(LIST, l, list, , , book *)
COLLECTION_GENERATE(LIST, il, intlist, , , int)
COLLECTION_GENERATE(QUEUE, q, queue, , , book *)
COLLECTION_GENERATE(TREEMAP, map, map, , int, char *)
COLLECTION_GENERATE(TREESET, set, set, , , char *)
list *load(void);
void shuffle(list *l);
@@ -48,7 +48,9 @@ int main(int argc, char const *argv[])
set *counter = set_new(chrcmp);
// Add everything to its place.
FOR_EACH(l, list, book *, books, {
FOR_EACH(l, list, books, {
book *value = l_iter_value(&iter);
// Keep the last added elements
if (q_count(shelf) > 7)
{
@@ -59,14 +61,15 @@ int main(int argc, char const *argv[])
map_insert(library, value->isbn, value->name);
set_insert(counter, value->name);
})
});
printf("Library Size: %d\n", map_count(library));
printf("Unique book titles: %d\n\n", set_count(counter));
printf("Showcase Books:\n");
FOR_EACH(q, queue, book *, shelf, {
FOR_EACH(q, queue, shelf, {
book *value = q_iter_value(&iter);
printf("[ %d : %-45s ]\n", value->isbn, value->name);
})
});
printf("\n");
set_free(counter);
@@ -113,24 +116,31 @@ int main(int argc, char const *argv[])
intlist *search_list = il_new(32);
FOR_EACH_MAP(map, map, int, char *, library, {
FOR_EACH(map, map, library, {
int key = map_iter_key(&iter);
char *value = map_iter_value(&iter);
if (chrcmp(buffer, value) == 0)
il_push_back(search_list, key);
})
});
FOR_EACH(il, intlist, int, search_list, {
printf("[ %d ]\n", value);
})
FOR_EACH(il, intlist, search_list, {
printf("[ %d ]\n", il_iter_value(&iter));
});
il_free(search_list);
}
}
// Free all memory used by struct book
FOR_EACH(l, list, book *, books, {
free(value->name);
free(value);
})
FOR_EACH(l, list, books, {
book *b = l_iter_value(&iter);
if (b)
free(b->name);
free(b);
});
l_free(books);
q_free(shelf);
+32 -20
View File
@@ -1,19 +1,19 @@
#include "macro_collections.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "macro_collections.h"
// Create containers to use only in this file
COLLECTION_GENERATE(LIST, PUBLIC, l, list, static, , int)
COLLECTION_GENERATE(LINKEDLIST, PUBLIC, ll, llist, static, , int)
COLLECTION_GENERATE(STACK, PUBLIC, s, stack, static, , int)
COLLECTION_GENERATE(QUEUE, PUBLIC, q, queue, static, , int)
COLLECTION_GENERATE(DEQUE, PUBLIC, d, deque, static, , int)
COLLECTION_GENERATE(TREESET, PUBLIC, ts, tset, static, , int)
COLLECTION_GENERATE(LIST, l, list, static, , int)
COLLECTION_GENERATE(LINKEDLIST, ll, llist, static, , int)
COLLECTION_GENERATE(STACK, s, stack, static, , int)
COLLECTION_GENERATE(QUEUE, q, queue, static, , int)
COLLECTION_GENERATE(DEQUE, d, deque, static, , int)
COLLECTION_GENERATE(TREESET, ts, tset, static, , int)
int intcmp(int a, int b)
{
return a - b;
return (a > b) - (a < b);
}
int main(int argc, char const *argv[])
@@ -58,59 +58,71 @@ int main(int argc, char const *argv[])
// - value : the elements that changes with each iteration
// - index : iteration index (first iteration is 0 and last is count - 1)
// - iter : iterator struct
FOR_EACH(l, list, int, l, {
FOR_EACH(l, list, l, {
int value = l_iter_value(&iter);
size_t index = l_iter_index(&iter);
if (index == 0)
printf("[ %d, ", value);
else if (index == iter.target->count - 1)
printf("%d ]\n", value);
else
printf("%d, ", value);
})
});
FOR_EACH(s, stack, int, s, {
FOR_EACH(s, stack, s, {
int value = s_iter_value(&iter);
size_t index = s_iter_index(&iter);
if (index == 0)
printf("[ %d, ", value);
else if (index == iter.target->count - 1)
printf("%d ]\n", value);
else
printf("%d, ", value);
})
});
FOR_EACH(q, queue, int, q, {
FOR_EACH(q, queue, q, {
int value = q_iter_value(&iter);
size_t index = q_iter_index(&iter);
if (index == 0)
printf("[ %d, ", value);
else if (index == iter.target->count - 1)
printf("%d ]\n", value);
else
printf("%d, ", value);
})
});
FOR_EACH(d, deque, int, d, {
FOR_EACH(d, deque, d, {
int value = d_iter_value(&iter);
size_t index = d_iter_index(&iter);
if (index == 0)
printf("[ %d, ", value);
else if (index == iter.target->count - 1)
printf("%d ]\n", value);
else
printf("%d, ", value);
})
});
FOR_EACH(ll, llist, int, ll, {
FOR_EACH(ll, llist, ll, {
int value = ll_iter_value(&iter);
size_t index = ll_iter_index(&iter);
if (index == 0)
printf("[ %d, ", value);
else if (index == iter.target->count - 1)
printf("%d ]\n", value);
else
printf("%d, ", value);
})
});
FOR_EACH(ts, tset, int, ts, {
FOR_EACH(ts, tset, ts, {
int value = ts_iter_value(&iter);
size_t index = ts_iter_index(&iter);
if (index == 0)
printf("[ %d, ", value);
else if (index == iter.target->count - 1)
printf("%d ]\n", value);
else
printf("%d, ", value);
})
});
l_free(l);
ll_free(ll);
@@ -1,6 +1,6 @@
#include "containers.h"
COLLECTION_GENERATE_SOURCE(LIST, PUBLIC, il, int_list, , , int)
COLLECTION_GENERATE_SOURCE(STACK, PRIVATE, cs, char_stack, , , char)
COLLECTION_GENERATE_SOURCE(QUEUE, PUBLIC, queue, index_queue, , , size_t)
COLLECTION_GENERATE_SOURCE(DEQUE, PUBLIC, dq, deque, , , int)
COLLECTION_GENERATE_SOURCE(LIST, il, int_list, , , int)
COLLECTION_GENERATE_SOURCE(STACK, cs, char_stack, , , char)
COLLECTION_GENERATE_SOURCE(QUEUE, queue, index_queue, , , size_t)
COLLECTION_GENERATE_SOURCE(DEQUE, dq, deque, , , int)
@@ -3,7 +3,7 @@
#include <stdbool.h>
#include "macro_collections.h"
COLLECTION_GENERATE_HEADER(LIST, PUBLIC, il, int_list, , , int)
COLLECTION_GENERATE_HEADER(STACK, PRIVATE, cs, char_stack, , , char)
COLLECTION_GENERATE_HEADER(QUEUE, PUBLIC, queue, index_queue, , , size_t)
COLLECTION_GENERATE_HEADER(DEQUE, PUBLIC, dq, deque, , , int)
COLLECTION_GENERATE_HEADER(LIST, il, int_list, , , int)
COLLECTION_GENERATE_HEADER(STACK, cs, char_stack, , , char)
COLLECTION_GENERATE_HEADER(QUEUE, queue, index_queue, , , size_t)
COLLECTION_GENERATE_HEADER(DEQUE, dq, deque, , , int)
@@ -184,10 +184,9 @@ int main(void)
il_push_back(integers, i);
int sum = 0;
FOR_EACH(il, int_list, int, integers, {
printf("%d, ", value);
sum += value;
})
FOR_EACH(il, int_list, integers, {
sum += il_iter_value(&iter);
});
printf("\n\nSUM: %d\n", sum);
@@ -255,9 +254,9 @@ int main(void)
int sum3 = 0;
FOR_EACH(dq, deque, int, d, {
sum3 += value;
})
FOR_EACH(dq, deque, d, {
sum3 += dq_iter_value(&iter);
});
printf("Deque sum: %d\n", sum3);
+29
View File
@@ -0,0 +1,29 @@
CFLAGS = -Wall -Wextra -g
LIB = pthread
INCLUDE = ../../../src
VFLAGS = --leak-check=full
EXAMPLES = ex1.txt ex2.txt ex3.txt ex4.txt ex5.txt ex6.txt
SOURCES = ../../../src/cmc/deque.h \
../../../src/cmc/hashmap.h \
../../../src/cmc/hashset.h \
../../../src/cmc/heap.h \
../../../src/cmc/linkedlist.h \
../../../src/cmc/list.h \
../../../src/cmc/queue.h \
../../../src/cmc/stack.h \
../../../src/cmc/treemap.h \
../../../src/cmc/treeset.h \
main: counter.c
gcc counter.c $(CFLAGS) -I $(INCLUDE) -l$(LIB)
example: main $(EXAMPLES)
./a.out $(EXAMPLES)
valgrind: main $(EXAMPLES)
valgrind $(VFLAGS) ./a.out $(EXAMPLES)
source: main
./a.out $(SOURCES)
+269
View File
@@ -0,0 +1,269 @@
/**
* counter.c
*
* Creation Date: 05/07/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* A multi-threading word counter in C using the C Macro Collections library
* and the pthread library.
*/
#include <cmc/hashmap.h>
#include <cmc/heap.h>
#include <cmc/list.h>
#include <ctype.h>
#include <inttypes.h>
#include <pthread.h>
#include <sac/stack.h>
#include <stdio.h>
#define CMC_LOG_COLOR
#include <utl/log.h>
// Maximum number of threads
#define n_threads 100
/* HashMap mutex */
pthread_mutex_t table_mutex = PTHREAD_MUTEX_INITIALIZER;
/* printf, fprintf mutex */
pthread_mutex_t print_mutex = PTHREAD_MUTEX_INITIALIZER;
/* A pair of word and number of how many times that word has appeared */
/* This will be used by Heap */
typedef struct wc_pair_s
{
char *word;
size_t count;
} wc_pair;
/* A stack allocated stack to keep track of each thread id */
SAC_STACK_GENERATE(tl, TList, , pthread_t, n_threads)
/* A list used as a dynamic string */
LIST_GENERATE(str, String, , char)
/* A mapping between word and word count */
HASHMAP_GENERATE(hm, HashMap, , char *, size_t)
/* Used by HashMap to hash its keys (char *) */
size_t djb2(char *str)
{
size_t hash = 5381;
int c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
/* Used by HashMap to compare its keys (char *) */
int chrcmp(char *a, char *b)
{
return strcmp(a, b);
}
/* Heap used to sort the { word : word_count } pairs */
HEAP_GENERATE(hp, Heap, , wc_pair)
/* Used by Heap to sort wc_pair */
int cmp_wcpair(wc_pair p1, wc_pair p2)
{
/* Sort by count, then by word */
int cmp = (p1.count > p2.count) - (p1.count < p2.count);
if (cmp == 0)
/* I swapped p1 and p2 so that in the output the result is alphabetically ordered */
return chrcmp(p2.word, p1.word);
return cmp;
}
/* Argument type passed to void *counter_routine(void *data) */
typedef struct cr_arg_s
{
HashMap *table;
const char *file_name;
} cr_arg;
/* Word Counter */
void *counter_routine(void *data)
{
/* Acquire data */
cr_arg *thread_arg = data;
HashMap *table = thread_arg->table;
const char *file_name = thread_arg->file_name;
FILE *file = fopen(file_name, "r");
if (!file)
{
pthread_mutex_lock(&print_mutex);
fprintf(stderr, "Failed to open file %s\n", file_name);
pthread_mutex_unlock(&print_mutex);
return NULL;
}
int ch = 0;
String *word = str_new(100);
/* Begin reading file */
/* Whenever a word is found, add it to the HashMap */
while ((ch = fgetc(file)) != EOF)
{
/* Normalize */
ch = tolower(ch);
/* Stop when is a space character or punctuation */
/* Only count alphabetical letter */
if ( ( isspace(ch) || ispunct(ch) ) && !str_empty(word) )
{
str_push_back(word, 0);
char *key = strdup(word->buffer);
pthread_mutex_lock(&table_mutex);
size_t *num = hm_get_ref(table, key);
if (num == NULL)
hm_insert(table, key, 1);
else
{
*num += 1;
free(key);
key = NULL;
}
pthread_mutex_unlock(&table_mutex);
str_clear(word);
}
else if (isalpha(ch))
{
str_push_back(word, ch);
}
}
str_free(word);
fclose(file);
return NULL;
}
int main(int argc, char const *argv[])
{
/* Check arguments*/
if (argc > n_threads)
{
fprintf(stderr, "Sorry but no more than %d arguments\n", n_threads);
return 2;
}
else if (argc == 1)
{
fprintf(stderr, "Usage:\n %s path/to/file.txt path/to/another/file.txt\n", argv[0]);
return 1;
}
cr_arg *thread_args = calloc(n_threads, sizeof(cr_arg));
/* Threads id storage */
TList ts = tl_new();
/* Resulting word - word_count mapping */
HashMap *result = hm_new(100000, 0.6, chrcmp, djb2);
/* Create one thread for each file */
for (int i = 1; i < argc; i++)
{
thread_args[i - 1].table = result;
thread_args[i - 1].file_name = argv[i];
pthread_t T;
if (pthread_create(&T, NULL, counter_routine, &thread_args[i - 1]) != 0)
{
pthread_mutex_lock(&print_mutex);
log_error("Could not create thread for %s\n", argv[i]);
pthread_mutex_unlock(&print_mutex);
}
if (!tl_push(&ts, T))
{
pthread_mutex_lock(&print_mutex);
log_error("Could not push to stack %lu", T);
pthread_mutex_unlock(&print_mutex);
}
}
/* Wait for all threads to finish */
for (TList_iter iter = ts.it_start(&ts); !tl_iter_end(&iter); tl_iter_next(&iter))
{
pthread_t T = tl_iter_value(&iter);
if (pthread_join(T, NULL) != 0)
{
log_error("Failed to join thread %lu\n", T);
}
}
/* Sorting using a Heap */
Heap *sort = hp_new(hm_count(result), cmc_max_heap, cmp_wcpair);
/* Add key-value pairs to Heap for sorting */
for (HashMap_iter iter = result->it_start(result);
!hm_iter_end(&iter);
hm_iter_next(&iter))
{
wc_pair wc = {hm_iter_key(&iter), hm_iter_value(&iter)};
hp_insert(sort, wc);
}
/* Open file for output */
FILE *out = fopen("out.txt", "w");
if (!out)
{
fprintf(stderr, "Failed to create file %s\n", "out.txt");
}
else
{
fprintf(out, "A total of %" PRIuMAX " unique words were found\n\n", hp_count(sort));
/* Until heap is exausted, print the pair into the file */
while (!hp_empty(sort))
{
wc_pair wc;
if (!hp_remove(sort, &wc))
{
fprintf(stderr, "Failed to remove element from heap");
}
else
{
fprintf(out, "%s, %" PRIuMAX "\n", wc.word, wc.count);
free(wc.word);
}
}
fclose(out);
}
hp_free(sort);
hm_free(result);
free(thread_args);
return 0;
}
+24
View File
@@ -0,0 +1,24 @@
Man, I'm sore all over. I feel like I just went ten rounds with mighty Thor.
I'm a thing. But I've never been to the moon! Bender, this is Fry's decision… and he made it wrong. So it's time for us to interfere in his life. Five hours? Aw, man! Couldn't you just get me the death penalty?
Shut up and get to the point! But I know you in the future. I cleaned your poop. Good man. Nixon's pro-war and pro-family. I usually try to keep my sadness pent up inside where it can fester quietly as a mental illness.
Robot 1-X, save my friends! And Zoidberg!
Bender, this is Fry's decision… and he made it wrong. So it's time for us to interfere in his life. Why would a robot need to drink? I can explain. It's very valuable. Ow, my spirit!
Calculon is gonna kill us and it's all everybody else's fault!
Of all the friends I've had… you're the first.
I'm Santa Claus!
Yeah, lots of people did.
My fellow Earthicans, as I have explained in my book 'Earth in the Balance'', and the much more popular ''Harry Potter and the Balance of Earth', we need to defend our planet against pollution. Also dark wizards. I videotape every customer that comes in here, so that I may blackmail them later.
Ask her how her day was.
If rubbin' frozen dirt in your crotch is wrong, hey I don't wanna be right.
And so we say goodbye to our beloved pet, Nibbler, who's gone to a place where I, too, hope one day to go. The toilet.
Guards! Bring me the forms I need to fill out to have her taken away! Now what? Fry! Quit doing the right thing, you jerk! It doesn't look so shiny to me. Who said that? SURE you can die! You want to die?!
And until then, I can never die? Shinier than yours, meatbag. Oh no! The professor will hit me! But if Zoidberg 'fixes' it… then perhaps gifts! Look, last night was a mistake.
Tell them I hate them. Have you ever tried just turning off the TV, sitting down with your children, and hitting them? You'll have all the Slurm you can drink when you're partying with Slurms McKenzie!
Fetal stemcells, aren't those controversial? You, minion. Lift my arm. AFTER HIM! OK, if everyone's finished being stupid. Kif might! Stop! Don't shoot fire stick in space canoe! Cause explosive decompression!
Alright, let's mafia things up a bit. Joey, burn down the ship. Clamps, burn down the crew. You don't know how to do any of those. Uh, is the puppy mechanical in any way? I've been there. My folks were always on me to groom myself and wear underpants. What am I, the pope?
Why not indeed! I'll tell them you went down prying the wedding ring off his cold, dead finger. Too much work. Let's burn it and say we dumped it in the sewer. Hey! I'm a porno-dealing monster, what do I care what you think?
WINDMILLS DO NOT WORK THAT WAY! GOOD NIGHT! Ah, the 'Breakfast Club' soundtrack! I can't wait til I'm old enough to feel ways about stuff! No! Don't jump! Michelle, I don't regret this, but I both rue and lament it.
Why would I want to know that? Well I'da done better, but it's plum hard pleading a case while awaiting trial for that there incompetence. Take me to your leader! Humans dating robots is sick. You people wonder why I'm still single? It's 'cause all the fine robot sisters are dating humans!
Isn't it true that you have been paid for your testimony? Why am I sticky and naked? Did I miss something fun? Whoa a real live robot; or is that some kind of cheesy New Year's costume? Yep, I remember. They came in last at the Olympics, then retired to promote alcoholic beverages!
Fry, we have a crate to deliver. These old Doomsday Devices are dangerously unstable. I'll rest easier not knowing where they are. No! The cat shelter's on to me. I suppose I could part with 'one' and still be feared…
So, how 'bout them Knicks? It's just like the story of the grasshopper and the octopus. All year long, the grasshopper kept burying acorns for winter, while the octopus mooched off his girlfriend and watched TV. But then the winter came, and the grasshopper died, and the octopus ate all his acorns. Also he got a race car. Is any of this getting through to you?
+10
View File
@@ -0,0 +1,10 @@
If you get asteroids about a kilometer in size, those are large enough and carry enough energy into our system to disrupt transportation, communication, the food chains, and that can be a really bad day on Earth.
In the animal kingdom, one of the keys to survival is to outwit your enemies. And when you're surrounded by carnivores, one of the best strategies is to fade into the background and disappear.
Most religious people in America fully embrace science. So the argument that religion has some issue with science applies to a small fraction of those who declare that they are religious. They just happen to be a very vocal fraction, so you got the impression that there are more of them than there actually is.
Do you realize that if you fall into a black hole, you will see the entire future of the Universe unfold in front of you in a matter of moments and you will emerge into another space-time created by the singularity of the black hole you just fell into?
When you put money directly to a problem, it makes a good headline. It makes a good campaign slogan. You get to claim that you've engaged in these activities within an election cycle. But certain investments take longer than an election cycle.
We have bred multiple generations of people who have not experienced knowing where you are the moment a news story broke, with that news story being great and grand and something that elevates society instead of diminishes it.
We think scientific literacy flows out of how many science facts can you recite rather than how was your brain wired for thinking. And it's the brain wiring that I'm more interested in rather than the facts that come out of the curriculum or the lesson plan that's been proposed.
What you need, above all else, is a love for your subject, whatever it is. You've got to be so deeply in love with your subject that when curve balls are thrown, when hurdles are put in place, you've got the energy to overcome them.
We didn't build the interstate system to connect New York to Los Angeles because the West Coast was a priority. No, we webbed the highways so people can go to multiple places and invent ways of doing things not thought of by the persons building the roads.
Stephen Hawking's been watching too many Hollywood movies. I think the only kind aliens in Hollywood are the ones created by Steven Spielberg - 'Close Encounters of the Third Kind' and 'E.T.,' for example. All other aliens are trying to suck our brains out.
+6
View File
@@ -0,0 +1,6 @@
Enlightenment snare transvaluation love right insofar madness zarathustra. God sexuality endless free disgust hatred hope. Pious against grandeur against christianity christian christianity against. Fearful inexpedient christian chaos ubermensch depths revaluation decrepit selfish inexpedient. Of society good oneself reason oneself. Eternal-return ocean spirit spirit evil society mountains. Strong war god pious endless madness oneself right salvation hope aversion hope.
Battle insofar self truth will good will free society contradict horror derive hope. Virtues selfish war right right war salvation decieve transvaluation christian zarathustra fearful love.
Superiority fearful law love sea burying decieve. Will against abstract snare reason truth noble of inexpedient. Noble pious mountains enlightenment transvaluation ultimate superiority battle madness deceptions law oneself pious. Revaluation morality society intentions decrepit inexpedient.
Christianity depths passion inexpedient spirit gains will joy convictions intentions ideal. Sea against ultimate burying inexpedient evil. Overcome fearful insofar right contradict depths love hope love. Noble intentions war derive snare dead insofar.
Faith philosophy abstract pinnacle war ocean philosophy free. Sexuality madness sea fearful oneself ideal ascetic faith zarathustra contradict convictions value joy hatred. Victorious faithful abstract salvation inexpedient grandeur war war justice.
Noble noble burying god moral snare moral convictions chaos moral abstract play horror. Pious will mountains decieve.
+10
View File
@@ -0,0 +1,10 @@
My capacity is full no scraps hit the floor agile and we don't need to boil the ocean here get all your ducks in a row, nor run it up the flag pole. Time vampire. Bottleneck mice can we take this offline, and scope creep. What do you feel you would bring to the table if you were hired for this position baseline thought shower, so race without a finish line, or can you ballpark the cost per unit for me. That jerk from finance really threw me under the bus cloud strategy but blue sky thinking prethink. Meeting assassin waste of resources. Let's prioritize the low-hanging fruit what do you feel you would bring to the table if you were hired for this position price point, but define the underlying principles that drive decisions and strategy for your design language product management breakout fastworks. Level the playing field. Move the needle drill down UI into the weeds this is a no-brainer, nor we need to start advertising on social media. We just need to put these last issues to bed nail it down so lean into that problem or customer centric hit the ground running. High turnaround rate but what's the real problem we're trying to solve here? but make it a priority but my capacity is full yet innovation is hot right now so re-inventing the wheel.
Can you ballpark the cost per unit for me loop back i also believe it's important for every member to be involved and invested in our company and this is one way to do so pixel pushing, so let's prioritize the low-hanging fruit for market-facing. Move the needle what about scaling components to a global audience? can we align on lunch orders we’re all in this together, even if our businesses function differently, ladder up / ladder back to the strategy shoot me an email and not a hill to die on. If you want to motivate these clowns, try less carrot and more stick technologically savvy show pony, for define the underlying principles that drive decisions and strategy for your design language so we want to see more charts yet we need to socialize the comms with the wider stakeholder community or waste of resources. Teams were able to drive adoption and awareness. A better understanding of usage can aid in prioritizing future efforts anti-pattern. Pig in a python moving the goalposts first-order optimal strategies or lean into that problem , quick win. We need to leverage our synergies. Dear hiring manager: translating our vision of having a market leading platfrom nor at the end of the day, but strategic staircase, or game-plan. Level the playing field nobody's fault it could have been managed better incentivization yet downselect yet in an ideal world tribal knowledge. Paddle on both sides helicopter view, and c-suite. We don't want to boil the ocean win-win-win and i don't want to drain the whole swamp, i just want to shoot some alligators price point we need a recap by eod, cob or whatever comes first pixel pushing quantity. Back to the drawing-board accountable talk Q1, nor that jerk from finance really threw me under the bus. Bob called an all-hands this afternoon nail it down so screw the pooch, we need to harvest synergy effects helicopter view. Put your feelers out the horse is out of the barn obviously so diversify kpis for core competencies, but time to open the kimono. Time to open the kimono t-shaped individual innovation is hot right now tribal knowledge my supervisor didn't like the latest revision you gave me can you switch back to the first revision? thinking outside the box, but high performance keywords. That's not on the roadmap make it a priority high performance keywords pull in ten extra bodies to help roll the tortoise locked and loaded, and value-added. The horse is out of the barn minimize backwards overflow. What's our go to market strategy? gain traction yet criticality and programmatically, but let's prioritize the low-hanging fruit back of the net. Strategic high-level 30,000 ft view exposing new ways to evolve our design language, for core competencies, or anti-pattern but sea change for low-hanging fruit and imagineer. Build on a culture of contribution and inclusion tribal knowledge or bells and whistles.
Can you send me an invite? cloud strategy. First-order optimal strategies. Cannibalize back to the drawing-board strategic fit low engagement. Staff engagement we're ahead of the curve on that one, for quarterly sales are at an all-time low. Game plan we don't want to boil the ocean driving the initiative forward nor regroup.
Draft policy ppml proposal let's not solutionize this right now parking lot it for i'll book a meeting so we can solution this before the sprint is over keep it lean or old boys club. Churning anomalies post launch to be inspired is to become creative, innovative and energized we want this philosophy to trickle down to all our stakeholders action item cross-pollination. But what's the real problem we're trying to solve here?. Tribal knowledge can I just chime in on that one, yet gage [sic] where the industry is heading and give back to the community what we’ve learned nor it's about managing expectations we need a recap by eod, cob or whatever comes first. Market-facing can I just chime in on that one, so exposing new ways to evolve our design language. Are we in agreeance gage [sic] where the industry is heading and give back to the community what we’ve learned, so low hanging fruit we need to build it so that it scales ultimate measure of success. Downselect into the weeds, but back of the net. Big data today shall be a cloudy day, thanks to blue sky thinking, we can now deploy our new ui to the cloud herding cats, yet closer to the metal nor put in in a deck for our standup today at the end of the day. Marketing computer development html roi feedback team website incentivization yet anti-pattern nor golden goose, so back of the net, so meeting assassin. Strategic staircase drink the Kool-aid design thinking, but blue money. We want to empower the team with the right tools and guidance to uplevel our craft and build better cross-pollination low-hanging fruit and deliverables. Imagineer roll back strategy can you ballpark the cost per unit for me. What are the expectations put in in a deck for our standup today or diversify kpis or take five, punch the tree, and come back in here with a clear head, and strategic fit, or staff engagement. Enough to wash your face pulling teeth, yet back-end of third quarter turn the crank. Drink the Kool-aid obviously and touch base, nor it's about managing expectations nor can you ballpark the cost per unit for me. High-level driving the initiative forward. Guerrilla marketing. Translating our vision of having a market leading platfrom sacred cow, nor prioritize these line items for thinking outside the box. Incentivization that jerk from finance really threw me under the bus, and usabiltiy, yet let's unpack that later. Poop personal development. PowerPointless push back for sea change nor pushback.
Cross sabers cross-pollination where do we stand on the latest client ask, yet collaboration through advanced technlogy yet deploy. Single wringable neck hit the ground running can you send me an invite?. Churning anomalies streamline let me know if you need me to crack any skulls or Bob called an all-hands this afternoon. Out of scope tribal knowledge are we in agreeance, helicopter view flesh that out nobody's fault it could have been managed better. Gain traction hard stop. Customer centric please use "solutionise" instead of solution ideas! :) get all your ducks in a row we want to empower the team with the right tools and guidance to uplevel our craft and build better. Hit the ground running new economy. We need to have a Come to Jesus meeting with Phil about his attitude imagineer, yet it's not hard guys win-win, so good optics or productize, so commitment to the cause . Going forward. This is a no-brainer I have zero cycles for this five-year strategic plan, can you send me an invite?. Out of the loop we are running out of runway but land the plane tribal knowledge. Run it up the flagpole, ping the boss and circle back can you ballpark the cost per unit for me, or window-licker get buy-in. Root-and-branch review when does this sunset? but draft policy ppml proposal can I just chime in on that one. Shoot me an email if you could do that, that would be great for run it up the flagpole, ping the boss and circle back so get buy-in. Window of opportunity technologically savvy. Bottleneck mice strategic staircase, programmatically. Upsell we need to button up our approach. Back of the net going forward cannibalize regroup and value-added.
Race without a finish line blue sky. We just need to put these last issues to bed innovation is hot right now. Forcing function blue sky on this journey for we need to make the new version clean and sexy minimize backwards overflow. Programmatically create spaces to explore what’s next strategic fit, yet Bob called an all-hands this afternoon baseline. Bottleneck mice. Deliverables. Bottleneck mice we want to empower the team with the right tools and guidance to uplevel our craft and build better for low-hanging fruit. Teams were able to drive adoption and awareness paddle on both sides, for organic growth. Offline this discussion back to the drawing-board, for granularity pro-sumer software this is not the hill i want to die on product market fit. Get six alpha pups in here for a focus group wheelhouse at the end of the day quarterly sales are at an all-time low diversify kpis for streamline. Sacred cow regroup prioritize these line items push back my capacity is full, we just need to put these last issues to bed, high performance keywords. Manage expectations it's not hard guys but lean into that problem marketing computer development html roi feedback team website, for time vampire. Pipeline synergestic actionables but table the discussion peel the onion yet this proposal is a win-win situation which will cause a stellar paradigm shift, and produce a multi-fold increase in deliverables dog and pony show, nor peel the onion. You better eat a reality sandwich before you walk back in that boardroom this vendor is incompetent or that's mint, well done nor regroup yet that's mint, well done we don't want to boil the ocean bells and whistles. That ipo will be a game-changer deep dive goalposts t-shaped individual. Touch base proceduralize. Overcome key issues to meet key milestones not a hill to die on bake it in. Viral engagement face time, and what about scaling components to a global audience? win-win, nor staff engagement. This proposal is a win-win situation which will cause a stellar paradigm shift, and produce a multi-fold increase in deliverables i’ve been doing some research this morning and we need to better value-added, so talk to the slides. Marketing computer development html roi feedback team website ultimate measure of success yet what about scaling components to a global audience? but show pony. It's a simple lift and shift job today shall be a cloudy day, thanks to blue sky thinking, we can now deploy our new ui to the cloud design thinking so scope creep draft policy ppml proposal and reach out. Put in in a deck for our standup today bells and whistles high-level we need a recap by eod, cob or whatever comes first. What's our go to market strategy?. Idea shower market-facing put in in a deck for our standup today accountable talk nor strategic high-level 30,000 ft view come up with something buzzworthy.
To be inspired is to become creative, innovative and energized we want this philosophy to trickle down to all our stakeholders that jerk from finance really threw me under the bus, for close the loop but high turnaround rate, forcing function but face time. Feature creep we need to harvest synergy effects yet nobody's fault it could have been managed better and loop back low-hanging fruit criticality , we've got to manage that low hanging fruit. Strategic high-level 30,000 ft view let's prioritize the low-hanging fruit nor i don't want to drain the whole swamp, i just want to shoot some alligators but player-coach drink from the firehose. Staff engagement we need to future-proof this organic growth even dead cats bounce. Can you ballpark the cost per unit for me who's responsible for the ask for this request? cloud strategy. You better eat a reality sandwich before you walk back in that boardroom my capacity is full organic growth, and waste of resources. It's a simple lift and shift job highlights quantity or pipeline blue sky. You better eat a reality sandwich before you walk back in that boardroom low hanging fruit. Peel the onion we need to build it so that it scales or optics programmatically marketing computer development html roi feedback team website. Low-hanging fruit prethink, yet when does this sunset? and crisp ppt for circle back work flows . Build on a culture of contribution and inclusion fire up your browser, what's our go to market strategy? so we need to future-proof this powerPointless. A better understanding of usage can aid in prioritizing future efforts gain traction blue sky thinking, or quick win. Regroup at the end of the day old boys club when does this sunset? , it just needs more cowbell. High performance keywords. Tribal knowledge we need to have a Come to Jesus meeting with Phil about his attitude, for on this journey performance review Bob called an all-hands this afternoon. Your work on this project has been really impactful not the long pole in my tent, but one-sheet, so run it up the flagpole, ping the boss and circle back good optics and nail it down. Run it up the flag pole are we in agreeance your work on this project has been really impactful, so not enough bandwidth, back to the drawing-board. Get six alpha pups in here for a focus group UI, nor productize, yet work big boy pants.
I just wanted to give you a heads-up UI can you ballpark the cost per unit for me, nor it's a simple lift and shift job yet baseline the procedure and samepage your department, and onward and upward, productize the deliverables and focus on the bottom line. Big picture it just needs more cowbell. Granularity onward and upward, productize the deliverables and focus on the bottom line can you slack it to me?, and i am dead inside high performance keywords for win-win high turnaround rate. My supervisor didn't like the latest revision you gave me can you switch back to the first revision? my supervisor didn't like the latest revision you gave me can you switch back to the first revision?. Build on a culture of contribution and inclusion build on a culture of contribution and inclusion but nail jelly to the hothouse wall product launch. Deliverables. Put your feelers out. Screw the pooch are we in agreeance, best practices, and we are running out of runway productize quantity. PowerPointless pre launch yet this is meaningless. Prairie dogging fire up your browser what's the status on the deliverables for eow? overcome key issues to meet key milestones. Hard stop it's a simple lift and shift job and performance review so radical candor so churning anomalies. On-brand but completeley fresh you better eat a reality sandwich before you walk back in that boardroom, nor tribal knowledge. Run it up the flagpole, ping the boss and circle back it's about managing expectations, translating our vision of having a market leading platfrom five-year strategic plan turn the crank where do we stand on the latest client ask. It just needs more cowbell. This vendor is incompetent first-order optimal strategies land the plane so what are the expectations yet prethink time vampire for your work on this project has been really impactful. Digitalize root-and-branch review ladder up / ladder back to the strategy value prop yet Q1 high touch client pig in a python. I am dead inside. What's our go to market strategy? touch base, and run it up the flagpole, ping the boss and circle back. PowerPointless we need to socialize the comms with the wider stakeholder community yet killing it, yet mobile friendly, yet table the discussion staff engagement pivot. The last person we talked to said this would be ready great plan! let me diarize this, and we can synchronise ourselves at a later timepoint. Can we align on lunch orders. Blue sky that ipo will be a game-changer. Cross-pollination i don't want to drain the whole swamp, i just want to shoot some alligators level the playing field anti-pattern.
Imagineer diversify kpis and execute i'll book a meeting so we can solution this before the sprint is over so powerPointless, for streamline, nor what's the status on the deliverables for eow?. That jerk from finance really threw me under the bus great plan! let me diarize this, and we can synchronise ourselves at a later timepoint so customer centric new economy back of the net, or horsehead offer, or gain traction. Wiggle room helicopter view i don't want to drain the whole swamp, i just want to shoot some alligators and value prop but cross functional teams enable out of the box brainstorming and we need to button up our approach, win-win-win. Who's responsible for the ask for this request? synergize productive mindfulness. Organic growth herding cats. Personal development. Marketing computer development html roi feedback team website. This is a no-brainer are we in agreeance. Touch base on-brand but completeley fresh. Granularity. Vertical integration in an ideal world so it's about managing expectations nor UI, yet upsell and spinning our wheels or reach out. Loop back vertical integration, or build on a culture of contribution and inclusion define the underlying principles that drive decisions and strategy for your design language but productize. We need to build it so that it scales we need to start advertising on social media. Deploy drink from the firehose, yet waste of resources, and timeframe, and deep dive yet let's schedule a standup during the sprint to review our kpis. Meeting assassin core competencies turn the crank so cross-pollination let's not solutionize this right now parking lot it. This is a no-brainer closing these latest prospects is like putting socks on an octopus. What about scaling components to a global audience?. Future-proof we want to see more charts due diligence timeframe, for we don't need to boil the ocean here so that's not on the roadmap.
Nail it down. Action item incentivization window of opportunity. Shotgun approach. Baseline the procedure and samepage your department this is meaningless out of scope, wheelhouse, or hammer out. Rock Star/Ninja. Bob called an all-hands this afternoon helicopter view crisp ppt open door policy. Post launch. Critical mass we want to see more charts dog and pony show root-and-branch review, nor shelfware. Flesh that out churning anomalies. Manage expectations looks great, can we try it a different way. Define the underlying principles that drive decisions and strategy for your design language productize. Spinning our wheels when does this sunset? are there any leftovers in the kitchen? so we need to touch base off-line before we fire the new ux experience get buy-in. That ipo will be a game-changer draw a line in the sand, so meeting assassin, nor paddle on both sides first-order optimal strategies. I'll book a meeting so we can solution this before the sprint is over. Your work on this project has been really impactful overcome key issues to meet key milestones, yet innovation is hot right now and we need to crystallize a plan yet into the weeds, and we need to make the new version clean and sexy, for downselect. Single wringable neck. (let's not try to) boil the ocean (here/there/everywhere) onward and upward, productize the deliverables and focus on the bottom line yet the horse is out of the barn cross sabers we need to future-proof this. Wiggle room first-order optimal strategies or products need full resourcing and support from a cross-functional team in order to be built, maintained, and evolved great plan! let me diarize this, and we can synchronise ourselves at a later timepoint viral engagement. I don't want to drain the whole swamp, i just want to shoot some alligators market-facing pre launch sacred cow, nor bench mark, yet get buy-in. Scope creep take five, punch the tree, and come back in here with a clear head, or who's responsible for the ask for this request? strategic fit. Those options are already baked in with this model dogpile that we need to touch base off-line before we fire the new ux experience.
+10
View File
@@ -0,0 +1,10 @@
We are a big name to have in your portfolio theres all this spanish text on my site. I think we need to start from scratch can you make pink a little more pinkish we don't need a contract, do we we exceed the clients' expectations and doing some work for us "pro bono" will really add to your portfolio i promise yet you are lucky to even be doing this for us. That's great, but we need to add this 2000 line essay low resolution? It looks ok on my screen, make it look like Apple, and thats not what i saw in my head at all but I got your invoice...it seems really high, why did you charge so much. Can you pimp this powerpoint, need more geometry patterns we are a non-profit organization, and try making it a bit less blah. Can you make it stand out more? this is just a 5 minutes job this was not according to brief. Can we barter services? can you make it faster? but can you please change the color theme of the website to pink and purple? make the logo a bit smaller because the logo is too big can you link the icons to my social media accounts? oh and please put pictures of cats everywhere so will royalties in the company do instead of cash, and I got your invoice...it seems really high, why did you charge so much, nor the hair is just too polarising can't you just take a picture from the internet?. Thanks for taking the time to make the website, but i already made it in wix. Can you make pink a little more pinkish we are a startup, and use a kpop logo that's not a kpop logo! ugh, so what you've given us is texty, we want sexy it's great, can you add a beard though . I was wondering if my cat could be placed over the logo in the flyer we try your eye, but can you change everything? nor are you busy this weekend? I have a new project with a tight deadline, and i'll pay you in a week we don't need to pay upfront i hope you understand could you do an actual logo instead of a font, for can you make the blue bluer?. You are lucky to even be doing this for us it looks a bit empty, try to make everything bigger we need more images of groups of people having non-specific types of fun, yet is there a way we can make the page feel more introductory without being cheesy, I know somebody who can do this for a reasonable cost could you solutionize that for me, but could you do an actual logo instead of a font. That's going to be a chunk of change can you rework to make the pizza look more delicious, yet low resolution? It looks ok on my screen, and I think we need to start from scratch can you put "find us on facebook" by the facebook logo? nor can you use a high definition screenshot. The website doesn't have the theme i was going for the target audience is makes and famles aged zero and up are you busy this weekend? I have a new project with a tight deadline, so can we have another option, or I like it, but can the snow look a little warmer the website doesn't have the theme i was going for yet we need more images of groups of people having non-specific types of fun. We don't need a backup, it never goes down!. Can it handle a million in one go can you make the font bigger? or can't you just take a picture from the internet? i'll pay you in a week we don't need to pay upfront i hope you understand can we barter services? that's going to be a chunk of change. Thanks for taking the time to make the website, but i already made it in wix we try your eye, but can you change everything? I like it, but can the snow look a little warmer. Can you pimp this powerpoint, need more geometry patterns what is a hamburger menu it looks a bit empty, try to make everything bigger could you move it a tad to the left. Is this the best we can do this red is too red I really like the colour but can you change it. Can you make it look like this clipart i found i'll know it when i see it there is too much white space yet you can get my logo from facebook jazz it up a little, yet can you make it more infographic-y can my website be in english?. Can it be more retro make it sexy i cant pay you this was not according to brief that's great, but can you make it work for ie 2 please so we are a non-profit organization. Can we have another option low resolution? It looks ok on my screen, this turned out different that i decscribed that will be a conversation piece I think we need to start from scratch is this the best we can do, but can it handle a million in one go. We don't need a contract, do we. Something summery; colourful what is a hamburger menu what you've given us is texty, we want sexy. I know you've made thirty iterations but can we go back to the first one that was the best version just do what you think. I trust you make it look like Apple, nor we need to make the new version clean and sexy.
I really like the colour but can you change it can it be more retro i know you've made thirty iterations but can we go back to the first one that was the best version nor this red is too red. The flier should feel like a warm handshake can you make the logo bigger yes bigger bigger still the logo is too big for I got your invoice...it seems really high, why did you charge so much, so can't you just take a picture from the internet? just do what you think. I trust you. Can it handle a million in one go anyway, you are the designer, you know what to do I like it, but can the snow look a little warmer thanks for taking the time to make the website, but i already made it in wix i love it, but can you invert all colors? can you put "find us on facebook" by the facebook logo? can you make it faster?. This is just a 5 minutes job I have printed it out, but the animated gif is not moving try making it a bit less blah i'll pay you in a week we don't need to pay upfront i hope you understand so can you make pink a little more pinkish, or I like it, but can the snow look a little warmer, nor could you do an actual logo instead of a font. Can you make pink a little more pinkish. Can you please send me the design specs again? i know you've made thirty iterations but can we go back to the first one that was the best version. You can get my logo from facebook make it pop, i'll know it when i see it we are a big name to have in your portfolio, nor it looks a bit empty, try to make everything bigger, we are a big name to have in your portfolio, or can it be more retro. Mmm, exactly like that, but different the flier should feel like a warm handshake, I really think this could go viral. Can you make the blue bluer? the hair is just too polarising. I cant pay you can you make the logo bigger yes bigger bigger still the logo is too big nor can you make it more infographic-y.
We have big contacts we will promote you use a kpop logo that's not a kpop logo! ugh yet we are a startup, but is this the best we can do, yet I need a website. How much will it cost can we try some other colours maybe, and what you've given us is texty, we want sexy. Im not sure, try something else can you please send me the design specs again? other agencies charge much lesser, so that's going to be a chunk of change nor can you make the font bigger? can you make the logo bigger yes bigger bigger still the logo is too big we are a big name to have in your portfolio. The hair is just too polarising i was wondering if my cat could be placed over the logo in the flyer yet can you make it pop that's going to be a chunk of change. Anyway, you are the designer, you know what to do are you busy this weekend? I have a new project with a tight deadline, nor can it be more retro. Could you do an actual logo instead of a font make it sexy. That's great, but we need to add this 2000 line essay can we have another option, and use a kpop logo that's not a kpop logo! ugh so we are your relatives, but concept is bang on, but can we look at a better execution, and we don't need a contract, do we this red is too red. Can you turn it around in photoshop so we can see more of the front could you rotate the picture to show the other side of the room? or jazz it up a little. Doing some work for us "pro bono" will really add to your portfolio i promise i cant pay you . Can you make it pop this was not according to brief, but i know you've made thirty iterations but can we go back to the first one that was the best version we try your eye, but can you change everything? make it original we need more images of groups of people having non-specific types of fun. We don't need a backup, it never goes down! I need a website. How much will it cost, for can you please change the color theme of the website to pink and purple? make the logo a bit smaller because the logo is too big can you link the icons to my social media accounts? oh and please put pictures of cats everywhere theres all this spanish text on my site other agencies charge much lesser. Can we have another option this looks perfect. Just Photoshop out the dog, add a baby, and make the curtains blue.
Are you busy this weekend? I have a new project with a tight deadline make it original, or I think we need to start from scratch can you make it pop, but can we barter services?. Something summery; colourful I got your invoice...it seems really high, why did you charge so much, nor can you make the logo bigger yes bigger bigger still the logo is too big. Can you make the font bigger? we need more images of groups of people having non-specific types of fun. Are you busy this weekend? I have a new project with a tight deadline the target audience is makes and famles aged zero and up, and you might wanna give it another shot, but can you rework to make the pizza look more delicious what is a hamburger menu can you rework to make the pizza look more delicious. We are a startup. Give us a complimentary logo along with the website. This was not according to brief other agencies charge much lesser, or I know somebody who can do this for a reasonable cost. Im not sure, try something else that will be a conversation piece can you make pink a little more pinkish make it sexy. Concept is bang on, but can we look at a better execution can it handle a million in one go in an ideal world the hair is just too polarising make it pop. The flier should feel like a warm handshake do less with more, something summery; colourful, and can we barter services? we try your eye, but can you change everything?. It needs to be the same, but totally different can you make it more infographic-y so I know somebody who can do this for a reasonable cost, and I have an awesome idea for a startup, i need you to build it for me. Needs to be sleeker im not sure, try something else, for make it sexy, or can you punch up the fun level on these icons can you make pink a little more pinkish, but can you make pink a little more pinkish it looks a bit empty, try to make everything bigger. Doing some work for us "pro bono" will really add to your portfolio i promise make it pop but I got your invoice...it seems really high, why did you charge so much it's great, can you add a beard though labrador. Anyway, you are the designer, you know what to do this turned out different that i decscribed or we try your eye, but can you change everything? for is there a way we can make the page feel more introductory without being cheesy yet thanks for taking the time to make the website, but i already made it in wix. Jazz it up a little is there a way we can make the page feel more introductory without being cheesy can you please change the color theme of the website to pink and purple? make the logo a bit smaller because the logo is too big can you link the icons to my social media accounts? oh and please put pictures of cats everywhere I need a website. How much will it cost. Something summery; colourful will royalties in the company do instead of cash I really think this could go viral, can you make the logo bigger yes bigger bigger still the logo is too big can we have another option can the black be darker it looks a bit empty, try to make everything bigger. Can it be more retro can you please send me the design specs again? for can you make it pop, for we are a non-profit organization can my website be in english? I need a website. How much will it cost. Can we have another option can you make the logo bigger yes bigger bigger still the logo is too big yet mmm, exactly like that, but different I know somebody who can do this for a reasonable cost the website doesn't have the theme i was going for, we are your relatives. Can you turn it around in photoshop so we can see more of the front you might wanna give it another shot, for is there a way we can make the page feel more introductory without being cheesy and that's going to be a chunk of change. Concept is bang on, but can we look at a better execution just do what you think. I trust you, nor can't you just take a picture from the internet? can it handle a million in one go. There is too much white space we don't need a backup, it never goes down! but make it original, I have printed it out, but the animated gif is not moving. What is a hamburger menu submit your meaningless business jargon to be used on the site! so do less with more. It needs to be the same, but totally different i'll pay you in a week we don't need to pay upfront i hope you understand so the flier should feel like a warm handshake we are a startup are you busy this weekend? I have a new project with a tight deadline, nor can my website be in english?. Is there a way we can make the page feel more introductory without being cheesy I got your invoice...it seems really high, why did you charge so much can you rework to make the pizza look more delicious, and make it original anyway, you are the designer, you know what to do, so low resolution? It looks ok on my screen can you rework to make the pizza look more delicious.
It's great, can you add a beard though use a kpop logo that's not a kpop logo! ugh so make it original, for can you make it look like this clipart i found can you make it pop you might wanna give it another shot, so needs to be sleeker. I'll pay you in a week we don't need to pay upfront i hope you understand. Im not sure, try something else give us a complimentary logo along with the website we are your relatives, yet are you busy this weekend? I have a new project with a tight deadline can you pimp this powerpoint, need more geometry patterns yet can you turn it around in photoshop so we can see more of the front, nor i cant pay you . Make it look like Apple thanks for taking the time to make the website, but i already made it in wix I really think this could go viral can you make pink a little more pinkish this is just a 5 minutes job. Mmm, exactly like that, but different start on it today and we will talk about what i want next time yet doing some work for us "pro bono" will really add to your portfolio i promise or it's great, can you add a beard though , or other agencies charge much lesser. Submit your meaningless business jargon to be used on the site! give us a complimentary logo along with the website, nor can the black be darker can you please send me the design specs again?. I love it, but can you invert all colors? we need to make the new version clean and sexy low resolution? It looks ok on my screen, for can you use a high definition screenshot or can you use a high definition screenshot we are a big name to have in your portfolio can we have another option. Can we try some other colours maybe. You can get my logo from facebook use a kpop logo that's not a kpop logo! ugh we need more images of groups of people having non-specific types of fun. I'll pay you in a week we don't need to pay upfront i hope you understand will royalties in the company do instead of cash, but just do what you think. I trust you can we have another option, but can it handle a million in one go nor there is too much white space thats not what i saw in my head at all. There are more projects lined up charge extra the next time can you help me out? you will get a lot of free exposure doing this. Just do what you think. I trust you. Low resolution? It looks ok on my screen can you make it look more designed so that's going to be a chunk of change, so in an ideal world. In an ideal world can you make the font bigger? and could you do an actual logo instead of a font. Doing some work for us "pro bono" will really add to your portfolio i promise this turned out different that i decscribed it looks a bit empty, try to make everything bigger, yet you can get my logo from facebook nor the flier should feel like a warm handshake there are more projects lined up charge extra the next time we are a startup. Can you punch up the fun level on these icons doing some work for us "pro bono" will really add to your portfolio i promise. Make it sexy. Can you please send me the design specs again? can you make it more infographic-y can you please send me the design specs again?, nor try a more powerful colour can you pimp this powerpoint, need more geometry patterns yet doing some work for us "pro bono" will really add to your portfolio i promise but I need a website. How much will it cost. Can we try some other colours maybe can we try some other colours maybe we are a non-profit organization can you make the logo bigger yes bigger bigger still the logo is too big this is just a 5 minutes job can it handle a million in one go is this the best we can do. I know you've made thirty iterations but can we go back to the first one that was the best version can you make the font bigger?. Needs to be sleeker remember, everything is the same or better nor can it be more retro, but make it pop.
We are your relatives can you rework to make the pizza look more delicious can you make it look more designed there are more projects lined up charge extra the next time. Use a kpop logo that's not a kpop logo! ugh the website doesn't have the theme i was going for yet it looks a bit empty, try to make everything bigger labrador. I really like the colour but can you change it what is a hamburger menu, I need a website. How much will it cost. Use a kpop logo that's not a kpop logo! ugh submit your meaningless business jargon to be used on the site!, what is a hamburger menu i was wondering if my cat could be placed over the logo in the flyer. Anyway, you are the designer, you know what to do this looks perfect. Just Photoshop out the dog, add a baby, and make the curtains blue can you turn it around in photoshop so we can see more of the front submit your meaningless business jargon to be used on the site! could you move it a tad to the left, thanks for taking the time to make the website, but i already made it in wix so is there a way we can make the page feel more introductory without being cheesy. Do less with more. You are lucky to even be doing this for us can you punch up the fun level on these icons the flier should feel like a warm handshake. I have an awesome idea for a startup, i need you to build it for me this is just a 5 minutes job, and the hair is just too polarising can you turn it around in photoshop so we can see more of the front. Submit your meaningless business jargon to be used on the site! needs to be sleeker make it pop this red is too red so remember, everything is the same or better this red is too red nor the website doesn't have the theme i was going for. I need a website. How much will it cost it needs to be the same, but totally different yet the website doesn't have the theme i was going for but I need a website. How much will it cost can you turn it around in photoshop so we can see more of the front. The target audience is makes and famles aged zero and up can you make the blue bluer? can you lower the price for the website? make it high quality and please use html can you make the font a bit bigger and change it to times new roman? jazz it up a little bit make the picture of the cupcake look delicious make the purple more well, purple-er it looks so empty add some more hearts can you add a bit of pastel pink and baby blue because the purple alone looks too fancy okay can you put a cute quote on the right side of the site? oh no it looks messed up! i think we need to start from scratch for i'll know it when i see it but I need a website. How much will it cost, thats not what i saw in my head at all. Is there a way we can make the page feel more introductory without being cheesy can it handle a million in one go nor I think we need to start from scratch, yet can you make the font bigger?. Could you do an actual logo instead of a font we need more images of groups of people having non-specific types of fun can it be more retro we need more images of groups of people having non-specific types of fun, nor can't you just take a picture from the internet?. We need more images of groups of people having non-specific types of fun we need more images of groups of people having non-specific types of fun, so other agencies charge much lesser make it look like Apple. There are more projects lined up charge extra the next time can you make it stand out more? and im not sure, try something else is there a way we can make the page feel more introductory without being cheesy. Submit your meaningless business jargon to be used on the site! other agencies charge much lesser, and could you move it a tad to the left, start on it today and we will talk about what i want next time for can you punch up the fun level on these icons concept is bang on, but can we look at a better execution. Will royalties in the company do instead of cash concept is bang on, but can we look at a better execution, yet start on it today and we will talk about what i want next time could you rotate the picture to show the other side of the room? we don't need a backup, it never goes down! give us a complimentary logo along with the website. Can you put "find us on facebook" by the facebook logo? can you lower the price for the website? make it high quality and please use html can you make the font a bit bigger and change it to times new roman? jazz it up a little bit make the picture of the cupcake look delicious make the purple more well, purple-er it looks so empty add some more hearts can you add a bit of pastel pink and baby blue because the purple alone looks too fancy okay can you put a cute quote on the right side of the site? oh no it looks messed up! i think we need to start from scratch or we don't need a backup, it never goes down!. We don't need a backup, it never goes down! needs to be sleeker, for can my website be in english? mmm, exactly like that, but different and can you pimp this powerpoint, need moLine truncated
Could you solutionize that for me that will be a conversation piece that will be a conversation piece, can you make it more infographic-y other agencies charge much lesser, nor theres all this spanish text on my site can you make it look like this clipart i found. Can you rework to make the pizza look more delicious needs to be sleeker. Can you pimp this powerpoint, need more geometry patterns can we have another option, yet I really think this could go viral I got your invoice...it seems really high, why did you charge so much. Can you lower the price for the website? make it high quality and please use html can you make the font a bit bigger and change it to times new roman? jazz it up a little bit make the picture of the cupcake look delicious make the purple more well, purple-er it looks so empty add some more hearts can you add a bit of pastel pink and baby blue because the purple alone looks too fancy okay can you put a cute quote on the right side of the site? oh no it looks messed up! i think we need to start from scratch are you busy this weekend? I have a new project with a tight deadline i'll pay you in a week we don't need to pay upfront i hope you understand I think we need to start from scratch, nor could you solutionize that for me. That's great, but we need to add this 2000 line essay I got your invoice...it seems really high, why did you charge so much, I got your invoice...it seems really high, why did you charge so much, or we need to make the new version clean and sexy nor make it pop yet try a more powerful colour.
We don't need a backup, it never goes down! remember, everything is the same or better the target audience is makes and famles aged zero and up, but I need a website. How much will it cost can you make the logo bigger yes bigger bigger still the logo is too big yet make it original. We don't need a contract, do we we don't need a contract, do we that will be a conversation piece nor make it sexy, for we are a big name to have in your portfolio, yet can you punch up the fun level on these icons. Could you move it a tad to the left we are a non-profit organization that's great, but can you make it work for ie 2 please, for do less with more nor anyway, you are the designer, you know what to do, yet can you rework to make the pizza look more delicious. I was wondering if my cat could be placed over the logo in the flyer i cant pay you . Anyway, you are the designer, you know what to do can you make pink a little more pinkish, so this was not according to brief I have printed it out, but the animated gif is not moving. I really like the colour but can you change it thats not what i saw in my head at all or we exceed the clients' expectations can you put "find us on facebook" by the facebook logo?. Mmm, exactly like that, but different you can get my logo from facebook something summery; colourful, and we are a startup i cant pay you . Can't you just take a picture from the internet? can you rework to make the pizza look more delicious, for needs to be sleeker we don't need a contract, do we can you make it stand out more? can you put "find us on facebook" by the facebook logo?. Can my website be in english? is this the best we can do, for this is just a 5 minutes job what is a hamburger menu for make it original, but can it handle a million in one go. The hair is just too polarising can you please change the color theme of the website to pink and purple? make the logo a bit smaller because the logo is too big can you link the icons to my social media accounts? oh and please put pictures of cats everywhere. You can get my logo from facebook can you make it faster? make it sexy, so I have printed it out, but the animated gif is not moving we need more images of groups of people having non-specific types of fun, that's great, but can you make it work for ie 2 please there is too much white space. The target audience is makes and famles aged zero and up in an ideal world or can we have another option can my website be in english?, so we are your relatives can you make it look like this clipart i found. Im not sure, try something else. Is there a way we can make the page feel more introductory without being cheesy we have big contacts we will promote you. Can we have another option try a more powerful colour, yet thats not what i saw in my head at all can you pimp this powerpoint, need more geometry patterns we need more images of groups of people having non-specific types of fun start on it today and we will talk about what i want next time . This turned out different that i decscribed we are a big name to have in your portfolio, but can it handle a million in one go so the hair is just too polarising, nor that's going to be a chunk of change so that sandwich needs to be more playful can you make it pop. We try your eye, but can you change everything? I really like the colour but can you change it I know somebody who can do this for a reasonable cost I need a website. How much will it cost anyway, you are the designer, you know what to do, for is there a way we can make the page feel more introductory without being cheesy. Can my website be in english? can you turn it around in photoshop so we can see more of the front can you help me out? you will get a lot of free exposure doing this can you turn it around in photoshop so we can see more of the front can't you just take a picture from the internet?, use a kpop logo that's not a kpop logo! ugh you are lucky to even be doing this for us. I cant pay you can't you just take a picture from the internet? but try making it a bit less blah. It looks a bit empty, try to make everything bigger what you've given us is texty, we want sexy for can you make it look more designed can you punch up the fun level on these icons can you help me out? you will get a lot of free exposure doing this. Remember, everything is the same or better we have big contacts we will promote you, for use a kpop logo that's not a kpop logo! ugh.
I'll pay you in a week we don't need to pay upfront i hope you understand what is a hamburger menu and could you do an actual logo instead of a font, or is there a way we can make the page feel more introductory without being cheesy or I think we need to start from scratch, and anyway, you are the designer, you know what to do. Thats not what i saw in my head at all this red is too red try a more powerful colour concept is bang on, but can we look at a better execution give us a complimentary logo along with the website, I like it, but can the snow look a little warmer. Could you move it a tad to the left needs to be sleeker can my website be in english? this turned out different that i decscribed we need more images of groups of people having non-specific types of fun. Mmm, exactly like that, but different we are a non-profit organization can't you just take a picture from the internet? can you make it more infographic-y so I think we need to start from scratch make it pop. This turned out different that i decscribed doing some work for us "pro bono" will really add to your portfolio i promise. Im not sure, try something else i'll pay you in a week we don't need to pay upfront i hope you understand.
Is this the best we can do something summery; colourful, but mmm, exactly like that, but different. Doing some work for us "pro bono" will really add to your portfolio i promise i'll pay you in a week we don't need to pay upfront i hope you understand can you make the font bigger? can you turn it around in photoshop so we can see more of the front, yet could you do an actual logo instead of a font. Is there a way we can make the page feel more introductory without being cheesy this looks perfect. Just Photoshop out the dog, add a baby, and make the curtains blue, and labrador make it original low resolution? It looks ok on my screen. Could you rotate the picture to show the other side of the room?. Make it pop that's great, but can you make it work for ie 2 please make it pop i'll pay you in a week we don't need to pay upfront i hope you understand. Give us a complimentary logo along with the website. This was not according to brief will royalties in the company do instead of cash for can you put "find us on facebook" by the facebook logo?. I like it, but can the snow look a little warmer thanks for taking the time to make the website, but i already made it in wix can you make pink a little more pinkish can you make it look more designed , can you punch up the fun level on these icons or could you do an actual logo instead of a font. Make it original. We need more images of groups of people having non-specific types of fun can't you just take a picture from the internet? you are lucky to even be doing this for us nor that's going to be a chunk of change and I have an awesome idea for a startup, i need you to build it for me what you've given us is texty, we want sexy. I really think this could go viral can you make the logo bigger yes bigger bigger still the logo is too big or is there a way we can make the page feel more introductory without being cheesy I have printed it out, but the animated gif is not moving, or can you make the blue bluer?. Can you pimp this powerpoint, need more geometry patterns. Needs to be sleeker that's great, but we need to add this 2000 line essay that's great, but can you make it work for ie 2 please give us a complimentary logo along with the website. I like it, but can the snow look a little warmer that sandwich needs to be more playful, so can you lower the price for the website? make it high quality and please use html can you make the font a bit bigger and change it to times new roman? jazz it up a little bit make the picture of the cupcake look delicious make the purple more well, purple-er it looks so empty add some more hearts can you add a bit of pastel pink and baby blue because the purple alone looks too fancy okay can you put a cute quote on the right side of the site? oh no it looks messed up! i think we need to start from scratch. Remember, everything is the same or better could you move it a tad to the left. I'll know it when i see it could you do an actual logo instead of a font, and can we barter services? or can you make pink a little more pinkish. Are you busy this weekend? I have a new project with a tight deadline. Can we have another option what is a hamburger menu. Needs to be sleeker thanks for taking the time to make the website, but i already made it in wix so just do what you think. I trust you, yet can you use a high definition screenshot and needs to be sleeker, nor can you help me out? you will get a lot of free exposure doing this. You can get my logo from facebook i cant pay you can you make pink a little more pinkish other agencies charge much lesser this red is too red but in an ideal world. Can you make it more infographic-y this red is too red can you make it pop. Can you make the font bigger? make it pop and can we try some other colours maybe. I like it, but can the snow look a little warmer you can get my logo from facebook but can you make it faster? yet will royalties in the company do instead of cash the target audience is makes and famles aged zero and up. Can't you just take a picture from the internet? can you please send me the design specs again?, so can you help me out? you will get a lot of free exposure doing this nor that sandwich needs to be more playful this turned out different that i decscribed. We don't need a backup, it never goes down! can you lower the price for the website? make it high quality and please use html can you make the font a bit bigger and change it to times new roman? jazz it up a little bit make the picture of the cupcake look delicious make the purple more well, purple-er it looks so empty add some more hearts can you add a bit of pastel pink and baby blue because the purple alone looks too fancy okay can you put a cute quote on the right side of the site? oh no it looks messed up! i think we need to start from scratch.
+14
View File
@@ -0,0 +1,14 @@
Breathe in your fears. Face them. To conquer fear, you must become fear. You must bask in the fear of other men. And men fear most what they cannot see. You have to become a terrible thought. A wraith. You have to become an idea! Feel terror cloud your senses. Feel its power to distort. To control. And know that this power can be yours. Embrace your worst fear. Become one with the darkness.
You wanna know how I got these scars? My father was... a drinker, and a fiend. And one night, he goes off crazier than usual. Mommy gets the kitchen knife to defend herself. He doesn't like that, not one bit. So, me watching he takes the knife to her, laughing while he does it. He turns to me and he says: "Why so serious?". He comes at me with the knife "Why so serious?". He sticks the blade in my mouth. "Let's put a smile on that face." and... Why so serious?
My name is Merely Ducard but I speak for Ra's al Ghul... a man greatly feared by the criminal underworld. A mon who can offer you a path. Someone like you is only here by choice. You have been exploring the criminal fraternity but whatever your original intentions you have to become truly lost. The path of a man who shares his hatred of evil and wishes to serve true justice. The path of the League of Shadows.
Every man who has lotted here over the centuries, has looked up to the light and imagined climbing to freedom. So easy, so simple! And like shipwrecked men turning to seawater foregoing uncontrollable thirst, many have died trying. And then here there can be no true despair without hope. So as I terrorize Gotham, I will feed its people hope to poison their souls. I will let them believe that they can survive so that you can watch them climbing over each other to stay in the sun. You can watch me torture an entire city. And then when you've truly understood the depth of your failure, we will fulfill Ra's Al Ghul's destiny. We will destroy Gotham. And then, when that is done, and Gotham is... ashes Then you have my permission to die.
But we've met before. That was a long time ago, I was a kid at St. Swithin's, It used to be funded by the Wayne Foundation. It's an orphanage. My mum died when I was small, it was a car accident. I don't remember it. My dad got shot a couple of years later for a gambling debt. Oh I remember that one just fine. Not a lot of people know what it feels like to be angry in your bones. I mean they understand. The fosters parents. Everybody understands, for a while. Then they want the angry little kid to do something he knows he can't do, move on. After a while they stop understanding. They send the angry kid to a boy's home, I figured it out too late. Yeah I learned to hide the anger, and practice smiling in the mirror. It's like putting on a mask. So you showed up this one day, in a cool car, pretty girl on your arm. We were so excited! Bruce Wayne, a billionaire orphan? We used to make up stories about you man, legends and you know with the other kids, that's all it was, just stories, but right when I saw you, I knew who you really were. I'd seen that look on your face before. It's the same one I taught myself. I don't why you took the fault for Dent's murder but I'm still a believer in the Batman. Even if you're not...
You wanna know how I got them? So I had a wife. She was beautiful, like you, who tells me I worry too much, who tells me I ought to smile more, who gambles and gets in deep with the sharks. Hey. One day they carve her face. And we have no money for surgeries. She can't take it. I just wanna see her smile again. I just want her to know that I don't care about the scars. So, I do this to myself. And you know what? She can't stand the sight of me. She leaves. Now I see the funny side. Now I'm always smiling.
Every year, I took a holiday. I went to Florence, this cafe on the banks of the Arno. Every fine evening, I would sit there and order a Fernet Branca. I had this fantasy, that I would look across the tables and I would see you there with a wife maybe a couple of kids. You wouldn't say anything to me, nor me to you. But we would both know that you've made it, that you were happy. I never wanted you to come back to Gotham. I always knew there was nothing here for you except pain and tragedy and I wanted something more for you than that. I still do.
Breathe in your fears. Face them. To conquer fear, you must become fear. You must bask in the fear of other men. And men fear most what they cannot see. You have to become a terrible thought. A wraith. You have to become an idea! Feel terror cloud your senses. Feel its power to distort. To control. And know that this power can be yours. Embrace your worst fear. Become one with the darkness.
You wanna know how I got these scars? My father was... a drinker, and a fiend. And one night, he goes off crazier than usual. Mommy gets the kitchen knife to defend herself. He doesn't like that, not one bit. So, me watching he takes the knife to her, laughing while he does it. He turns to me and he says: "Why so serious?". He comes at me with the knife "Why so serious?". He sticks the blade in my mouth. "Let's put a smile on that face." and... Why so serious?
My name is Merely Ducard but I speak for Ra's al Ghul... a man greatly feared by the criminal underworld. A mon who can offer you a path. Someone like you is only here by choice. You have been exploring the criminal fraternity but whatever your original intentions you have to become truly lost. The path of a man who shares his hatred of evil and wishes to serve true justice. The path of the League of Shadows.
Every man who has lotted here over the centuries, has looked up to the light and imagined climbing to freedom. So easy, so simple! And like shipwrecked men turning to seawater foregoing uncontrollable thirst, many have died trying. And then here there can be no true despair without hope. So as I terrorize Gotham, I will feed its people hope to poison their souls. I will let them believe that they can survive so that you can watch them climbing over each other to stay in the sun. You can watch me torture an entire city. And then when you've truly understood the depth of your failure, we will fulfill Ra's Al Ghul's destiny. We will destroy Gotham. And then, when that is done, and Gotham is... ashes Then you have my permission to die.
But we've met before. That was a long time ago, I was a kid at St. Swithin's, It used to be funded by the Wayne Foundation. It's an orphanage. My mum died when I was small, it was a car accident. I don't remember it. My dad got shot a couple of years later for a gambling debt. Oh I remember that one just fine. Not a lot of people know what it feels like to be angry in your bones. I mean they understand. The fosters parents. Everybody understands, for a while. Then they want the angry little kid to do something he knows he can't do, move on. After a while they stop understanding. They send the angry kid to a boy's home, I figured it out too late. Yeah I learned to hide the anger, and practice smiling in the mirror. It's like putting on a mask. So you showed up this one day, in a cool car, pretty girl on your arm. We were so excited! Bruce Wayne, a billionaire orphan? We used to make up stories about you man, legends and you know with the other kids, that's all it was, just stories, but right when I saw you, I knew who you really were. I'd seen that look on your face before. It's the same one I taught myself. I don't why you took the fault for Dent's murder but I'm still a believer in the Batman. Even if you're not...
You wanna know how I got them? So I had a wife. She was beautiful, like you, who tells me I worry too much, who tells me I ought to smile more, who gambles and gets in deep with the sharks. Hey. One day they carve her face. And we have no money for surgeries. She can't take it. I just wanna see her smile again. I just want her to know that I don't care about the scars. So, I do this to myself. And you know what? She can't stand the sight of me. She leaves. Now I see the funny side. Now I'm always smiling.
Every year, I took a holiday. I went to Florence, this cafe on the banks of the Arno. Every fine evening, I would sit there and order a Fernet Branca. I had this fantasy, that I would look across the tables and I would see you there with a wife maybe a couple of kids. You wouldn't say anything to me, nor me to you. But we would both know that you've made it, that you were happy. I never wanted you to come back to Gotham. I always knew there was nothing here for you except pain and tragedy and I wanted something more for you than that. I still do.
+208
View File
@@ -0,0 +1,208 @@
#include <cmc/list.h>
#include <utl/log.h>
#define TAB_SIZE 4
#define ROW_INI_CAP DOC_LETTERS_IN_ROW
#define DOC_LETTERS_IN_ROW 100
#define DOC_ROWS_IN_PAGE 50
#define DOC_MARGIN 4
CMC_GENERATE_LIST(row, row, char)
CMC_GENERATE_LIST(doc, document, row *)
void row_deallocator(row *r)
{
row_free(r, NULL);
}
document *document_load(const char *file_name);
void document_empty_line(FILE *fptr);
void document_page_outline(FILE *fptr, int outline);
void document_page_margin(FILE *fptr, int margin);
void document_print(document *doc, FILE *fptr);
document *document_load(const char *file_name)
{
FILE *file = fopen(file_name, "r");
if (!file)
{
cmc_log_error("File %s not found\n", file_name);
return NULL;
}
row *initial_row = row_new(ROW_INI_CAP);
document *doc = doc_new(100);
doc_push_back(doc, initial_row);
int ch;
while ((ch = getc(file)) != EOF)
{
char c = (char)ch;
row *current_row = doc_back(doc);
if (c == '\n')
{
row *new_row = row_new(ROW_INI_CAP);
doc_push_back(doc, new_row);
}
else if (c == '\t')
{
intmax_t left = TAB_SIZE;
while (left > 0 && row_count(current_row) < DOC_LETTERS_IN_ROW)
{
row_push_back(current_row, ' ');
left--;
}
if (left > 0)
{
row *new_row = row_new(ROW_INI_CAP);
doc_push_back(doc, new_row);
while (left > 0)
{
row_push_back(new_row, ' ');
left--;
}
}
}
else if (DOC_LETTERS_IN_ROW == row_count(current_row))
{
row *new_row = row_new(ROW_INI_CAP);
row_push_back(new_row, c);
doc_push_back(doc, new_row);
}
else
row_push_back(current_row, c);
}
return doc;
}
void document_empty_line(FILE *fptr)
{
fputs("|", fptr);
for (size_t i = 0; i < DOC_LETTERS_IN_ROW + DOC_MARGIN * 2; i++)
{
fputc(' ', fptr);
}
fputs("|\n", fptr);
}
void document_page_outline(FILE *fptr, int outline /* 0 - header, 1 - footer */)
{
if (outline == 1)
{
document_empty_line(fptr);
#ifdef DOC_PAGE_NUMBER
static intmax_t page = 1;
fputs("|", fptr);
for (size_t i = 0; i < (DOC_LETTERS_IN_ROW + DOC_MARGIN) - 8; i++)
{
fputc(' ', fptr);
}
fprintf(fptr, "%8" PRIdMAX "", page);
page++;
document_page_margin(fptr, 1);
document_empty_line(fptr);
#endif
}
fputs("+", fptr);
for (size_t i = 0; i < DOC_LETTERS_IN_ROW + DOC_MARGIN * 2; i++)
{
fputc('-', fptr);
}
fputs("+\n", fptr);
if (outline == 0)
document_empty_line(fptr);
}
void document_page_margin(FILE *fptr, int margin /* 0 - first margin, 1 - second margin */)
{
if (margin == 0)
fputs("|", fptr);
for (size_t i = 0; i < DOC_MARGIN; i++)
{
fputc(' ', fptr);
}
if (margin == 1)
fputs("|\n", fptr);
}
void document_print(document *doc, FILE *fptr)
{
fputc('\n', fptr);
intmax_t current_page_row = 0, total_rows = doc_count(doc);
// Print document
for (intmax_t i = 0; i < total_rows; i++, current_page_row++)
{
if (current_page_row == 0)
document_page_outline(fptr, 0);
row *current_row = doc_get(doc, i);
if (!current_row)
cmc_log_fatal("Unexpected NULL pointer for %s", "current_row");
document_page_margin(fptr, 0);
for (size_t k = 0; k < row_count(current_row); k++)
fputc(row_get(current_row, k), fptr);
// Trailing margin
for (size_t k = 0; k < DOC_LETTERS_IN_ROW - row_count(current_row); k++)
fputc(' ', fptr);
document_page_margin(fptr, 1);
// Print the end of the page and reset
if (current_page_row == DOC_ROWS_IN_PAGE - 1)
{
document_page_outline(fptr, 1);
current_page_row = -1;
fputc('\n', fptr);
}
}
// Print trailing page
if (total_rows % DOC_ROWS_IN_PAGE != 0)
{
for (size_t i = 0; i < DOC_ROWS_IN_PAGE - current_page_row; i++)
document_empty_line(fptr);
document_page_outline(fptr, 1);
}
fputc('\n', fptr);
}
int main(int argc, char const *argv[])
{
if (argc != 2)
{
cmc_log_error("Please define one argument only for %s", argv[0]);
return 1;
}
document *doc = document_load(argv[1]);
document_print(doc, stdout);
doc_free(doc, row_deallocator);
return 0;
}
+1
View File
@@ -1,3 +1,4 @@
# Queue examples
* ice_cream.c - Example of what happens when you get late to the queue and the ice creams are sold out!
* iterator.c - A complete example of the queue iterator
+1 -1
View File
@@ -7,10 +7,10 @@
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/queue.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "queue.h"
QUEUE_GENERATE(q, queue, /* static */, const char *)
+195
View File
@@ -0,0 +1,195 @@
/**
* iterator.c
*
* Creation Date: 15/05/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Iterator Example
*/
#include "cmc/queue.h"
#include <stdio.h>
#include <inttypes.h>
// Creates a queue of integers
QUEUE_GENERATE(q, queue, /* FMOD */, int)
int main(int argc, char const *argv[])
{
// Create a new queue with an initial capacity of 100
queue *my_queue = q_new(100);
// Add elements to the queue
for (int i = 0; i < 20; i++)
{
q_enqueue(my_queue, i);
}
// Iterate from the start (front) to the end (rear) of the queue
for (queue_iter it = my_queue->it_start(my_queue); // Initialize iterator 'it' to the start of the queue
!q_iter_end(&it); // Conditional stop (until it is not at the end)
q_iter_next(&it)) // Iterator goes one position forward
{
// Access the current element
int e = q_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = q_iter_index(&it);
// Print queue
// Index is useful in situations like this
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == q_count(my_queue) - 1)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// Index can also be used to iterate over a certain portion of a collection
size_t limit = q_count(my_queue) / 2;
for (queue_iter it = my_queue->it_start(my_queue); !q_iter_end(&it); q_iter_next(&it))
{
// Access the current element
int e = q_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = q_iter_index(&it);
// Print queue up until limit
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == limit - 1) // -1 because index is 0 based and we want half of the queue
{
printf("%d ]\n", e);
break;
}
// For elements at the middle
else
printf("%d, ", e);
}
// Going backwards
for (queue_iter it = my_queue->it_end(my_queue); // Initialize iterator 'it' to the end of the queue
!q_iter_start(&it); // Conditional stop (until it is not at the start)
q_iter_prev(&it)) // Iterator goes one position backwards
{
// Access the current element
int e = q_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = q_iter_index(&it);
// Print queue
// Note how the conditions for the first and last elements are simply swapped
// Because iterating backwards make the first element be the index count - 1
// and the last one be the index 0
// If it is the first element
if (i == q_count(my_queue) - 1)
printf("[ %d, ", e);
// If it is the last element
else if (i == 0)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// You can also use iterators in a while loop
// But to do so you must declare the iterator struct outside the loop first
queue_iter it;
// You have three options:
// - Initialize it using the functions provided by the queue [ my_queue->it_start() and my_queue->it_end() ]
// - Initialize it using the init() function (when the iterator is already allocated)
// - Initialize it using the new() function (allocates on the heap, pointers only)
it = my_queue->it_start(my_queue);
it = my_queue->it_end(my_queue);
// This is equivalent to it_start()
q_iter_init(&it, my_queue);
// For pointers
// Also equivalent to it_start()
queue_iter *iter = q_iter_new(my_queue);
// The actual while loop
while (!q_iter_end(iter))
{
// Accessing elements
int e = q_iter_value(iter);
size_t i = q_iter_index(iter);
// Print index and element
printf("queue[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator forwards
q_iter_next(iter);
}
// Send the iterator to the start of the queue
q_iter_to_start(iter);
// Send the iterator to the end of the queue
q_iter_to_end(iter);
// Backwards loop
while (!q_iter_start(iter))
{
// Accessing elements
int e = q_iter_value(iter);
size_t i = q_iter_index(iter);
// Print index and element
printf("queue[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator backwards
q_iter_prev(iter);
}
// Certain iterators also allow you to modify the contents it is iterating over
// Exceptions are collections that depend of the current state of the element
// like tree-based collections and heap (collections that have some kind of ordering).
// You also can't change the keys of an associative collection
// Change every element that is divisible by 3 to the number 7
for (q_iter_to_start(&it); !q_iter_end(&it); q_iter_next(&it))
{
// Get a reference to the current value
int *r = q_iter_rvalue(&it);
if (r != NULL && *r % 3 == 0)
*r = 7;
}
// Now print it to see the difference
for (queue_iter it = my_queue->it_start(my_queue); !q_iter_end(&it); q_iter_next(&it))
{
int e = q_iter_value(&it);
size_t i = q_iter_index(&it);
if (i == 0)
printf("[ %d, ", e);
else if (i == q_count(my_queue) - 1)
printf("%d ]\n", e);
else
printf("%d, ", e);
}
// Dispose the iterator called by q_iter_new()
q_iter_free(iter);
// Dispose the queue created
q_free(my_queue);
return 0;
}
+1
View File
@@ -1,3 +1,4 @@
# Stack examples
* hanoi.c - Animated example of solving the hanoi tower.
* iterator.c - A complete example of the stack iterator
+1 -3
View File
@@ -7,14 +7,12 @@
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/stack.h"
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
STACK_GENERATE(s, stack, /* static */, int)
#define MAX(a, b) a > b ? a : b
void print_hanoi(stack *t1, stack *t2, stack *t3);
const char *draw(int value);
void move_disc(stack *from, stack *to);
+195
View File
@@ -0,0 +1,195 @@
/**
* iterator.c
*
* Creation Date: 15/05/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Iterator Example
*/
#include "cmc/stack.h"
#include <stdio.h>
#include <inttypes.h>
// Creates a stack of integers
STACK_GENERATE(s, stack, /* FMOD */, int)
int main(int argc, char const *argv[])
{
// Create a new stack with an initial capacity of 100
stack *my_stack = s_new(100);
// Add elements to the stack
for (int i = 0; i < 20; i++)
{
s_push(my_stack, i);
}
// Iterate from the start (top) to the end (bottom) of the stack
for (stack_iter it = my_stack->it_start(my_stack); // Initialize iterator 'it' to the start of the stack
!s_iter_end(&it); // Conditional stop (until it is not at the end)
s_iter_next(&it)) // Iterator goes one position forward
{
// Access the current element
int e = s_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = s_iter_index(&it);
// Print stack
// Index is useful in situations like this
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == s_count(my_stack) - 1)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// Index can also be used to iterate over a certain portion of a collection
size_t limit = s_count(my_stack) / 2;
for (stack_iter it = my_stack->it_start(my_stack); !s_iter_end(&it); s_iter_next(&it))
{
// Access the current element
int e = s_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = s_iter_index(&it);
// Print stack up until limit
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == limit - 1) // -1 because index is 0 based and we want half of the stack
{
printf("%d ]\n", e);
break;
}
// For elements at the middle
else
printf("%d, ", e);
}
// Going backwards
for (stack_iter it = my_stack->it_end(my_stack); // Initialize iterator 'it' to the end of the stack
!s_iter_start(&it); // Conditional stop (until it is not at the start)
s_iter_prev(&it)) // Iterator goes one position backwards
{
// Access the current element
int e = s_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = s_iter_index(&it);
// Print stack
// Note how the conditions for the first and last elements are simply swapped
// Because iterating backwards make the first element be the index count - 1
// and the last one be the index 0
// If it is the first element
if (i == s_count(my_stack) - 1)
printf("[ %d, ", e);
// If it is the last element
else if (i == 0)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// You can also use iterators in a while loop
// But to do so you must declare the iterator struct outside the loop first
stack_iter it;
// You have three options:
// - Initialize it using the functions provided by the stack [ my_stack->it_start() and my_stack->it_end() ]
// - Initialize it using the init() function (when the iterator is already allocated)
// - Initialize it using the new() function (allocates on the heap, pointers only)
it = my_stack->it_start(my_stack);
it = my_stack->it_end(my_stack);
// This is equivalent to it_start()
s_iter_init(&it, my_stack);
// For pointers
// Also equivalent to it_start()
stack_iter *iter = s_iter_new(my_stack);
// The actual while loop
while (!s_iter_end(iter))
{
// Accessing elements
int e = s_iter_value(iter);
size_t i = s_iter_index(iter);
// Print index and element
printf("stack[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator forwards
s_iter_next(iter);
}
// Send the iterator to the start of the stack
s_iter_to_start(iter);
// Send the iterator to the end of the stack
s_iter_to_end(iter);
// Backwards loop
while (!s_iter_start(iter))
{
// Accessing elements
int e = s_iter_value(iter);
size_t i = s_iter_index(iter);
// Print index and element
printf("stack[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator backwards
s_iter_prev(iter);
}
// Certain iterators also allow you to modify the contents it is iterating over
// Exceptions are collections that depend of the current state of the element
// like tree-based collections and heap (collections that have some kind of ordering).
// You also can't change the keys of an associative collection
// Change every element that is divisible by 3 to the number 7
for (s_iter_to_start(&it); !s_iter_end(&it); s_iter_next(&it))
{
// Get a reference to the current value
int *r = s_iter_rvalue(&it);
if (r != NULL && *r % 3 == 0)
*r = 7;
}
// Now print it to see the difference
for (stack_iter it = my_stack->it_start(my_stack); !s_iter_end(&it); s_iter_next(&it))
{
int e = s_iter_value(&it);
size_t i = s_iter_index(&it);
if (i == 0)
printf("[ %d, ", e);
else if (i == s_count(my_stack) - 1)
printf("%d ]\n", e);
else
printf("%d, ", e);
}
// Dispose the iterator called by s_iter_new()
s_iter_free(iter);
// Dispose the stack created
s_free(my_stack);
return 0;
}
+2 -1
View File
@@ -1,3 +1,4 @@
# Treemap examples
Currently none
* pseudo_multiset.c - An example of how to make a multiset using a map.
* iterator.c - A complete example of the treemap iterator
+217
View File
@@ -0,0 +1,217 @@
/**
* iterator.c
*
* Creation Date: 16/05/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Iterator Example
*/
#include "cmc/treemap.h"
#include <stdio.h>
#include <inttypes.h>
// Int compare function
int intcmp(int a, int b)
{
return a - b;
}
// Creates a treemap of integers
TREEMAP_GENERATE(tm, treemap, /* FMOD */, int, double)
int main(int argc, char const *argv[])
{
// Create a new treemap
treemap *my_map = tm_new(intcmp);
// Add pairs to the treemap
for (int i = 0; i < 20; i++)
{
// Map integers to doubles
tm_insert(my_map, i, (double)i / 10.0);
}
// Iterate from the start (left-most node) to the end (right-most node) of the treemap
for (treemap_iter it = my_map->it_start(my_map); // Initialize iterator 'it' to the start of the treemap
!tm_iter_end(&it); // Conditional stop (until it is not at the end)
tm_iter_next(&it)) // Iterator goes one position forward
{
// Access the current key
int k = tm_iter_key(&it);
// Access the current value
double v = tm_iter_value(&it);
// Access the current index (index is relative to all the pairs in the iteration)
size_t i = tm_iter_index(&it);
// Print treemap
// Index is useful in situations like this
// If it is the first pair
if (i == 0)
printf("[ {%d:%.2lf}, ", k, v);
// If it is the last pair
else if (i == tm_count(my_map) - 1)
printf("{%d:%.2lf} ]\n", k, v);
// For pairs at the middle
else
printf("{%d:%.2lf}, ", k, v);
}
// Index can also be used to iterate over a certain portion of a collection
size_t limit = tm_count(my_map) / 2;
for (treemap_iter it = my_map->it_start(my_map); !tm_iter_end(&it); tm_iter_next(&it))
{
// Access the current key
int k = tm_iter_key(&it);
// Access the current value
double v = tm_iter_value(&it);
// Access the current index (index is relative to all the pairs in the iteration)
size_t i = tm_iter_index(&it);
// Print treemap up until limit
// If it is the first pair
if (i == 0)
printf("[ {%d:%.2lf}, ", k, v);
// If it is the last pair
else if (i == limit - 1) // -1 because index is 0 based and we want half of the treemap
{
printf("{%d:%.2lf} ]\n", k, v);
break;
}
// For pairs at the middle
else
printf("{%d:%.2lf}, ", k, v);
}
// Going backwards
for (treemap_iter it = my_map->it_end(my_map); // Initialize iterator 'it' to the end of the treemap
!tm_iter_start(&it); // Conditional stop (until it is not at the start)
tm_iter_prev(&it)) // Iterator goes one position backwards
{
// Access the current key
int k = tm_iter_key(&it);
// Access the current value
double v = tm_iter_value(&it);
// Access the current index (index is relative to all the pairs in the iteration)
size_t i = tm_iter_index(&it);
// Print treemap
// Note how the conditions for the first and last pairs are simply swapped
// Because iterating backwards make the first pair be the index count - 1
// and the last one be the index 0
// If it is the first pair
if (i == tm_count(my_map) - 1)
printf("[ {%d:%.2lf}, ", k, v);
// If it is the last pair
else if (i == 0)
printf("{%d:%.2lf} ]\n", k, v);
// For pairs at the middle
else
printf("{%d:%.2lf}, ", k, v);
}
// You can also use iterators in a while loop
// But to do so you must declare the iterator struct outside the loop first
treemap_iter it;
// You have three options:
// - Initialize it using the functions provided by the treemap [ my_map->it_start() and my_map->it_end() ]
// - Initialize it using the init() function (when the iterator is already allocated)
// - Initialize it using the new() function (allocates on the heap, pointers only)
it = my_map->it_start(my_map);
it = my_map->it_end(my_map);
// This is equivalent to it_start()
tm_iter_init(&it, my_map);
// For pointers
// Also equivalent to it_start()
treemap_iter *iter = tm_iter_new(my_map);
// The actual while loop
while (!tm_iter_end(iter))
{
// Accessing pairs
int k = tm_iter_key(iter);
double v = tm_iter_value(iter);
size_t i = tm_iter_index(iter);
// Print index and key value pair
printf("treemap[%2" PRIuMAX "] = { %2d : %.2lf }\n", i, k, v);
// Move iterator forwards
tm_iter_next(iter);
}
// Send the iterator to the start of the treemap
tm_iter_to_start(iter);
// Send the iterator to the end of the treemap
tm_iter_to_end(iter);
// Backwards loop
while (!tm_iter_start(iter))
{
// Accessing pairs
int k = tm_iter_key(iter);
double v = tm_iter_value(iter);
size_t i = tm_iter_index(iter);
// Print index and the key value pair
printf("treemap[%2" PRIuMAX "] = { %2d : %.2lf }\n", i, k, v);
// Move iterator backwards
tm_iter_prev(iter);
}
// Certain iterators also allow you to modify the contents it is iterating over
// Exceptions are collections that depend of the current state of the pair
// like tree-based collections and heap (collections that have some kind of ordering).
// You also can't change the keys of an associative collection
// Change every value where its key is divisible by 3 to the number 7
for (tm_iter_to_start(&it); !tm_iter_end(&it); tm_iter_next(&it))
{
// Get current key
int k = tm_iter_key(&it);
// Get a reference to the current value
double *v = tm_iter_rvalue(&it);
if (k % 3 == 0)
*v = 7;
}
// Now print it to see the difference
for (treemap_iter it = my_map->it_start(my_map); !tm_iter_end(&it); tm_iter_next(&it))
{
int k = tm_iter_key(&it);
double v = tm_iter_value(&it);
size_t i = tm_iter_index(&it);
if (i == 0)
printf("[ {%d:%.2lf}, ", k, v);
else if (i == tm_count(my_map) - 1)
printf("{%d:%.2lf} ]\n", k, v);
else
printf("{%d:%.2lf}, ", k, v);
}
// Dispose the iterator called by tm_iter_new()
tm_iter_free(iter);
// Dispose the treemap created
tm_free(my_map);
return 0;
}
+86
View File
@@ -0,0 +1,86 @@
/**
* pseudo_multiset.c
*
* Creation Date: 26/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
// How to make a multiset using a map
#include "cmc/treemap.h"
#include <stdio.h>
#include <inttypes.h>
// Mapping an integer by size_t which will represent the key's multiplicity
// (key could be anything and multiplicity could be an integer, preferably
// unsigned)
TREEMAP_GENERATE(tm, tmap, , int, size_t)
// Compare function used by the treemap
int intcmp(int a, int b)
{
return (a > b) - (a < b);
}
// Little helper to print the tree
void print_tree(tmap_node *root, int height)
{
if (!root)
return;
print_tree(root->right, height + 1);
for (int i = 0; i < height; i++)
printf("|------- ");
// Key:Multiplicity
printf("%d:%" PRIuMAX "\n", root->key, root->value);
print_tree(root->left, height + 1);
}
int main(int argc, char const *argv[])
{
tmap *map = tm_new(intcmp);
// Start adding elements
for (int i = 0; i < 100; i++)
{
// Modulo of 8 so we get some repetition
int key = i % 8;
// Get the reference to a value in the map with the key
size_t *rvalue = tm_get_ref(map, key);
// If the key exists, rvalue is not null
if (rvalue != NULL)
{
// Incrementing it means we have added another key to the set
// The value represents the multiplicity, that is, how many times
// we have added the key in the set
(*rvalue)++;
}
else
// Create a new entry with key with an initial multiplicity of 1
tm_insert(map, key, 1);
}
print_tree(map->root, 0);
// Summary
printf("\n---------- SUMMARY ----------\n\n");
// Print using iterator
for (tmap_iter it = map->it_start(map); !tm_iter_end(&it); tm_iter_next(&it))
{
// Map[key] = multiplicity
printf("Map[%2d] = %" PRIuMAX "\n", tm_iter_key(&it), tm_iter_value(&it));
}
tm_free(map);
return 0;
}
+1
View File
@@ -1,4 +1,5 @@
# Treeset examples
* iterator.c - A complete example of the treeset iterator
* set_ops.c - Demonstrates common set operations like *union*, *intersection*, *difference* and *symmetric difference*.
* tree_print.c - How to print a binary tree.
+194
View File
@@ -0,0 +1,194 @@
/**
* iterator.c
*
* Creation Date: 16/05/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
* Iterator Example
*/
#include "cmc/treeset.h"
#include <stdio.h>
#include <inttypes.h>
// Int hash function
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;
}
// Int compare function
int intcmp(int a, int b)
{
return a - b;
}
// Creates a treeset of integers
TREESET_GENERATE(ts, treeset, /* FMOD */, int)
int main(int argc, char const *argv[])
{
// Create a new treeset with an initial capacity of 100 and load factor of 0.6
treeset *my_treeset = ts_new(intcmp);
// Add elements to the treeset
for (int i = 0; i < 20; i++)
{
ts_insert(my_treeset, i);
}
// Iterate from the start (index 0) to the end (index count - 1) of the treeset
for (treeset_iter it = my_treeset->it_start(my_treeset); // Initialize iterator 'it' to the start of the treeset
!ts_iter_end(&it); // Conditional stop (until it is not at the end)
ts_iter_next(&it)) // Iterator goes one position forward
{
// Access the current element
int e = ts_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = ts_iter_index(&it);
// Print treeset
// Index is useful in situations like this
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == ts_count(my_treeset) - 1)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// Index can also be used to iterate over a certain portion of a collection
size_t limit = ts_count(my_treeset) / 2;
for (treeset_iter it = my_treeset->it_start(my_treeset); !ts_iter_end(&it); ts_iter_next(&it))
{
// Access the current element
int e = ts_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = ts_iter_index(&it);
// Print treeset up until limit
// If it is the first element
if (i == 0)
printf("[ %d, ", e);
// If it is the last element
else if (i == limit - 1) // -1 because index is 0 based and we want half of the treeset
{
printf("%d ]\n", e);
break;
}
// For elements at the middle
else
printf("%d, ", e);
}
// Going backwards
for (treeset_iter it = my_treeset->it_end(my_treeset); // Initialize iterator 'it' to the end of the treeset
!ts_iter_start(&it); // Conditional stop (until it is not at the start)
ts_iter_prev(&it)) // Iterator goes one position backwards
{
// Access the current element
int e = ts_iter_value(&it);
// Access the current index (index is relative to all the elements in the iteration)
size_t i = ts_iter_index(&it);
// Print treeset
// Note how the conditions for the first and last elements are simply swapped
// Because iterating backwards make the first element be the index count - 1
// and the last one be the index 0
// If it is the first element
if (i == ts_count(my_treeset) - 1)
printf("[ %d, ", e);
// If it is the last element
else if (i == 0)
printf("%d ]\n", e);
// For elements at the middle
else
printf("%d, ", e);
}
// You can also use iterators in a while loop
// But to do so you must declare the iterator struct outside the loop first
treeset_iter it;
// You have three options:
// - Initialize it using the functions provided by the treeset [ my_treeset->it_start() and my_treeset->it_end() ]
// - Initialize it using the init() function (when the iterator is already allocated)
// - Initialize it using the new() function (allocates on the heap, pointers only)
it = my_treeset->it_start(my_treeset);
it = my_treeset->it_end(my_treeset);
// This is equivalent to it_start()
ts_iter_init(&it, my_treeset);
// For pointers
// Also equivalent to it_start()
treeset_iter *iter = ts_iter_new(my_treeset);
// The actual while loop
while (!ts_iter_end(iter))
{
// Accessing elements
int e = ts_iter_value(iter);
size_t i = ts_iter_index(iter);
// Print index and element
printf("treeset[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator forwards
ts_iter_next(iter);
}
// Send the iterator to the start of the treeset
ts_iter_to_start(iter);
// Send the iterator to the end of the treeset
ts_iter_to_end(iter);
// Backwards loop
while (!ts_iter_start(iter))
{
// Accessing elements
int e = ts_iter_value(iter);
size_t i = ts_iter_index(iter);
// Print index and element
printf("treeset[%2" PRIuMAX "] = %2d\n", i, e);
// Move iterator backwards
ts_iter_prev(iter);
}
// Certain iterators also allow you to modify the contents it is iterating over
// Exceptions are collections that depend of the current state of the element
// like tree-based collections and heap (collections that have some kind of ordering).
// You also can't change the keys of an associative collection
// In the case of a treeset or any set, this is not possible because the
// values of a set are its keys. Changing the elements could cause the set
// to be in an invalid state.
// Dispose the iterator called by ts_iter_new()
ts_iter_free(iter);
// Dispose the treeset created
ts_free(my_treeset);
return 0;
}
+6 -6
View File
@@ -14,21 +14,21 @@
// - Difference
// - Symmetric Difference
#include "cmc/treeset.h"
#include <stdio.h>
#include <stdlib.h>
#include "treeset.h"
TREESET_GENERATE(set, set, /* static */, int)
void print_set(set *s)
{
size_t index;
int result;
set_iter iter;
set_iter_new(&iter, s);
for (set_iter_tostart(&iter); !set_iter_end(&iter);)
set_iter_init(&iter, s);
for (set_iter_to_start(&iter); !set_iter_end(&iter); set_iter_next(&iter))
{
set_iter_next(&iter, &result, &index);
int result = set_iter_value(&iter);
size_t index = set_iter_index(&iter);
if (index == 0)
printf("[ %2d, ", result);
else if (index == s->count - 1)
+2 -2
View File
@@ -7,10 +7,10 @@
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include "cmc/treeset.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "treeset.h"
TREESET_GENERATE(set, set, , int)
@@ -24,7 +24,7 @@ void print_tree(set_node *root, int height)
for (int i = 0; i < height; i++)
printf("|------- ");
printf("%d\n", root->key);
printf("%d\n", root->value);
print_tree(root->left, height + 1);
}
+633
View File
@@ -0,0 +1,633 @@
/**
* 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.
*/
#ifndef CMC_DEQUE_H
#define CMC_DEQUE_H
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../utl/cmc_string.h"
/* to_string format */
static const char *cmc_string_fmt_deque = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
#define CMC_GENERATE_DEQUE(PFX, SNAME, V) \
CMC_GENERATE_DEQUE_HEADER(PFX, SNAME, V) \
CMC_GENERATE_DEQUE_SOURCE(PFX, SNAME, V)
#define CMC_WRAPGEN_DEQUE_HEADER(PFX, SNAME, K, V) \
CMC_GENERATE_DEQUE_HEADER(PFX, SNAME, V)
#define CMC_WRAPGEN_DEQUE_SOURCE(PFX, SNAME, K, V) \
CMC_GENERATE_DEQUE_SOURCE(PFX, SNAME, V)
/* HEADER ********************************************************************/
#define CMC_GENERATE_DEQUE_HEADER(PFX, SNAME, V) \
\
/* Deque Structure */ \
typedef struct SNAME##_s \
{ \
/* 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; \
\
/* Function that returns an iterator to the start of the deque */ \
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
\
/* Function that returns an iterator to the end of the deque */ \
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
\
} SNAME, *SNAME##_ptr; \
\
/* Deque Iterator */ \
typedef struct SNAME##_iter_s \
{ \
/* Target deque */ \
struct SNAME##_s *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; \
\
} SNAME##_iter, *SNAME##_iter_ptr; \
\
/* Collection Functions */ \
/* Collection Allocation and Deallocation */ \
SNAME *PFX##_new(size_t capacity); \
void PFX##_clear(SNAME *_deque_, void (*deallocator)(V)); \
void PFX##_free(SNAME *_deque_, void (*deallocator)(V)); \
/* Collection Input and Output */ \
bool PFX##_push_front(SNAME *_deque_, V element); \
bool PFX##_push_back(SNAME *_deque_, V element); \
bool PFX##_pop_front(SNAME *_deque_); \
bool PFX##_pop_back(SNAME *_deque_); \
/* Element Access */ \
V PFX##_front(SNAME *_deque_); \
V PFX##_back(SNAME *_deque_); \
/* Collection State */ \
bool PFX##_contains(SNAME *_deque_, V element, int (*comparator)(V, V)); \
bool PFX##_empty(SNAME *_deque_); \
bool PFX##_full(SNAME *_deque_); \
size_t PFX##_count(SNAME *_deque_); \
size_t PFX##_capacity(SNAME *_deque_); \
/* Collection Utility */ \
bool PFX##_resize(SNAME *_deque_, size_t capacity); \
SNAME *PFX##_copy_of(SNAME *_deque_, V (*copy_func)(V)); \
bool PFX##_equals(SNAME *_deque1_, SNAME *_deque2_, int (*comparator)(V, V)); \
cmc_string PFX##_to_string(SNAME *_deque_); \
\
/* Iterator Functions */ \
/* Iterator Allocation and Deallocation */ \
SNAME##_iter *PFX##_iter_new(SNAME *target); \
void PFX##_iter_free(SNAME##_iter *iter); \
/* Iterator Initialization */ \
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
/* Iterator State */ \
bool PFX##_iter_start(SNAME##_iter *iter); \
bool PFX##_iter_end(SNAME##_iter *iter); \
/* Iterator Movement */ \
void PFX##_iter_to_start(SNAME##_iter *iter); \
void PFX##_iter_to_end(SNAME##_iter *iter); \
bool PFX##_iter_next(SNAME##_iter *iter); \
bool PFX##_iter_prev(SNAME##_iter *iter); \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
/* Iterator Access */ \
V PFX##_iter_value(SNAME##_iter *iter); \
V *PFX##_iter_rvalue(SNAME##_iter *iter); \
size_t PFX##_iter_index(SNAME##_iter *iter); \
\
/* SOURCE ********************************************************************/
#define CMC_GENERATE_DEQUE_SOURCE(PFX, SNAME, V) \
\
/* Implementation Detail Functions */ \
static SNAME##_iter PFX##_impl_it_start(SNAME *_deque_); \
static SNAME##_iter PFX##_impl_it_end(SNAME *_deque_); \
\
SNAME *PFX##_new(size_t capacity) \
{ \
if (capacity < 1) \
return NULL; \
\
SNAME *_deque_ = malloc(sizeof(SNAME)); \
\
if (!_deque_) \
return NULL; \
\
_deque_->buffer = malloc(sizeof(V) * capacity); \
\
if (!_deque_->buffer) \
{ \
free(_deque_); \
return NULL; \
} \
\
memset(_deque_->buffer, 0, sizeof(V) * capacity); \
\
_deque_->capacity = capacity; \
_deque_->count = 0; \
_deque_->front = 0; \
_deque_->back = 0; \
\
_deque_->it_start = PFX##_impl_it_start; \
_deque_->it_end = PFX##_impl_it_end; \
\
return _deque_; \
} \
\
void PFX##_clear(SNAME *_deque_, void (*deallocator)(V)) \
{ \
if (deallocator) \
{ \
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \
{ \
deallocator(_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; \
} \
\
void PFX##_free(SNAME *_deque_, void (*deallocator)(V)) \
{ \
if (deallocator) \
{ \
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \
{ \
deallocator(_deque_->buffer[i]); \
\
i = (i + 1) % _deque_->capacity; \
} \
} \
\
free(_deque_->buffer); \
free(_deque_); \
} \
\
bool PFX##_push_front(SNAME *_deque_, V element) \
{ \
if (PFX##_full(_deque_)) \
{ \
if (!PFX##_resize(_deque_, PFX##_capacity(_deque_) * 2)) \
return false; \
} \
\
_deque_->front = (_deque_->front == 0) ? _deque_->capacity - 1 : _deque_->front - 1; \
\
_deque_->buffer[_deque_->front] = element; \
\
_deque_->count++; \
\
return true; \
} \
\
bool PFX##_push_back(SNAME *_deque_, V element) \
{ \
if (PFX##_full(_deque_)) \
{ \
if (!PFX##_resize(_deque_, PFX##_capacity(_deque_) * 2)) \
return false; \
} \
\
_deque_->buffer[_deque_->back] = element; \
\
_deque_->back = (_deque_->back == _deque_->capacity - 1) ? 0 : _deque_->back + 1; \
\
_deque_->count++; \
\
return true; \
} \
\
bool PFX##_pop_front(SNAME *_deque_) \
{ \
if (PFX##_empty(_deque_)) \
return false; \
\
_deque_->buffer[_deque_->front] = (V){0}; \
\
_deque_->front = (_deque_->front == _deque_->capacity - 1) ? 0 : _deque_->front + 1; \
\
_deque_->count--; \
\
return true; \
} \
\
bool PFX##_pop_back(SNAME *_deque_) \
{ \
if (PFX##_empty(_deque_)) \
return false; \
\
_deque_->back = (_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1; \
\
_deque_->buffer[_deque_->back] = (V){0}; \
\
_deque_->count--; \
\
return true; \
} \
\
V PFX##_front(SNAME *_deque_) \
{ \
if (PFX##_empty(_deque_)) \
return (V){0}; \
\
return _deque_->buffer[_deque_->front]; \
} \
\
V PFX##_back(SNAME *_deque_) \
{ \
if (PFX##_empty(_deque_)) \
return (V){0}; \
\
return _deque_->buffer[(_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1]; \
} \
\
bool PFX##_contains(SNAME *_deque_, V element, int (*comparator)(V, V)) \
{ \
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \
{ \
if (comparator(_deque_->buffer[i], element) == 0) \
return true; \
\
i = (i + 1) % _deque_->capacity; \
} \
\
return false; \
} \
\
bool PFX##_empty(SNAME *_deque_) \
{ \
return _deque_->count == 0; \
} \
\
bool PFX##_full(SNAME *_deque_) \
{ \
return _deque_->count >= _deque_->capacity; \
} \
\
size_t PFX##_count(SNAME *_deque_) \
{ \
return _deque_->count; \
} \
\
size_t PFX##_capacity(SNAME *_deque_) \
{ \
return _deque_->capacity; \
} \
\
bool PFX##_resize(SNAME *_deque_, size_t capacity) \
{ \
if (PFX##_capacity(_deque_) == capacity) \
return true; \
\
if (capacity < PFX##_count(_deque_)) \
return false; \
\
V *new_buffer = malloc(sizeof(V) * capacity); \
\
if (!new_buffer) \
return false; \
\
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \
{ \
new_buffer[j] = _deque_->buffer[i]; \
\
i = (i + 1) % PFX##_capacity(_deque_); \
} \
\
free(_deque_->buffer); \
\
_deque_->buffer = new_buffer; \
_deque_->capacity = capacity; \
_deque_->front = 0; \
_deque_->back = _deque_->count; \
\
return true; \
} \
\
SNAME *PFX##_copy_of(SNAME *_deque_, V (*copy_func)(V)) \
{ \
SNAME *result = PFX##_new(_deque_->capacity); \
\
if (!result) \
return NULL; \
\
if (copy_func) \
{ \
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \
{ \
result->buffer[j] = copy_func(_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; \
\
return result; \
} \
\
bool PFX##_equals(SNAME *_deque1_, SNAME *_deque2_, int (*comparator)(V, V)) \
{ \
if (PFX##_count(_deque1_) != PFX##_count(_deque2_)) \
return false; \
\
size_t i, j, k; \
for (i = _deque1_->front, j = _deque2_->front, k = 0; k < PFX##_count(_deque1_); k++) \
{ \
if (comparator(_deque1_->buffer[i], _deque2_->buffer[j]) != 0) \
return false; \
\
i = (i + 1) % _deque1_->capacity; \
j = (j + 1) % _deque2_->capacity; \
} \
\
return true; \
} \
\
cmc_string PFX##_to_string(SNAME *_deque_) \
{ \
cmc_string str; \
SNAME *d_ = _deque_; \
const char *name = #SNAME; \
\
snprintf(str.s, cmc_string_len, cmc_string_fmt_deque, \
name, d_, d_->buffer, d_->capacity, d_->count, d_->front, d_->back); \
\
return str; \
} \
\
SNAME##_iter *PFX##_iter_new(SNAME *target) \
{ \
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
\
if (!iter) \
return NULL; \
\
PFX##_iter_init(iter, target); \
\
return iter; \
} \
\
void PFX##_iter_free(SNAME##_iter *iter) \
{ \
free(iter); \
} \
\
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
{ \
iter->target = target; \
iter->cursor = target->front; \
iter->index = 0; \
iter->start = true; \
iter->end = PFX##_empty(target); \
} \
\
bool PFX##_iter_start(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->start; \
} \
\
bool PFX##_iter_end(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->end; \
} \
\
void PFX##_iter_to_start(SNAME##_iter *iter) \
{ \
iter->cursor = iter->target->front; \
iter->index = 0; \
iter->start = true; \
iter->end = PFX##_empty(iter->target); \
} \
\
void PFX##_iter_to_end(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
{ \
iter->cursor = 0; \
iter->index = 0; \
} \
else \
{ \
if (iter->target->back == 0) \
iter->cursor = iter->target->capacity - 1; \
else \
iter->cursor = iter->target->back - 1; \
\
iter->index = PFX##_count(iter->target) - 1; \
} \
\
iter->start = PFX##_empty(iter->target); \
iter->end = true; \
} \
\
bool PFX##_iter_next(SNAME##_iter *iter) \
{ \
if (iter->end) \
return false; \
\
if (iter->index + 1 == PFX##_count(iter->target)) \
{ \
iter->end = true; \
return false; \
} \
\
iter->start = PFX##_empty(iter->target); \
\
iter->cursor = (iter->cursor + 1) % (iter->target->capacity); \
iter->index++; \
\
return true; \
} \
\
bool PFX##_iter_prev(SNAME##_iter *iter) \
{ \
if (iter->start) \
return false; \
\
if (iter->index == 0) \
{ \
iter->start = true; \
return false; \
} \
\
iter->end = 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 PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->end) \
return false; \
\
if (iter->index + 1 == PFX##_count(iter->target)) \
{ \
iter->end = true; \
return false; \
} \
\
if (steps == 0 || iter->index + steps >= PFX##_count(iter->target)) \
return false; \
\
iter->start = 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 PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->start) \
return false; \
\
if (iter->index == 0) \
{ \
iter->start = true; \
return false; \
} \
\
if (steps == 0 || iter->index < steps) \
return false; \
\
iter->end = PFX##_empty(iter->target); \
\
iter->index -= steps; \
\
/* Prevent underflow */ \
if (iter->cursor < steps) \
iter->cursor += PFX##_capacity(iter->target); \
\
iter->cursor -= steps; \
\
return true; \
} \
\
/* Returns true only if the iterator was able to be positioned at the given index */ \
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
{ \
if (index >= PFX##_count(iter->target)) \
return false; \
\
if (iter->index > index) \
return PFX##_iter_rewind(iter, iter->index - index); \
else if (iter->index < index) \
return PFX##_iter_advance(iter, index - iter->index); \
\
return true; \
} \
\
V PFX##_iter_value(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return (V){0}; \
\
return iter->target->buffer[iter->cursor]; \
} \
\
V *PFX##_iter_rvalue(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return NULL; \
\
return &(iter->target->buffer[iter->cursor]); \
} \
\
size_t PFX##_iter_index(SNAME##_iter *iter) \
{ \
return iter->index; \
} \
\
static SNAME##_iter PFX##_impl_it_start(SNAME *_deque_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _deque_); \
\
return iter; \
} \
\
static SNAME##_iter PFX##_impl_it_end(SNAME *_deque_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _deque_); \
PFX##_iter_to_end(&iter); \
\
return iter; \
}
#endif /* CMC_DEQUE_H */
+927
View File
@@ -0,0 +1,927 @@
/**
* 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 hashtable
* with robin hood hashing.
*/
#ifndef CMC_HASHMAP_H
#define CMC_HASHMAP_H
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../utl/cmc_string.h"
/* to_string format */
static const char *cmc_string_fmt_hashmap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
#ifndef CMC_IMPL_HASHTABLE_STATE
#define CMC_IMPL_HASHTABLE_STATE
enum cmc_entry_state_e
{
CMC_ES_DELETED = -1,
CMC_ES_EMPTY = 0,
CMC_ES_FILLED = 1
};
#endif /* CMC_IMPL_HASHTABLE_STATE */
#ifndef CMC_IMPL_HASHTABLE_SETUP
#define CMC_IMPL_HASHTABLE_SETUP
static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
3067, 6143, 12289, 24571, 49157,
98299, 196613, 393209, 786431,
1572869, 3145721, 6291449,
12582917, 25165813, 50331653,
100663291, 201326611, 402653189,
805306357, 1610612741,
3221225473, 6442450939,
12884901893, 25769803799,
51539607551, 103079215111,
206158430209, 412316860441,
824633720831, 1649267441651,
3298534883309, 6597069766657,
13194139533299, 26388279066623,
52776558133303, 105553116266489,
211106232532969, 422212465066001,
844424930131963,
1688849860263953,
3377699720527861,
6755399441055731,
13510798882111483,
27021597764222939,
54043195528445957,
108086391056891903,
216172782113783773,
432345564227567621,
864691128455135207,
1729382256910270481,
3458764513820540933,
6917529027641081903,
13835058055282163729llu};
#endif /* CMC_IMPL_HASHTABLE_SETUP */
#define CMC_GENERATE_HASHMAP(PFX, SNAME, K, V) \
CMC_GENERATE_HASHMAP_HEADER(PFX, SNAME, K, V) \
CMC_GENERATE_HASHMAP_SOURCE(PFX, SNAME, K, V)
#define CMC_WRAPGEN_HASHMAP_HEADER(PFX, SNAME, K, V) \
CMC_GENERATE_HASHMAP_HEADER(PFX, SNAME, K, V)
#define CMC_WRAPGEN_HASHMAP_SOURCE(PFX, SNAME, K, V) \
CMC_GENERATE_HASHMAP_SOURCE(PFX, SNAME, K, V)
/* HEADER ********************************************************************/
#define CMC_GENERATE_HASHMAP_HEADER(PFX, SNAME, K, V) \
\
/* Hashmap Structure */ \
typedef struct SNAME##_s \
{ \
/* Array of Entries */ \
struct SNAME##_entry_s *buffer; \
\
/* Current array capacity */ \
size_t capacity; \
\
/* Current amount of keys */ \
size_t count; \
\
/* Load factor in range (0.0, 1.0) */ \
double load; \
\
/* Key comparison function */ \
int (*cmp)(K, K); \
\
/* Key hash function */ \
size_t (*hash)(K); \
\
/* Function that returns an iterator to the start of the hashmap */ \
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
\
/* Function that returns an iterator to the end of the hashmap */ \
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
\
} SNAME, *SNAME##_ptr; \
\
/* Hashmap Entry */ \
typedef struct SNAME##_entry_s \
{ \
/* 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_e state; \
\
} SNAME##_entry, *SNAME##_entry_ptr; \
\
/* Hashmap Iterator */ \
typedef struct SNAME##_iter_s \
{ \
/* Target hashmap */ \
struct SNAME##_s *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; \
\
} SNAME##_iter, *SNAME##_iter_ptr; \
\
/* Collection Functions */ \
/* Collection Allocation and Deallocation */ \
SNAME *PFX##_new(size_t capacity, double load, int (*compare)(K, K), size_t (*hash)(K)); \
void PFX##_clear(SNAME *_map_, void (*deallocator)(K, V)); \
void PFX##_free(SNAME *_map_, void (*deallocator)(K, V)); \
/* Collection Input and Output */ \
bool PFX##_insert(SNAME *_map_, K key, V value); \
bool PFX##_update(SNAME *_map_, K key, V new_value, V *old_value); \
bool PFX##_remove(SNAME *_map_, K key, V *out_value); \
/* Element Access */ \
bool PFX##_max(SNAME *_map_, K *key, V *value); \
bool PFX##_min(SNAME *_map_, K *key, V *value); \
V PFX##_get(SNAME *_map_, K key); \
V *PFX##_get_ref(SNAME *_map_, K key); \
/* Collection State */ \
bool PFX##_contains(SNAME *_map_, K key); \
bool PFX##_empty(SNAME *_map_); \
bool PFX##_full(SNAME *_map_); \
size_t PFX##_count(SNAME *_map_); \
size_t PFX##_capacity(SNAME *_map_); \
double PFX##_load(SNAME *_map_); \
/* Collection Utility */ \
bool PFX##_resize(SNAME *_map_, size_t capacity); \
SNAME *PFX##_copy_of(SNAME *_map_, K (*key_copy_func)(K), V (*value_copy_func)(V)); \
bool PFX##_equals(SNAME *_map1_, SNAME *_map2_, int (*value_comparator)(V, V)); \
cmc_string PFX##_to_string(SNAME *_map_); \
\
/* Iterator Functions */ \
/* Iterator Allocation and Deallocation */ \
SNAME##_iter *PFX##_iter_new(SNAME *target); \
void PFX##_iter_free(SNAME##_iter *iter); \
/* Iterator Initialization */ \
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
/* Iterator State */ \
bool PFX##_iter_start(SNAME##_iter *iter); \
bool PFX##_iter_end(SNAME##_iter *iter); \
/* Iterator Movement */ \
void PFX##_iter_to_start(SNAME##_iter *iter); \
void PFX##_iter_to_end(SNAME##_iter *iter); \
bool PFX##_iter_next(SNAME##_iter *iter); \
bool PFX##_iter_prev(SNAME##_iter *iter); \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
/* Iterator Access */ \
K PFX##_iter_key(SNAME##_iter *iter); \
V PFX##_iter_value(SNAME##_iter *iter); \
V *PFX##_iter_rvalue(SNAME##_iter *iter); \
size_t PFX##_iter_index(SNAME##_iter *iter); \
\
/* SOURCE ********************************************************************/
#define CMC_GENERATE_HASHMAP_SOURCE(PFX, SNAME, K, V) \
\
/* Implementation Detail Functions */ \
static SNAME##_entry *PFX##_impl_get_entry(SNAME *_map_, K key); \
static size_t PFX##_impl_calculate_size(size_t required); \
static SNAME##_iter PFX##_impl_it_start(SNAME *_map_); \
static SNAME##_iter PFX##_impl_it_end(SNAME *_map_); \
\
SNAME *PFX##_new(size_t capacity, double load, int (*compare)(K, K), size_t (*hash)(K)) \
{ \
if (capacity == 0 || load <= 0 || load >= 1) \
return NULL; \
\
/* Prevent integer overflow */ \
if (capacity >= UINTMAX_MAX * load) \
return NULL; \
\
size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \
\
SNAME *_map_ = malloc(sizeof(SNAME)); \
\
if (!_map_) \
return NULL; \
\
_map_->buffer = malloc(sizeof(SNAME##_entry) * real_capacity); \
\
if (!_map_->buffer) \
{ \
free(_map_); \
return NULL; \
} \
\
memset(_map_->buffer, 0, sizeof(SNAME##_entry) * real_capacity); \
\
_map_->count = 0; \
_map_->capacity = real_capacity; \
_map_->load = load; \
_map_->cmp = compare; \
_map_->hash = hash; \
\
_map_->it_start = PFX##_impl_it_start; \
_map_->it_end = PFX##_impl_it_end; \
\
return _map_; \
} \
\
void PFX##_clear(SNAME *_map_, void (*deallocator)(K, V)) \
{ \
if (deallocator) \
{ \
for (size_t i = 0; i < _map_->capacity; i++) \
{ \
SNAME##_entry *entry = &(_map_->buffer[i]); \
\
if (entry->state == CMC_ES_FILLED) \
{ \
deallocator(entry->key, entry->value); \
} \
} \
} \
\
memset(_map_->buffer, 0, sizeof(SNAME##_entry) * _map_->capacity); \
\
_map_->count = 0; \
} \
\
void PFX##_free(SNAME *_map_, void (*deallocator)(K, V)) \
{ \
if (deallocator) \
{ \
for (size_t i = 0; i < _map_->capacity; i++) \
{ \
SNAME##_entry *entry = &(_map_->buffer[i]); \
\
if (entry->state == CMC_ES_FILLED) \
{ \
deallocator(entry->key, entry->value); \
} \
} \
} \
\
free(_map_->buffer); \
free(_map_); \
} \
\
bool PFX##_insert(SNAME *_map_, K key, V value) \
{ \
if (PFX##_full(_map_)) \
{ \
if (!PFX##_resize(_map_, PFX##_capacity(_map_) + 1)) \
return false; \
} \
\
size_t hash = _map_->hash(key); \
size_t original_pos = hash % _map_->capacity; \
size_t pos = original_pos; \
\
SNAME##_entry *target = &(_map_->buffer[pos]); \
\
if (PFX##_impl_get_entry(_map_, key) != NULL) \
return false; \
\
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++; \
\
return true; \
} \
\
bool PFX##_update(SNAME *_map_, K key, V new_value, V *old_value) \
{ \
SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \
\
if (!entry) \
return false; \
\
if (old_value) \
*old_value = entry->value; \
\
entry->value = new_value; \
\
return true; \
} \
\
bool PFX##_remove(SNAME *_map_, K key, V *out_value) \
{ \
SNAME##_entry *result = PFX##_impl_get_entry(_map_, key); \
\
if (result == NULL) \
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--; \
\
return true; \
} \
\
bool PFX##_max(SNAME *_map_, K *key, V *value) \
{ \
if (PFX##_empty(_map_)) \
return false; \
\
SNAME##_iter iter; \
PFX##_iter_init(&iter, _map_); \
\
K max_key = PFX##_iter_key(&iter); \
V max_val = PFX##_iter_value(&iter); \
\
PFX##_iter_next(&iter); \
\
for (; !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
{ \
K iter_key = PFX##_iter_key(&iter); \
V iter_val = PFX##_iter_value(&iter); \
\
if (_map_->cmp(iter_key, max_key) > 0) \
{ \
max_key = iter_key; \
max_val = iter_val; \
} \
} \
\
if (key) \
*key = max_key; \
if (value) \
*value = max_val; \
\
return true; \
} \
\
bool PFX##_min(SNAME *_map_, K *key, V *value) \
{ \
if (PFX##_empty(_map_)) \
return false; \
\
SNAME##_iter iter; \
PFX##_iter_init(&iter, _map_); \
\
K min_key = PFX##_iter_key(&iter); \
V min_val = PFX##_iter_value(&iter); \
\
PFX##_iter_next(&iter); \
\
for (; !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
{ \
K iter_key = PFX##_iter_key(&iter); \
V iter_val = PFX##_iter_value(&iter); \
\
if (_map_->cmp(iter_key, min_key) < 0) \
{ \
min_key = iter_key; \
min_val = iter_val; \
} \
} \
\
if (key) \
*key = min_key; \
if (value) \
*value = min_val; \
\
return true; \
} \
\
V PFX##_get(SNAME *_map_, K key) \
{ \
SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \
\
if (!entry) \
return (V){0}; \
\
return entry->value; \
} \
\
V *PFX##_get_ref(SNAME *_map_, K key) \
{ \
SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \
\
if (!entry) \
return NULL; \
\
return &(entry->value); \
} \
\
bool PFX##_contains(SNAME *_map_, K key) \
{ \
return PFX##_impl_get_entry(_map_, key) != NULL; \
} \
\
bool PFX##_empty(SNAME *_map_) \
{ \
return _map_->count == 0; \
} \
\
bool PFX##_full(SNAME *_map_) \
{ \
return (double)PFX##_capacity(_map_) * PFX##_load(_map_) <= (double)PFX##_count(_map_); \
} \
\
size_t PFX##_count(SNAME *_map_) \
{ \
return _map_->count; \
} \
\
size_t PFX##_capacity(SNAME *_map_) \
{ \
return _map_->capacity; \
} \
\
double PFX##_load(SNAME *_map_) \
{ \
return _map_->load; \
} \
\
bool PFX##_resize(SNAME *_map_, size_t capacity) \
{ \
if (PFX##_capacity(_map_) == capacity) \
return true; \
\
if (PFX##_capacity(_map_) > capacity / PFX##_load(_map_)) \
return true; \
\
/* Prevent integer overflow */ \
if (capacity >= UINTMAX_MAX * PFX##_load(_map_)) \
return false; \
\
/* Calculate required capacity based on the prime numbers */ \
size_t theoretical_size = PFX##_impl_calculate_size(capacity); \
\
/* Not possible to shrink with current available prime numbers */ \
if (theoretical_size < PFX##_count(_map_) / PFX##_load(_map_)) \
return false; \
\
SNAME *_new_map_ = PFX##_new(capacity, PFX##_load(_map_), _map_->cmp, _map_->hash); \
\
if (!_new_map_) \
return false; \
\
SNAME##_iter iter; \
\
for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
{ \
K key = PFX##_iter_key(&iter); \
V value = PFX##_iter_value(&iter); \
\
PFX##_insert(_new_map_, key, value); \
} \
\
if (PFX##_count(_map_) != PFX##_count(_new_map_)) \
{ \
PFX##_free(_new_map_, NULL); \
return false; \
} \
\
SNAME##_entry *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; \
\
PFX##_free(_new_map_, NULL); \
\
return true; \
} \
\
SNAME *PFX##_copy_of(SNAME *_map_, K (*key_copy_func)(K), V (*value_copy_func)(V)) \
{ \
SNAME *result = PFX##_new(_map_->capacity, _map_->load, _map_->cmp, _map_->hash); \
\
if (!result) \
return NULL; \
\
if (key_copy_func || value_copy_func) \
{ \
for (size_t i = 0; i < _map_->capacity; i++) \
{ \
SNAME##_entry *scan = &(_map_->buffer[i]); \
\
if (scan->state != CMC_ES_EMPTY) \
{ \
SNAME##_entry *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 (key_copy_func) \
target->key = key_copy_func(scan->key); \
else \
target->key = scan->key; \
\
if (value_copy_func) \
target->value = value_copy_func(scan->value); \
else \
target->value = scan->value; \
} \
} \
} \
} \
else \
memcpy(result->buffer, _map_->buffer, sizeof(SNAME##_entry) * _map_->capacity); \
\
result->count = _map_->count; \
\
return result; \
} \
\
bool PFX##_equals(SNAME *_map1_, SNAME *_map2_, int (*value_comparator)(V, V)) \
{ \
if (PFX##_count(_map1_) != PFX##_count(_map2_)) \
return false; \
\
SNAME##_iter iter; \
PFX##_iter_init(&iter, _map1_); \
\
for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
{ \
SNAME##_entry *entry = PFX##_impl_get_entry(_map2_, PFX##_iter_key(&iter)); \
\
if (entry == NULL) \
return false; \
\
if (value_comparator) \
{ \
if (value_comparator(entry->value, PFX##_iter_value(&iter)) != 0) \
return false; \
} \
} \
\
return true; \
} \
\
cmc_string PFX##_to_string(SNAME *_map_) \
{ \
cmc_string str; \
SNAME *m_ = _map_; \
const char *name = #SNAME; \
\
snprintf(str.s, cmc_string_len, cmc_string_fmt_hashmap, \
name, m_, m_->buffer, m_->capacity, m_->count, m_->load, m_->cmp, m_->hash); \
\
return str; \
} \
\
SNAME##_iter *PFX##_iter_new(SNAME *target) \
{ \
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
\
if (!iter) \
return NULL; \
\
PFX##_iter_init(iter, target); \
\
return iter; \
} \
\
void PFX##_iter_free(SNAME##_iter *iter) \
{ \
free(iter); \
} \
\
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
{ \
memset(iter, 0, sizeof(SNAME##_iter)); \
\
iter->target = target; \
iter->start = true; \
iter->end = PFX##_empty(target); \
\
if (!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; \
} \
} \
} \
} \
\
bool PFX##_iter_start(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->start; \
} \
\
bool PFX##_iter_end(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->end; \
} \
\
void PFX##_iter_to_start(SNAME##_iter *iter) \
{ \
if (!PFX##_empty(iter->target)) \
{ \
iter->cursor = iter->first; \
iter->index = 0; \
iter->start = true; \
iter->end = PFX##_empty(iter->target); \
} \
} \
\
void PFX##_iter_to_end(SNAME##_iter *iter) \
{ \
if (!PFX##_empty(iter->target)) \
{ \
iter->cursor = iter->last; \
iter->index = PFX##_count(iter->target) - 1; \
iter->start = PFX##_empty(iter->target); \
iter->end = true; \
} \
} \
\
bool PFX##_iter_next(SNAME##_iter *iter) \
{ \
if (iter->end) \
return false; \
\
if (iter->index + 1 == PFX##_count(iter->target)) \
{ \
iter->end = true; \
return false; \
} \
\
iter->start = PFX##_empty(iter->target); \
\
SNAME##_entry *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 PFX##_iter_prev(SNAME##_iter *iter) \
{ \
if (iter->start) \
return false; \
\
if (iter->index == 0) \
{ \
iter->start = true; \
return false; \
} \
\
iter->end = PFX##_empty(iter->target); \
\
SNAME##_entry *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 PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->end) \
return false; \
\
if (iter->index + 1 == PFX##_count(iter->target)) \
{ \
iter->end = true; \
return false; \
} \
\
if (steps == 0 || iter->index + steps >= PFX##_count(iter->target)) \
return false; \
\
for (size_t i = 0; i < steps; i++) \
PFX##_iter_next(iter); \
\
return true; \
} \
\
/* Returns true only if the iterator moved */ \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
{ \
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++) \
PFX##_iter_prev(iter); \
\
return true; \
} \
\
/* Returns true only if the iterator was able to be positioned at the given index */ \
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
{ \
if (index >= PFX##_count(iter->target)) \
return false; \
\
if (iter->index > index) \
return PFX##_iter_rewind(iter, iter->index - index); \
else if (iter->index < index) \
return PFX##_iter_advance(iter, index - iter->index); \
\
return true; \
} \
\
K PFX##_iter_key(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return (K){0}; \
\
return iter->target->buffer[iter->cursor].key; \
} \
\
V PFX##_iter_value(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return (V){0}; \
\
return iter->target->buffer[iter->cursor].value; \
} \
\
V *PFX##_iter_rvalue(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return NULL; \
\
return &(iter->target->buffer[iter->cursor].value); \
} \
\
size_t PFX##_iter_index(SNAME##_iter *iter) \
{ \
return iter->index; \
} \
\
static SNAME##_entry *PFX##_impl_get_entry(SNAME *_map_, K key) \
{ \
size_t hash = _map_->hash(key); \
size_t pos = hash % _map_->capacity; \
\
SNAME##_entry *target = &(_map_->buffer[pos]); \
\
while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED) \
{ \
if (_map_->cmp(target->key, key) == 0) \
return target; \
\
pos++; \
target = &(_map_->buffer[pos % _map_->capacity]); \
} \
\
return NULL; \
} \
\
static size_t PFX##_impl_calculate_size(size_t required) \
{ \
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]; \
} \
\
static SNAME##_iter PFX##_impl_it_start(SNAME *_map_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _map_); \
\
return iter; \
} \
\
static SNAME##_iter PFX##_impl_it_end(SNAME *_map_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _map_); \
PFX##_iter_to_end(&iter); \
\
return iter; \
}
#endif /* CMC_HASHMAP_H */
+1033
View File
File diff suppressed because it is too large. Load diff
+612
View File
@@ -0,0 +1,612 @@
/**
* 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
*/
#ifndef CMC_HEAP_H
#define CMC_HEAP_H
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../utl/cmc_string.h"
/* to_string format */
static const char *cmc_string_fmt_heap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", type:%s, cmp:%p }";
typedef enum cmc_heap_order_e
{
cmc_max_heap = 1,
cmc_min_heap = -1
} cmc_heap_order;
#define CMC_GENERATE_HEAP(PFX, SNAME, V) \
CMC_GENERATE_HEAP_HEADER(PFX, SNAME, V) \
CMC_GENERATE_HEAP_SOURCE(PFX, SNAME, V)
#define CMC_WRAPGEN_HEAP_HEADER(PFX, SNAME, K, V) \
CMC_GENERATE_HEAP_HEADER(PFX, SNAME, V)
#define CMC_WRAPGEN_HEAP_SOURCE(PFX, SNAME, K, V) \
CMC_GENERATE_HEAP_SOURCE(PFX, SNAME, V)
/* HEADER ********************************************************************/
#define CMC_GENERATE_HEAP_HEADER(PFX, SNAME, V) \
\
/* Heap Structure */ \
typedef struct SNAME##_s \
{ \
/* 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_e HO; \
\
/* Element comparison function */ \
int (*cmp)(V, V); \
\
/* Function that returns an iterator to the start of the heap */ \
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
\
/* Function that returns an iterator to the end of the heap */ \
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
\
} SNAME, *SNAME##_ptr; \
\
/* Heap Iterator */ \
typedef struct SNAME##_iter_s \
{ \
/* Target heap */ \
struct SNAME##_s *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; \
\
} SNAME##_iter, *SNAME##_iter_ptr; \
\
/* Collection Functions */ \
/* Collection Allocation and Deallocation */ \
SNAME *PFX##_new(size_t capacity, cmc_heap_order HO, int (*compare)(V, V)); \
void PFX##_clear(SNAME *_heap_, void (*deallocator)(V)); \
void PFX##_free(SNAME *_heap_, void (*deallocator)(V)); \
/* Collection Input and Output */ \
bool PFX##_insert(SNAME *_heap_, V element); \
bool PFX##_remove(SNAME *_heap_, V *result); \
/* Element Access */ \
V PFX##_peek(SNAME *_heap_); \
/* Collection State */ \
bool PFX##_contains(SNAME *_heap_, V element); \
bool PFX##_empty(SNAME *_heap_); \
bool PFX##_full(SNAME *_heap_); \
size_t PFX##_count(SNAME *_heap_); \
size_t PFX##_capacity(SNAME *_heap_); \
/* Collection Utility */ \
bool PFX##_resize(SNAME *_heap_, size_t capacity); \
SNAME *PFX##_copy_of(SNAME *_heap_, V (*copy_func)(V)); \
bool PFX##_equals(SNAME *_heap1_, SNAME *_heap2_); \
cmc_string PFX##_to_string(SNAME *_heap_); \
\
/* Iterator Functions */ \
/* Iterator Allocation and Deallocation */ \
SNAME##_iter *PFX##_iter_new(SNAME *target); \
void PFX##_iter_free(SNAME##_iter *iter); \
/* Iterator Initialization */ \
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
/* Iterator State */ \
bool PFX##_iter_start(SNAME##_iter *iter); \
bool PFX##_iter_end(SNAME##_iter *iter); \
/* Iterator Movement */ \
void PFX##_iter_to_start(SNAME##_iter *iter); \
void PFX##_iter_to_end(SNAME##_iter *iter); \
bool PFX##_iter_next(SNAME##_iter *iter); \
bool PFX##_iter_prev(SNAME##_iter *iter); \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
/* Iterator Access */ \
V PFX##_iter_value(SNAME##_iter *iter); \
size_t PFX##_iter_index(SNAME##_iter *iter); \
\
/* SOURCE ********************************************************************/
#define CMC_GENERATE_HEAP_SOURCE(PFX, SNAME, V) \
\
/* Implementation Detail Functions */ \
static bool PFX##_impl_float_up(SNAME *_heap_, size_t index); \
static bool PFX##_impl_float_down(SNAME *_heap_, size_t index); \
static SNAME##_iter PFX##_impl_it_start(SNAME *_heap_); \
static SNAME##_iter PFX##_impl_it_end(SNAME *_heap_); \
\
SNAME *PFX##_new(size_t capacity, cmc_heap_order HO, int (*compare)(V, V)) \
{ \
if (capacity < 1) \
return NULL; \
\
if (HO != cmc_min_heap && HO != cmc_max_heap) \
return NULL; \
\
SNAME *_heap_ = malloc(sizeof(SNAME)); \
\
if (!_heap_) \
return NULL; \
\
_heap_->buffer = malloc(sizeof(V) * capacity); \
\
if (!_heap_->buffer) \
{ \
free(_heap_); \
return NULL; \
} \
\
memset(_heap_->buffer, 0, sizeof(V) * capacity); \
\
_heap_->capacity = capacity; \
_heap_->count = 0; \
_heap_->HO = HO; \
_heap_->cmp = compare; \
\
_heap_->it_start = PFX##_impl_it_start; \
_heap_->it_end = PFX##_impl_it_end; \
\
return _heap_; \
} \
\
void PFX##_clear(SNAME *_heap_, void (*deallocator)(V)) \
{ \
if (deallocator) \
{ \
for (size_t i = 0; i < _heap_->count; i++) \
{ \
deallocator(_heap_->buffer[i]); \
} \
} \
\
memset(_heap_->buffer, 0, sizeof(V) * _heap_->capacity); \
\
_heap_->count = 0; \
} \
\
void PFX##_free(SNAME *_heap_, void (*deallocator)(V)) \
{ \
if (deallocator) \
{ \
for (size_t i = 0; i < _heap_->count; i++) \
{ \
deallocator(_heap_->buffer[i]); \
} \
} \
\
free(_heap_->buffer); \
free(_heap_); \
} \
\
bool PFX##_insert(SNAME *_heap_, V element) \
{ \
if (PFX##_full(_heap_)) \
{ \
if (!PFX##_resize(_heap_, PFX##_count(_heap_) * 2)) \
return false; \
} \
\
if (PFX##_empty(_heap_)) \
{ \
_heap_->buffer[_heap_->count++] = element; \
return true; \
} \
\
_heap_->buffer[_heap_->count++] = element; \
\
if (!PFX##_impl_float_up(_heap_, _heap_->count - 1)) \
return false; \
\
return true; \
} \
\
bool PFX##_remove(SNAME *_heap_, V *result) \
{ \
if (PFX##_empty(_heap_)) \
return false; \
\
*result = _heap_->buffer[0]; \
_heap_->buffer[0] = _heap_->buffer[_heap_->count - 1]; \
_heap_->buffer[_heap_->count - 1] = (V){0}; \
\
_heap_->count--; \
\
if (!PFX##_impl_float_down(_heap_, 0)) \
return false; \
\
return true; \
} \
\
V PFX##_peek(SNAME *_heap_) \
{ \
if (PFX##_empty(_heap_)) \
return (V){0}; \
\
return _heap_->buffer[0]; \
} \
\
bool PFX##_contains(SNAME *_heap_, V element) \
{ \
for (size_t i = 0; i < _heap_->count; i++) \
{ \
if (_heap_->cmp(_heap_->buffer[i], element) == 0) \
return true; \
} \
\
return false; \
} \
\
bool PFX##_empty(SNAME *_heap_) \
{ \
return _heap_->count == 0; \
} \
\
bool PFX##_full(SNAME *_heap_) \
{ \
return _heap_->count >= _heap_->capacity; \
} \
\
size_t PFX##_count(SNAME *_heap_) \
{ \
return _heap_->count; \
} \
\
size_t PFX##_capacity(SNAME *_heap_) \
{ \
return _heap_->capacity; \
} \
\
bool PFX##_resize(SNAME *_heap_, size_t capacity) \
{ \
if (PFX##_capacity(_heap_) == capacity) \
return true; \
\
if (capacity < PFX##_count(_heap_)) \
return false; \
\
V *new_buffer = realloc(_heap_->buffer, sizeof(V) * capacity); \
\
if (!new_buffer) \
return false; \
\
_heap_->buffer = new_buffer; \
_heap_->capacity = capacity; \
\
return true; \
} \
\
SNAME *PFX##_copy_of(SNAME *_heap_, V (*copy_func)(V)) \
{ \
SNAME *result = PFX##_new(_heap_->capacity, _heap_->HO, _heap_->cmp); \
\
if (!result) \
return NULL; \
\
if (copy_func) \
{ \
for (size_t i = 0; i < _heap_->count; i++) \
result->buffer[i] = copy_func(_heap_->buffer[i]); \
} \
else \
memcpy(result->buffer, _heap_->buffer, sizeof(V) * _heap_->count); \
\
result->count = _heap_->count; \
\
return result; \
} \
\
bool PFX##_equals(SNAME *_heap1_, SNAME *_heap2_) \
{ \
if (PFX##_count(_heap1_) != PFX##_count(_heap2_)) \
return false; \
\
for (size_t i = 0; i < PFX##_count(_heap1_); i++) \
{ \
if (_heap1_->cmp(_heap1_->buffer[i], _heap2_->buffer[i]) != 0) \
return false; \
} \
\
return true; \
} \
\
cmc_string PFX##_to_string(SNAME *_heap_) \
{ \
cmc_string str; \
SNAME *h_ = _heap_; \
const char *name = #SNAME; \
const char *t = h_->HO == 1 ? "MaxHeap" : "MinHeap"; \
\
snprintf(str.s, cmc_string_len, cmc_string_fmt_heap, \
name, h_, h_->buffer, h_->capacity, h_->count, t, h_->cmp); \
\
return str; \
} \
\
SNAME##_iter *PFX##_iter_new(SNAME *target) \
{ \
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
\
if (!iter) \
return NULL; \
\
PFX##_iter_init(iter, target); \
\
return iter; \
} \
\
void PFX##_iter_free(SNAME##_iter *iter) \
{ \
free(iter); \
} \
\
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
{ \
iter->target = target; \
iter->cursor = 0; \
iter->start = true; \
iter->end = PFX##_empty(target); \
} \
\
bool PFX##_iter_start(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->start; \
} \
\
bool PFX##_iter_end(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->end; \
} \
\
void PFX##_iter_to_start(SNAME##_iter *iter) \
{ \
if (!PFX##_empty(iter->target)) \
{ \
iter->cursor = 0; \
iter->start = true; \
iter->end = PFX##_empty(iter->target); \
} \
} \
\
void PFX##_iter_to_end(SNAME##_iter *iter) \
{ \
if (!PFX##_empty(iter->target)) \
{ \
iter->cursor = PFX##_count(iter->target) - 1; \
iter->start = PFX##_empty(iter->target); \
iter->end = true; \
} \
} \
\
bool PFX##_iter_next(SNAME##_iter *iter) \
{ \
if (iter->end) \
return false; \
\
if (iter->cursor + 1 == PFX##_count(iter->target)) \
{ \
iter->end = true; \
return false; \
} \
\
iter->start = PFX##_empty(iter->target); \
\
iter->cursor++; \
\
return true; \
} \
\
bool PFX##_iter_prev(SNAME##_iter *iter) \
{ \
if (iter->start) \
return false; \
\
if (iter->cursor == 0) \
{ \
iter->start = true; \
return false; \
} \
\
iter->end = PFX##_empty(iter->target); \
\
iter->cursor--; \
\
return true; \
} \
\
/* Returns true only if the iterator moved */ \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->start) \
return false; \
\
if (iter->cursor + 1 == PFX##_count(iter->target)) \
{ \
iter->end = true; \
return false; \
} \
\
if (steps == 0 || iter->cursor + steps >= PFX##_count(iter->target)) \
return false; \
\
iter->start = PFX##_empty(iter->target); \
\
if (iter->end) \
return false; \
\
iter->cursor += steps; \
\
return true; \
} \
\
/* Returns true only if the iterator moved */ \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->start) \
return false; \
\
if (iter->cursor == 0) \
{ \
iter->start = true; \
return false; \
} \
\
if (steps == 0 || iter->cursor < steps) \
return false; \
\
iter->end = 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 PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
{ \
if (index >= PFX##_count(iter->target)) \
return false; \
\
if (iter->cursor > index) \
return PFX##_iter_rewind(iter, iter->cursor - index); \
else if (iter->cursor < index) \
return PFX##_iter_advance(iter, index - iter->cursor); \
\
return true; \
} \
\
V PFX##_iter_value(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return (V){0}; \
\
return iter->target->buffer[iter->cursor]; \
} \
\
size_t PFX##_iter_index(SNAME##_iter *iter) \
{ \
return iter->cursor; \
} \
\
static bool PFX##_impl_float_up(SNAME *_heap_, size_t index) \
{ \
/* 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_->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; \
\
child = _heap_->buffer[C]; \
parent = _heap_->buffer[(C - 1) / 2]; \
} \
\
return true; \
} \
\
static bool PFX##_impl_float_down(SNAME *_heap_, size_t index) \
{ \
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_->cmp(_heap_->buffer[L], _heap_->buffer[C]) * mod > 0) \
{ \
C = L; \
} \
\
if (R < _heap_->count && _heap_->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; \
} \
\
return true; \
} \
\
static SNAME##_iter PFX##_impl_it_start(SNAME *_heap_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _heap_); \
PFX##_iter_to_start(&iter); \
\
return iter; \
} \
\
static SNAME##_iter PFX##_impl_it_end(SNAME *_heap_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _heap_); \
PFX##_iter_to_end(&iter); \
\
return iter; \
}
#endif /* CMC_HEAP_H */
+905
View File
@@ -0,0 +1,905 @@
/**
* 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.
*/
#ifndef CMC_LINKEDLIST_H
#define CMC_LINKEDLIST_H
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../utl/cmc_string.h"
/* to_string format */
static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", head:%p, tail:%p }";
#define CMC_GENERATE_LINKEDLIST(PFX, SNAME, V) \
CMC_GENERATE_LINKEDLIST_HEADER(PFX, SNAME, V) \
CMC_GENERATE_LINKEDLIST_SOURCE(PFX, SNAME, V)
#define CMC_WRAPGEN_LINKEDLIST_HEADER(PFX, SNAME, K, V) \
CMC_GENERATE_LINKEDLIST_HEADER(PFX, SNAME, V)
#define CMC_WRAPGEN_LINKEDLIST_SOURCE(PFX, SNAME, K, V) \
CMC_GENERATE_LINKEDLIST_SOURCE(PFX, SNAME, V)
/* HEADER ********************************************************************/
#define CMC_GENERATE_LINKEDLIST_HEADER(PFX, SNAME, V) \
\
/* Linked List Structure */ \
typedef struct SNAME##_s \
{ \
/* First node in the list */ \
struct SNAME##_node_s *head; \
\
/* Last node in the list */ \
struct SNAME##_node_s *tail; \
\
/* Current amount of elements in the list */ \
size_t count; \
\
/* Function that returns an iterator to the start of the list */ \
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
\
/* Function that returns an iterator to the end of the list */ \
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
\
} SNAME, *SNAME##_ptr; \
\
/* Doubly-linked list node */ \
typedef struct SNAME##_node_s \
{ \
/* Node's data */ \
V data; \
\
/* Pointer to the next node on the linked list */ \
struct SNAME##_node_s *next; \
\
/* Pointer to the previous node on the linked list */ \
struct SNAME##_node_s *prev; \
\
} SNAME##_node, *SNAME##_node_ptr; \
\
/* Linked List Iterator */ \
typedef struct SNAME##_iter_s \
{ \
/* Target Linked List */ \
struct SNAME##_s *target; \
\
/* Cursor's current node */ \
struct SNAME##_node_s *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; \
\
} SNAME##_iter, *SNAME##_iter_ptr; \
\
/* Collection Functions */ \
/* Collection Allocation and Deallocation */ \
SNAME *PFX##_new(void); \
void PFX##_clear(SNAME *_list_, void (*deallocator)(V)); \
void PFX##_free(SNAME *_list_, void (*deallocator)(V)); \
/* Collection Input and Output */ \
bool PFX##_push_front(SNAME *_list_, V element); \
bool PFX##_push_at(SNAME *_list_, V element, size_t index); \
bool PFX##_push_back(SNAME *_list_, V element); \
bool PFX##_pop_front(SNAME *_list_); \
bool PFX##_pop_at(SNAME *_list_, size_t index); \
bool PFX##_pop_back(SNAME *_list_); \
/* Element Access */ \
V PFX##_front(SNAME *_list_); \
V PFX##_get(SNAME *_list_, size_t index); \
V *PFX##_get_ref(SNAME *_list_, size_t index); \
V PFX##_back(SNAME *_list_); \
/* Collection State */ \
bool PFX##_contains(SNAME *_list_, V element, int (*comparator)(V, V)); \
bool PFX##_empty(SNAME *_list_); \
size_t PFX##_count(SNAME *_list_); \
/* Collection Utility */ \
SNAME *PFX##_copy_of(SNAME *_list_, V (*copy_func)(V)); \
bool PFX##_equals(SNAME *_list1_, SNAME *_list2_, int (*comparator)(V, V)); \
cmc_string PFX##_to_string(SNAME *_list_); \
\
/* Node Related Functions */ \
/* Node Allocation and Deallocation */ \
SNAME##_node *PFX##_new_node(V element); \
void PFX##_free_node(SNAME##_node *_node_); \
/* Node Access Relative to a Linked List */ \
SNAME##_node *PFX##_head(SNAME *_list_); \
SNAME##_node *PFX##_get_node(SNAME *_list_, size_t index); \
SNAME##_node *PFX##_tail(SNAME *_list_); \
/* Input and Output Relative to a Node */ \
bool PFX##_insert_after(SNAME *_owner_, SNAME##_node *_node_, V element); \
bool PFX##_insert_before(SNAME *_owner_, SNAME##_node *_node_, V element); \
bool PFX##_remove_after(SNAME *_owner_, SNAME##_node *_node_); \
bool PFX##_remove_current(SNAME *_owner_, SNAME##_node *_node_); \
bool PFX##_remove_before(SNAME *_owner_, SNAME##_node *_node_); \
/* Node Access Relative to a Linked List Node */ \
SNAME##_node *PFX##_next_node(SNAME##_node *_node_); \
SNAME##_node *PFX##_prev_node(SNAME##_node *_node_); \
\
/* Iterator Functions */ \
/* Iterator Allocation and Deallocation */ \
SNAME##_iter *PFX##_iter_new(SNAME *target); \
void PFX##_iter_free(SNAME##_iter *iter); \
/* Iterator Initialization */ \
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
/* Iterator State */ \
bool PFX##_iter_start(SNAME##_iter *iter); \
bool PFX##_iter_end(SNAME##_iter *iter); \
/* Iterator Movement */ \
void PFX##_iter_to_start(SNAME##_iter *iter); \
void PFX##_iter_to_end(SNAME##_iter *iter); \
bool PFX##_iter_next(SNAME##_iter *iter); \
bool PFX##_iter_prev(SNAME##_iter *iter); \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
/* Iterator Access */ \
V PFX##_iter_value(SNAME##_iter *iter); \
V *PFX##_iter_rvalue(SNAME##_iter *iter); \
size_t PFX##_iter_index(SNAME##_iter *iter); \
SNAME##_node *PFX##_iter_node(SNAME##_iter *iter); \
\
/* SOURCE ********************************************************************/
#define CMC_GENERATE_LINKEDLIST_SOURCE(PFX, SNAME, V) \
\
/* Implementation Detail Functions */ \
static SNAME##_iter PFX##_impl_it_start(SNAME *_list_); \
static SNAME##_iter PFX##_impl_it_end(SNAME *_list_); \
\
SNAME *PFX##_new(void) \
{ \
SNAME *_list_ = malloc(sizeof(SNAME)); \
\
if (!_list_) \
return NULL; \
\
_list_->count = 0; \
_list_->head = NULL; \
_list_->tail = NULL; \
\
_list_->it_start = PFX##_impl_it_start; \
_list_->it_end = PFX##_impl_it_end; \
\
return _list_; \
} \
\
void PFX##_clear(SNAME *_list_, void (*deallocator)(V)) \
{ \
SNAME##_node *scan = _list_->head; \
\
while (_list_->head != NULL) \
{ \
_list_->head = _list_->head->next; \
\
if (deallocator) \
{ \
deallocator(scan->data); \
} \
\
free(scan); \
\
scan = _list_->head; \
} \
\
_list_->count = 0; \
_list_->head = NULL; \
_list_->tail = NULL; \
} \
\
void PFX##_free(SNAME *_list_, void (*deallocator)(V)) \
{ \
PFX##_clear(_list_, deallocator); \
\
free(_list_); \
} \
\
bool PFX##_push_front(SNAME *_list_, V element) \
{ \
SNAME##_node *_node_ = PFX##_new_node(element); \
\
if (!_node_) \
return false; \
\
if (PFX##_empty(_list_)) \
{ \
_list_->head = _node_; \
_list_->tail = _node_; \
} \
else \
{ \
_node_->next = _list_->head; \
_list_->head->prev = _node_; \
_list_->head = _node_; \
} \
\
_list_->count++; \
\
return true; \
} \
\
bool PFX##_push_at(SNAME *_list_, V element, size_t index) \
{ \
if (index > _list_->count) \
return false; \
\
if (index == 0) \
{ \
return PFX##_push_front(_list_, element); \
} \
else if (index == _list_->count) \
{ \
return PFX##_push_back(_list_, element); \
} \
\
SNAME##_node *_node_ = PFX##_new_node(element); \
\
if (!_node_) \
return false; \
\
SNAME##_node *scan = PFX##_get_node(_list_, index - 1); \
\
_node_->next = scan->next; \
_node_->prev = scan; \
_node_->next->prev = _node_; \
_node_->prev->next = _node_; \
\
_list_->count++; \
\
return true; \
} \
\
bool PFX##_push_back(SNAME *_list_, V element) \
{ \
SNAME##_node *_node_ = PFX##_new_node(element); \
\
if (!_node_) \
return false; \
\
if (PFX##_empty(_list_)) \
{ \
_list_->head = _node_; \
_list_->tail = _node_; \
} \
else \
{ \
_node_->prev = _list_->tail; \
_list_->tail->next = _node_; \
_list_->tail = _node_; \
} \
\
_list_->count++; \
\
return true; \
} \
\
bool PFX##_pop_front(SNAME *_list_) \
{ \
if (PFX##_empty(_list_)) \
return false; \
\
SNAME##_node *_node_ = _list_->head; \
_list_->head = _list_->head->next; \
\
free(_node_); \
\
if (_list_->head == NULL) \
_list_->tail = NULL; \
else \
_list_->head->prev = NULL; \
\
_list_->count--; \
\
return true; \
} \
\
bool PFX##_pop_at(SNAME *_list_, size_t index) \
{ \
if (PFX##_empty(_list_)) \
return false; \
\
if (index >= _list_->count) \
return false; \
\
if (index == 0) \
{ \
return PFX##_pop_front(_list_); \
} \
else if (index == _list_->count - 1) \
{ \
return PFX##_pop_back(_list_); \
} \
\
SNAME##_node *_node_ = PFX##_get_node(_list_, index); \
\
if (!_node_) \
return false; \
\
_node_->next->prev = _node_->prev; \
_node_->prev->next = _node_->next; \
\
free(_node_); \
\
_list_->count--; \
\
return true; \
} \
\
bool PFX##_pop_back(SNAME *_list_) \
{ \
if (PFX##_empty(_list_)) \
return false; \
\
SNAME##_node *_node_ = _list_->tail; \
_list_->tail = _list_->tail->prev; \
\
free(_node_); \
\
if (_list_->tail == NULL) \
_list_->head = NULL; \
else \
_list_->tail->next = NULL; \
\
_list_->count--; \
\
return true; \
} \
\
V PFX##_front(SNAME *_list_) \
{ \
if (PFX##_empty(_list_)) \
return (V){0}; \
\
return _list_->head->data; \
} \
\
V PFX##_get(SNAME *_list_, size_t index) \
{ \
if (index >= _list_->count || PFX##_empty(_list_)) \
return (V){0}; \
\
SNAME##_node *scan = PFX##_get_node(_list_, index); \
\
if (scan == NULL) \
return (V){0}; \
\
return scan->data; \
} \
\
V *PFX##_get_ref(SNAME *_list_, size_t index) \
{ \
if (index >= _list_->count) \
return NULL; \
\
if (PFX##_empty(_list_)) \
return NULL; \
\
SNAME##_node *scan = PFX##_get_node(_list_, index); \
\
if (scan == NULL) \
return NULL; \
\
return &(scan->data); \
} \
\
V PFX##_back(SNAME *_list_) \
{ \
if (PFX##_empty(_list_)) \
return (V){0}; \
\
return _list_->tail->data; \
} \
\
bool PFX##_contains(SNAME *_list_, V element, int (*comparator)(V, V)) \
{ \
SNAME##_node *scan = _list_->head; \
\
while (scan != NULL) \
{ \
if (comparator(scan->data, element) == 0) \
return true; \
\
scan = scan->next; \
} \
\
return false; \
} \
\
bool PFX##_empty(SNAME *_list_) \
{ \
return _list_->count == 0; \
} \
\
size_t PFX##_count(SNAME *_list_) \
{ \
return _list_->count; \
} \
\
SNAME *PFX##_copy_of(SNAME *_list_, V (*copy_func)(V)) \
{ \
SNAME *result = PFX##_new(); \
\
if (!result) \
return NULL; \
\
SNAME##_node *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 */ \
SNAME##_node *new_node; \
\
if (copy_func) \
new_node = PFX##_new_node(copy_func(scan->data)); \
else \
new_node = PFX##_new_node(scan->data); \
\
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; \
\
return result; \
} \
\
bool PFX##_equals(SNAME *_list1_, SNAME *_list2_, int (*comparator)(V, V)) \
{ \
if (PFX##_count(_list1_) != PFX##_count(_list2_)) \
return false; \
\
SNAME##_node *scan1 = _list1_->head; \
SNAME##_node *scan2 = _list2_->head; \
\
while (scan1 != NULL && scan2 != NULL) \
{ \
if (comparator(scan1->data, scan2->data) != 0) \
return false; \
\
scan1 = scan1->next; \
scan2 = scan2->next; \
} \
\
return true; \
} \
\
cmc_string PFX##_to_string(SNAME *_list_) \
{ \
cmc_string str; \
SNAME *l_ = _list_; \
const char *name = #SNAME; \
\
snprintf(str.s, cmc_string_len, cmc_string_fmt_linkedlist, \
name, l_, l_->count, l_->head, l_->tail); \
\
return str; \
} \
\
SNAME##_node *PFX##_new_node(V element) \
{ \
SNAME##_node *_node_ = malloc(sizeof(SNAME##_node)); \
\
if (!_node_) \
return NULL; \
\
_node_->data = element; \
_node_->next = NULL; \
_node_->prev = NULL; \
\
return _node_; \
} \
\
void PFX##_free_node(SNAME##_node *_node_) \
{ \
free(_node_); \
} \
\
SNAME##_node *PFX##_head(SNAME *_list_) \
{ \
return _list_->head; \
} \
\
SNAME##_node *PFX##_get_node(SNAME *_list_, size_t index) \
{ \
if (index >= _list_->count) \
return NULL; \
\
if (PFX##_empty(_list_)) \
return NULL; \
\
SNAME##_node *_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; \
} \
} \
\
return _node_; \
} \
\
SNAME##_node *PFX##_tail(SNAME *_list_) \
{ \
return _list_->tail; \
} \
\
bool PFX##_insert_after(SNAME *_owner_, SNAME##_node *_node_, V element) \
{ \
SNAME##_node *new_node = PFX##_new_node(element); \
\
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++; \
\
return true; \
} \
\
bool PFX##_insert_before(SNAME *_owner_, SNAME##_node *_node_, V element) \
{ \
SNAME##_node *new_node = PFX##_new_node(element); \
\
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++; \
\
return true; \
} \
\
bool PFX##_remove_after(SNAME *_owner_, SNAME##_node *_node_) \
{ \
if (_node_->next == NULL) \
return false; \
\
SNAME##_node *tmp = _node_->next; \
\
if (tmp->next != NULL) \
{ \
_node_->next = _node_->next->next; \
_node_->next->prev = _node_; \
} \
else \
_owner_->tail = _node_; \
\
free(tmp); \
\
_owner_->count--; \
\
return true; \
} \
\
bool PFX##_remove_current(SNAME *_owner_, SNAME##_node *_node_) \
{ \
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; \
\
free(_node_); \
\
_owner_->count--; \
\
return true; \
} \
\
bool PFX##_remove_before(SNAME *_owner_, SNAME##_node *_node_) \
{ \
if (_node_->prev == NULL) \
return false; \
\
SNAME##_node *tmp = _node_->prev; \
\
if (tmp->prev != NULL) \
{ \
_node_->prev = _node_->prev->prev; \
_node_->prev->next = _node_; \
} \
else \
_owner_->head = _node_; \
\
free(tmp); \
\
_owner_->count--; \
\
return true; \
} \
\
SNAME##_node *PFX##_next_node(SNAME##_node *_node_) \
{ \
return _node_->next; \
} \
\
SNAME##_node *PFX##_prev_node(SNAME##_node *_node_) \
{ \
return _node_->prev; \
} \
\
SNAME##_iter *PFX##_iter_new(SNAME *target) \
{ \
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
\
if (!iter) \
return NULL; \
\
PFX##_iter_init(iter, target); \
\
return iter; \
} \
\
void PFX##_iter_free(SNAME##_iter *iter) \
{ \
free(iter); \
} \
\
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
{ \
iter->target = target; \
iter->cursor = target->head; \
iter->index = 0; \
iter->start = true; \
iter->end = PFX##_empty(target); \
} \
\
bool PFX##_iter_start(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->start; \
} \
\
bool PFX##_iter_end(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->end; \
} \
\
void PFX##_iter_to_start(SNAME##_iter *iter) \
{ \
if (!PFX##_empty(iter->target)) \
{ \
iter->cursor = iter->target->head; \
iter->index = 0; \
iter->start = true; \
iter->end = PFX##_empty(iter->target); \
} \
} \
\
void PFX##_iter_to_end(SNAME##_iter *iter) \
{ \
if (!PFX##_empty(iter->target)) \
{ \
iter->cursor = iter->target->tail; \
iter->index = iter->target->count - 1; \
iter->start = PFX##_empty(iter->target); \
iter->end = true; \
} \
} \
\
bool PFX##_iter_next(SNAME##_iter *iter) \
{ \
if (iter->end) \
return false; \
\
if (iter->cursor->next == NULL) \
{ \
iter->end = true; \
return false; \
} \
\
iter->start = PFX##_empty(iter->target); \
\
iter->cursor = iter->cursor->next; \
iter->index++; \
\
return true; \
} \
\
bool PFX##_iter_prev(SNAME##_iter *iter) \
{ \
if (iter->start) \
return false; \
\
if (iter->cursor->prev == NULL) \
{ \
iter->start = true; \
return false; \
} \
\
iter->end = PFX##_empty(iter->target); \
\
iter->cursor = iter->cursor->prev; \
iter->index--; \
\
return true; \
} \
\
/* Returns true only if the iterator moved */ \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->end) \
return false; \
\
if (iter->cursor->next == NULL) \
{ \
iter->end = true; \
return false; \
} \
\
if (steps == 0 || iter->index + steps >= PFX##_count(iter->target)) \
return false; \
\
iter->start = 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 PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
{ \
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 = 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 PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
{ \
if (index >= PFX##_count(iter->target)) \
return false; \
\
if (iter->index > index) \
return PFX##_iter_rewind(iter, iter->index - index); \
else if (iter->index < index) \
return PFX##_iter_advance(iter, index - iter->index); \
\
return true; \
} \
\
V PFX##_iter_value(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return (V){0}; \
\
return iter->cursor->data; \
} \
\
V *PFX##_iter_rvalue(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return NULL; \
\
return &(iter->cursor->data); \
} \
\
size_t PFX##_iter_index(SNAME##_iter *iter) \
{ \
return iter->index; \
} \
\
SNAME##_node *PFX##_iter_node(SNAME##_iter *iter) \
{ \
return iter->cursor; \
} \
\
static SNAME##_iter PFX##_impl_it_start(SNAME *_list_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _list_); \
PFX##_iter_to_start(&iter); \
\
return iter; \
} \
\
static SNAME##_iter PFX##_impl_it_end(SNAME *_list_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _list_); \
PFX##_iter_to_end(&iter); \
\
return iter; \
}
#endif /* CMC_LINKEDLIST_H */
+788
View File
@@ -0,0 +1,788 @@
/**
* list.h
*
* Creation Date: 12/02/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* List
*
* A List is a Dynamic Array that store its elements contiguously. It has an
* internal buffer that is pre-allocated with a greater capacity than necessary
* in order to foresee new elements being added. The items can be added at both
* ends of the list and at the middle (with a given index).
*
* Insertions at the start are more costly as it is necessary to shift all
* elements one position to the right to give space to a new element being added
* at index 0. Insertions at the end are instantaneous as long as there is
* enough space in the buffer. Insertions at the middle will be based on an
* index. The index represents where the element being added will be located
* once the operation ends. This operation might also need to shift elements. It
* is also possible to add arrays of elements in the list.
*
* When the buffer is filled, it is reallocated with a greater capacity, usually
* being doubled.
*
* Removing elements follows the same principle. Removing the front element will
* require to shift all other elements one position to the left, thus being
* slower than removing from the end in which is done in constant time. Removing
* elements in the middle of the list will also require shifting elements to the
* left. Is is also possible to remove a range of elements or extract them,
* creating a new list with the removed items.
*
* The iterator is a simple structure that is capable of going back and
* forwards. Any modifications to the target list during iteration is considered
* undefined behavior. Its sole purpose is to facilitate navigation through a
* list.
*/
#ifndef CMC_LIST_H
#define CMC_LIST_H
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../utl/cmc_string.h"
/* to_string format */
static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
#define CMC_GENERATE_LIST(PFX, SNAME, V) \
CMC_GENERATE_LIST_HEADER(PFX, SNAME, V) \
CMC_GENERATE_LIST_SOURCE(PFX, SNAME, V)
#define CMC_WRAPGEN_LIST_HEADER(PFX, SNAME, K, V) \
CMC_GENERATE_LIST_HEADER(PFX, SNAME, V)
#define CMC_WRAPGEN_LIST_SOURCE(PFX, SNAME, K, V) \
CMC_GENERATE_LIST_SOURCE(PFX, SNAME, V)
/* HEADER ********************************************************************/
#define CMC_GENERATE_LIST_HEADER(PFX, SNAME, V) \
\
/* List Structure */ \
typedef struct SNAME##_s \
{ \
/* Dynamic array of elements */ \
V *buffer; \
\
/* Current array capacity */ \
size_t capacity; \
\
/* Current amount of elements */ \
size_t count; \
\
/* Function that returns an iterator to the start of the list */ \
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
\
/* Function that returns an iterator to the end of the list */ \
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
\
} SNAME, *SNAME##_ptr; \
\
/* List Iterator */ \
typedef struct SNAME##_iter_s \
{ \
/* Target list */ \
struct SNAME##_s *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; \
\
} SNAME##_iter, *SNAME##_iter_ptr; \
\
/* Collection Functions */ \
/* Collection Allocation and Deallocation */ \
SNAME *PFX##_new(size_t capacity); \
SNAME *PFX##_new_from(V *elements, size_t size); \
void PFX##_clear(SNAME *_list_, void (*deallocator)(V)); \
void PFX##_free(SNAME *_list_, void (*deallocator)(V)); \
/* Collection Input and Output */ \
bool PFX##_push_front(SNAME *_list_, V element); \
bool PFX##_push_at(SNAME *_list_, V element, size_t index); \
bool PFX##_push_back(SNAME *_list_, V element); \
bool PFX##_pop_front(SNAME *_list_); \
bool PFX##_pop_at(SNAME *_list_, size_t index); \
bool PFX##_pop_back(SNAME *_list_); \
/* Collection Sequence Input and Output */ \
bool PFX##_seq_push_front(SNAME *_list_, V *elements, size_t size); \
bool PFX##_seq_push_at(SNAME *_list_, V *elements, size_t size, size_t index); \
bool PFX##_seq_push_back(SNAME *_list_, V *elements, size_t size); \
bool PFX##_seq_pop_at(SNAME *_list_, size_t from, size_t to); \
SNAME *PFX##_seq_sublist(SNAME *_list_, size_t from, size_t to); \
/* Element Access */ \
V PFX##_front(SNAME *_list_); \
V PFX##_get(SNAME *_list_, size_t index); \
V *PFX##_get_ref(SNAME *_list_, size_t index); \
V PFX##_back(SNAME *_list_); \
size_t PFX##_indexof(SNAME *_list_, V element, int (*comparator)(V, V), bool from_start); \
/* Collection State */ \
bool PFX##_contains(SNAME *_list_, V element, int (*comparator)(V, V)); \
bool PFX##_empty(SNAME *_list_); \
bool PFX##_full(SNAME *_list_); \
size_t PFX##_count(SNAME *_list_); \
bool PFX##_fits(SNAME *_list_, size_t size); \
size_t PFX##_capacity(SNAME *_list_); \
/* Collection Utility */ \
bool PFX##_resize(SNAME *_list_, size_t capacity); \
SNAME *PFX##_copy_of(SNAME *_list_, V (*copy_func)(V)); \
bool PFX##_equals(SNAME *_list1_, SNAME *_list2_, int (*comparator)(V, V)); \
cmc_string PFX##_to_string(SNAME *_list_); \
\
/* Iterator Functions */ \
/* Iterator Allocation and Deallocation */ \
SNAME##_iter *PFX##_iter_new(SNAME *target); \
void PFX##_iter_free(SNAME##_iter *iter); \
/* Iterator Initialization */ \
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
/* Iterator State */ \
bool PFX##_iter_start(SNAME##_iter *iter); \
bool PFX##_iter_end(SNAME##_iter *iter); \
/* Iterator Movement */ \
void PFX##_iter_to_start(SNAME##_iter *iter); \
void PFX##_iter_to_end(SNAME##_iter *iter); \
bool PFX##_iter_next(SNAME##_iter *iter); \
bool PFX##_iter_prev(SNAME##_iter *iter); \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
/* Iterator Access */ \
V PFX##_iter_value(SNAME##_iter *iter); \
V *PFX##_iter_rvalue(SNAME##_iter *iter); \
size_t PFX##_iter_index(SNAME##_iter *iter); \
\
/* SOURCE ********************************************************************/
#define CMC_GENERATE_LIST_SOURCE(PFX, SNAME, V) \
\
/* Implementation Detail Functions */ \
static SNAME##_iter PFX##_impl_it_start(SNAME *_list_); \
static SNAME##_iter PFX##_impl_it_end(SNAME *_list_); \
\
SNAME *PFX##_new(size_t capacity) \
{ \
if (capacity < 1) \
return NULL; \
\
SNAME *_list_ = malloc(sizeof(SNAME)); \
\
if (!_list_) \
return NULL; \
\
_list_->buffer = malloc(capacity * sizeof(V)); \
\
if (!_list_->buffer) \
{ \
free(_list_); \
return NULL; \
} \
\
memset(_list_->buffer, 0, capacity * sizeof(V)); \
\
_list_->capacity = capacity; \
_list_->count = 0; \
\
_list_->it_start = PFX##_impl_it_start; \
_list_->it_end = PFX##_impl_it_end; \
\
return _list_; \
} \
\
SNAME *PFX##_new_from(V *elements, size_t size) \
{ \
if (size == 0) \
return NULL; \
\
SNAME *_list_ = PFX##_new(size + size / 2); \
\
if (!_list_) \
return NULL; \
\
memcpy(_list_->buffer, elements, size * sizeof(V)); \
\
_list_->count = size; \
\
return _list_; \
} \
\
void PFX##_clear(SNAME *_list_, void (*deallocator)(V)) \
{ \
if (deallocator) \
{ \
for (size_t i = 0; i < _list_->count; i++) \
deallocator(_list_->buffer[i]); \
} \
\
memset(_list_->buffer, 0, sizeof(V) * _list_->capacity); \
\
_list_->count = 0; \
} \
\
void PFX##_free(SNAME *_list_, void (*deallocator)(V)) \
{ \
if (deallocator) \
{ \
for (size_t i = 0; i < _list_->count; i++) \
deallocator(_list_->buffer[i]); \
} \
\
free(_list_->buffer); \
free(_list_); \
} \
\
bool PFX##_push_front(SNAME *_list_, V element) \
{ \
if (PFX##_full(_list_)) \
{ \
if (!PFX##_resize(_list_, PFX##_count(_list_) * 2)) \
return false; \
} \
\
if (!PFX##_empty(_list_)) \
{ \
memmove(_list_->buffer + 1, _list_->buffer, _list_->count * sizeof(V)); \
} \
\
_list_->buffer[0] = element; \
\
_list_->count++; \
\
return true; \
} \
\
bool PFX##_push_at(SNAME *_list_, V element, size_t index) \
{ \
if (index > _list_->count) \
return false; \
\
if (PFX##_full(_list_)) \
{ \
if (!PFX##_resize(_list_, PFX##_count(_list_) * 2)) \
return false; \
} \
\
memmove(_list_->buffer + index + 1, _list_->buffer + index, \
(_list_->count - index) * sizeof(V)); \
\
_list_->buffer[index] = element; \
_list_->count++; \
\
return true; \
} \
\
bool PFX##_push_back(SNAME *_list_, V element) \
{ \
if (PFX##_full(_list_)) \
{ \
if (!PFX##_resize(_list_, PFX##_count(_list_) * 2)) \
return false; \
} \
\
_list_->buffer[_list_->count++] = element; \
\
return true; \
} \
\
bool PFX##_pop_front(SNAME *_list_) \
{ \
if (PFX##_empty(_list_)) \
return false; \
\
memmove(_list_->buffer, _list_->buffer + 1, _list_->count * sizeof(V)); \
\
_list_->buffer[--_list_->count] = (V){0}; \
\
return true; \
} \
\
bool PFX##_pop_at(SNAME *_list_, size_t index) \
{ \
if (index >= _list_->count) \
return false; \
\
memmove(_list_->buffer + index, _list_->buffer + index + 1, \
(_list_->count - index) * sizeof(V)); \
\
_list_->buffer[--_list_->count] = (V){0}; \
\
return true; \
} \
\
bool PFX##_pop_back(SNAME *_list_) \
{ \
if (PFX##_empty(_list_)) \
return false; \
\
_list_->buffer[--_list_->count] = (V){0}; \
\
return true; \
} \
\
bool PFX##_seq_push_front(SNAME *_list_, V *elements, size_t size) \
{ \
if (size == 0) \
return false; \
\
if (!PFX##_fits(_list_, size)) \
{ \
if (!PFX##_resize(_list_, PFX##_count(_list_) + size)) \
return false; \
} \
\
memmove(_list_->buffer + size, _list_->buffer, _list_->count * sizeof(V)); \
\
memcpy(_list_->buffer, elements, size * sizeof(V)); \
\
_list_->count += size; \
\
return true; \
} \
\
bool PFX##_seq_push_at(SNAME *_list_, V *elements, size_t size, size_t index) \
{ \
if (size == 0 || index > _list_->count) \
return false; \
\
if (index == 0) \
return PFX##_seq_push_front(_list_, elements, size); \
else if (index == _list_->count) \
return PFX##_seq_push_back(_list_, elements, size); \
else \
{ \
if (!PFX##_fits(_list_, size)) \
{ \
if (!PFX##_resize(_list_, PFX##_count(_list_) + size)) \
return false; \
} \
\
memmove(_list_->buffer + index + size, _list_->buffer + index, \
(_list_->count - index) * sizeof(V)); \
\
memcpy(_list_->buffer + index, elements, size * sizeof(V)); \
\
_list_->count += size; \
} \
\
return true; \
} \
\
bool PFX##_seq_push_back(SNAME *_list_, V *elements, size_t size) \
{ \
if (size == 0) \
return false; \
\
if (!PFX##_fits(_list_, size)) \
{ \
if (!PFX##_resize(_list_, _list_->count + size)) \
return false; \
} \
\
memcpy(_list_->buffer + _list_->count, elements, size * sizeof(V)); \
\
_list_->count += size; \
\
return true; \
} \
\
bool PFX##_seq_pop_at(SNAME *_list_, size_t from, size_t to) \
{ \
if (from > to || to >= _list_->count) \
return false; \
\
size_t length = (to - from + 1); \
\
memmove(_list_->buffer + from, _list_->buffer + to + 1, \
(_list_->count - to - 1) * sizeof(V)); \
\
memset(_list_->buffer + _list_->count - length, 0, length * sizeof(V)); \
\
_list_->count -= to - from + 1; \
\
return true; \
} \
\
SNAME *PFX##_seq_sublist(SNAME *_list_, size_t from, size_t to) \
{ \
if (from > to || to >= _list_->count) \
return false; \
\
size_t length = to - from + 1; \
\
SNAME *result = PFX##_new(length); \
\
if (!result) \
return NULL; \
\
memcpy(result->buffer, _list_->buffer, _list_->count * sizeof(V)); \
\
memmove(_list_->buffer + from, _list_->buffer + to + 1, \
(_list_->count - to - 1) * sizeof(V)); \
\
memset(_list_->buffer + _list_->count - length, 0, length * sizeof(V)); \
\
_list_->count -= length; \
result->count = length; \
\
return result; \
} \
\
V PFX##_front(SNAME *_list_) \
{ \
if (PFX##_empty(_list_)) \
return (V){0}; \
\
return _list_->buffer[0]; \
} \
\
V PFX##_get(SNAME *_list_, size_t index) \
{ \
if (index >= _list_->count || PFX##_empty(_list_)) \
return (V){0}; \
\
return _list_->buffer[index]; \
} \
\
V *PFX##_get_ref(SNAME *_list_, size_t index) \
{ \
if (index >= _list_->count) \
return NULL; \
\
if (PFX##_empty(_list_)) \
return NULL; \
\
return &(_list_->buffer[index]); \
} \
\
V PFX##_back(SNAME *_list_) \
{ \
if (PFX##_empty(_list_)) \
return (V){0}; \
\
return _list_->buffer[_list_->count - 1]; \
} \
\
size_t PFX##_indexof(SNAME *_list_, V element, int (*comparator)(V, V), bool from_start) \
{ \
if (from_start) \
{ \
for (size_t i = 0; i < _list_->count; i++) \
{ \
if (comparator(_list_->buffer[i], element) == 0) \
return i; \
} \
} \
else \
{ \
for (size_t i = _list_->count; i > 0; i--) \
{ \
if (comparator(_list_->buffer[i - 1], element) == 0) \
return i - 1; \
} \
} \
\
return _list_->count; \
} \
\
bool PFX##_contains(SNAME *_list_, V element, int (*comparator)(V, V)) \
{ \
for (size_t i = 0; i < _list_->count; i++) \
{ \
if (comparator(_list_->buffer[i], element) == 0) \
return true; \
} \
\
return false; \
} \
\
bool PFX##_empty(SNAME *_list_) \
{ \
return _list_->count == 0; \
} \
\
bool PFX##_full(SNAME *_list_) \
{ \
return _list_->count >= _list_->capacity; \
} \
\
size_t PFX##_count(SNAME *_list_) \
{ \
return _list_->count; \
} \
\
bool PFX##_fits(SNAME *_list_, size_t size) \
{ \
return _list_->count + size <= _list_->capacity; \
} \
\
size_t PFX##_capacity(SNAME *_list_) \
{ \
return _list_->capacity; \
} \
\
bool PFX##_resize(SNAME *_list_, size_t capacity) \
{ \
if (PFX##_capacity(_list_) == capacity) \
return true; \
\
if (capacity < PFX##_count(_list_)) \
return false; \
\
V *new_buffer = realloc(_list_->buffer, sizeof(V) * capacity); \
\
if (!new_buffer) \
return false; \
\
_list_->buffer = new_buffer; \
_list_->capacity = capacity; \
\
return true; \
} \
\
SNAME *PFX##_copy_of(SNAME *_list_, V (*copy_func)(V)) \
{ \
SNAME *result = PFX##_new(_list_->capacity); \
\
if (!result) \
return NULL; \
\
if (copy_func) \
{ \
for (size_t i = 0; i < _list_->count; i++) \
result->buffer[i] = copy_func(_list_->buffer[i]); \
} \
else \
memcpy(result->buffer, _list_->buffer, sizeof(V) * _list_->count); \
\
result->count = _list_->count; \
\
return result; \
} \
\
bool PFX##_equals(SNAME *_list1_, SNAME *_list2_, int (*comparator)(V, V)) \
{ \
if (PFX##_count(_list1_) != PFX##_count(_list2_)) \
return false; \
\
for (size_t i = 0; i < PFX##_count(_list1_); i++) \
{ \
if (comparator(_list1_->buffer[i], _list2_->buffer[i]) != 0) \
return false; \
} \
\
return false; \
} \
\
cmc_string PFX##_to_string(SNAME *_list_) \
{ \
cmc_string str; \
SNAME *l_ = _list_; \
const char *name = #SNAME; \
\
snprintf(str.s, cmc_string_len, cmc_string_fmt_list, \
name, l_, l_->buffer, l_->capacity, l_->count); \
\
return str; \
} \
\
SNAME##_iter *PFX##_iter_new(SNAME *target) \
{ \
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
\
if (!iter) \
return NULL; \
\
PFX##_iter_init(iter, target); \
\
return iter; \
} \
\
void PFX##_iter_free(SNAME##_iter *iter) \
{ \
free(iter); \
} \
\
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
{ \
iter->target = target; \
iter->cursor = 0; \
iter->start = true; \
iter->end = PFX##_empty(target); \
} \
\
bool PFX##_iter_start(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->start; \
} \
\
bool PFX##_iter_end(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->end; \
} \
\
void PFX##_iter_to_start(SNAME##_iter *iter) \
{ \
if (!PFX##_empty(iter->target)) \
{ \
iter->cursor = 0; \
iter->start = true; \
iter->end = PFX##_empty(iter->target); \
} \
} \
\
void PFX##_iter_to_end(SNAME##_iter *iter) \
{ \
if (!PFX##_empty(iter->target)) \
{ \
iter->start = PFX##_empty(iter->target); \
iter->cursor = PFX##_empty(iter->target) ? 0 : iter->target->count - 1; \
iter->end = true; \
} \
} \
\
bool PFX##_iter_next(SNAME##_iter *iter) \
{ \
if (iter->end) \
return false; \
\
if (iter->cursor + 1 == PFX##_count(iter->target)) \
{ \
iter->end = true; \
return false; \
} \
\
iter->start = PFX##_empty(iter->target); \
\
iter->cursor++; \
\
return true; \
} \
\
bool PFX##_iter_prev(SNAME##_iter *iter) \
{ \
if (iter->start) \
return false; \
\
if (iter->cursor == 0) \
{ \
iter->start = true; \
return false; \
} \
\
iter->end = PFX##_empty(iter->target); \
\
iter->cursor--; \
\
return true; \
} \
\
/* Returns true only if the iterator moved */ \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->end) \
return false; \
\
if (iter->cursor + 1 == iter->target->count) \
{ \
iter->end = true; \
return false; \
} \
\
if (steps == 0 || iter->cursor + steps >= PFX##_count(iter->target)) \
return false; \
\
iter->start = PFX##_empty(iter->target); \
\
iter->cursor += steps; \
\
return true; \
} \
\
/* Returns true only if the iterator moved */ \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->start) \
return false; \
\
if (iter->cursor == 0) \
{ \
iter->start = true; \
return false; \
} \
\
if (steps == 0 || iter->cursor < steps) \
return false; \
\
iter->end = 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 PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
{ \
if (index >= PFX##_count(iter->target)) \
return false; \
\
if (iter->cursor > index) \
return PFX##_iter_rewind(iter, iter->cursor - index); \
else if (iter->cursor < index) \
return PFX##_iter_advance(iter, index - iter->cursor); \
\
return true; \
} \
\
V PFX##_iter_value(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return (V){0}; \
\
return iter->target->buffer[iter->cursor]; \
} \
\
V *PFX##_iter_rvalue(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return NULL; \
\
return &(iter->target->buffer[iter->cursor]); \
} \
\
size_t PFX##_iter_index(SNAME##_iter *iter) \
{ \
return iter->cursor; \
} \
\
static SNAME##_iter PFX##_impl_it_start(SNAME *_list_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _list_); \
PFX##_iter_to_start(&iter); \
\
return iter; \
} \
\
static SNAME##_iter PFX##_impl_it_end(SNAME *_list_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _list_); \
PFX##_iter_to_end(&iter); \
\
return iter; \
}
#endif /* CMC_LIST_H */
+598
View File
@@ -0,0 +1,598 @@
/**
* queue.h
*
* Creation Date: 15/02/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Queue
*
* A Queue is a First-In First-out (or Last-in Last-out) data structure. It is
* a Dynamic Circular Array where elements are added from one end of the array
* and removed from the other end. The circular array here (also known as
* circular buffer or ring buffer) is very important so that both adding and
* removing elements from the Queue are done instantly. The array is linear but
* with the modulo operator it is treated as a circular sequence of elements.
*
* If the Queue was implemented as a regular Dynamic Array, when adding or
* removing an element at the front, it would be necessary to shift all elements
* currently present in the Queue and this would add up a lot of computing time.
* Shifting `100000` elements in memory by one position every time an element is
* added to the Queue is simply not efficient.
*
* The Queue has two ends. The `front` and `back`. In this implementation all
* elements are added to the back of the Queue and removed from the front, which
* is more or less how queues work in real life. Unlike a Stack that only has
* operations at one end of the buffer, the Queue needs to be implemented as a
* circular array in order to quickly add or remove elements.
*
* The Queue has three main functions: `enqueue` which adds an element to the
* Queue; `dequeue` which removes an element from the Queue; and `peek` which
* return the element at the front of the Queue, that is, the next element to
* be removed from it.
*
* The Queue is used in many applications where a resource is shared among
* multiple consumers and the Queue is responsible for scheduling the access to
* the resource.
*/
#ifndef CMC_QUEUE_H
#define CMC_QUEUE_H
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../utl/cmc_string.h"
/* to_string format */
static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
#define CMC_GENERATE_QUEUE(PFX, SNAME, V) \
CMC_GENERATE_QUEUE_HEADER(PFX, SNAME, V) \
CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V)
#define CMC_WRAPGEN_QUEUE_HEADER(PFX, SNAME, K, V) \
CMC_GENERATE_QUEUE_HEADER(PFX, SNAME, V)
#define CMC_WRAPGEN_QUEUE_SOURCE(PFX, SNAME, K, V) \
CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V)
/* HEADER ********************************************************************/
#define CMC_GENERATE_QUEUE_HEADER(PFX, SNAME, V) \
\
/* Queue Structure */ \
typedef struct SNAME##_s \
{ \
/* 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 queue */ \
size_t front; \
\
/* Index representing the back of the queue */ \
size_t back; \
\
/* Function that returns an iterator to the start of the queue */ \
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
\
/* Function that returns an iterator to the end of the queue */ \
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
\
} SNAME, *SNAME##_ptr; \
\
/* Queue Iterator */ \
typedef struct SNAME##_iter_s \
{ \
/* Target queue */ \
struct SNAME##_s *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; \
\
} SNAME##_iter, *SNAME##_iter_ptr; \
\
/* Collection Functions */ \
/* Collection Allocation and Deallocation */ \
SNAME *PFX##_new(size_t capacity); \
void PFX##_clear(SNAME *_queue_, void (*deallocator)(V)); \
void PFX##_free(SNAME *_queue_, void (*deallocator)(V)); \
/* Collection Input and Output */ \
bool PFX##_enqueue(SNAME *_queue_, V element); \
bool PFX##_dequeue(SNAME *_queue_); \
/* Element Access */ \
V PFX##_peek(SNAME *_queue_); \
/* Collection State */ \
bool PFX##_contains(SNAME *_queue_, V element, int (*comparator)(V, V)); \
bool PFX##_empty(SNAME *_queue_); \
bool PFX##_full(SNAME *_queue_); \
size_t PFX##_count(SNAME *_queue_); \
size_t PFX##_capacity(SNAME *_queue_); \
/* Collection Utility */ \
bool PFX##_resize(SNAME *_queue_, size_t capacity); \
SNAME *PFX##_copy_of(SNAME *_queue_, V (*copy_func)(V)); \
bool PFX##_equals(SNAME *_queue1_, SNAME *_queue2_, int (*comparator)(V, V)); \
cmc_string PFX##_to_string(SNAME *_queue_); \
\
/* Iterator Functions */ \
/* Iterator Allocation and Deallocation */ \
SNAME##_iter *PFX##_iter_new(SNAME *target); \
void PFX##_iter_free(SNAME##_iter *iter); \
/* Iterator Initialization */ \
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
/* Iterator State */ \
bool PFX##_iter_start(SNAME##_iter *iter); \
bool PFX##_iter_end(SNAME##_iter *iter); \
/* Iterator Movement */ \
void PFX##_iter_to_start(SNAME##_iter *iter); \
void PFX##_iter_to_end(SNAME##_iter *iter); \
bool PFX##_iter_next(SNAME##_iter *iter); \
bool PFX##_iter_prev(SNAME##_iter *iter); \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
/* Iterator Access */ \
V PFX##_iter_value(SNAME##_iter *iter); \
V *PFX##_iter_rvalue(SNAME##_iter *iter); \
size_t PFX##_iter_index(SNAME##_iter *iter); \
\
/* SOURCE ********************************************************************/
#define CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V) \
\
/* Implementation Detail Functions */ \
static SNAME##_iter PFX##_impl_it_start(SNAME *_queue_); \
static SNAME##_iter PFX##_impl_it_end(SNAME *_queue_); \
\
SNAME *PFX##_new(size_t capacity) \
{ \
if (capacity < 1) \
return NULL; \
\
SNAME *_queue_ = malloc(sizeof(SNAME)); \
\
if (!_queue_) \
return NULL; \
\
_queue_->buffer = malloc(sizeof(V) * capacity); \
\
if (!_queue_->buffer) \
{ \
free(_queue_); \
return NULL; \
} \
\
memset(_queue_->buffer, 0, sizeof(V) * capacity); \
\
_queue_->capacity = capacity; \
_queue_->count = 0; \
_queue_->front = 0; \
_queue_->back = 0; \
\
_queue_->it_start = PFX##_impl_it_start; \
_queue_->it_end = PFX##_impl_it_end; \
\
return _queue_; \
} \
\
void PFX##_clear(SNAME *_queue_, void (*deallocator)(V)) \
{ \
if (deallocator) \
{ \
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \
{ \
deallocator(_queue_->buffer[i]); \
\
i = (i + 1) % _queue_->capacity; \
} \
} \
\
memset(_queue_->buffer, 0, sizeof(V) * _queue_->capacity); \
\
_queue_->count = 0; \
_queue_->front = 0; \
_queue_->back = 0; \
} \
\
void PFX##_free(SNAME *_queue_, void (*deallocator)(V)) \
{ \
if (deallocator) \
{ \
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \
{ \
deallocator(_queue_->buffer[i]); \
\
i = (i + 1) % _queue_->capacity; \
} \
} \
\
free(_queue_->buffer); \
free(_queue_); \
} \
\
bool PFX##_enqueue(SNAME *_queue_, V element) \
{ \
if (PFX##_full(_queue_)) \
{ \
if (!PFX##_resize(_queue_, PFX##_capacity(_queue_) * 2)) \
return false; \
} \
\
_queue_->buffer[_queue_->back] = element; \
\
_queue_->back = (_queue_->back == _queue_->capacity - 1) ? 0 : _queue_->back + 1; \
_queue_->count++; \
\
return true; \
} \
\
bool PFX##_dequeue(SNAME *_queue_) \
{ \
if (PFX##_empty(_queue_)) \
return false; \
\
_queue_->buffer[_queue_->front] = (V){0}; \
\
_queue_->front = (_queue_->front == _queue_->capacity - 1) ? 0 : _queue_->front + 1; \
_queue_->count--; \
\
return true; \
} \
\
V PFX##_peek(SNAME *_queue_) \
{ \
if (PFX##_empty(_queue_)) \
return (V){0}; \
\
return _queue_->buffer[_queue_->front]; \
} \
\
bool PFX##_contains(SNAME *_queue_, V element, int (*comparator)(V, V)) \
{ \
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \
{ \
if (comparator(_queue_->buffer[i], element) == 0) \
return true; \
\
i = (i + 1) % _queue_->capacity; \
} \
\
return false; \
} \
\
bool PFX##_empty(SNAME *_queue_) \
{ \
return _queue_->count == 0; \
} \
\
bool PFX##_full(SNAME *_queue_) \
{ \
return _queue_->count >= _queue_->capacity; \
} \
\
size_t PFX##_count(SNAME *_queue_) \
{ \
return _queue_->count; \
} \
\
size_t PFX##_capacity(SNAME *_queue_) \
{ \
return _queue_->capacity; \
} \
\
bool PFX##_resize(SNAME *_queue_, size_t capacity) \
{ \
if (PFX##_capacity(_queue_) == capacity) \
return true; \
\
if (capacity < PFX##_count(_queue_)) \
return false; \
\
V *new_buffer = malloc(sizeof(V) * capacity); \
\
if (!new_buffer) \
return false; \
\
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \
{ \
new_buffer[j] = _queue_->buffer[i]; \
\
i = (i + 1) % PFX##_capacity(_queue_); \
} \
\
free(_queue_->buffer); \
\
_queue_->buffer = new_buffer; \
_queue_->capacity = capacity; \
_queue_->front = 0; \
_queue_->back = _queue_->count; \
\
return true; \
} \
\
SNAME *PFX##_copy_of(SNAME *_queue_, V (*copy_func)(V)) \
{ \
SNAME *result = PFX##_new(_queue_->capacity); \
\
if (!result) \
return NULL; \
\
if (copy_func) \
{ \
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \
{ \
result->buffer[j] = copy_func(_queue_->buffer[i]); \
\
i = (i + 1) % _queue_->capacity; \
} \
} \
else \
{ \
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \
{ \
result->buffer[j] = _queue_->buffer[i]; \
\
i = (i + 1) % _queue_->capacity; \
} \
} \
\
result->count = _queue_->count; \
\
return result; \
} \
\
bool PFX##_equals(SNAME *_queue1_, SNAME *_queue2_, int (*comparator)(V, V)) \
{ \
if (PFX##_count(_queue1_) != PFX##_count(_queue2_)) \
return false; \
\
size_t i, j, k; \
for (i = _queue1_->front, j = _queue2_->front, k = 0; k < PFX##_count(_queue1_); k++) \
{ \
if (comparator(_queue1_->buffer[i], _queue2_->buffer[j]) != 0) \
return false; \
\
i = (i + 1) % _queue1_->capacity; \
j = (j + 1) % _queue2_->capacity; \
} \
\
return true; \
} \
\
cmc_string PFX##_to_string(SNAME *_queue_) \
{ \
cmc_string str; \
SNAME *q_ = _queue_; \
const char *name = #SNAME; \
\
snprintf(str.s, cmc_string_len, cmc_string_fmt_queue, \
name, q_, q_->buffer, q_->capacity, q_->count, q_->front, q_->back); \
\
return str; \
} \
\
SNAME##_iter *PFX##_iter_new(SNAME *target) \
{ \
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
\
if (!iter) \
return NULL; \
\
PFX##_iter_init(iter, target); \
\
return iter; \
} \
\
void PFX##_iter_free(SNAME##_iter *iter) \
{ \
free(iter); \
} \
\
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
{ \
iter->target = target; \
iter->cursor = target->front; \
iter->index = 0; \
iter->start = true; \
iter->end = PFX##_empty(target); \
} \
\
bool PFX##_iter_start(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->start; \
} \
\
bool PFX##_iter_end(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->end; \
} \
\
void PFX##_iter_to_start(SNAME##_iter *iter) \
{ \
iter->cursor = iter->target->front; \
iter->index = 0; \
iter->start = true; \
iter->end = PFX##_empty(iter->target); \
} \
\
void PFX##_iter_to_end(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
iter->cursor = 0; \
else \
{ \
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 = PFX##_empty(iter->target); \
iter->end = true; \
} \
\
bool PFX##_iter_next(SNAME##_iter *iter) \
{ \
if (iter->end) \
return false; \
\
if (iter->index + 1 == PFX##_count(iter->target)) \
{ \
iter->end = true; \
return false; \
} \
\
iter->start = PFX##_empty(iter->target); \
\
iter->cursor = (iter->cursor + 1) % (iter->target->capacity); \
iter->index++; \
\
return true; \
} \
\
bool PFX##_iter_prev(SNAME##_iter *iter) \
{ \
if (iter->start) \
return false; \
\
if (iter->index == 0) \
{ \
iter->start = true; \
return false; \
} \
\
iter->end = 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 PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->end) \
return false; \
\
if (iter->index + 1 == PFX##_count(iter->target)) \
{ \
iter->end = true; \
return false; \
} \
\
if (steps == 0 || iter->index + steps >= PFX##_count(iter->target)) \
return false; \
\
iter->start = 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 PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->start) \
return false; \
\
if (iter->index == 0) \
{ \
iter->start = true; \
return false; \
} \
\
if (steps == 0 || iter->index < steps) \
return false; \
\
iter->end = PFX##_empty(iter->target); \
\
iter->index -= steps; \
\
/* Prevent underflow */ \
if (iter->cursor < steps) \
iter->cursor += PFX##_capacity(iter->target); \
\
iter->cursor -= steps; \
\
return true; \
} \
\
/* Returns true only if the iterator was able to be positioned at the given index */ \
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
{ \
if (index >= PFX##_count(iter->target)) \
return false; \
\
if (iter->index > index) \
return PFX##_iter_rewind(iter, iter->index - index); \
else if (iter->index < index) \
return PFX##_iter_advance(iter, index - iter->index); \
\
return true; \
} \
\
V PFX##_iter_value(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return (V){0}; \
\
return iter->target->buffer[iter->cursor]; \
} \
\
V *PFX##_iter_rvalue(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return NULL; \
\
return &(iter->target->buffer[iter->cursor]); \
} \
\
size_t PFX##_iter_index(SNAME##_iter *iter) \
{ \
return iter->index; \
} \
\
static SNAME##_iter PFX##_impl_it_start(SNAME *_queue_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _queue_); \
PFX##_iter_to_start(&iter); \
\
return iter; \
} \
\
static SNAME##_iter PFX##_impl_it_end(SNAME *_queue_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _queue_); \
PFX##_iter_to_end(&iter); \
\
return iter; \
}
#endif /* CMC_QUEUE_H */
+517
View File
@@ -0,0 +1,517 @@
/**
* stack.h
*
* Creation Date: 14/02/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Stack
*
* A Stack is a Last-in First-out (or First-in Last-out) data structure used in
* a variety of algorithms. It is a Dynamic Array that can only add or remove
* its elements at the end of the buffer, in this case, it represents the top of
* the stack.
*
* It has three main functions: `push` which adds an element at the top of the
* stack; `pop` which removes the top element from the stack; and `top` which
* returns the top element without removing it (it is also sometimes called
* `peek`).
*
* A Stack is used in algorithms like backtracking, depth-first search,
* expression evaluation, syntax parsing and many more.
*/
#ifndef CMC_STACK_H
#define CMC_STACK_H
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../utl/cmc_string.h"
/* to_string format */
static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
#define CMC_GENERATE_STACK(PFX, SNAME, V) \
CMC_GENERATE_STACK_HEADER(PFX, SNAME, V) \
CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V)
#define CMC_WRAPGEN_STACK_HEADER(PFX, SNAME, K, V) \
CMC_GENERATE_STACK_HEADER(PFX, SNAME, V)
#define CMC_WRAPGEN_STACK_SOURCE(PFX, SNAME, K, V) \
CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V)
/* HEADER ********************************************************************/
#define CMC_GENERATE_STACK_HEADER(PFX, SNAME, V) \
\
/* Stack Structure */ \
typedef struct SNAME##_s \
{ \
/* Dynamic array of elements */ \
V *buffer; \
\
/* Current array capacity */ \
size_t capacity; \
\
/* Current amount of elements */ \
size_t count; \
\
/* Function that returns an iterator to the start of the stack */ \
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
\
/* Function that returns an iterator to the end of the stack */ \
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
\
} SNAME, *SNAME##_ptr; \
\
/* Stack Iterator */ \
typedef struct SNAME##_iter_s \
{ \
/* Target stack */ \
struct SNAME##_s *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; \
\
} SNAME##_iter, *SNAME##_iter_ptr; \
\
/* Collection Functions */ \
/* Collection Allocation and Deallocation */ \
SNAME *PFX##_new(size_t capacity); \
void PFX##_clear(SNAME *_stack_, void (*deallocator)(V)); \
void PFX##_free(SNAME *_stack_, void (*deallocator)(V)); \
/* Collection Input and Output */ \
bool PFX##_push(SNAME *_stack_, V element); \
bool PFX##_pop(SNAME *_stack_); \
/* Element Access */ \
V PFX##_top(SNAME *_stack_); \
/* Collection State */ \
bool PFX##_contains(SNAME *_stack_, V element, int (*comparator)(V, V)); \
bool PFX##_empty(SNAME *_stack_); \
bool PFX##_full(SNAME *_stack_); \
size_t PFX##_count(SNAME *_stack_); \
size_t PFX##_capacity(SNAME *_stack_); \
/* Collection Utility */ \
bool PFX##_resize(SNAME *_stack_, size_t capacity); \
SNAME *PFX##_copy_of(SNAME *_stack_, V (*copy_func)(V)); \
bool PFX##_equals(SNAME *_stack1_, SNAME *_stack2_, int (*comparator)(V, V)); \
cmc_string PFX##_to_string(SNAME *_stack_); \
\
/* Iterator Functions */ \
/* Iterator Allocation and Deallocation */ \
SNAME##_iter *PFX##_iter_new(SNAME *target); \
void PFX##_iter_free(SNAME##_iter *iter); \
/* Iterator Initialization */ \
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
/* Iterator State */ \
bool PFX##_iter_start(SNAME##_iter *iter); \
bool PFX##_iter_end(SNAME##_iter *iter); \
/* Iterator Movement */ \
void PFX##_iter_to_start(SNAME##_iter *iter); \
void PFX##_iter_to_end(SNAME##_iter *iter); \
bool PFX##_iter_next(SNAME##_iter *iter); \
bool PFX##_iter_prev(SNAME##_iter *iter); \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
/* Iterator Access */ \
V PFX##_iter_value(SNAME##_iter *iter); \
V *PFX##_iter_rvalue(SNAME##_iter *iter); \
size_t PFX##_iter_index(SNAME##_iter *iter); \
\
/* SOURCE ********************************************************************/
#define CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V) \
\
/* Implementation Detail Functions */ \
static SNAME##_iter PFX##_impl_it_start(SNAME *_stack_); \
static SNAME##_iter PFX##_impl_it_end(SNAME *_stack_); \
\
SNAME *PFX##_new(size_t capacity) \
{ \
if (capacity < 1) \
return NULL; \
\
SNAME *_stack_ = malloc(sizeof(SNAME)); \
\
if (!_stack_) \
return NULL; \
\
_stack_->buffer = malloc(sizeof(V) * capacity); \
\
if (!_stack_->buffer) \
{ \
free(_stack_); \
return NULL; \
} \
\
memset(_stack_->buffer, 0, sizeof(V) * capacity); \
\
_stack_->capacity = capacity; \
_stack_->count = 0; \
\
_stack_->it_start = PFX##_impl_it_start; \
_stack_->it_end = PFX##_impl_it_end; \
\
return _stack_; \
} \
\
void PFX##_clear(SNAME *_stack_, void (*deallocator)(V)) \
{ \
if (deallocator) \
{ \
for (size_t i = 0; i < _stack_->count; i++) \
deallocator(_stack_->buffer[i]); \
} \
\
memset(_stack_->buffer, 0, sizeof(V) * _stack_->capacity); \
\
_stack_->count = 0; \
} \
\
void PFX##_free(SNAME *_stack_, void (*deallocator)(V)) \
{ \
free(_stack_->buffer); \
if (deallocator) \
{ \
for (size_t i = 0; i < _stack_->count; i++) \
deallocator(_stack_->buffer[i]); \
} \
\
free(_stack_); \
} \
\
bool PFX##_push(SNAME *_stack_, V element) \
{ \
if (PFX##_full(_stack_)) \
{ \
if (!PFX##_resize(_stack_, PFX##_capacity(_stack_) * 2)) \
return false; \
} \
\
_stack_->buffer[_stack_->count++] = element; \
\
return true; \
} \
\
bool PFX##_pop(SNAME *_stack_) \
{ \
if (PFX##_empty(_stack_)) \
return false; \
\
_stack_->buffer[--_stack_->count] = (V){0}; \
\
return true; \
} \
\
V PFX##_top(SNAME *_stack_) \
{ \
if (PFX##_empty(_stack_)) \
return (V){0}; \
\
return _stack_->buffer[_stack_->count - 1]; \
} \
\
bool PFX##_contains(SNAME *_stack_, V element, int (*comparator)(V, V)) \
{ \
for (size_t i = 0; i < _stack_->count; i++) \
{ \
if (comparator(_stack_->buffer[i], element) == 0) \
return true; \
} \
\
return false; \
} \
\
bool PFX##_empty(SNAME *_stack_) \
{ \
return _stack_->count == 0; \
} \
\
bool PFX##_full(SNAME *_stack_) \
{ \
return _stack_->count >= _stack_->capacity; \
} \
\
size_t PFX##_count(SNAME *_stack_) \
{ \
return _stack_->count; \
} \
\
size_t PFX##_capacity(SNAME *_stack_) \
{ \
return _stack_->capacity; \
} \
\
bool PFX##_resize(SNAME *_stack_, size_t capacity) \
{ \
if (PFX##_capacity(_stack_) == capacity) \
return true; \
\
if (capacity < PFX##_count(_stack_)) \
return false; \
\
V *new_buffer = realloc(_stack_->buffer, sizeof(V) * capacity); \
\
if (!new_buffer) \
return false; \
\
_stack_->buffer = new_buffer; \
_stack_->capacity = capacity; \
\
return true; \
} \
\
SNAME *PFX##_copy_of(SNAME *_stack_, V (*copy_func)(V)) \
{ \
SNAME *result = PFX##_new(_stack_->capacity); \
\
if (!result) \
return NULL; \
\
if (copy_func) \
{ \
for (size_t i = 0; i < _stack_->count; i++) \
result->buffer[i] = copy_func(_stack_->buffer[i]); \
} \
else \
memcpy(result->buffer, _stack_->buffer, sizeof(V) * _stack_->count); \
\
result->count = _stack_->count; \
\
return result; \
} \
\
bool PFX##_equals(SNAME *_stack1_, SNAME *_stack2_, int (*comparator)(V, V)) \
{ \
if (PFX##_count(_stack1_) != PFX##_count(_stack2_)) \
return false; \
\
for (size_t i = 0; i < PFX##_count(_stack1_); i++) \
{ \
if (comparator(_stack1_->buffer[i], _stack2_->buffer[i]) != 0) \
return false; \
} \
\
return true; \
} \
\
cmc_string PFX##_to_string(SNAME *_stack_) \
{ \
cmc_string str; \
SNAME *s_ = _stack_; \
const char *name = #SNAME; \
\
snprintf(str.s, cmc_string_len, cmc_string_fmt_stack, \
name, s_, s_->buffer, s_->capacity, s_->count); \
\
return str; \
} \
\
SNAME##_iter *PFX##_iter_new(SNAME *target) \
{ \
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
\
if (!iter) \
return NULL; \
\
PFX##_iter_init(iter, target); \
\
return iter; \
} \
\
void PFX##_iter_free(SNAME##_iter *iter) \
{ \
free(iter); \
} \
\
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
{ \
iter->target = target; \
iter->cursor = PFX##_empty(target) ? 0 : iter->target->count - 1; \
iter->start = true; \
iter->end = PFX##_empty(target); \
} \
\
bool PFX##_iter_start(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->start; \
} \
\
bool PFX##_iter_end(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->end; \
} \
\
void PFX##_iter_to_start(SNAME##_iter *iter) \
{ \
if (!PFX##_empty(iter->target)) \
{ \
iter->cursor = iter->target->count - 1; \
iter->start = true; \
iter->end = PFX##_empty(iter->target); \
} \
} \
\
void PFX##_iter_to_end(SNAME##_iter *iter) \
{ \
if (!PFX##_empty(iter->target)) \
{ \
iter->cursor = 0; \
iter->start = PFX##_empty(iter->target); \
iter->end = true; \
} \
} \
\
bool PFX##_iter_next(SNAME##_iter *iter) \
{ \
if (iter->end) \
return false; \
\
if (iter->cursor == 0) \
{ \
iter->end = true; \
return false; \
} \
\
iter->start = PFX##_empty(iter->target); \
\
iter->cursor--; \
\
return true; \
} \
\
bool PFX##_iter_prev(SNAME##_iter *iter) \
{ \
if (iter->start) \
return false; \
\
if (iter->cursor + 1 == PFX##_count(iter->target)) \
{ \
iter->start = true; \
return false; \
} \
\
iter->end = PFX##_empty(iter->target); \
\
iter->cursor++; \
\
return true; \
} \
\
/* Returns true only if the iterator moved */ \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->end) \
return false; \
\
if (iter->cursor == 0) \
{ \
iter->end = true; \
return false; \
} \
\
if (steps == 0 || iter->cursor < steps) \
return false; \
\
iter->start = PFX##_empty(iter->target); \
\
iter->cursor -= steps; \
\
return true; \
} \
\
/* Returns true only if the iterator moved */ \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->start) \
return false; \
\
if (iter->cursor + 1 == PFX##_count(iter->target)) \
{ \
iter->start = true; \
return false; \
} \
\
if (steps == 0 || iter->cursor + steps >= PFX##_count(iter->target)) \
return false; \
\
iter->end = 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 PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
{ \
if (index >= PFX##_count(iter->target)) \
return false; \
\
if (iter->cursor > index) \
return PFX##_iter_rewind(iter, iter->cursor - index); \
else if (iter->cursor < index) \
return PFX##_iter_advance(iter, index - iter->cursor); \
\
return true; \
} \
\
V PFX##_iter_value(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return (V){0}; \
\
return iter->target->buffer[iter->cursor]; \
} \
\
V *PFX##_iter_rvalue(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return NULL; \
\
return &(iter->target->buffer[iter->cursor]); \
} \
\
size_t PFX##_iter_index(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return 0; \
\
return iter->target->count - 1 - iter->cursor; \
} \
\
static SNAME##_iter PFX##_impl_it_start(SNAME *_stack_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _stack_); \
PFX##_iter_to_start(&iter); \
\
return iter; \
} \
\
static SNAME##_iter PFX##_impl_it_end(SNAME *_stack_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _stack_); \
PFX##_iter_to_end(&iter); \
\
return iter; \
}
#endif /* CMC_STACK_H */
+1020
View File
File diff suppressed because it is too large. Load diff
+1166
View File
File diff suppressed because it is too large. Load diff
-375
View File
@@ -1,375 +0,0 @@
/**
* deque.h
*
* Creation Date: 20/03/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/*****************************************************************************/
/********************************************************************* DEQUE */
/*****************************************************************************/
#ifndef CMC_DEQUE_H
#define CMC_DEQUE_H
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define DEQUE_GENERATE(PFX, SNAME, FMOD, V) \
DEQUE_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \
DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
/* PRIVATE *******************************************************************/
#define DEQUE_GENERATE_HEADER_PRIVATE(PFX, SNAME, FMOD, K, V) \
DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V)
#define DEQUE_GENERATE_SOURCE_PRIVATE(PFX, SNAME, FMOD, K, V) \
DEQUE_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \
DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
/* PUBLIC ********************************************************************/
#define DEQUE_GENERATE_HEADER_PUBLIC(PFX, SNAME, FMOD, K, V) \
DEQUE_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \
DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V)
#define DEQUE_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, V) \
DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
/* STRUCT ********************************************************************/
#define DEQUE_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \
\
struct SNAME##_s \
{ \
V *buffer; \
size_t capacity; \
size_t count; \
size_t front; \
size_t rear; \
}; \
\
struct SNAME##_iter_s \
{ \
struct SNAME##_s *target; \
size_t cursor; \
size_t index; \
bool start; \
bool end; \
}; \
\
/* HEADER ********************************************************************/
#define DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
\
typedef struct SNAME##_s SNAME; \
typedef struct SNAME##_iter_s SNAME##_iter; \
\
FMOD SNAME *PFX##_new(size_t size); \
FMOD void PFX##_clear(SNAME *_deque_); \
FMOD void PFX##_free(SNAME *_deque_); \
FMOD bool PFX##_push_front(SNAME *_deque_, V element); \
FMOD bool PFX##_push_back(SNAME *_deque_, V element); \
FMOD bool PFX##_pop_front(SNAME *_deque_); \
FMOD bool PFX##_pop_back(SNAME *_deque_); \
FMOD bool PFX##_push_front_if(SNAME *_deque_, V element, bool condition); \
FMOD bool PFX##_push_back_if(SNAME *_deque_, V element, bool condition); \
FMOD bool PFX##_pop_front_if(SNAME *_deque_, bool condition); \
FMOD bool PFX##_pop_back_if(SNAME *_deque_, bool condition); \
FMOD V PFX##_front(SNAME *_deque_); \
FMOD V PFX##_back(SNAME *_deque_); \
FMOD bool PFX##_empty(SNAME *_deque_); \
FMOD bool PFX##_full(SNAME *_deque_); \
FMOD size_t PFX##_count(SNAME *_deque_); \
FMOD size_t PFX##_capacity(SNAME *_deque_); \
\
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target); \
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
FMOD void PFX##_iter_tostart(SNAME##_iter *iter); \
FMOD void PFX##_iter_toend(SNAME##_iter *iter); \
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index); \
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index); \
\
/* SOURCE ********************************************************************/
#define DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
\
FMOD bool PFX##_grow(SNAME *_deque_); \
\
FMOD SNAME *PFX##_new(size_t size) \
{ \
if (size < 1) \
return NULL; \
\
SNAME *_deque_ = malloc(sizeof(SNAME)); \
\
if (!_deque_) \
return NULL; \
\
_deque_->buffer = malloc(sizeof(V) * size); \
\
if (!_deque_->buffer) \
{ \
free(_deque_); \
return NULL; \
} \
\
memset(_deque_->buffer, 0, sizeof(V) * size); \
\
_deque_->capacity = size; \
_deque_->count = 0; \
_deque_->front = 0; \
_deque_->rear = 0; \
\
return _deque_; \
} \
\
FMOD void PFX##_clear(SNAME *_deque_) \
{ \
memset(_deque_->buffer, 0, sizeof(V) * _deque_->capacity); \
\
_deque_->count = 0; \
_deque_->front = 0; \
_deque_->rear = 0; \
} \
\
FMOD void PFX##_free(SNAME *_deque_) \
{ \
free(_deque_->buffer); \
free(_deque_); \
} \
\
FMOD bool PFX##_push_front(SNAME *_deque_, V element) \
{ \
if (PFX##_full(_deque_)) \
{ \
if (!PFX##_grow(_deque_)) \
return false; \
} \
\
_deque_->front = (_deque_->front == 0) ? _deque_->capacity - 1 : _deque_->front - 1; \
\
_deque_->buffer[_deque_->front] = element; \
\
_deque_->count++; \
\
return true; \
} \
\
FMOD bool PFX##_push_back(SNAME *_deque_, V element) \
{ \
if (PFX##_full(_deque_)) \
{ \
if (!PFX##_grow(_deque_)) \
return false; \
} \
\
_deque_->buffer[_deque_->rear] = element; \
\
_deque_->rear = (_deque_->rear == _deque_->capacity - 1) ? 0 : _deque_->rear + 1; \
\
_deque_->count++; \
\
return true; \
} \
\
FMOD bool PFX##_pop_front(SNAME *_deque_) \
{ \
if (PFX##_empty(_deque_)) \
return false; \
\
_deque_->buffer[_deque_->front] = 0; \
\
_deque_->front = (_deque_->front == _deque_->capacity - 1) ? 0 : _deque_->front + 1; \
\
_deque_->count--; \
\
return true; \
} \
\
FMOD bool PFX##_pop_back(SNAME *_deque_) \
{ \
if (PFX##_empty(_deque_)) \
return false; \
\
_deque_->rear = (_deque_->rear == 0) ? _deque_->capacity - 1 : _deque_->rear - 1; \
\
_deque_->buffer[_deque_->rear] = 0; \
\
_deque_->count--; \
\
return true; \
} \
\
FMOD bool PFX##_push_front_if(SNAME *_deque_, V element, bool condition) \
{ \
if (condition) \
return PFX##_push_front(_deque_, element); \
\
return false; \
} \
\
FMOD bool PFX##_push_back_if(SNAME *_deque_, V element, bool condition) \
{ \
if (condition) \
return PFX##_push_back(_deque_, element); \
\
return false; \
} \
\
FMOD bool PFX##_pop_front_if(SNAME *_deque_, bool condition) \
{ \
if (condition) \
return PFX##_pop_front(_deque_); \
\
return false; \
} \
\
FMOD bool PFX##_pop_back_if(SNAME *_deque_, bool condition) \
{ \
if (condition) \
return PFX##_pop_back(_deque_); \
\
return false; \
} \
\
FMOD V PFX##_front(SNAME *_deque_) \
{ \
if (PFX##_empty(_deque_)) \
return 0; \
\
return _deque_->buffer[_deque_->front]; \
} \
\
FMOD V PFX##_back(SNAME *_deque_) \
{ \
if (PFX##_empty(_deque_)) \
return 0; \
\
return _deque_->buffer[(_deque_->rear == 0) ? _deque_->capacity - 1 : _deque_->rear - 1]; \
} \
\
FMOD bool PFX##_empty(SNAME *_deque_) \
{ \
return _deque_->count == 0; \
} \
\
FMOD bool PFX##_full(SNAME *_deque_) \
{ \
return _deque_->count >= _deque_->capacity; \
} \
\
FMOD size_t PFX##_count(SNAME *_deque_) \
{ \
return _deque_->count; \
} \
\
FMOD size_t PFX##_capacity(SNAME *_deque_) \
{ \
return _deque_->capacity; \
} \
\
FMOD bool PFX##_grow(SNAME *_deque_) \
{ \
\
size_t new_capacity = _deque_->capacity * 2; \
\
V *new_buffer = malloc(sizeof(V) * new_capacity); \
\
if (!new_buffer) \
return false; \
\
for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->capacity, j++) \
{ \
new_buffer[j] = _deque_->buffer[i]; \
} \
\
free(_deque_->buffer); \
\
_deque_->buffer = new_buffer; \
_deque_->capacity = new_capacity; \
_deque_->front = 0; \
_deque_->rear = _deque_->count; \
\
return true; \
} \
\
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target) \
{ \
iter->target = target; \
iter->cursor = target->front; \
iter->index = 0; \
iter->start = true; \
iter->end = PFX##_empty(target); \
} \
\
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
{ \
return iter->cursor == iter->target->front && iter->start; \
} \
\
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
{ \
size_t real_rear = iter->target->rear == 0 ? iter->target->capacity - 1 : iter->target->rear - 1; \
return iter->cursor == real_rear && iter->end; \
} \
\
FMOD void PFX##_iter_tostart(SNAME##_iter *iter) \
{ \
iter->cursor = iter->target->front; \
iter->index = 0; \
iter->start = true; \
iter->end = PFX##_empty(iter->target); \
} \
\
FMOD void PFX##_iter_toend(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
iter->cursor = 0; \
else \
iter->cursor = (iter->target->rear == 0) ? iter->target->count - 1 : iter->target->rear - 1; \
\
iter->index = iter->target->count - 1; \
iter->start = PFX##_empty(iter->target); \
iter->end = true; \
} \
\
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index) \
{ \
if (iter->end) \
return false; \
\
*index = iter->index; \
*result = iter->target->buffer[iter->cursor]; \
iter->start = false; \
\
if (iter->index == iter->target->count - 1) \
iter->end = true; \
else \
{ \
iter->cursor = (iter->cursor + 1) % (iter->target->capacity); \
iter->index++; \
} \
\
return true; \
} \
\
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index) \
{ \
if (iter->start) \
return false; \
\
*index = iter->index; \
*result = iter->target->buffer[iter->cursor]; \
iter->end = false; \
\
if (iter->index == 0) \
iter->start = true; \
else \
{ \
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1; \
iter->index--; \
} \
\
return true; \
}
#endif /* CMC_DEQUE_H */
+654
View File
@@ -0,0 +1,654 @@
/**
* deque.h
*
* Creation Date: 21/06/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/*****************************************************************************/
/********************************************************************* DEQUE */
/*****************************************************************************/
#ifndef CMC_DEQUE_H
#define CMC_DEQUE_H
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include "utl/log.h"
#define DEQUE_GENERATE(PFX, SNAME, FMOD, V) \
DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
#define DEQUE_WRAPGEN_HEADER(PFX, SNAME, FMOD, K, V) \
DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V)
#define DEQUE_WRAPGEN_SOURCE(PFX, SNAME, FMOD, K, V) \
DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
/* HEADER ********************************************************************/
#define DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
\
/* Deque Structure */ \
typedef struct SNAME##_s \
{ \
/* 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; \
\
/* Function that returns an iterator to the start of the deque */ \
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
\
/* Function that returns an iterator to the end of the deque */ \
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
\
} SNAME, *SNAME##_ptr; \
\
/* Deque Iterator */ \
typedef struct SNAME##_iter_s \
{ \
/* Target deque */ \
struct SNAME##_s *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; \
\
} SNAME##_iter, *SNAME##_iter_ptr; \
\
/* Collection Functions */ \
/* Collection Allocation and Deallocation */ \
FMOD SNAME *PFX##_new(size_t capacity); \
FMOD void PFX##_clear(SNAME *_deque_); \
FMOD void PFX##_free(SNAME *_deque_); \
/* Collection Input and Output */ \
FMOD bool PFX##_push_front(SNAME *_deque_, V element); \
FMOD bool PFX##_push_back(SNAME *_deque_, V element); \
FMOD bool PFX##_pop_front(SNAME *_deque_); \
FMOD bool PFX##_pop_back(SNAME *_deque_); \
/* Conditional Input and Output */ \
FMOD bool PFX##_push_front_if(SNAME *_deque_, V element, bool condition); \
FMOD bool PFX##_push_back_if(SNAME *_deque_, V element, bool condition); \
FMOD bool PFX##_pop_front_if(SNAME *_deque_, bool condition); \
FMOD bool PFX##_pop_back_if(SNAME *_deque_, bool condition); \
/* Element Access */ \
FMOD V PFX##_front(SNAME *_deque_); \
FMOD V PFX##_back(SNAME *_deque_); \
/* Collection State */ \
FMOD bool PFX##_contains(SNAME *_deque_, V element, int (*comparator)(V, V)); \
FMOD bool PFX##_empty(SNAME *_deque_); \
FMOD bool PFX##_full(SNAME *_deque_); \
FMOD size_t PFX##_count(SNAME *_deque_); \
FMOD size_t PFX##_capacity(SNAME *_deque_); \
\
/* Iterator Functions */ \
/* Iterator Allocation and Deallocation */ \
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \
FMOD void PFX##_iter_free(SNAME##_iter *iter); \
/* Iterator Initialization */ \
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
/* Iterator State */ \
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
/* Iterator Movement */ \
FMOD void PFX##_iter_to_start(SNAME##_iter *iter); \
FMOD void PFX##_iter_to_end(SNAME##_iter *iter); \
FMOD bool PFX##_iter_next(SNAME##_iter *iter); \
FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \
/* Iterator Access */ \
FMOD V PFX##_iter_value(SNAME##_iter *iter); \
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \
FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \
\
/* Default Value */ \
static inline V PFX##_impl_default_value(void) \
{ \
V _empty_value_; \
\
memset(&_empty_value_, 0, sizeof(V)); \
\
return _empty_value_; \
} \
\
/* SOURCE ********************************************************************/
#define DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
\
/* Implementation Detail Functions */ \
static bool PFX##_impl_grow(SNAME *_deque_); \
static SNAME##_iter PFX##_impl_it_start(SNAME *_deque_); \
static SNAME##_iter PFX##_impl_it_end(SNAME *_deque_); \
\
FMOD SNAME *PFX##_new(size_t capacity) \
{ \
if (capacity < 1) \
{ \
log_warn("Invalid capacity for %s given: %s", "Heap", capacity); \
return NULL; \
} \
\
SNAME *_deque_ = malloc(sizeof(SNAME)); \
\
if (!_deque_) \
{ \
log_info("%s allocation failed", "Deque"); \
return NULL; \
} \
\
_deque_->buffer = malloc(sizeof(V) * capacity); \
\
if (!_deque_->buffer) \
{ \
log_info("%s allocation failed", "Deque buffer"); \
free(_deque_); \
return NULL; \
} \
\
memset(_deque_->buffer, 0, sizeof(V) * capacity); \
\
_deque_->capacity = capacity; \
_deque_->count = 0; \
_deque_->front = 0; \
_deque_->back = 0; \
\
_deque_->it_start = PFX##_impl_it_start; \
_deque_->it_end = PFX##_impl_it_end; \
\
log_info("Deque at %p successfully allocated", _deque_); \
\
return _deque_; \
} \
\
FMOD void PFX##_clear(SNAME *_deque_) \
{ \
if (_deque_ == NULL) \
log_fatal("Invalid null pointer parameter: %s", "_deque_"); \
\
memset(_deque_->buffer, 0, sizeof(V) * _deque_->capacity); \
\
_deque_->count = 0; \
_deque_->front = 0; \
_deque_->back = 0; \
\
log_trace("Deque at %p cleared", _deque_); \
} \
\
FMOD void PFX##_free(SNAME *_deque_) \
{ \
if (_deque_ == NULL) \
log_fatal("Invalid null pointer parameter: %s", "_deque_"); \
\
free(_deque_->buffer); \
\
uintptr_t address = (uintptr_t)(void *)_deque_; \
\
free(_deque_); \
\
log_info("Heap at %p successfully deallocated", address); \
} \
\
FMOD bool PFX##_push_front(SNAME *_deque_, V element) \
{ \
if (_deque_ == NULL) \
log_fatal("Invalid null pointer parameter: %s", "_deque_"); \
\
if (PFX##_full(_deque_)) \
{ \
if (!PFX##_impl_grow(_deque_)) \
{ \
log_info("Deque at %p failed to be reallocated", _deque_); \
return false; \
} \
} \
\
_deque_->front = (_deque_->front == 0) ? _deque_->capacity - 1 : _deque_->front - 1; \
\
_deque_->buffer[_deque_->front] = element; \
\
log_trace("Element added at %" PRIuMAX " to Deque at %p", _deque_->front, _deque_); \
\
_deque_->count++; \
\
return true; \
} \
\
FMOD bool PFX##_push_back(SNAME *_deque_, V element) \
{ \
if (_deque_ == NULL) \
log_fatal("Invalid null pointer parameter: %s", "_deque_"); \
\
if (PFX##_full(_deque_)) \
{ \
if (!PFX##_impl_grow(_deque_)) \
{ \
log_info("Deque at %p failed to be reallocated", _deque_); \
return false; \
} \
} \
\
_deque_->buffer[_deque_->back] = element; \
\
log_trace("Element added at %" PRIuMAX " to Deque at %p", _deque_->back, _deque_); \
\
_deque_->back = (_deque_->back == _deque_->capacity - 1) ? 0 : _deque_->back + 1; \
\
_deque_->count++; \
\
return true; \
} \
\
FMOD bool PFX##_pop_front(SNAME *_deque_) \
{ \
if (_deque_ == NULL) \
log_fatal("Invalid null pointer parameter: %s", "_deque_"); \
\
if (PFX##_empty(_deque_)) \
{ \
log_debug("Attempt of removing an element from empty Deque at %p", _deque_); \
\
return false; \
} \
\
_deque_->buffer[_deque_->front] = PFX##_impl_default_value(); \
\
log_trace("Element removed from %" PRIuMAX " to Deque at %p", _deque_->front, _deque_); \
\
_deque_->front = (_deque_->front == _deque_->capacity - 1) ? 0 : _deque_->front + 1; \
\
_deque_->count--; \
\
return true; \
} \
\
FMOD bool PFX##_pop_back(SNAME *_deque_) \
{ \
if (_deque_ == NULL) \
{ \
log_fatal("Invalid null pointer parameter: %s", "_deque_"); \
} \
\
if (PFX##_empty(_deque_)) \
{ \
log_debug("Attempt of removing an element from empty Deque at %p", _deque_); \
\
return false; \
} \
\
_deque_->back = (_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1; \
\
_deque_->buffer[_deque_->back] = PFX##_impl_default_value(); \
\
log_trace("Element removed from %" PRIuMAX " to Deque at %p", _deque_->back, _deque_); \
\
_deque_->count--; \
\
return true; \
} \
\
FMOD bool PFX##_push_front_if(SNAME *_deque_, V element, bool condition) \
{ \
if (condition) \
return PFX##_push_front(_deque_, element); \
\
return false; \
} \
\
FMOD bool PFX##_push_back_if(SNAME *_deque_, V element, bool condition) \
{ \
if (condition) \
return PFX##_push_back(_deque_, element); \
\
return false; \
} \
\
FMOD bool PFX##_pop_front_if(SNAME *_deque_, bool condition) \
{ \
if (condition) \
return PFX##_pop_front(_deque_); \
\
return false; \
} \
\
FMOD bool PFX##_pop_back_if(SNAME *_deque_, bool condition) \
{ \
if (condition) \
return PFX##_pop_back(_deque_); \
\
return false; \
} \
\
FMOD V PFX##_front(SNAME *_deque_) \
{ \
if (_deque_ == NULL) \
log_fatal("Invalid null pointer parameter: %s", "_deque_"); \
\
if (PFX##_empty(_deque_)) \
{ \
log_debug("Attempt to access element from empty Deque at %p", _deque_); \
\
PFX##_impl_default_value(); \
} \
\
log_trace("Element access at %" PRIuMAX "", _deque_->front); \
\
return _deque_->buffer[_deque_->front]; \
} \
\
FMOD V PFX##_back(SNAME *_deque_) \
{ \
if (_deque_ == NULL) \
log_fatal("Invalid null pointer parameter: %s", "_deque_"); \
\
if (PFX##_empty(_deque_)) \
{ \
log_debug("Attempt to access element from empty Deque at %p", _deque_); \
\
PFX##_impl_default_value(); \
} \
\
size_t index = (_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1; \
\
log_trace("Element access at %" PRIuMAX "", index); \
\
return _deque_->buffer[index]; \
} \
\
FMOD bool PFX##_contains(SNAME *_deque_, V element, int (*comparator)(V, V)) \
{ \
if (_deque_ == NULL) \
log_fatal("Invalid null pointer parameter: %s", "_deque_"); \
\
if (comparator == NULL) \
log_fatal("Invalid null pointer parameter: %s", "comparator"); \
\
for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->count, j++) \
{ \
if (comparator(_deque_->buffer[i], element) == 0) \
return true; \
} \
\
return false; \
} \
\
FMOD bool PFX##_empty(SNAME *_deque_) \
{ \
if (_deque_ == NULL) \
log_fatal("Invalid null pointer parameter: %s", "_deque_"); \
\
return _deque_->count == 0; \
} \
\
FMOD bool PFX##_full(SNAME *_deque_) \
{ \
if (_deque_ == NULL) \
log_fatal("Invalid null pointer parameter: %s", "_deque_"); \
\
return _deque_->count >= _deque_->capacity; \
} \
\
FMOD size_t PFX##_count(SNAME *_deque_) \
{ \
if (_deque_ == NULL) \
log_fatal("Invalid null pointer parameter: %s", "_deque_"); \
\
return _deque_->count; \
} \
\
FMOD size_t PFX##_capacity(SNAME *_deque_) \
{ \
if (_deque_ == NULL) \
log_fatal("Invalid null pointer parameter: %s", "_deque_"); \
\
return _deque_->capacity; \
} \
\
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \
{ \
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
\
if (!iter) \
{ \
log_info("%s allocation failed", "Deque Iterator"); \
return NULL; \
} \
\
PFX##_iter_init(iter, target); \
\
log_info("Deque Iterator allocated at %p referencing Heap at %p", iter, target); \
\
return iter; \
} \
\
FMOD void PFX##_iter_free(SNAME##_iter *iter) \
{ \
uintptr_t address = (uintptr_t)(void *)iter; \
\
free(iter); \
\
log_info("Deque Iterator deallocated at %" PRIxPTR "", address); \
} \
\
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
{ \
if (target == NULL) \
log_fatal("Heap Iterator at %p initialized with null pointer target", iter); \
\
if (PFX##_empty(target)) \
log_warn("Deque Iterator at %p initialized with empty target", iter); \
\
iter->target = target; \
iter->cursor = target->front; \
iter->index = 0; \
iter->start = true; \
iter->end = PFX##_empty(target); \
} \
\
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
{ \
if (iter == NULL) \
log_fatal("Invalid null pointer parameter: %s", "iter"); \
\
return PFX##_empty(iter->target) || iter->start; \
} \
\
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
{ \
if (iter == NULL) \
log_fatal("Invalid null pointer parameter: %s", "iter"); \
\
return PFX##_empty(iter->target) || iter->end; \
} \
\
FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \
{ \
if (iter == NULL) \
log_fatal("Invalid null pointer parameter: %s", "iter"); \
\
iter->cursor = iter->target->front; \
iter->index = 0; \
iter->start = true; \
iter->end = PFX##_empty(iter->target); \
\
log_trace("Deque Iterator at %p with cursor at %" PRIuMAX "", iter, iter->cursor); \
} \
\
FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \
{ \
if (iter == NULL) \
log_fatal("Invalid null pointer parameter: %s", "iter"); \
\
if (PFX##_empty(iter->target)) \
iter->cursor = 0; \
else \
iter->cursor = (iter->target->back == 0) ? iter->target->capacity - 1 : iter->target->back - 1; \
\
iter->index = iter->target->count - 1; \
iter->start = PFX##_empty(iter->target); \
iter->end = true; \
\
log_trace("Deque Iterator at %p with cursor at %" PRIuMAX "", iter, iter->cursor); \
} \
\
FMOD bool PFX##_iter_next(SNAME##_iter *iter) \
{ \
if (iter == NULL) \
log_fatal("Invalid null pointer parameter: %s", "iter"); \
\
if (iter->end) \
return false; \
\
iter->start = PFX##_empty(iter->target); \
\
if (iter->index == iter->target->count - 1) \
{ \
log_trace("Deque Iterator at %p reached the end of Deque %p", iter, iter->target); \
iter->end = true; \
} \
else \
{ \
iter->cursor = (iter->cursor + 1) % (iter->target->capacity); \
iter->index++; \
\
log_trace("Deque Iterator at %p moved to %" PRIuMAX "", iter, iter->cursor); \
} \
\
return true; \
} \
\
FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \
{ \
if (iter == NULL) \
log_fatal("Invalid null pointer parameter: %s", "iter"); \
\
if (iter->start) \
return false; \
\
iter->end = PFX##_empty(iter->target); \
\
if (iter->index == 0) \
{ \
log_trace("Deque Iterator at %p reached the start of Deque %p", iter, iter->target); \
iter->start = true; \
} \
else \
{ \
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1; \
iter->index--; \
\
log_trace("Deque Iterator at %p moved to %" PRIuMAX "", iter, iter->cursor); \
} \
\
return true; \
} \
\
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
{ \
if (iter == NULL) \
log_fatal("Invalid null pointer parameter: %s", "iter"); \
\
if (PFX##_empty(iter->target)) \
{ \
log_debug("Attempt to access element from iterator %p with empty target %p", iter, iter->target); \
PFX##_impl_default_value(); \
} \
\
log_trace("Element access at %" PRIuMAX "", iter->cursor); \
\
return iter->target->buffer[iter->cursor]; \
} \
\
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \
{ \
if (iter == NULL) \
log_fatal("Invalid null pointer parameter: %s", "iter"); \
\
if (PFX##_empty(iter->target)) \
{ \
log_debug("Attempt to access element from iterator %p with empty target %p", iter, iter->target); \
return NULL; \
} \
\
log_trace("Element access at %" PRIuMAX "", iter->cursor); \
\
return &(iter->target->buffer[iter->cursor]); \
} \
\
FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \
{ \
if (iter == NULL) \
log_fatal("Invalid null pointer parameter: %s", "iter"); \
\
return iter->index; \
} \
\
static bool PFX##_impl_grow(SNAME *_deque_) \
{ \
size_t new_capacity = _deque_->capacity * 2; \
\
V *new_buffer = malloc(sizeof(V) * new_capacity); \
\
if (!new_buffer) \
{ \
log_info("%s reallocation failed", "Deque buffer"); \
return false; \
} \
\
for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->capacity, j++) \
{ \
new_buffer[j] = _deque_->buffer[i]; \
} \
\
free(_deque_->buffer); \
\
_deque_->buffer = new_buffer; \
_deque_->capacity = new_capacity; \
_deque_->front = 0; \
_deque_->back = _deque_->count; \
\
return true; \
} \
\
static SNAME##_iter PFX##_impl_it_start(SNAME *_deque_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _deque_); \
\
return iter; \
} \
\
static SNAME##_iter PFX##_impl_it_end(SNAME *_deque_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _deque_); \
PFX##_iter_to_end(&iter); \
\
return iter; \
}
#endif /* CMC_DEQUE_H */
+873
View File
@@ -0,0 +1,873 @@
/**
* bidimap.h
*
* Creation Date: 26/09/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#ifndef CMC_BIDIMAP_H
#define CMC_BIDIMAP_H
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../utl/cmc_string.h"
/**
* THIS IS A PREVIEW ONLY
*
* BidiMap
*
* A bidirectional map is a map that allows you to create a bijection in both
* directions between two sets of elements (K <-> V).
*
* This implementation uses two arrays of pointers to an entry containing both
* the key and the value.
*/
/* to_string format */
static const char *cmc_string_fmt_bidimap = "%s at %p { key_buffer:%p, val_buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, key_cmp:%p, val_cmp:%p, key_hash:%p, val_hash:%p }";
#ifndef CMC_ENTRY_DELETED
#define CMC_ENTRY_DELETED ((void *)1)
#endif /* CMC_ENTRY_DELETED */
#ifndef CMC_IMPL_HASHTABLE_SETUP
#define CMC_IMPL_HASHTABLE_SETUP
static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
3067, 6143, 12289, 24571, 49157,
98299, 196613, 393209, 786431,
1572869, 3145721, 6291449,
12582917, 25165813, 50331653,
100663291, 201326611, 402653189,
805306357, 1610612741,
3221225473, 6442450939,
12884901893, 25769803799,
51539607551, 103079215111,
206158430209, 412316860441,
824633720831, 1649267441651,
3298534883309, 6597069766657,
13194139533299, 26388279066623,
52776558133303, 105553116266489,
211106232532969, 422212465066001,
844424930131963,
1688849860263953,
3377699720527861,
6755399441055731,
13510798882111483,
27021597764222939,
54043195528445957,
108086391056891903,
216172782113783773,
432345564227567621,
864691128455135207,
1729382256910270481,
3458764513820540933,
6917529027641081903,
13835058055282163729llu};
#endif /* CMC_IMPL_HASHTABLE_SETUP */
#define CMC_GENERATE_BIDIMAP(PFX, SNAME, K, V) \
CMC_GENERATE_BIDIMAP_HEADER(PFX, SNAME, K, V) \
CMC_GENERATE_BIDIMAP_SOURCE(PFX, SNAME, K, V)
#define CMC_WRAPGEN_BIDIMAP_HEADER(PFX, SNAME, K, V) \
CMC_GENERATE_BIDIMAP_HEADER(PFX, SNAME, K, V)
#define CMC_WRAPGEN_BIDIMAP_SOURCE(PFX, SNAME, K, V) \
CMC_GENERATE_BIDIMAP_SOURCE(PFX, SNAME, K, V)
/* HEADER ********************************************************************/
#define CMC_GENERATE_BIDIMAP_HEADER(PFX, SNAME, K, V) \
\
/* BidiMap Structure */ \
typedef struct SNAME##_s \
{ \
/* Array of Entries mapping K -> V */ \
struct SNAME##_entry_s **key_buffer; \
\
/* Array of entries mapping V -> K */ \
struct SNAME##_entry_s **val_buffer; \
\
/* Current arrays capacity */ \
size_t capacity; \
\
/* Current amount of keys */ \
size_t count; \
\
/* Load factor in range (0.0, 1.0) */ \
double load; \
\
/* Key comparison function */ \
int (*key_cmp)(K, K); \
\
/* Value comparison function */ \
int (*val_cmp)(V, V); \
\
/* Key hash function */ \
size_t (*key_hash)(K); \
\
/* Value hash function */ \
size_t (*val_hash)(V); \
\
/* Function that returns an iterator to the start of the bidimap */ \
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
\
/* Function that returns an iterator to the end of the bidimap */ \
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
\
} SNAME, *SNAME##_ptr; \
\
/* BidiMap Entry */ \
typedef struct SNAME##_entry_s \
{ \
/* Entry Key */ \
K key; \
\
/* Entry Value */ \
V value; \
\
/* The distance of this node to its original position, used by */ \
/* robin-hood hashing relative to the key_buffer */ \
size_t key_dist; \
\
/* The distance of this node to its original position, used by */ \
/* robin-hood hashing relative to the value_buffer */ \
size_t val_dist; \
\
} SNAME##_entry, *SNAME##_entry_ptr; \
\
/* BidiMap Iterator */ \
typedef struct SNAME##_iter_s \
{ \
/* Target bidimap */ \
struct SNAME##_s *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; \
\
} SNAME##_iter, *SNAME##_iter_ptr; \
\
/* Collection Functions */ \
/* Collection Allocation and Deallocation */ \
SNAME *PFX##_new(size_t capacity, double load, \
int (*key_cmp)(K, K), size_t (*key_hash)(K), \
int (*val_cmp)(V, V), size_t (*val_hash)(V)); \
void PFX##_clear(SNAME *_map_, void (*deallocator)(K, V)); \
void PFX##_free(SNAME *_map_, void (*deallocator)(K, V)); \
/* Collection Input and Output */ \
bool PFX##_insert(SNAME *_map_, K key, V value); \
bool PFX##_update_key(SNAME *_map_, K key, K *old_key); \
bool PFX##_update_val(SNAME *_map_, V val, V *old_val); \
bool PFX##_remove_by_key(SNAME *_map_, K key, V *out_value); \
bool PFX##_remove_by_val(SNAME *_map_, V value, K *out_key); \
/* Element Access */ \
K PFX##_get_key(SNAME *_map_, V val); \
V PFX##_get_val(SNAME *_map_, K key); \
/* Collection State */ \
bool PFX##_contains_key(SNAME *_map_, K key); \
bool PFX##_contains_val(SNAME *_map_, V val); \
bool PFX##_empty(SNAME *_map_); \
bool PFX##_full(SNAME *_map_); \
size_t PFX##_count(SNAME *_map_); \
size_t PFX##_capacity(SNAME *_map_); \
double PFX##_load(SNAME *_map_); \
/* Collection Utility */ \
SNAME *PFX##_copy_of(SNAME *_map_, K (*key_copy_func)(K), V (*value_copy_func)(V)); \
bool PFX##_equals(SNAME *_map1_, SNAME *_map2_); \
cmc_string PFX##_to_string(SNAME *_map_); \
\
/* Iterator Functions */ \
/* Iterator Allocation and Deallocation */ \
SNAME##_iter *PFX##_iter_new(SNAME *target); \
void PFX##_iter_free(SNAME##_iter *iter); \
/* Iterator Initialization */ \
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
/* Iterator State */ \
bool PFX##_iter_start(SNAME##_iter *iter); \
bool PFX##_iter_end(SNAME##_iter *iter); \
/* Iterator Movement */ \
void PFX##_iter_to_start(SNAME##_iter *iter); \
void PFX##_iter_to_end(SNAME##_iter *iter); \
bool PFX##_iter_next(SNAME##_iter *iter); \
bool PFX##_iter_prev(SNAME##_iter *iter); \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
/* Iterator Access */ \
K PFX##_iter_key(SNAME##_iter *iter); \
V PFX##_iter_value(SNAME##_iter *iter); \
size_t PFX##_iter_index(SNAME##_iter *iter); \
\
/* SOURCE ********************************************************************/
#define CMC_GENERATE_BIDIMAP_SOURCE(PFX, SNAME, K, V) \
\
/* Implementation Detail Functions */ \
static bool PFX##_impl_grow(SNAME *_map_); \
static SNAME##_entry *PFX##_impl_new_entry(K key, V value); \
static SNAME##_entry **PFX##_impl_get_entry_by_key(SNAME *_map_, K key); \
static SNAME##_entry **PFX##_impl_get_entry_by_val(SNAME *_map_, V val); \
static SNAME##_entry **PFX##_impl_add_entry_to_key(SNAME *_map_, SNAME##_entry *entry); \
static SNAME##_entry **PFX##_impl_add_entry_to_val(SNAME *_map_, SNAME##_entry *entry); \
static size_t PFX##_impl_calculate_size(size_t required); \
static SNAME##_iter PFX##_impl_it_start(SNAME *_map_); \
static SNAME##_iter PFX##_impl_it_end(SNAME *_map_); \
\
SNAME *PFX##_new(size_t capacity, double load, \
int (*key_cmp)(K, K), size_t (*key_hash)(K), \
int (*val_cmp)(V, V), size_t (*val_hash)(V)) \
{ \
if (capacity == 0 || load <= 0 || load >= 1) \
return NULL; \
\
/* Prevent integer overflow */ \
if (capacity >= UINTMAX_MAX * load) \
return NULL; \
\
size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \
\
SNAME *_map_ = malloc(sizeof(SNAME)); \
\
if (!_map_) \
return NULL; \
\
_map_->key_buffer = calloc(real_capacity, sizeof(SNAME##_entry *)); \
_map_->val_buffer = calloc(real_capacity, sizeof(SNAME##_entry *)); \
\
if (!_map_->key_buffer || !_map_->val_buffer) \
{ \
free(_map_->key_buffer); \
free(_map_->val_buffer); \
free(_map_); \
return NULL; \
} \
\
_map_->count = 0; \
_map_->capacity = real_capacity; \
_map_->load = load; \
_map_->key_cmp = key_cmp; \
_map_->val_cmp = val_cmp; \
_map_->key_hash = key_hash; \
_map_->val_hash = val_hash; \
\
_map_->it_start = PFX##_impl_it_start; \
_map_->it_end = PFX##_impl_it_end; \
\
return _map_; \
} \
\
void PFX##_clear(SNAME *_map_, void (*deallocator)(K, V)) \
{ \
for (size_t i = 0; i < _map_->capacity; i++) \
{ \
SNAME##_entry *entry = _map_->key_buffer[i]; \
\
if (entry != NULL && entry != CMC_ENTRY_DELETED) \
{ \
if (deallocator) \
deallocator(entry->key, entry->value); \
\
free(entry); \
} \
\
_map_->key_buffer[i] = NULL; \
_map_->val_buffer[i] = NULL; \
} \
\
_map_->count = 0; \
} \
\
void PFX##_free(SNAME *_map_, void (*deallocator)(K, V)) \
{ \
PFX##_clear(_map_, deallocator); \
\
free(_map_->key_buffer); \
free(_map_->val_buffer); \
free(_map_); \
} \
\
bool PFX##_insert(SNAME *_map_, K key, V value) \
{ \
if (PFX##_full(_map_)) \
{ \
if (!PFX##_impl_grow(_map_)) \
return false; \
} \
\
if (PFX##_impl_get_entry_by_key(_map_, key) != NULL || \
PFX##_impl_get_entry_by_val(_map_, value) != NULL) \
return false; \
\
SNAME##_entry *entry = PFX##_impl_new_entry(key, value); \
\
SNAME##_entry **key_entry = PFX##_impl_add_entry_to_key(_map_, entry); \
SNAME##_entry **val_entry = 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; \
\
free(entry); \
\
return false; \
} \
\
_map_->count++; \
\
return true; \
} \
\
bool PFX##_update_key(SNAME *_map_, K key, K *old_key) \
{ \
if (PFX##_empty(_map_)) \
return false; \
\
return true; \
} \
\
bool PFX##_update_val(SNAME *_map_, V val, V *old_val) \
{ \
if (PFX##_empty(_map_)) \
return false; \
\
return true; \
} \
\
bool PFX##_remove_by_key(SNAME *_map_, K key, V *out_value) \
{ \
if (PFX##_empty(_map_)) \
return false; \
\
return true; \
} \
\
bool PFX##_remove_by_val(SNAME *_map_, V value, K *out_key) \
{ \
if (PFX##_empty(_map_)) \
return false; \
\
return true; \
} \
\
K PFX##_get_key(SNAME *_map_, V val) \
{ \
SNAME##_entry **entry = PFX##_impl_get_entry_by_val(_map_, val); \
\
if (!entry) \
return (V){0}; \
\
return (*entry)->key; \
} \
\
V PFX##_get_val(SNAME *_map_, K key) \
{ \
SNAME##_entry **entry = PFX##_impl_get_entry_by_key(_map_, key); \
\
if (!entry) \
return (V){0}; \
\
return (*entry)->value; \
} \
\
bool PFX##_contains_key(SNAME *_map_, K key) \
{ \
return PFX##_impl_get_entry_by_key(_map_, key) != NULL; \
} \
\
bool PFX##_contains_val(SNAME *_map_, V val) \
{ \
return PFX##_impl_get_entry_by_val(_map_, val) != NULL; \
} \
\
bool PFX##_empty(SNAME *_map_) \
{ \
return _map_->count == 0; \
} \
\
bool PFX##_full(SNAME *_map_) \
{ \
return (double)PFX##_capacity(_map_) * PFX##_load(_map_) <= (double)PFX##_count(_map_); \
} \
\
size_t PFX##_count(SNAME *_map_) \
{ \
return _map_->count; \
} \
\
size_t PFX##_capacity(SNAME *_map_) \
{ \
return _map_->capacity; \
} \
\
double PFX##_load(SNAME *_map_) \
{ \
return _map_->load; \
} \
\
SNAME *PFX##_copy_of(SNAME *_map_, K (*key_copy_func)(K), V (*value_copy_func)(V)) \
{ \
return NULL; \
} \
\
bool PFX##_equals(SNAME *_map1_, SNAME *_map2_) \
{ \
return false; \
} \
\
cmc_string PFX##_to_string(SNAME *_map_) \
{ \
cmc_string str; \
SNAME *m_ = _map_; \
const char *name = #SNAME; \
\
snprintf(str.s, cmc_string_len, cmc_string_fmt_bidimap, \
name, m_, m_->key_buffer, m_->val_buffer, m_->capacity, m_->count, \
m_->load, m_->key_cmp, m_->val_cmp, m_->key_hash, m_->val_hash); \
\
return str; \
} \
\
SNAME##_iter *PFX##_iter_new(SNAME *target) \
{ \
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
\
if (!iter) \
return NULL; \
\
PFX##_iter_init(iter, target); \
\
return iter; \
} \
\
void PFX##_iter_free(SNAME##_iter *iter) \
{ \
free(iter); \
} \
\
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
{ \
memset(iter, 0, sizeof(SNAME##_iter)); \
\
iter->target = target; \
iter->start = true; \
iter->end = PFX##_empty(target); \
\
if (!PFX##_empty(target)) \
{ \
for (size_t i = 0; i < target->capacity; i++) \
{ \
SNAME##_entry *tmp = target->key_buffer[i]; \
\
if (tmp != NULL && tmp != CMC_ENTRY_DELETED) \
{ \
iter->first = i; \
break; \
} \
} \
\
iter->cursor = iter->first; \
\
for (size_t i = target->capacity; i > 0; i--) \
{ \
SNAME##_entry *tmp = target->key_buffer[i - 1]; \
\
if (tmp != NULL && tmp != CMC_ENTRY_DELETED) \
{ \
iter->last = i - 1; \
break; \
} \
} \
} \
} \
\
bool PFX##_iter_start(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->start; \
} \
\
bool PFX##_iter_end(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->end; \
} \
\
void PFX##_iter_to_start(SNAME##_iter *iter) \
{ \
if (!PFX##_empty(iter->target)) \
{ \
iter->cursor = iter->first; \
iter->index = 0; \
iter->start = true; \
iter->end = false; \
} \
} \
\
void PFX##_iter_to_end(SNAME##_iter *iter) \
{ \
if (!PFX##_empty(iter->target)) \
{ \
iter->cursor = iter->last; \
iter->index = PFX##_count(iter->target) - 1; \
iter->start = false; \
iter->end = true; \
} \
} \
\
bool PFX##_iter_next(SNAME##_iter *iter) \
{ \
if (iter->end) \
return false; \
\
if (iter->index + 1 == PFX##_count(iter->target)) \
{ \
iter->end = true; \
return false; \
} \
\
iter->start = PFX##_empty(iter->target); \
\
SNAME##_entry *scan = iter->target->key_buffer[iter->cursor]; \
\
iter->index++; \
\
while (1) \
{ \
iter->cursor++; \
scan = iter->target->key_buffer[iter->cursor]; \
\
if (scan != NULL && scan != CMC_ENTRY_DELETED) \
break; \
} \
\
return true; \
} \
\
bool PFX##_iter_prev(SNAME##_iter *iter) \
{ \
if (iter->start) \
return false; \
\
if (iter->index == 0) \
{ \
iter->start = true; \
return false; \
} \
\
iter->end = PFX##_empty(iter->target); \
\
SNAME##_entry *scan = iter->target->key_buffer[iter->cursor]; \
\
iter->index--; \
\
while (1) \
{ \
iter->cursor--; \
scan = iter->target->key_buffer[iter->cursor]; \
\
if (scan != NULL && scan != CMC_ENTRY_DELETED) \
break; \
} \
\
return true; \
} \
\
/* Returns true only if the iterator moved */ \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->end) \
return false; \
\
if (iter->index + 1 == PFX##_count(iter->target)) \
{ \
iter->end = true; \
return false; \
} \
\
if (steps == 0 || iter->index + steps >= PFX##_count(iter->target)) \
return false; \
\
for (size_t i = 0; i < steps; i++) \
PFX##_iter_next(iter); \
\
return true; \
} \
\
/* Returns true only if the iterator moved */ \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
{ \
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++) \
PFX##_iter_prev(iter); \
\
return true; \
} \
\
/* Returns true only if the iterator was able to be positioned at the given index */ \
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
{ \
if (index >= PFX##_count(iter->target)) \
return false; \
\
if (iter->index > index) \
return PFX##_iter_rewind(iter, iter->index - index); \
else if (iter->index < index) \
return PFX##_iter_advance(iter, index - iter->index); \
\
return true; \
} \
\
K PFX##_iter_key(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return (K){0}; \
\
return iter->target->key_buffer[iter->cursor]->key; \
} \
\
V PFX##_iter_value(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return (V){0}; \
\
return iter->target->key_buffer[iter->cursor]->value; \
} \
\
size_t PFX##_iter_index(SNAME##_iter *iter) \
{ \
return iter->index; \
} \
\
static bool PFX##_impl_grow(SNAME *_map_) \
{ \
/* TODO */ \
return false; \
} \
\
static SNAME##_entry *PFX##_impl_new_entry(K key, V value) \
{ \
SNAME##_entry *entry = malloc(sizeof(SNAME##_entry)); \
\
if (!entry) \
return NULL; \
\
entry->key = key; \
entry->value = value; \
entry->key_dist = 0; \
entry->val_dist = 0; \
\
return entry; \
} \
\
static SNAME##_entry **PFX##_impl_get_entry_by_key(SNAME *_map_, K key) \
{ \
size_t hash = _map_->key_hash(key); \
size_t pos = hash % _map_->capacity; \
\
SNAME##_entry *target = _map_->key_buffer[pos]; \
\
while (target != NULL) \
{ \
if (target != CMC_ENTRY_DELETED && _map_->key_cmp(target->key, key) == 0) \
return &(_map_->key_buffer[pos % _map_->capacity]); \
\
pos++; \
target = _map_->key_buffer[pos % _map_->capacity]; \
} \
\
return NULL; \
} \
\
static SNAME##_entry **PFX##_impl_get_entry_by_val(SNAME *_map_, V val) \
{ \
size_t hash = _map_->val_hash(val); \
size_t pos = hash % _map_->capacity; \
\
SNAME##_entry *target = _map_->val_buffer[pos]; \
\
while (target != NULL) \
{ \
if (target != CMC_ENTRY_DELETED && _map_->val_cmp(target->value, val) == 0) \
return &(_map_->val_buffer[pos % _map_->capacity]); \
\
pos++; \
target = _map_->val_buffer[pos % _map_->capacity]; \
} \
\
return NULL; \
} \
\
static SNAME##_entry **PFX##_impl_add_entry_to_key(SNAME *_map_, SNAME##_entry *entry) \
{ \
SNAME##_entry **to_return = NULL; \
\
size_t hash = _map_->key_hash(entry->key); \
size_t original_pos = hash % _map_->capacity; \
size_t pos = original_pos; \
\
SNAME##_entry **scan = &(_map_->key_buffer[hash % _map_->capacity]); \
\
if (*scan == NULL) \
{ \
*scan = entry; \
\
return scan; \
} \
else \
{ \
while (true) \
{ \
pos++; \
scan = &(_map_->key_buffer[pos % _map_->capacity]); \
\
if (*scan == NULL || *scan == CMC_ENTRY_DELETED) \
{ \
if (!to_return) \
to_return = scan; \
\
*scan = entry; \
entry->key_dist = pos - original_pos; \
\
return to_return; \
} \
else if ((*scan)->key_dist < pos - original_pos) \
{ \
if (!to_return) \
to_return = scan; \
\
size_t tmp_dist = (*scan)->key_dist; \
entry->key_dist = pos - original_pos; \
original_pos = pos - tmp_dist; \
\
SNAME##_entry *_tmp_ = *scan; \
*scan = entry; \
entry = _tmp_; \
} \
} \
} \
\
return NULL; \
} \
\
static SNAME##_entry **PFX##_impl_add_entry_to_val(SNAME *_map_, SNAME##_entry *entry) \
{ \
SNAME##_entry **to_return = NULL; \
\
size_t hash = _map_->val_hash(entry->value); \
size_t original_pos = hash % _map_->capacity; \
size_t pos = original_pos; \
\
SNAME##_entry **scan = &(_map_->val_buffer[hash % _map_->capacity]); \
\
if (*scan == NULL) \
{ \
*scan = entry; \
\
return scan; \
} \
else \
{ \
while (true) \
{ \
pos++; \
scan = &(_map_->val_buffer[pos % _map_->capacity]); \
\
if (*scan == NULL || *scan == CMC_ENTRY_DELETED) \
{ \
if (!to_return) \
to_return = scan; \
\
*scan = entry; \
entry->val_dist = pos - original_pos; \
\
return to_return; \
} \
else if ((*scan)->val_dist < pos - original_pos) \
{ \
if (!to_return) \
to_return = scan; \
\
size_t tmp_dist = (*scan)->val_dist; \
entry->val_dist = pos - original_pos; \
original_pos = pos - tmp_dist; \
\
SNAME##_entry *_tmp_ = *scan; \
*scan = entry; \
entry = _tmp_; \
} \
} \
} \
\
return NULL; \
} \
\
static size_t PFX##_impl_calculate_size(size_t required) \
{ \
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]; \
} \
\
static SNAME##_iter PFX##_impl_it_start(SNAME *_map_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _map_); \
\
return iter; \
} \
\
static SNAME##_iter PFX##_impl_it_end(SNAME *_map_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _map_); \
PFX##_iter_to_end(&iter); \
\
return iter; \
}
#endif /* CMC_BIDIMAP_H */
+952
View File
@@ -0,0 +1,952 @@
/**
* intervalheap.h
*
* Creation Date: 06/07/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* 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
*/
#ifndef CMC_INTERVALHEAP_H
#define CMC_INTERVALHEAP_H
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../utl/cmc_string.h"
/* to_string format */
static const char *cmc_string_fmt_intervalheap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", size:%" PRIuMAX ", count:%" PRIuMAX ", cmp:%p }";
#define CMC_GENERATE_INTERVALHEAP(PFX, SNAME, V) \
CMC_GENERATE_INTERVALHEAP_HEADER(PFX, SNAME, V) \
CMC_GENERATE_INTERVALHEAP_SOURCE(PFX, SNAME, V)
#define CMC_WRAPGEN_INTERVALHEAP_HEADER(PFX, SNAME, K, V) \
CMC_GENERATE_INTERVALHEAP_HEADER(PFX, SNAME, V)
#define CMC_WRAPGEN_INTERVALHEAP_SOURCE(PFX, SNAME, K, V) \
CMC_GENERATE_INTERVALHEAP_SOURCE(PFX, SNAME, V)
/* HEADER ********************************************************************/
#define CMC_GENERATE_INTERVALHEAP_HEADER(PFX, SNAME, V) \
\
/* Heap Structure */ \
typedef struct SNAME##_s \
{ \
/* Dynamic array of nodes */ \
struct SNAME##_node_s *buffer; \
\
/* Current array capacity (how many nodes can be stored) */ \
size_t capacity; \
\
/* Current amount of nodes in the dynamic array */ \
size_t size; \
\
/* Current amount of elements in the heap */ \
size_t count; \
\
/* Element comparison function */ \
int (*cmp)(V, V); \
\
/* Function that returns an iterator to the start of the heap */ \
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
\
/* Function that returns an iterator to the end of the heap */ \
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
\
} SNAME, *SNAME##_ptr; \
\
/* Heap Node */ \
typedef struct SNAME##_node_s \
{ \
/* 0 - Value belonging to the MinHeap */ \
/* 1 - Value belonging to the MaxHeap */ \
V data[2]; \
\
} SNAME##_node, *SNAME##_node_ptr; \
\
/* Heap Iterator */ \
typedef struct SNAME##_iter_s \
{ \
/* Target heap */ \
struct SNAME##_s *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; \
\
} SNAME##_iter, *SNAME##_iter_ptr; \
\
/* Collection Functions */ \
/* Collection Allocation and Deallocation */ \
SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)); \
void PFX##_clear(SNAME *_heap_, void (*deallocator)(V)); \
void PFX##_free(SNAME *_heap_, void (*deallocator)(V)); \
/* Collection Input and Output */ \
bool PFX##_insert(SNAME *_heap_, V element); \
bool PFX##_remove_max(SNAME *_heap_, V *result); \
bool PFX##_remove_min(SNAME *_heap_, V *result); \
/* Collection Update */ \
bool PFX##_update_max(SNAME *_heap_, V element); \
bool PFX##_update_min(SNAME *_heap_, V element); \
/* Element Access */ \
bool PFX##_max(SNAME *_heap_, V *value); \
bool PFX##_min(SNAME *_heap_, V *value); \
/* Collection State */ \
bool PFX##_contains(SNAME *_heap_, V element); \
bool PFX##_empty(SNAME *_heap_); \
bool PFX##_full(SNAME *_heap_); \
size_t PFX##_count(SNAME *_heap_); \
size_t PFX##_capacity(SNAME *_heap_); \
/* Collection Utility */ \
bool PFX##_resize(SNAME *_heap_, size_t capacity); \
SNAME *PFX##_copy_of(SNAME *_set_, V (*copy_func)(V)); \
bool PFX##_equals(SNAME *_heap1_, SNAME *_heap2_); \
cmc_string PFX##_to_string(SNAME *_heap_); \
\
/* Iterator Functions */ \
/* Iterator Allocation and Deallocation */ \
SNAME##_iter *PFX##_iter_new(SNAME *target); \
void PFX##_iter_free(SNAME##_iter *iter); \
/* Iterator Initialization */ \
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
/* Iterator State */ \
bool PFX##_iter_start(SNAME##_iter *iter); \
bool PFX##_iter_end(SNAME##_iter *iter); \
/* Iterator Movement */ \
void PFX##_iter_to_start(SNAME##_iter *iter); \
void PFX##_iter_to_end(SNAME##_iter *iter); \
bool PFX##_iter_next(SNAME##_iter *iter); \
bool PFX##_iter_prev(SNAME##_iter *iter); \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
/* Iterator Access */ \
V PFX##_iter_value(SNAME##_iter *iter); \
size_t PFX##_iter_index(SNAME##_iter *iter); \
\
/* SOURCE ********************************************************************/
#define CMC_GENERATE_INTERVALHEAP_SOURCE(PFX, SNAME, V) \
\
/* Implementation Detail Functions */ \
static void PFX##_impl_float_up_max(SNAME *_heap_); \
static void PFX##_impl_float_up_min(SNAME *_heap_); \
static void PFX##_impl_float_down_max(SNAME *_heap_); \
static void PFX##_impl_float_down_min(SNAME *_heap_); \
static SNAME##_iter PFX##_impl_it_start(SNAME *_heap_); \
static SNAME##_iter PFX##_impl_it_end(SNAME *_heap_); \
\
SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)) \
{ \
if (capacity == 0 || capacity == UINT64_MAX) \
return NULL; \
\
SNAME *_heap_ = malloc(sizeof(SNAME)); \
\
if (!_heap_) \
return NULL; \
\
/* Since each node can store two elements, divide the actual capacity by 2 */ \
/* Round the capacity of nodes up */ \
capacity = capacity % 2 == 0 ? capacity / 2 : (capacity + 1) / 2; \
\
_heap_->buffer = malloc(sizeof(SNAME##_node) * capacity); \
\
if (!_heap_->buffer) \
{ \
free(_heap_); \
return NULL; \
} \
\
memset(_heap_->buffer, 0, sizeof(SNAME##_node) * capacity); \
\
_heap_->capacity = capacity; \
_heap_->size = 0; \
_heap_->count = 0; \
_heap_->cmp = compare; \
\
_heap_->it_start = PFX##_impl_it_start; \
_heap_->it_end = PFX##_impl_it_end; \
\
return _heap_; \
} \
\
void PFX##_clear(SNAME *_heap_, void (*deallocator)(V)) \
{ \
if (deallocator) \
{ \
for (size_t i = 0; i < _heap_->count; i++) \
{ \
deallocator(_heap_->buffer[i / 2].data[i % 2]); \
} \
} \
\
memset(_heap_->buffer, 0, sizeof(V) * _heap_->capacity); \
\
_heap_->size = 0; \
_heap_->count = 0; \
} \
\
void PFX##_free(SNAME *_heap_, void (*deallocator)(V)) \
{ \
if (deallocator) \
{ \
for (size_t i = 0; i < _heap_->count; i++) \
{ \
deallocator(_heap_->buffer[i / 2].data[i % 2]); \
} \
} \
\
free(_heap_->buffer); \
\
free(_heap_); \
} \
\
bool PFX##_insert(SNAME *_heap_, V element) \
{ \
if (PFX##_full(_heap_)) \
{ \
if (!PFX##_resize(_heap_, PFX##_capacity(_heap_) * 4)) \
return false; \
} \
\
if (PFX##_count(_heap_) % 2 == 0) \
{ \
/* Occupying a new node */ \
_heap_->buffer[_heap_->size].data[0] = element; \
_heap_->buffer[_heap_->size].data[1] = (V){0}; \
\
_heap_->size++; \
} \
else \
{ \
SNAME##_node *curr_node = &(_heap_->buffer[_heap_->size - 1]); \
\
/* Decide if the new element goes into the MinHeap or MaxHeap */ \
if (_heap_->cmp(curr_node->data[0], element) > 0) \
{ \
/* Swap current value and add new element to the MinHeap */ \
curr_node->data[1] = curr_node->data[0]; \
curr_node->data[0] = element; \
} \
else \
{ \
/* No need to swap and add the new element to the MaxHeap */ \
curr_node->data[1] = element; \
} \
} \
\
_heap_->count++; \
\
if (PFX##_count(_heap_) <= 2) \
return true; \
\
/* Determine wheather to do a MaxHeap insert or a MinHeap insert */ \
SNAME##_node *parent = &(_heap_->buffer[(_heap_->size - 1) / 2]); \
\
if (_heap_->cmp(parent->data[0], element) > 0) \
PFX##_impl_float_up_min(_heap_); \
else if (_heap_->cmp(parent->data[1], element) < 0) \
PFX##_impl_float_up_max(_heap_); \
/* else no float up required */ \
\
return true; \
} \
\
bool PFX##_remove_max(SNAME *_heap_, V *result) \
{ \
if (PFX##_empty(_heap_)) \
return false; \
\
if (PFX##_count(_heap_) == 1) \
{ \
*result = _heap_->buffer[0].data[0]; \
\
_heap_->buffer[0].data[0] = (V){0}; \
\
_heap_->count--; \
\
return true; \
} \
else \
*result = _heap_->buffer[0].data[1]; \
\
/* Swap the result with the last element in the MaxHeap and float it down */ \
SNAME##_node *last_node = &(_heap_->buffer[_heap_->size - 1]); \
\
if (PFX##_count(_heap_) % 2 == 1) \
{ \
/* Grab from MinHeap and discard last node */ \
_heap_->buffer[0].data[1] = last_node->data[0]; \
\
last_node->data[0] = (V){0}; \
\
_heap_->size--; \
} \
else \
{ \
_heap_->buffer[0].data[1] = last_node->data[1]; \
\
last_node->data[1] = (V){0}; \
} \
\
_heap_->count--; \
\
/* FLoat Down on the MaxHeap */ \
PFX##_impl_float_down_max(_heap_); \
\
return true; \
} \
\
bool PFX##_remove_min(SNAME *_heap_, V *result) \
{ \
if (PFX##_empty(_heap_)) \
return false; \
\
*result = _heap_->buffer[0].data[0]; \
\
if (PFX##_count(_heap_) == 1) \
{ \
_heap_->buffer[0].data[0] = (V){0}; \
\
_heap_->count--; \
\
return true; \
} \
\
/* Swap the result with the last element in the MinHeap and float it down */ \
SNAME##_node *last_node = &(_heap_->buffer[_heap_->size - 1]); \
\
_heap_->buffer[0].data[0] = last_node->data[0]; \
\
if (PFX##_count(_heap_) % 2 == 1) \
{ \
/* Discard last node */ \
last_node->data[0] = (V){0}; \
\
_heap_->size--; \
} \
else \
{ \
/* Place the MaxHeap value in the MinHeap value spot */ \
last_node->data[0] = last_node->data[1]; \
last_node->data[1] = (V){0}; \
} \
\
_heap_->count--; \
\
/* FLoat Down on the MinHeap */ \
PFX##_impl_float_down_min(_heap_); \
\
return true; \
} \
\
bool PFX##_update_max(SNAME *_heap_, V element) \
{ \
if (PFX##_empty(_heap_)) \
return false; \
\
if (PFX##_count(_heap_) == 1) \
{ \
_heap_->buffer[0].data[0] = element; \
} \
else if (_heap_->cmp(element, _heap_->buffer[0].data[0]) < 0) \
{ \
/* Corner case: we are updating the Max value but it is less than */ \
/* the Min value */ \
_heap_->buffer[0].data[1] = _heap_->buffer[0].data[0]; \
_heap_->buffer[0].data[0] = element; \
\
PFX##_impl_float_down_max(_heap_); \
} \
else \
{ \
/* Update Max element and float it down */ \
_heap_->buffer[0].data[1] = element; \
\
PFX##_impl_float_down_max(_heap_); \
} \
\
return true; \
} \
\
bool PFX##_update_min(SNAME *_heap_, V element) \
{ \
if (PFX##_empty(_heap_)) \
return false; \
\
if (PFX##_count(_heap_) == 1) \
{ \
_heap_->buffer[0].data[0] = element; \
} \
else if (_heap_->cmp(element, _heap_->buffer[0].data[1]) > 0) \
{ \
/* Corner case: we are updating the Min value but it is greater */ \
/* than the Max value. */ \
_heap_->buffer[0].data[0] = _heap_->buffer[0].data[1]; \
_heap_->buffer[0].data[1] = element; \
\
PFX##_impl_float_down_min(_heap_); \
} \
else \
{ \
/* Update Min element and float it down */ \
_heap_->buffer[0].data[0] = element; \
\
PFX##_impl_float_down_min(_heap_); \
} \
\
return true; \
} \
\
bool PFX##_max(SNAME *_heap_, V *value) \
{ \
if (PFX##_empty(_heap_)) \
return false; \
\
/* If there is only one element, then the maximum element is the same */ \
/* as the one in the MinHeap */ \
if (PFX##_count(_heap_) == 1) \
*value = _heap_->buffer[0].data[0]; \
else \
*value = _heap_->buffer[0].data[1]; \
\
return true; \
} \
\
bool PFX##_min(SNAME *_heap_, V *value) \
{ \
if (PFX##_empty(_heap_)) \
return false; \
\
*value = _heap_->buffer[0].data[0]; \
\
return true; \
} \
\
bool PFX##_contains(SNAME *_heap_, V element) \
{ \
for (size_t i = 0; i < _heap_->count; i++) \
{ \
if (_heap_->cmp(_heap_->buffer[i / 2].data[i % 2], element) == 0) \
return true; \
} \
\
return false; \
} \
\
bool PFX##_empty(SNAME *_heap_) \
{ \
return _heap_->count == 0; \
} \
\
bool PFX##_full(SNAME *_heap_) \
{ \
/* The heap is full if all nodes are completely filled */ \
return _heap_->size >= _heap_->capacity && _heap_->count % 2 == 0; \
} \
\
size_t PFX##_count(SNAME *_heap_) \
{ \
return _heap_->count; \
} \
\
size_t PFX##_capacity(SNAME *_heap_) \
{ \
return _heap_->capacity; \
} \
\
bool PFX##_resize(SNAME *_heap_, size_t capacity) \
{ \
if (PFX##_capacity(_heap_) == capacity) \
return true; \
\
if (capacity < PFX##_count(_heap_)) \
return false; \
\
capacity = capacity % 2 == 0 ? capacity / 2 : (capacity + 1) / 2; \
\
SNAME##_node *new_buffer = realloc(_heap_->buffer, sizeof(SNAME##_node) * capacity); \
\
if (!new_buffer) \
return false; \
\
memset(new_buffer + _heap_->capacity, 0, sizeof(SNAME##_node) * _heap_->capacity); \
\
_heap_->buffer = new_buffer; \
_heap_->capacity = capacity; \
\
return true; \
} \
\
SNAME *PFX##_copy_of(SNAME *_heap_, V (*copy_func)(V)) \
{ \
SNAME *result = malloc(sizeof(SNAME)); \
\
if (!result) \
return NULL; \
\
memcpy(result, _heap_, sizeof(SNAME)); \
\
result->buffer = malloc(sizeof(SNAME##_node) * _heap_->capacity); \
\
if (!result->buffer) \
{ \
free(result); \
return NULL; \
} \
\
if (copy_func) \
{ \
for (size_t i = 0; i < _heap_->count; i++) \
result->buffer[i / 2].data[i % 2] = copy_func(_heap_->buffer[i / 2].data[i % 2]); \
} \
else \
memcpy(result->buffer, _heap_->buffer, sizeof(SNAME##_node) * _heap_->capacity); \
\
return result; \
} \
\
bool PFX##_equals(SNAME *_heap1_, SNAME *_heap2_) \
{ \
if (PFX##_count(_heap1_) != PFX##_count(_heap2_)) \
return false; \
\
for (size_t i = 0; i < _heap1_->count; i++) \
{ \
V element1 = _heap1_->buffer[i / 2].data[i % 2]; \
V element2 = _heap2_->buffer[i / 2].data[i % 2]; \
\
if (_heap1_->cmp(element1, element2) == 0) \
return true; \
} \
\
return false; \
} \
\
cmc_string PFX##_to_string(SNAME *_heap_) \
{ \
cmc_string str; \
SNAME *h_ = _heap_; \
const char *name = #SNAME; \
\
snprintf(str.s, cmc_string_len, cmc_string_fmt_intervalheap, \
name, h_, h_->buffer, h_->capacity, h_->size, h_->count, h_->cmp); \
\
return str; \
} \
\
SNAME##_iter *PFX##_iter_new(SNAME *target) \
{ \
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
\
if (!iter) \
return NULL; \
\
PFX##_iter_init(iter, target); \
\
return iter; \
} \
\
void PFX##_iter_free(SNAME##_iter *iter) \
{ \
free(iter); \
} \
\
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
{ \
iter->target = target; \
iter->cursor = 0; \
iter->start = true; \
iter->end = PFX##_empty(target); \
} \
\
bool PFX##_iter_start(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->start; \
} \
\
bool PFX##_iter_end(SNAME##_iter *iter) \
{ \
return PFX##_empty(iter->target) || iter->end; \
} \
\
void PFX##_iter_to_start(SNAME##_iter *iter) \
{ \
if (!PFX##_empty(iter->target)) \
{ \
iter->cursor = 0; \
iter->start = true; \
iter->end = PFX##_empty(iter->target); \
} \
} \
\
void PFX##_iter_to_end(SNAME##_iter *iter) \
{ \
if (!PFX##_empty(iter->target)) \
{ \
iter->cursor = iter->target->count - 1; \
iter->start = PFX##_empty(iter->target); \
iter->end = true; \
} \
} \
\
bool PFX##_iter_next(SNAME##_iter *iter) \
{ \
if (iter->end) \
return false; \
\
if (iter->cursor + 1 == PFX##_count(iter->target)) \
{ \
iter->end = true; \
return false; \
} \
\
iter->start = PFX##_empty(iter->target); \
\
iter->cursor++; \
\
return true; \
} \
\
bool PFX##_iter_prev(SNAME##_iter *iter) \
{ \
if (iter->start) \
return false; \
\
if (iter->cursor == 0) \
{ \
iter->start = true; \
return false; \
} \
\
iter->end = PFX##_empty(iter->target); \
\
iter->cursor--; \
\
return true; \
} \
\
/* Returns true only if the iterator moved */ \
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->start) \
return false; \
\
if (iter->cursor == 0) \
{ \
iter->start = true; \
return false; \
} \
\
if (steps == 0 || iter->cursor + steps >= PFX##_count(iter->target)) \
return false; \
\
iter->start = PFX##_empty(iter->target); \
\
iter->cursor += steps; \
\
return true; \
} \
\
/* Returns true only if the iterator moved */ \
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
{ \
if (iter->start) \
return false; \
\
if (iter->cursor == 0) \
{ \
iter->start = true; \
return false; \
} \
\
if (steps == 0 || iter->cursor < steps) \
return false; \
\
iter->end = 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 PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
{ \
if (index >= PFX##_count(iter->target)) \
return false; \
\
if (iter->cursor > index) \
return PFX##_iter_rewind(iter, iter->cursor - index); \
else if (iter->cursor < index) \
return PFX##_iter_advance(iter, index - iter->cursor); \
\
return true; \
} \
\
V PFX##_iter_value(SNAME##_iter *iter) \
{ \
if (PFX##_empty(iter->target)) \
return (V){0}; \
\
return iter->target->buffer[iter->cursor / 2].data[iter->cursor % 2]; \
} \
\
size_t PFX##_iter_index(SNAME##_iter *iter) \
{ \
return iter->cursor; \
} \
\
static void PFX##_impl_float_up_max(SNAME *_heap_) \
{ \
size_t index = _heap_->size - 1; \
\
SNAME##_node *curr_node = &(_heap_->buffer[index]); \
\
/* FLoat Up on the MaxHeap */ \
while (index > 0) \
{ \
/* Parent index */ \
size_t P_index = (index - 1) / 2; \
\
SNAME##_node *parent = &(_heap_->buffer[P_index]); \
\
if (index == _heap_->size - 1 && PFX##_count(_heap_) % 2 != 0) \
{ \
/* In this case, the current node has no MaxHeap value so we */ \
/* instead compare with the MinHeap value */ \
if (_heap_->cmp(curr_node->data[0], parent->data[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->data[0]; \
curr_node->data[0] = parent->data[1]; \
parent->data[1] = tmp; \
} \
else \
{ \
/* Usual case, just compare both MaxHeap values */ \
if (_heap_->cmp(curr_node->data[1], parent->data[1]) < 0) \
break; \
\
/* Swap with parent and repeat */ \
V tmp = curr_node->data[1]; \
curr_node->data[1] = parent->data[1]; \
parent->data[1] = tmp; \
} \
\
/* Update indexe and node */ \
index = P_index; \
curr_node = parent; \
} \
} \
\
static void PFX##_impl_float_up_min(SNAME *_heap_) \
{ \
size_t index = _heap_->size - 1; \
\
SNAME##_node *curr_node = &(_heap_->buffer[index]); \
\
/* FLoat Up on the MinHeap */ \
while (index > 0) \
{ \
/* Parent index */ \
size_t P_index = (index - 1) / 2; \
\
SNAME##_node *parent = &(_heap_->buffer[P_index]); \
\
if (_heap_->cmp(curr_node->data[0], parent->data[0]) >= 0) \
break; \
\
/* Swap with parent and repeat */ \
V tmp = curr_node->data[0]; \
curr_node->data[0] = parent->data[0]; \
parent->data[0] = tmp; \
\
/* Update indexe and node */ \
index = P_index; \
curr_node = parent; \
} \
} \
\
static void PFX##_impl_float_down_max(SNAME *_heap_) \
{ \
/* Floats Down from the MinHeap */ \
size_t index = 0; \
\
SNAME##_node *curr_node = &(_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) \
{ \
SNAME##_node *L = &(_heap_->buffer[L_index]); \
SNAME##_node *R = &(_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 && PFX##_count(_heap_) % 2 != 0) \
child = _heap_->cmp(L->data[1], R->data[0]) > 0 ? L_index : R_index; \
else \
child = _heap_->cmp(L->data[1], R->data[1]) > 0 ? L_index : R_index; \
} \
/* Pick the only one available */ \
else \
child = L_index; \
\
SNAME##_node *child_node = &(_heap_->buffer[child]); \
\
/* Again, check if the child node is the last one and has no MaxHeap value */ \
if (child == _heap_->size - 1 && PFX##_count(_heap_) % 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_->cmp(curr_node->data[1], child_node->data[0]) >= 0) \
break; \
\
/* Otherwise swap and continue */ \
V tmp = child_node->data[0]; \
child_node->data[0] = curr_node->data[1]; \
curr_node->data[1] = tmp; \
} \
else \
{ \
/* If current value is not less than the child node's value, it is done */ \
if (_heap_->cmp(curr_node->data[1], child_node->data[1]) >= 0) \
break; \
\
/* Otherwise swap and continue */ \
V tmp = child_node->data[1]; \
child_node->data[1] = curr_node->data[1]; \
curr_node->data[1] = tmp; \
\
/* Check if the MinHeap and MaxHeap values need to be swapped */ \
if (_heap_->cmp(child_node->data[0], child_node->data[1]) > 0) \
{ \
/* Swap because the MinHeap value is greater than the MaxHeap value */ \
tmp = child_node->data[0]; \
child_node->data[0] = child_node->data[1]; \
child_node->data[1] = tmp; \
} \
} \
\
/* Update index and node */ \
index = child; \
curr_node = child_node; \
} \
} \
\
static void PFX##_impl_float_down_min(SNAME *_heap_) \
{ \
/* Floats Down from the MinHeap */ \
size_t index = 0; \
\
SNAME##_node *curr_node = &(_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) \
{ \
SNAME##_node *L = &(_heap_->buffer[L_index]); \
SNAME##_node *R = &(_heap_->buffer[R_index]); \
\
child = _heap_->cmp(L->data[0], R->data[0]) < 0 ? L_index : R_index; \
} \
/* Pick the only one available */ \
else \
child = L_index; \
\
SNAME##_node *child_node = &(_heap_->buffer[child]); \
\
/* If current value is smaller than the child node's value, it is done */ \
if (_heap_->cmp(curr_node->data[0], child_node->data[0]) < 0) \
break; \
\
/* Otherwise swap and continue */ \
V tmp = child_node->data[0]; \
child_node->data[0] = curr_node->data[0]; \
curr_node->data[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 || PFX##_count(_heap_) % 2 == 0) \
{ \
if (_heap_->cmp(child_node->data[0], child_node->data[1]) > 0) \
{ \
/* Swap because the MinHeap value is greater than the MaxHeap value */ \
tmp = child_node->data[0]; \
child_node->data[0] = child_node->data[1]; \
child_node->data[1] = tmp; \
} \
} \
\
/* Update index and node */ \
index = child; \
curr_node = child_node; \
} \
} \
\
static SNAME##_iter PFX##_impl_it_start(SNAME *_heap_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _heap_); \
PFX##_iter_to_start(&iter); \
\
return iter; \
} \
\
static SNAME##_iter PFX##_impl_it_end(SNAME *_heap_) \
{ \
SNAME##_iter iter; \
\
PFX##_iter_init(&iter, _heap_); \
PFX##_iter_to_end(&iter); \
\
return iter; \
}
#endif /* CMC_INTERVALHEAP_H */
+1125
View File
File diff suppressed because it is too large. Load diff
+1230
View File
File diff suppressed because it is too large. Load diff
Loaded 100 of 186 files, more files were not shown because too many files have changed in this diff. Show more