Compare commits
394
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bcfdc87cd6 | ||
|
|
2c1eb41280 | ||
|
|
53960a3bce | ||
|
|
e4dbeae46d | ||
|
|
32deb8356c | ||
|
|
3593957bb8 | ||
|
|
a8735889c7 | ||
|
|
655b7fa825 | ||
|
|
78fe5c2b09 | ||
|
|
015d14216f | ||
|
|
a46ba1f255 | ||
|
|
feb5dab0ce | ||
|
|
6f8496d39e | ||
|
|
b330790bf9 | ||
|
|
82ac5a4748 | ||
|
|
9a5e5d3aa7 | ||
|
|
bd338f2fe3 | ||
|
|
a8c1619be6 | ||
|
|
301f080713 | ||
|
|
84f73ab623 | ||
|
|
1802771546 | ||
|
|
71fd0b8ad5 | ||
|
|
e4d58db474 | ||
|
|
c1070c4858 | ||
|
|
f6bc58a3d7 | ||
|
|
0e6c44ac46 | ||
|
|
bf02cede2b | ||
|
|
2c9759e5ec | ||
|
|
9cadaeea85 | ||
|
|
26175688bd | ||
|
|
b58ff6a656 | ||
|
|
a7ee017bcd | ||
|
|
09d1cb649d | ||
|
|
4925b5fa06 | ||
|
|
3d4733fd5f | ||
|
|
dba782ccd6 | ||
|
|
3a1d244286 | ||
|
|
bd3198adf5 | ||
|
|
4e194f28ee | ||
|
|
1911415879 | ||
|
|
5740815a49 | ||
|
|
2424f0d8cd | ||
|
|
0226b91d81 | ||
|
|
1e16bc1c77 | ||
|
|
6cb2160456 | ||
|
|
61aa8b879e | ||
|
|
209d45be5d | ||
|
|
b6343b4857 | ||
|
|
f1ab010701 | ||
|
|
18a8810c4c | ||
|
|
3f97fca40e | ||
|
|
27d70cb32c | ||
|
|
cf9c684ecb | ||
|
|
6308936e65 | ||
|
|
4d8d49019d | ||
|
|
b51efa5c45 | ||
|
|
835caa8333 | ||
|
|
645b02708d | ||
|
|
7d4abfb66b | ||
|
|
fa2e3d1fcd | ||
|
|
4d4f1256ee | ||
|
|
fe056c1b06 | ||
|
|
ce470f50b5 | ||
|
|
a23dfb0ab0 | ||
|
|
c93f4bac6b | ||
|
|
e1bb3542ee | ||
|
|
a1e0a4edbb | ||
|
|
feaac16804 | ||
|
|
66b6677afa | ||
|
|
f80b17ff82 | ||
|
|
c16ecd886c | ||
|
|
922d8b01b8 | ||
|
|
203516d8cf | ||
|
|
767fc0d7fd | ||
|
|
10e0b4b397 | ||
|
|
22ab6fdb64 | ||
|
|
e08a8f89f3 | ||
|
|
4bebb90cb6 | ||
|
|
f8607e8cdc | ||
|
|
2b8f778c59 | ||
|
|
aec7efd4c3 | ||
|
|
1987152b03 | ||
|
|
649f02665f | ||
|
|
59a1e2a682 | ||
|
|
e85bc72203 | ||
|
|
aa033b0316 | ||
|
|
770ec1c4c7 | ||
|
|
90a6b4ef0d | ||
|
|
63eb525406 | ||
|
|
97f46b3a81 | ||
|
|
424ba074ff | ||
|
|
9209e0d5ec | ||
|
|
546ac80030 | ||
|
|
69eed72838 | ||
|
|
ce4fadff01 | ||
|
|
624d1613f0 | ||
|
|
b85f3d1f81 | ||
|
|
89254ab5db | ||
|
|
e39d60ade9 | ||
|
|
77a7178857 | ||
|
|
85bef64551 | ||
|
|
720e55bfcc | ||
|
|
8e0183a7d7 | ||
|
|
7fa0eafd2c | ||
|
|
e9ee0a88b7 | ||
|
|
ab776dd7f3 | ||
|
|
a9661c3485 | ||
|
|
9680f6a923 | ||
|
|
aa53485d62 | ||
|
|
8112ea6f42 | ||
|
|
7340866da1 | ||
|
|
e4a7b01d3a | ||
|
|
7c82fff41d | ||
|
|
160c6d4d1c | ||
|
|
9081734fc9 | ||
|
|
7c53d0c516 | ||
|
|
4402a70415 | ||
|
|
2a919483e0 | ||
|
|
14251ea378 | ||
|
|
d0958c7d0c | ||
|
|
f0e116293f | ||
|
|
0e34f21aab | ||
|
|
ea36906d02 | ||
|
|
f520c38583 | ||
|
|
1380d131ea | ||
|
|
bd96dfdc8f | ||
|
|
e86950d4ab | ||
|
|
13e3f6047b | ||
|
|
51d7a58424 | ||
|
|
360e08b6b3 | ||
|
|
7fa41df65a | ||
|
|
66c829701d | ||
|
|
9cd3bf3b31 | ||
|
|
8fc432b76c | ||
|
|
2f59d5fcaf | ||
|
|
3bb7f241f2 | ||
|
|
9f596f7974 | ||
|
|
bf3535970e | ||
|
|
981fef3def | ||
|
|
303e3b57b8 | ||
|
|
adfa5abbc0 | ||
|
|
2cacbc5348 | ||
|
|
fdfb81d08c | ||
|
|
254bb3eacc | ||
|
|
c41ce371d3 | ||
|
|
9962981047 | ||
|
|
b35281b8dc | ||
|
|
c58f3df50a | ||
|
|
963056c42d | ||
|
|
fb0674b0c7 | ||
|
|
7ad2462254 | ||
|
|
53f6202709 | ||
|
|
0702b7f51b | ||
|
|
9ade952392 | ||
|
|
5d68dcc538 | ||
|
|
3c0ce0a623 | ||
|
|
27ac934ab6 | ||
|
|
db6f12d3e8 | ||
|
|
3d9abc66a7 | ||
|
|
af5abff115 | ||
|
|
64201cb630 | ||
|
|
6d4b8618bf | ||
|
|
fe78937150 | ||
|
|
5af021ec0a | ||
|
|
2e48a033a0 | ||
|
|
980fb6d432 | ||
|
|
181a8999a7 | ||
|
|
05883903c9 | ||
|
|
656c0e3b3a | ||
|
|
6f1fb7554e | ||
|
|
2a7aa8e4cb | ||
|
|
831037df42 | ||
|
|
277139656e | ||
|
|
e1c736ab46 | ||
|
|
952292462a | ||
|
|
14845d9b23 | ||
|
|
cd8260a879 | ||
|
|
5cf8904c58 | ||
|
|
75f2756611 | ||
|
|
eb13fcad01 | ||
|
|
5e13c7ba91 | ||
|
|
7701364f13 | ||
|
|
1dd0f25ff8 | ||
|
|
8e73cde6ae | ||
|
|
67590790c4 | ||
|
|
aa214d179e | ||
|
|
da6f5ea05c | ||
|
|
480b99b384 | ||
|
|
56326b2dd9 | ||
|
|
07668aba75 | ||
|
|
e37cf42c12 | ||
|
|
4c16cae56d | ||
|
|
ee1174d1b5 | ||
|
|
0d665c46d0 | ||
|
|
2c732dbadf | ||
|
|
fcb8f3a005 | ||
|
|
1e861383e7 | ||
|
|
701a24f47c | ||
|
|
5b8f64b421 | ||
|
|
cf5ceb9c48 | ||
|
|
062c03091c | ||
|
|
4e96d3aba0 | ||
|
|
0089abc84a | ||
|
|
d7f44e0dbe | ||
|
|
d4f30e3693 | ||
|
|
9999275ad0 | ||
|
|
2391729541 | ||
|
|
ffb03890df | ||
|
|
b3fa566725 | ||
|
|
db2de0b855 | ||
|
|
f82fb45242 | ||
|
|
101b839801 | ||
|
|
0c8e12ce30 | ||
|
|
efcf831cb5 | ||
|
|
8f64d4bca2 | ||
|
|
01b8bee8b1 | ||
|
|
f3192b731b | ||
|
|
863a3a2d8d | ||
|
|
dea981c154 | ||
|
|
157aea6055 | ||
|
|
8bd297f4a3 | ||
|
|
e4bb9fde74 | ||
|
|
ecc0b51e4b | ||
|
|
f020df12f6 | ||
|
|
6e49fb8174 | ||
|
|
4b7678a621 | ||
|
|
5794760ceb | ||
|
|
9e206635be | ||
|
|
5ed65668e0 | ||
|
|
7efc0e26e0 | ||
|
|
aa7c5f775a | ||
|
|
147e622580 | ||
|
|
683decfa64 | ||
|
|
64c3a99922 | ||
|
|
fa49fddd8f | ||
|
|
7dd6218017 | ||
|
|
13f63cea23 | ||
|
|
4c54567eec | ||
|
|
9344440f41 | ||
|
|
b2bef4e3cc | ||
|
|
cbf24ab217 | ||
|
|
e34443233f | ||
|
|
8498b97f4c | ||
|
|
87916ab71b | ||
|
|
359f282784 | ||
|
|
26fa80f7e0 | ||
|
|
74177f891d | ||
|
|
3ee070b4dd | ||
|
|
49bed825c2 | ||
|
|
26cc284618 | ||
|
|
345cedcfd3 | ||
|
|
994a168364 | ||
|
|
db7af704a6 | ||
|
|
f388ed6808 | ||
|
|
f550b0dfa3 | ||
|
|
3b8182d751 | ||
|
|
9996eefc69 | ||
|
|
ad2ae84c13 | ||
|
|
0d57698d2f | ||
|
|
e3a8745a0b | ||
|
|
415720c6a6 | ||
|
|
33c33e8947 | ||
|
|
db61269d42 | ||
|
|
8f06e8abce | ||
|
|
122d012ffd | ||
|
|
616327f054 | ||
|
|
de744f5822 | ||
|
|
5583ca38b3 | ||
|
|
2d3b441d74 | ||
|
|
99cd01ba1e | ||
|
|
1f11b6d2da | ||
|
|
e41fe14502 | ||
|
|
63d0453341 | ||
|
|
5e1a26b72e | ||
|
|
e06e795ed8 | ||
|
|
b9b507bf07 | ||
|
|
9f8671f75f | ||
|
|
f0b7b125b9 | ||
|
|
8483eda701 | ||
|
|
b870649627 | ||
|
|
93ac623ffe | ||
|
|
5997302a8c | ||
|
|
f52a9ff702 | ||
|
|
376c0ad4e7 | ||
|
|
34e649d82a | ||
|
|
bfb8426183 | ||
|
|
4f755f0915 | ||
|
|
dea77b5ca2 | ||
|
|
b300c889f3 | ||
|
|
2126da3f25 | ||
|
|
fb7854ef5d | ||
|
|
1ff3142769 | ||
|
|
331fb32b73 | ||
|
|
fa03379580 | ||
|
|
43f4ae9f16 | ||
|
|
d9171a11cf | ||
|
|
344e9f77fe | ||
|
|
2c84c35264 | ||
|
|
c27edd53f6 | ||
|
|
a0db76b50d | ||
|
|
bb3efd75ff | ||
|
|
3d7e218195 | ||
|
|
191c47fc7c | ||
|
|
f2f806612f | ||
|
|
5e2e001265 | ||
|
|
2ca2210a77 | ||
|
|
747aa8cb4e | ||
|
|
4fe4e96811 | ||
|
|
0df0ebbdeb | ||
|
|
e834aaee81 | ||
|
|
1928fdd6d5 | ||
|
|
abdbfa2018 | ||
|
|
a1a940399a | ||
|
|
855e085996 | ||
|
|
e95379bdd7 | ||
|
|
762b95db26 | ||
|
|
396066f289 | ||
|
|
f070d274f4 | ||
|
|
1f50add1bb | ||
|
|
e68b8a8e0e | ||
|
|
5ee7bfa23a | ||
|
|
8ec768d30e | ||
|
|
35d27ffb39 | ||
|
|
613392ae76 | ||
|
|
f74ce7519a | ||
|
|
01d0b42e1a | ||
|
|
e470021d13 | ||
|
|
7de3ce5c0c | ||
|
|
976965bcfa | ||
|
|
1254e657c5 | ||
|
|
90ee6a424d | ||
|
|
bf79616e7e | ||
|
|
09ebb1eae8 | ||
|
|
ba6d8edde1 | ||
|
|
2f76ad4b6f | ||
|
|
407141661a | ||
|
|
38620ba457 | ||
|
|
f8f704f432 | ||
|
|
8ae83acd1a | ||
|
|
af26f6c081 | ||
|
|
d82be005da | ||
|
|
e37b54fc62 | ||
|
|
9eb8d5f682 | ||
|
|
7ecb2e90fd | ||
|
|
354cd538f8 | ||
|
|
0c883b0a74 | ||
|
|
9c23c3ca77 | ||
|
|
d0244a0513 | ||
|
|
875678d7a9 | ||
|
|
65f2b79157 | ||
|
|
c60ee10185 | ||
|
|
f7a598efc8 | ||
|
|
e8142f96b1 | ||
|
|
97d50bc3d9 | ||
|
|
8c457eeb12 | ||
|
|
846d0bbba6 | ||
|
|
a9314ee8f7 | ||
|
|
9bff706bba | ||
|
|
31c871c4c2 | ||
|
|
82b374ec83 | ||
|
|
940552d6cd | ||
|
|
6a2cb70fb5 | ||
|
|
78cfc0c335 | ||
|
|
f454934b07 | ||
|
|
5504f82052 | ||
|
|
d01997b7cb | ||
|
|
7b349ea426 | ||
|
|
1edb12a83c | ||
|
|
176bbc66ad | ||
|
|
41eebe546a | ||
|
|
afaecb2dde | ||
|
|
9062415322 | ||
|
|
6213b42d5a | ||
|
|
8010cce8c7 | ||
|
|
dad9b7a81f | ||
|
|
21a2bea746 | ||
|
|
b0a2e42cfe | ||
|
|
b6cbadd8e2 | ||
|
|
870cfe302d | ||
|
|
ea04c7ddaa | ||
|
|
a86140094c | ||
|
|
85c49a92fd | ||
|
|
aac07a645c | ||
|
|
efdb1c80a3 | ||
|
|
a9c7439d15 | ||
|
|
26555bc10a | ||
|
|
0f84d65656 | ||
|
|
a9b775419d | ||
|
|
a384a8b180 | ||
|
|
424582f969 | ||
|
|
6044e92262 | ||
|
|
ee96bcbc55 | ||
|
|
37bfcbb9c4 | ||
|
|
d2692a8dbe |
No files matched your search
@@ -0,0 +1,19 @@
|
||||
# clang-format 9.0.0
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
BreakBeforeBraces: Allman
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 120
|
||||
Cpp11BracedListStyle: false
|
||||
ForEachMacros: ["CMC_FOREACH", "CMC_FOREACH_REV"]
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MaxEmptyLinesToKeep: 1
|
||||
SpacesInContainerLiterals: false
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
@@ -0,0 +1,5 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
*.h linguist-language=C
|
||||
*.c linguist-language=C
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
# Bug Report template
|
||||
|
||||
### Describe the bug
|
||||
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
### How to Reproduce
|
||||
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
### Expected behavior
|
||||
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
### Screenshots
|
||||
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
### Please complete the following information:
|
||||
|
||||
- Type: [e.g. src, tests, examples, benchmarks]
|
||||
- OS: [e.g. linux, win32]
|
||||
- Compiler [e.g. gcc, clang]
|
||||
- Compiler Version [e.g. 8.1.0]
|
||||
|
||||
### Additional context
|
||||
|
||||
Add any other context about the problem here.
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: feature request
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
# Feature Request Template
|
||||
|
||||
### What is the nature of this request?
|
||||
|
||||
* New functionalities
|
||||
* Change in standards
|
||||
* Change in source code details (names of variables, functions, parameters, etc)
|
||||
|
||||
### Is your feature request related to a problem? Please describe.
|
||||
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
### Describe the solution you'd like
|
||||
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
### Describe alternatives you've considered
|
||||
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
### Additional context
|
||||
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -0,0 +1,25 @@
|
||||
name: Test Suit
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, dev ]
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Environment
|
||||
run: sudo apt install make valgrind gcc
|
||||
- name: Versions
|
||||
run: |
|
||||
gcc --version \
|
||||
make --version \
|
||||
valgrind --version \
|
||||
- name: Test Suite
|
||||
run: make tests --always-make
|
||||
- name: Upload Coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
directory: ./tests
|
||||
verbose: true
|
||||
+10
-1
@@ -52,4 +52,13 @@ Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
# vscode folder
|
||||
.vscode
|
||||
.vscode
|
||||
|
||||
# Experimental folder
|
||||
experimental/
|
||||
|
||||
# Test / Code Coverage build folder
|
||||
build
|
||||
|
||||
tests/coverage
|
||||
tests/out
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
dist: trusty
|
||||
os: linux
|
||||
language: c
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-7
|
||||
script:
|
||||
- sudo ln -s /usr/bin/gcc-6 /usr/local/bin/gcc
|
||||
- export CC=gcc-7
|
||||
- cd ./tests
|
||||
- gcc foreach.c -Wall -Wextra -o foreach -std=c11
|
||||
- ./foreach
|
||||
- gcc iterators.c -Wall -Wextra -o iterators -std=c11
|
||||
- ./iterators
|
||||
- gcc contains.c -Wall -Wextra -o contains -std=c11
|
||||
- ./contains
|
||||
- gcc pointertype.c -Wall -Wextra -o pointertype -std=c11
|
||||
- ./pointertype
|
||||
@@ -1,6 +1,246 @@
|
||||
# MAJOR.MINOR.ADJUSTMENTS
|
||||
# RELEASE.MAJOR.MINOR
|
||||
|
||||
1.0.0
|
||||
0.26.0
|
||||
Complete refactor of the library, using a different approach to code generation
|
||||
|
||||
0.25.0
|
||||
New Project Architecture - Files are no longer separated in folders, but rather prefixed by their sub-library
|
||||
Added sac_list.h
|
||||
|
||||
0.24.0
|
||||
A lot of breaking changes, with the library more modular now
|
||||
Comeback of PUBLIC and PRIVATE for the CMC sub-library
|
||||
Callbacks are now optional and can be turned off by defining CMC_NO_CALLBACKS
|
||||
Added EXT library
|
||||
New macro CMC_CAMEL_CASE can change the library's style where the default is snake case
|
||||
Added:
|
||||
./cor/alloc.h
|
||||
./cor/callbacks.h
|
||||
./cor/heap.h
|
||||
Complete rework of tests and code coverage using autogen.py
|
||||
Removed cmc_flags, where now every flag is an enum (CMC_FLAGS_OK, CMC_FLAGS_ERROR, etc)
|
||||
Different include guards
|
||||
New way to generate code using PARAM
|
||||
Code now completely changed by using the CMC_ macro to concatenate tokens
|
||||
Token concatenation with SNAME now uses special macros that allow customization of the suffixes
|
||||
|
||||
0.23.1
|
||||
Added ./cor/bitset.h
|
||||
Added foreach tests
|
||||
Updating foreach macros with the new iterators API
|
||||
Bug fixes for ./cmc/hashmultiset.h
|
||||
|
||||
0.23.0
|
||||
Added ./cmc/bitset.h
|
||||
Added ./cor/flags.h
|
||||
Added ./utl/futils.h
|
||||
Added ./utl/mutex.h
|
||||
Added ./utl/thread.h
|
||||
Added cmc_flags_to_str
|
||||
Added autogen.py for automated code generation for code coverage
|
||||
Changed the iterator API
|
||||
Merged ./tests/codecov and ./tests/main
|
||||
Renamed ftab_key to fkey and ftab_val to fval
|
||||
Renamed collections
|
||||
- bidimap -> hashbidimap
|
||||
- multimap -> hashmultimap
|
||||
- multiset -> hashmultiset
|
||||
|
||||
-- Versioning restarted for compatibility with SemVer (https://semver.org/)
|
||||
|
||||
1.8.0 (0.22.0)
|
||||
Added Function Tables
|
||||
Added Error Codes
|
||||
Added Callback Functions
|
||||
Added custom allocation functions support
|
||||
Added .clang-format
|
||||
Added makefile in root folder for automated code formatting
|
||||
Created into core folder for implementation of common data structures:
|
||||
- ./cor/core.h
|
||||
- ./cor/hashtable.h
|
||||
Documentation changed to mdbook
|
||||
Removed ./utl/cmc_string.h
|
||||
Replaced CMC_FOR_EACH and CMC_FOR_EACH_REV by CMC_FOREACH and CMC_FOREACH_REV
|
||||
|
||||
1.7.3 (0.21.0)
|
||||
Breaking changes:
|
||||
- ext collections merged to cmc
|
||||
- No more typedefs in code generated
|
||||
Fast forwarded codecov
|
||||
|
||||
1.7.2 (0.20.0)
|
||||
Added resize function to array based collections
|
||||
Added the following functions to hashtable based collections:
|
||||
- load
|
||||
- full
|
||||
Added more assert macros utility
|
||||
Added plenty more tests
|
||||
Substituted impl_default_value / key by compound literals
|
||||
Removed unnecessary conditional input and output functions
|
||||
Minor fixes throughout the library
|
||||
|
||||
1.7.1 (0.19.0)
|
||||
Added new assert macro cmc_assert_sorted
|
||||
Fixed some include guards for hashtables
|
||||
Moved the cmc string format to each file
|
||||
Renamed some list functions (sequence input/output)
|
||||
Renamed list and linkedlist functions push and pop to push_at and pop_at
|
||||
|
||||
1.7.0 (0.18.0)
|
||||
Removed FMOD (function modifier)
|
||||
Added CMC prefix to all macros defined within the library
|
||||
|
||||
1.6.3 (0.17.0)
|
||||
Added iterator functions to all collections:
|
||||
- iter_advance
|
||||
- iter_rewind
|
||||
- iter_go_to
|
||||
Added cmc prefix to the logging utility
|
||||
Integrated the assert utility with the test utility. Now any assertion that fails inside the unit test will trigger failure and is no longer needed to manually pass or fail tests.
|
||||
|
||||
1.6.2 (0.16.0)
|
||||
Added new functions to all collections:
|
||||
- copy_of
|
||||
- equals
|
||||
Added the new collections to the tests
|
||||
Fixed some collections and some improvements to the hashtables
|
||||
Unified the functions set and update from the map implementations
|
||||
|
||||
1.6.1 (0.15.0)
|
||||
Removed ./ext/linkedqueue.h
|
||||
Added a deallocator parameter to all _free and _clear functions
|
||||
|
||||
1.6.0 (0.14.0)
|
||||
Added ./ext/intervalheap.h
|
||||
Added ./ext/multimap.h
|
||||
Added ./ext/multiset.h
|
||||
Added to_string function to most collections
|
||||
Added the cmc prefix to the enum entry_state used by hashtables and to the enum heap_type used by the heap
|
||||
Fixed return type on some functions from ./cmc/hashset.h and ./cmc/treeset.h
|
||||
Fixed hashtables integer overflow when the capacity is divided by the load factor
|
||||
Changed timer.h struct name from timer_t to cmc_timer to prevent name collisions on linux
|
||||
|
||||
1.5.3 (0.13.0)
|
||||
Tests completely reorganized and now with full code coverage
|
||||
Some fixes where there was a missing return statement
|
||||
Expanded ./utl/assert.h
|
||||
|
||||
1.5.2 (0.12.0)
|
||||
Added ./utl/test.h
|
||||
Added ./utl/assert.h
|
||||
Added ./tests/list.c - UnitTest for LIST
|
||||
Small fixes on ./utl/foreach.h, ./utl/test.h and redone ./utl/timer.h
|
||||
Removed ./utl/log.h functions that were unnecessary
|
||||
Added the CMC namespace to CONCATC and CONCATH at macro_collections.h
|
||||
|
||||
1.5.1 (0.11.0)
|
||||
New queue benchmark
|
||||
Added ./sac/queue.h
|
||||
Added ./utl/timer.h
|
||||
Fixing descriptions and other minor fixes
|
||||
|
||||
1.5.0 (0.10.0)
|
||||
Changed tests compilation and execution to a single Makefile
|
||||
Changed project structure
|
||||
./src/
|
||||
./cmc/ - Main C Macro Collections Library
|
||||
./dev/ - A copy of ./cmc/ used for development (logging utility)
|
||||
./ext/ - Extra collections
|
||||
./sac/ - Stack Allocated Collections
|
||||
./utl/ - Utility like ForEach, logging, etc
|
||||
Added ./utl/log.h a logging utility
|
||||
Added ./dev/deque.h - A mirror of ./cmc/deque.h but with logging utility
|
||||
Added ./ext/linkedqueue.h - A singly-linked list based queue
|
||||
Added ./sac/stack.h - A Stack purely allocated on the stack
|
||||
|
||||
1.4.3 (0.9.0)
|
||||
Fixed some functions names
|
||||
Added set functions for both Tree and Hash Set
|
||||
- is_subset
|
||||
- is_proper_subset
|
||||
- is_superset
|
||||
- is_proper_subset
|
||||
- is_disjointset
|
||||
|
||||
1.4.2 (0.8.0)
|
||||
Adapted code so that plain struct type is accepted
|
||||
Changed TreeSet max and min to be compatible with the TreeMap and the hash collections
|
||||
Changed function modifier of all implementation detail to static
|
||||
Fixed some implementation detail functions that were not prefixed with impl
|
||||
Added types.c to test if it is possible to compile all the collections' generated code accepting all C data types
|
||||
Removed pointertype.c (replaced by types.c)
|
||||
|
||||
1.4.1 (0.7.0)
|
||||
Removed PUBLIC and PRIVATE from the main macro
|
||||
Corrected examples and benchmark
|
||||
Added new test consisting of compiling the header and source separately
|
||||
|
||||
1.4.0 (0.6.0)
|
||||
New way on how iterators work to all collections
|
||||
Added iter_init to work with stack allocated iterators
|
||||
Added iter_new and iter_free to work with heap allocated iterators
|
||||
Added two pointers to functions (it_start and it_end) that allow you to access iterators to both start and end of the target collection easily
|
||||
iter_next and iter_prev now only move the iterator
|
||||
To access the key, value and index, use a separate function
|
||||
Removed FOR_EACH_MAP as it is no longer necessary since FOR_EACH also works to associative containers now
|
||||
Updated benchmark, examples and tests to work on these new iterators
|
||||
Changed pointertype test to be a pointer to struct instead of pointer to char
|
||||
Added CHANGELOG and TODO
|
||||
|
||||
1.3.0 (0.5.0)
|
||||
Changed how the linkedlist functions relative to nodes work
|
||||
Removed reference to owner list on each node
|
||||
Renamed some functions for consistency
|
||||
|
||||
1.2.4 (0.4.1)
|
||||
Fixing some declarations in hashset and hashmap where a pointer type would cause problems
|
||||
Added a test to make sure all collections support pointer type
|
||||
Tests:
|
||||
- pointertype
|
||||
|
||||
1.2.3 (0.4.0)
|
||||
Added get_ref functions to all collections that support it (only included in hashmap, linkedlist, list and treemap)
|
||||
|
||||
1.2.2 (0.3.2)
|
||||
Removed unnecessary modulo operation in hashtable functions
|
||||
|
||||
1.2.1 (0.3.1)
|
||||
Optimized list - now using 'string.h' functions to shift elements around instead of for-loops:
|
||||
- memset
|
||||
- memcpy
|
||||
- memmove
|
||||
|
||||
1.2.0 (0.3.0)
|
||||
'contains' functions added to all collections
|
||||
'contains' tests and benchmark
|
||||
Unified Benchmark
|
||||
Updated examples
|
||||
|
||||
1.1.3 (0.2.3)
|
||||
Renamed deque's 'rear' struct member to 'back' to be more consistent with other collections
|
||||
Better benchmark and foreach tests are alphabetically ordered
|
||||
|
||||
1.1.2 (0.2.2)
|
||||
Fixing iterators for when they are initialized with an empty target
|
||||
Better iterator tests
|
||||
More examples
|
||||
|
||||
1.1.1 (0.2.1)
|
||||
Reordering functions (implementation details are now at the end of each file)
|
||||
|
||||
1.1.0 (0.2.0)
|
||||
Added new list functions:
|
||||
- new_from
|
||||
- prepend
|
||||
- insert
|
||||
- append
|
||||
- remove
|
||||
- fits
|
||||
|
||||
1.0.1 (0.1.1)
|
||||
Fixed hashset logic in robin-hood hashing
|
||||
|
||||
1.0.0 (0.1.0)
|
||||
First stable version
|
||||
Includes the following collections:
|
||||
- deque
|
||||
@@ -18,68 +258,3 @@
|
||||
Tests:
|
||||
- foreach
|
||||
- iterator
|
||||
|
||||
1.0.1
|
||||
Fixed hashset logic in robin-hood hashing
|
||||
|
||||
1.1.0
|
||||
Added new list functions:
|
||||
- new_from
|
||||
- prepend
|
||||
- insert
|
||||
- append
|
||||
- remove
|
||||
- fits
|
||||
|
||||
1.1.1
|
||||
Reordering functions (implementation details are now at the end of each file)
|
||||
|
||||
1.1.2
|
||||
Fixing iterators for when they are initialized with an empty target
|
||||
Better iterator tests
|
||||
More examples
|
||||
|
||||
1.1.3
|
||||
Renamed deque's 'rear' struct member to 'back' to be more consistent with other collections
|
||||
Better benchmark and foreach tests are alphabetically ordered
|
||||
|
||||
1.2.0
|
||||
'contains' functions added to all collections
|
||||
'contains' tests and benchmark
|
||||
Unified Benchmark
|
||||
Updated examples
|
||||
|
||||
1.2.1
|
||||
Optimized list - now using 'string.h' functions to shift elements around instead of for-loops:
|
||||
- memset
|
||||
- memcpy
|
||||
- memmove
|
||||
|
||||
1.2.2
|
||||
Removed unnecessary modulo operation in hashtable functions
|
||||
|
||||
1.2.3
|
||||
Added get_ref functions to all collections that support it (only included in hashmap, linkedlist, list and treemap)
|
||||
|
||||
1.2.4
|
||||
Fixing some declarations in hashset and hashmap where a pointer type would cause problems
|
||||
Added a test to make sure all collections support pointer type
|
||||
Tests:
|
||||
- pointertype
|
||||
|
||||
1.3.0
|
||||
Changed how the linkedlist functions relative to nodes work
|
||||
Removed reference to owner list on each node
|
||||
Renamed some functions for consistency
|
||||
|
||||
1.4.0
|
||||
New way on how iterators work to all collections
|
||||
Added iter_init to work with stack allocated iterators
|
||||
Added iter_new and iter_free to work with heap allocated iterators
|
||||
Added two pointers to functions (it_start and it_end) that allow you to access iterators to both start and end of the target collection easily
|
||||
iter_next and iter_prev now only move the iterator
|
||||
To access the key, value and index, use a separate function
|
||||
Removed FOR_EACH_MAP as it is no longer necessary since FOR_EACH also works to associative containers now
|
||||
Updated benchmark, examples and tests to work on these new iterators
|
||||
Changed pointertype test to be a pointer to struct instead of pointer to char
|
||||
Added CHANGELOG and TODO
|
||||
@@ -13,6 +13,8 @@ Check out `bug_report.md` and `feature_request.md` templates in the `.github` fo
|
||||
|
||||
## Here are things you could work on:
|
||||
|
||||
> You can check out the TODO file to see what I've planned on doing, in case you want to work on any of those topics
|
||||
|
||||
1. New features, new functions, new stuff!
|
||||
* Before adding anything new, please, first create an issue for it to be discussed;
|
||||
* Write tests to anything new you make.
|
||||
|
||||
-2766
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,35 @@
|
||||
|
||||
help:
|
||||
@echo Welcome to the C Macro Collections Library. Targets:
|
||||
@echo
|
||||
@echo - tests: run tests
|
||||
@echo - tests_dev: run tests for dev
|
||||
@echo - format: formats the entire project
|
||||
@echo - bench: runs benchmarks
|
||||
@echo - docbuild: builds documentation to ./docs
|
||||
@echo - docserve: serves mdbook docs
|
||||
@echo - install_dev_deps: install dev dependencies
|
||||
|
||||
tests:
|
||||
make -C ./tests
|
||||
|
||||
tests_dev:
|
||||
make -C ./tests dev
|
||||
|
||||
format:
|
||||
- find ./ -name *.h -type f | xargs clang-format --style=file --verbose -i
|
||||
|
||||
bench:
|
||||
make -C ./benchmarks benchmark
|
||||
|
||||
docbuild:
|
||||
mdbook build -d ../docs documentation
|
||||
|
||||
docserve:
|
||||
mdbook serve documentation
|
||||
|
||||
install_dev_deps:
|
||||
sudo apt install gcc make valgrind lcov clang-format hyperfine
|
||||
cargo install mdbook
|
||||
|
||||
.PHONY: tests tests_dev format bench docbuild docserve install_dev_deps
|
||||
@@ -1,113 +1,281 @@
|
||||
# C-Macro-Collections
|
||||
# C Macro Collections
|
||||
|
||||
Generate Simple Data Structures of any type in C for you to use in your projects.
|
||||
<p align="center">
|
||||
<img src="https://leoven.github.io/C-Macro-Collections/img/logo.png" alt="C Macro Collections Logo" width="300"/>
|
||||
</p>
|
||||
|
||||

|
||||

|
||||

|
||||
<p align="center">Easy to use, modular, header only, macro based, generic and type-safe Data Structures in C</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/LeoVen/C-Macro-Collections"><img src="https://img.shields.io/badge/GitHub-C%20Macro%20Collections-2195F3.svg?logo=github" alt="LinkToRepo"/></a>
|
||||
<a href="https://leoven.github.io/C-Macro-Collections/"><img style="color: #ffffff;" src="https://img.shields.io/badge/Read%20the%20Docs-D13636.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHN0eWxlPSIiPjxyZWN0IGlkPSJiYWNrZ3JvdW5kcmVjdCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgeD0iMCIgeT0iMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJub25lIi8%2BPHRpdGxlPmljbi9kb2MtdGV4dDwvdGl0bGU%2BPGcgY2xhc3M9ImN1cnJlbnRMYXllciIgc3R5bGU9IiI%2BPHRpdGxlPkxheWVyIDE8L3RpdGxlPjxwYXRoIGQ9Ik01IDFoNC4yNDRhMiAyIDAgMCAxIDEuNDM0LjYwNmwyLjc1NiAyLjgzNEEyIDIgMCAwIDEgMTQgNS44MzVWMTJhMyAzIDAgMCAxLTMgM0g1YTMgMyAwIDAgMS0zLTNWNGEzIDMgMCAwIDEgMy0zem0wIDJhMSAxIDAgMCAwLTEgMXY4YTEgMSAwIDAgMCAxIDFoNmExIDEgMCAwIDAgMS0xVjUuODM1TDkuMjQ0IDNINXptMS41IDdoM2EuNS41IDAgMSAxIDAgMWgtM2EuNS41IDAgMSAxIDAtMXptMC0yaDJhLjUuNSAwIDAgMSAwIDFoLTJhLjUuNSAwIDAgMSAwLTF6TTggMmwzIDEuOTk1TDEzIDdIOWExIDEgMCAwIDEtMS0xVjJ6IiBpZD0iYSIgY2xhc3M9IiIgZmlsbD0iI2ZmZmZmZiIgZmlsbC1vcGFjaXR5PSIxIi8%2BPC9nPjwvc3ZnPg%3D%3D" alt="LinkToDocs"/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/LeoVen/C-Macro-Collections/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License"/></a>
|
||||
<a href="https://github.com/LeoVen/C-Macro-Collections/releases"><img src="https://img.shields.io/badge/Version-v0.26.0-orange.svg" alt="Version"/></a>
|
||||
<a href="https://travis-ci.org/LeoVen/C-Macro-Collections"><img src="https://travis-ci.org/LeoVen/C-Macro-Collections.svg?branch=master" alt="travis-ci"/></a>
|
||||
<a href="https://codecov.io/gh/LeoVen/C-Macro-Collections"><img src="https://codecov.io/gh/LeoVen/C-Macro-Collections/branch/master/graph/badge.svg" alt="codecov"/></a>
|
||||
<a href="https://github.com/LeoVen/C-Macro-Collections/actions"><img src="https://github.com/LeoVen/C-Macro-Collections/workflows/Test%20Suit/badge.svg?branch=master" alt="test_suit"/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/LeoVen/C-Macro-Collections/stargazers"><img src="https://img.shields.io/github/stars/LeoVen/C-Macro-Collections?style=flat&color=ffa000" alt="Stars"/></a>
|
||||
<a href="https://github.com/XAMPPRocky/tokei"><img src="https://img.shields.io/badge/Lines%20of%20Code-28513-007596.svg" alt="loc"/></a>
|
||||
<a href="https://github.com/XAMPPRocky/tokei"><img src="https://img.shields.io/badge/Files-130-961c00.svg" alt="loc"/></a>
|
||||
</p>
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* [Installation](#installation)
|
||||
* [Contributing](#contributing)
|
||||
* [Usage](#usage)
|
||||
* [Features](#features)
|
||||
* [Project Structure](#project-structure)
|
||||
* [Available Collections](#available-collections)
|
||||
* [Other Features](#other-features)
|
||||
* [Design Decisions](#design-decisions)
|
||||
|
||||
## Installation
|
||||
|
||||
No installation is required. The entire library is made of header files and can be directly included into your project.
|
||||
|
||||
## Contributing
|
||||
|
||||
There is a lot to be done. You can check the `TODO` file in the root of the repository or the issues in the github page. Also, tests and documentation are in constant development.
|
||||
|
||||
## Usage
|
||||
|
||||
Below is a minimal example that makes use of some core functionalities. And a lot of explanation too!
|
||||
|
||||
```c
|
||||
// The C Macro Collections takes advantage of headers that can be included
|
||||
// multiple times. You can check the contents of src/cmc/list.h and there are no
|
||||
// include guards, meaning they can be included multiple times and this is what
|
||||
// generates the code.
|
||||
// Before including it though we need to define a few basic macros. You can
|
||||
// check the documentation to see which ones are required.
|
||||
#define V int // list value data type
|
||||
#define PFX intl // list function's prefix
|
||||
#define SNAME int_list // list struct name (struct int_list)
|
||||
#define CMC_EXT_STR // Enables an extra functionality (STR) of the list
|
||||
#include "cmc/list.h"
|
||||
|
||||
// This header file includes a lot of functions that can be used as methods to
|
||||
// basic data types. In this case, cmc_i32_str is used
|
||||
#include "cmc/utl/futils.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Our list type is defined by SNAME and all functions are prefixed by PFX
|
||||
// (PFX can also be thought as the function's namespace). Also, nodes,
|
||||
// entries, iterators and other structures are prefixed by SNAME. So PFX is
|
||||
// for functions and SNAME is for structs, where the main one is simply
|
||||
// 'struct SNAME'.
|
||||
// To initialize a list we need to pass in an initial capacity and something
|
||||
// that is called a function table for the V type.
|
||||
// This function table is a struct with methods that will extract some
|
||||
// (sometimes) necessary behaviour from your custom data type. Things like
|
||||
// hash, comparison and printing. A list doesn't require any of these
|
||||
// functions. That is, the CORE module doesn't use any of them.
|
||||
// But since we are using the STR module, we will need to define the 'str'
|
||||
// function. Luckily, for the 'int' type, the library already provides such
|
||||
// function (cmc_i32_str), provided by the cmc/utl/futils.h header file.
|
||||
struct int_list *list = intl_new(32, &(struct int_list_fval){ .str = cmc_i32_str, NULL });
|
||||
|
||||
// Check if the list was successfully initialized. It could fail if the
|
||||
// initial capacity is too big or if 'struct int_list_fval *' is NULL,
|
||||
// because every data structure must have a valid function table.
|
||||
if (!list)
|
||||
return 1;
|
||||
|
||||
// Add some items to the list. The CMC data structures are all dynamically
|
||||
// sized. So there can be as many items as you want as long as you have
|
||||
// enough memory.
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// Try to add an element to the list. If it fails you can check what
|
||||
// caused it by getting its flag.
|
||||
if (!intl_push_back(list, i))
|
||||
{
|
||||
enum cmc_flags flag = intl_flag(list);
|
||||
// Use cmc_flags_to_str (global variable) to map the enum error to a
|
||||
// string.
|
||||
fprintf(stderr, "%s : push_back failed\n", cmc_flags_to_str[flag]);
|
||||
}
|
||||
}
|
||||
|
||||
// Now we will use the STR module, the _print() function. This is where the
|
||||
// '.str' from the function table comes into play. If we haven't defined it,
|
||||
// the program would've crashed. We also need to define to which file we
|
||||
// will be printing the list's content. In this case, the terminal. Also,
|
||||
// some strings need to be defined. They will be printed: before all
|
||||
// elements, between each one, and after all elements. This is very useful
|
||||
// for debugging.
|
||||
intl_print(list, stdout, "[ ", ", ", " ]\n");
|
||||
|
||||
// Free all of its resources
|
||||
intl_free(list);
|
||||
}
|
||||
```
|
||||
|
||||
Now all you have to do is to compile the source code with `-I /path/to/library/src`. There is no required installation or pre-compilation.
|
||||
|
||||
## Features
|
||||
|
||||
The C Macro Collections library is organized into many other sub-libraries. The following table is a quick overview.
|
||||
|
||||
| Library | Name | Description |
|
||||
| :-----: | -------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| CMC | Macro Collections | The main library with dynamically-sized collections |
|
||||
| COR | Core | Core functionalities used by more than one collection, usually from different sub-libraries |
|
||||
| EXT | Extensions | Extension to collections |
|
||||
| SAC | Statically Allocated Collections | Collections with a fixed sized array that don't use any heap allocation |
|
||||
| TSC | Thread-Safe Collections | Collections that allow multiple operations from multiple threads |
|
||||
| UTL | Utilities | General utilities |
|
||||
|
||||
## Project Structure
|
||||
|
||||
* __benchmarks__ - Where all benchmarks are hosted
|
||||
* __docs__ - A folder hosting the generated documentation by [mdBook](https://github.com/rust-lang/mdBook)
|
||||
* __documentation__ - The markdowns used by [mdBook](https://github.com/rust-lang/mdBook) to generate the website
|
||||
* __examples__ - Examples using the C Macro Collections Library
|
||||
* __src__ - All headers part of the C Macro Collections Library
|
||||
* __tests__ - Where all tests are hosted
|
||||
|
||||
## Available Collections
|
||||
|
||||
* List
|
||||
* LinkedList
|
||||
* Stack
|
||||
* Queue
|
||||
* Deque
|
||||
* Heap
|
||||
* TreeSet
|
||||
* TreeMap
|
||||
* HashSet
|
||||
* HashMap
|
||||
__The following table is an overview of all the currently available or upcoming data structures__:
|
||||
|
||||
## Available Collections in future updates
|
||||
| Collection <img width=250/> | Abstract Data Type <img width=250/> | Data Structure <img width=250/> | Details |
|
||||
| :--------------------------------: | :---------------------------------: | :-----------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------: |
|
||||
| BitSet <br> _bitset.h_ | Set | Dynamic Array | A set of bits that can be individually modified and queried, each identified by a bit index |
|
||||
| Deque <br> _deque.h_ | Double-Ended Queue | Dynamic Circular Array | A circular array that allows `push` and `pop` on both ends (only) at constant time |
|
||||
| HashBidiMap <br> _hashbidimap.h_ | Bidirectional Map | Two Hashtables | A bijection between two sets of unique keys and unique values `K <-> V` using two hashtables |
|
||||
| HashMap <br> _hashmap.h_ | Map | Flat Hashtable | A unique set of keys associated with a value `K -> V` with constant time look up using a hashtable with open addressing and robin hood hashing |
|
||||
| HashMultiMap <br> _hashmultimap.h_ | Multimap | Hashtable | A mapping of multiple keys with one node per key using a hashtable with separate chaining |
|
||||
| HashMultiSet <br> _hashmultiset.h_ | Multiset | Flat Hashtable | A mapping of a value and its multiplicity using a hashtable with open addressing and robin hood hashing |
|
||||
| HashSet <br> _hashset.h_ | Set | Flat Hashtable | A unique set of values with constant time look up using a hashtable with open addressing and robin hood hashing |
|
||||
| Heap <br> _heap.h_ | Priority Queue | Dynamic Array | A binary heap as a dynamic array as an implicit data structure |
|
||||
| IntervalHeap <br> _intervalheap.h_ | Double-Ended Priority Queue | Custom Dynamic Array | A dynamic array of nodes, each hosting one value from the MinHeap and one from the MaxHeap |
|
||||
| LinkedList <br> _linkedlist.h_ | List | Doubly-Linked List | A default doubly-linked list |
|
||||
| List <br> _list.h_ | List | Dynamic Array | A dynamic array with `push` and `pop` anywhere on the array |
|
||||
| Queue <br> _queue.h_ | FIFO | Dynamic Circular Array | A queue using a circular array with `enqueue` at the `back` index and `dequeue` at the `front` index |
|
||||
| SkipList <br> _WIP_ | Sorted List | Skip List | A sorted Linked List with average O(log n) search, insertion and deletion complexity |
|
||||
| SortedList <br> _sortedlist.h_ | Sorted List | Sorted Dynamic Array | A lazily sorted dynamic array that is sorted only when necessary |
|
||||
| Stack <br> _stack.h_ | FILO | Dynamic Array | A stack with push and pop at the end of a dynamic array |
|
||||
| TreeBidiMap <br> _WIP_ | Sorted Bidirectional Map | Two AVL Trees | A sorted bijection between two sets of unique keys and unique values `K <-> V` using two AVL trees |
|
||||
| TreeMap <br> _treemap.h_ | Sorted Map | AVL Tree | A unique set of keys associated with a value `K -> V` using an AVL tree with `log(n)` look up and sorted iteration |
|
||||
| TreeMultiMap <br> _WIP_ | Sorted Multimap | AVL Tree | A sorted mapping of multiple keys with one node per key using an AVL Tree of linked-lists |
|
||||
| TreeMultiSet <br> _WIP_ | Sorted Multiset | AVL Tree | A sorted mapping of a value and its multiplicity using an AVL tree |
|
||||
| TreeSet <br> _treeset.h_ | Sorted Set | AVL Tree | A unique set of keys using an AVL tree with `log(n)` look up and sorted iteration |
|
||||
|
||||
* Multimap
|
||||
* Multiset
|
||||
* Treehashmap
|
||||
* Heap will be a MinMaxHeap
|
||||
## Other Features
|
||||
|
||||
Check out **Documentation.md** for more information about each collection.
|
||||
These are some features within the library that are implemented by all collections.
|
||||
|
||||
## What to use
|
||||
## Two-way iterators
|
||||
|
||||
The following table shows how each collection is implemented and how well they do when using as common [abstract data types](https://en.wikipedia.org/wiki/Abstract_data_type).
|
||||
All collections come with a two-way iterator. You can go back and forwards in constant time and access elements in constant time.
|
||||
|
||||
* **Ideal** - The collection implements correctly the abstract data type;
|
||||
* **Not Ideal** - The implementation is fulfilled but some functionalities are either not part of the ADT or not present;
|
||||
* **Bad** - It can be done, but its a bad idea.
|
||||
## Custom Allocation
|
||||
|
||||

|
||||
All collections have a `cmc_alloc_node` which provides pointers to the four dynamic memory allocation functions in C: `malloc`, `calloc`, `realloc` and `free`. These pointers can be customized for each individual collection created or a default can be used, as specified in `cmc_alloc_node_default`.
|
||||
|
||||

|
||||

|
||||

|
||||
## Callbacks
|
||||
|
||||
## How to use
|
||||
Every function that operates on a collection can be separated in 5 different types. Create, Read, Update, Delete and (an extra one besides CRUD) Resize. You can define one callback function for each operation. Check out the documentation to see when each callback function is called.
|
||||
|
||||
To generate the collection, all you need to do is to include the necessary header files. You can include the containers you want to use individually or you can include the master header, `macro_collections.h`, that comes with all collections and other functionalities like the `FOR_EACH` macro.
|
||||
## Functions Table
|
||||
|
||||
There are three C standard headers that all collections use:
|
||||
Functions table is a `struct` of function pointers containing 'methods' for a custom data type. Some methods are optional and others are needed in order for a collection to operate. They are:
|
||||
|
||||
* `<stdlib.h>`
|
||||
* `<stdbool.h>`
|
||||
* `<string.h>`
|
||||
#### CMP
|
||||
|
||||
With the last one being used only by array based containers. These headers are already included by default.
|
||||
A comparator function is used in sorted collections or when an equality is being checked like when trying to find a certain element in a list. It is responsible for taking two arguments of the same data type and comparing them. The return value is an `int` with the following definitions:
|
||||
|
||||
### Macros
|
||||
* Return `1` if the first argument is greater than the second;
|
||||
* Return `0` if the first argument equals the second;
|
||||
* Return `-1` if the first argument is less than the second.
|
||||
|
||||
> Note here that `SNAME` represents the uppercase name of the collection.
|
||||
#### CPY
|
||||
|
||||
Every collection is separated by two parts:
|
||||
A copy function is used when a collection is being copied. It can be used to make a deep copy of of your custom data type. It must take a single parameter and return a new copy of that same data type. If this function is absent (`NULL`) the data type will be copied by assignment (for pointers this is a shallow copy).
|
||||
|
||||
* `HEADER` - Contains all struct definitions and function definitions.
|
||||
* `SOURCE` - Contains all function implementations.
|
||||
#### STR
|
||||
|
||||
All collections have three main macros:
|
||||
A string function is responsible for taking a `FILE` pointer and a custom data type and outputting the string representation of that data returning a `bool` indication success or failure. It is useful for debugging.
|
||||
|
||||
* `SNAME_GENERATE` - Generates `SNAME_GENERATE_HEADER` and `SNAME_GENERATE_SOURCE`.
|
||||
#### FREE
|
||||
|
||||
Or you can generate each part individually:
|
||||
The free function is called when a collection is cleared (all elements removed) or freed (all elements removed and freed from memory) and it is responsible for completely freeing all resources that are usually acquired by your data type.
|
||||
|
||||
* `SNAME_GENERATE_HEADER` - Generates all struct definitions and function definitions.
|
||||
* `SNAME_GENERATE_SOURCE` - Generates all function implementations.
|
||||
#### HASH
|
||||
|
||||
### For Each
|
||||
This function receives a custom data type as parameter and returns a `size_t` hash of that data. Used in hashtables.
|
||||
|
||||
There are 2 for-each macros:
|
||||
#### PRI
|
||||
|
||||
* `FOR_EACH` - Starts at the start of the collection towards the end.
|
||||
* `FOR_EACH_REV` - Starts at the end of the collection towards the start.
|
||||
A priority function works much like the comparator function except that it compares the priority between two elements. It is used in collections whose structure is based on the priority of elements and not in their general comparison.
|
||||
|
||||
Check out the **Documentation.md** to know exactly what represents the *end* and the *start* of each collection.
|
||||
* Return `1` if the first argument has a greater priority than the second;
|
||||
* Return `0` if the first argument has the same priority as second;
|
||||
* Return `-1` if the first argument has a lower priority than the second.
|
||||
|
||||
### Parameters
|
||||
The following table shows which functions are required, optional or never used for each Collection:
|
||||
|
||||
When including `macro_collections.h` in your source code you gain access to a macro called `COLLECTION_GENERATE` with the following parameters:
|
||||
| Collection | CMP | CPY | STR | FREE | HASH | PRI |
|
||||
| ------------ | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: |
|
||||
| BitSet |  |  |  |  |  |  |
|
||||
| Deque |  |  |  |  |  |  |
|
||||
| HashMap |  |  |  |  |  |  |
|
||||
| HashBidiMap |  |  |  |  |  |  |
|
||||
| HashMultiMap |  |  |  |  |  |  |
|
||||
| HashMultiSet |  |  |  |  |  |  |
|
||||
| HashSet |  |  |  |  |  |  |
|
||||
| Heap |  |  |  |  |  |  |
|
||||
| IntervalHeap |  |  |  |  |  |  |
|
||||
| List |  |  |  |  |  |  |
|
||||
| LinkedList |  |  |  |  |  |  |
|
||||
| Queue |  |  |  |  |  |  |
|
||||
| SortedList |  |  |  |  |  |  |
|
||||
| Stack |  |  |  |  |  |  |
|
||||
| TreeMap |  |  |  |  |  |  |
|
||||
| TreeSet |  |  |  |  |  |  |
|
||||
|
||||
> Note: in future updates, PRIVATE and PUBLIC will no longer exist
|
||||
| Color | Label |
|
||||
| :-------------------------------------------------------------: | ----------------------------------------- |
|
||||
|  | Required for basic functionality. |
|
||||
|  | Required for specific functions. |
|
||||
|  | Required for non-core specific functions. |
|
||||
|  | Optional. |
|
||||
|  | Not Used. |
|
||||
|
||||
* \*__C__ - Container name in uppercase (*LIST*, *LINKEDLIST*, *STACK*, *QUEUE*, *DEQUE*, *HEAP*, *TREESET*, *TREEMAP*, *HASHSET*, *HASHMAP*).
|
||||
* \*__P__ - Permission (PRIVATE, PUBLIC). Only matters when header and source are declared in separate files.
|
||||
* *PRIVATE* - Members of a struct are hidden in source file and only accessible through functions.
|
||||
* *PUBLIC* - Members of a struct are visible.
|
||||
* \*__PFX__ - Functions prefix or namespace.
|
||||
* \*__SNAME__ - Structure name (`typedef struct SNAME##_s SNAME`).
|
||||
* __FMOD__ - Function modifier (`static` or empty).
|
||||
* \*\*__K__ - Key type. Only used in *HASHMAP* and *TREEMAP*; ignored by others.
|
||||
* \*__V__ - Value type. Primary type for most collections, or value to be mapped by *HASHMAP* and *TREEMAP*.
|
||||
## Design Decisions
|
||||
|
||||
\* Required parameters
|
||||
### Stack vs Heap Allocation
|
||||
|
||||
\*\* Required only by *HASHMAP* and *TREEMAP*
|
||||
Currently all collections need to be allocated on the heap. Iterators have both options but it is encouraged to allocate them on the stack since they don't require dynamic memory.
|
||||
|
||||
**In fact, all macros follow this pattern.** So whenever you see a macro with a bunch of parameters and you don't know what they are, you can check out the above list.
|
||||
### Some collections overlap others in terms of functionality
|
||||
|
||||
When including `foreach.h` in your source code you gain access to all for-each macros with the following parameters:
|
||||
Yes, you can use a Deque as a Queue or a List as a Stack without any major cost, but the idea is to have the least amount of code to fulfill the needs of a collection.
|
||||
|
||||
* __PFX__ - Functions prefix or namespace.
|
||||
* __SNAME__ - Structure name.
|
||||
* __TARGET__ - The variable name of the collection you wish to iterate over.
|
||||
* __BODY__ - Block of code.
|
||||
Take for example the Stack. It is simple, small and doesn't have many functions. If you generate a List to be used (only) as a Stack (which is one of the bulkiest collections) you'll end up with a lot of code generated and compiled for nothing.
|
||||
|
||||
Inside body you will have access to the iterator variable. With it you can use functions to access the key, value or index from the iterator.
|
||||
The Deque versus Queue situation is a little less problematic, but again, you need to be careful when generating a lot of code as compilation times might go up to 15 seconds even with modern ultra-fast compilers.
|
||||
|
||||
Another example is using a HashMap/TreeMap as a HashSet/TreeSet (with a dummy value that is never used), but I just think that this is a bad thing to do and you would be wasting some memory. Also, the sets generate a lot of code related to set theory, whereas maps don't.
|
||||
|
||||
### But what about the LinkedList ?
|
||||
|
||||
You can use them as Stacks, Queues and Deques, but with modern memory hierarchy models, array-based data structures have a significantly faster runtime due to caching, so I didn't bother to have specific implementations of those aforementioned collections.
|
||||
|
||||
### You can't structurally modify a collection when iterating over it
|
||||
|
||||
Modifying a collection will possibly invalidate all iterators currently initialized by it. Currently, the only collection that allows this is the LinkedList (using the node-based functions, not the iterator).
|
||||
|
||||
## Special Macros
|
||||
|
||||
* `CMC_NO_ALLOC` - disables `"cor/alloc.h"`, useful for statically allocated collections (SAC)
|
||||
* `CMC_NO_IMPORTS` - disables all imports from the standard library at `"cor/core.h"`
|
||||
@@ -1,56 +1,104 @@
|
||||
TODO
|
||||
|
||||
[ ] Finish Documentation
|
||||
[ ] Simplify PUBLIC and PRIVATE
|
||||
[ ] Add multiset
|
||||
[ ] Add multimap
|
||||
[ ] Upgrade heap to a min-max heap
|
||||
[ ] Add dispose function
|
||||
Patch - Changes that can be released by a patch version
|
||||
Minor - Changes that require a bit more time than a simple patch
|
||||
Major - 1.0.0 version or breaking changes
|
||||
|
||||
The library follows https://semver.org/
|
||||
Check out CHANGELOG
|
||||
|
||||
[/] - In Progress
|
||||
[X] - Finished
|
||||
|
||||
|
||||
#!! Next Patch -----------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#!! Major ----------------------------------------------------------------------
|
||||
|
||||
[ ] Stabilize the library
|
||||
[ ] Add SAC library
|
||||
[ ] Add TSC library
|
||||
[ ] Separate inner Data Structure implementation from the Collection's one
|
||||
[ ] CMC_NAMES - Full customization of function names (see CMC_CAMEL_CASE)
|
||||
[\] Tests
|
||||
[\] Documentation
|
||||
|
||||
|
||||
#!! Minor ----------------------------------------------------------------------
|
||||
|
||||
[ ] Fix BitSet, using capacity vs. counter
|
||||
[ ] #13 - Properly implement HashBidiMap iterator
|
||||
[ ] More SortedList functions
|
||||
[ ] BidiMap's _is_mapping() to check if a mapping K <=> V exists
|
||||
[ ] New asserts - _array_int(), _array_not_in() and str
|
||||
[ ] Add Stack's _peek() and _top() (get by value, get by pointer)
|
||||
[ ] CMC_TIMED for timed blocks
|
||||
[ ] _iter_at() iterator
|
||||
|
||||
|
||||
#!! Patch ----------------------------------------------------------------------
|
||||
|
||||
[ ] MultiSets replace existing value with the new added one
|
||||
|
||||
|
||||
#!! Considerations -------------------------------------------------------------
|
||||
|
||||
[ ] rand.h utility
|
||||
[ ] Redo `while (true)` in hashtables' _insert()
|
||||
[ ] Add to_array and from_array functions
|
||||
[ ] Serialization
|
||||
[ ] Iterator based functions (like C++ collections)
|
||||
[ ] save {all}
|
||||
[ ] load {all}
|
||||
[ ] serialize {all}
|
||||
[ ] deserialize {all}
|
||||
[ ] Zip Iterators
|
||||
[ ] Consumer Iterators
|
||||
|
||||
|
||||
MAYBE
|
||||
#!! Optimizations --------------------------------------------------------------
|
||||
|
||||
[ ] Add conditional code generation based on variadic macros
|
||||
[ ] Use binary search to find optimum hashtable prime size inside
|
||||
impl_calculate_size
|
||||
|
||||
|
||||
PLANNED
|
||||
#!! Done -----------------------------------------------------------------------
|
||||
|
||||
Before 2.0
|
||||
Get Documentation fixed and completed
|
||||
|
||||
1.5
|
||||
Simplify PUBLIC and PRIVATE (simply remove them)
|
||||
Conditional code generation
|
||||
Add extra content macro (Insert/Remove/Append/Prepend) and let user decide if he wants to include them or not
|
||||
Separate Implementation Detail into a different MACRO (LIST_GENERATE_DETAIL)
|
||||
|
||||
1.6
|
||||
Iterator move and move_to
|
||||
LinkedList - Insert/Remove/Append/Prepend/Extract
|
||||
to_array - Creates an array with all the elements inside the collection
|
||||
|
||||
1.7
|
||||
Add shrink function that shrinks the internal buffer to current count of elements
|
||||
|
||||
2.0
|
||||
Add multiset, multimap and new heap implementation
|
||||
|
||||
2.1
|
||||
Adapt multiset, multimap, treehashmap and new heap implementation to the current standards
|
||||
Add dispose method to each collection in order to automatically free its data
|
||||
|
||||
2.2
|
||||
Add serialization functions
|
||||
Header:
|
||||
%d - Type specifier (LIST = 0, DEQUE = 1, STACK = 2, etc) for quick check
|
||||
%llu - How many elements there are
|
||||
%d - If data varies in size
|
||||
%llu - Data size
|
||||
|
||||
2.3
|
||||
Iterator functions (functions that operate relative to iterators position) like add or remove ranges
|
||||
|
||||
Sometime
|
||||
Add treehashmap
|
||||
[X] Remove PUBLIC and PRIVATE
|
||||
[X] Utility
|
||||
[X] assert.h
|
||||
[X] foreach.h
|
||||
[X] log.h
|
||||
[X] test.h
|
||||
[X] timer.h
|
||||
[X] Extra Collections
|
||||
[X] Add MultiSet
|
||||
[X] Add MultiMap
|
||||
[X] Add IntervalHeap
|
||||
[X] Add SortedList
|
||||
[X] Add BidiMap
|
||||
[X] Add functions
|
||||
[X] update {hashmap, treemap, multimap}
|
||||
[X] set {hashmap, treemap, multimap}
|
||||
[X] to_string {all}
|
||||
[X] iter_advance {all} (iterators)
|
||||
[X] iter_rewind {all} (iterators)
|
||||
[X] iter_go_to {all} (iterators)
|
||||
[X] equals {all}
|
||||
[X] copy_of {all}
|
||||
[X] resize {array based collections}
|
||||
[X] Custom allocators
|
||||
[X] Each file needs to be independent without including external files
|
||||
[X] Fix cases where new_custom() should be used instead of just new()
|
||||
[X] Add Function Tables that contains data type functions
|
||||
(compare, copy, display, free, hash, priority)
|
||||
[X] Add error codes that can be accessed from the collection's struct
|
||||
[X] Merge bidirectional map key_buffer and val_buffer to a single buffer and make key_dist and val_dist into dist[2]
|
||||
[X] Callback utility
|
||||
on_create, on_read, on_update, on_delete, on_resize
|
||||
[X] Replace IntervalHeap node by a simple buffer of two pointers (V (*buffer)[2])
|
||||
[X] PUBLIC and PRIVATE is back (opaque data structures)
|
||||
[X] Add EXT library
|
||||
[X] #12 - Fix the collections that depend on ITER
|
||||
[X] #10 - Fix Benchmarks and Examples
|
||||
@@ -0,0 +1,11 @@
|
||||
CC=gcc
|
||||
INCLUDE=-I ..
|
||||
CFLAGS=-Wall -Wextra -Werror
|
||||
|
||||
benchmark: benchmark.c
|
||||
$(CC) $(CFLAGS) $(INCLUDE) $< -o ./$@.exe -lm
|
||||
./$@.exe
|
||||
|
||||
clean:
|
||||
rm *.exe -f
|
||||
rm *.txt -f
|
||||
+203
-139
@@ -12,14 +12,19 @@
|
||||
* - Iteration
|
||||
* - Output
|
||||
*/
|
||||
#include "macro_collections.h"
|
||||
#include "util/timer.h"
|
||||
#include "util/twister.c"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "util/twister.c"
|
||||
|
||||
#include "cmc/cor/hashtable.h"
|
||||
#include "cmc/cor/heap.h"
|
||||
#include "cmc/utl/foreach.h"
|
||||
#include "cmc/utl/futils.h"
|
||||
#include "cmc/utl/timer.h"
|
||||
|
||||
#define NTOTAL UINT64_C(10000000)
|
||||
#define NMIN UINT64_C(100)
|
||||
@@ -27,23 +32,6 @@
|
||||
// Percentage % macro
|
||||
#define PC(x) x * 100.0
|
||||
|
||||
static int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
size_t randsize(size_t min, size_t max, mt_state_ptr st)
|
||||
{
|
||||
return (size_t)floor(twist_real(st) * ((double)max - (double)min + 1.0) + (double)min);
|
||||
@@ -60,128 +48,190 @@ void shuffle(int *array, mt_state_ptr st)
|
||||
}
|
||||
}
|
||||
|
||||
COLLECTION_GENERATE(LIST, PUBLIC, l, list, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(STACK, PUBLIC, s, stack, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(QUEUE, PUBLIC, q, queue, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(DEQUE, PUBLIC, d, deque, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(LINKEDLIST, PUBLIC, ll, linked, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HEAP, PUBLIC, h, heap, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREESET, PUBLIC, ts, tset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREEMAP, PUBLIC, tm, tmap, /* FMOD */, int, int)
|
||||
COLLECTION_GENERATE(HASHSET, PUBLIC, hs, hset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HASHMAP, PUBLIC, hm, hmap, /* FMOD */, int, int)
|
||||
struct
|
||||
{
|
||||
CMC_DEF_FTAB_CMP(size_t);
|
||||
CMC_DEF_FTAB_CPY(size_t);
|
||||
CMC_DEF_FTAB_STR(size_t);
|
||||
CMC_DEF_FTAB_FREE(size_t);
|
||||
CMC_DEF_FTAB_HASH(size_t);
|
||||
CMC_DEF_FTAB_PRI(size_t);
|
||||
} int_ftab = { cmc_size_cmp, NULL, cmc_size_str, NULL, cmc_size_hash, cmc_size_cmp };
|
||||
|
||||
#define BENCHMARK(NAME, PFX, sname, initfunc, insertbody, removebody, searchbody) \
|
||||
void NAME##_io_benchmark(int *array, int *sarray, size_t s) \
|
||||
{ \
|
||||
printf("+------------------------------------------------------------ %10s\n", #NAME); \
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
timer_t timer, total; \
|
||||
int r, k, v; \
|
||||
size_t j; \
|
||||
\
|
||||
sname *coll = initfunc; \
|
||||
\
|
||||
TIMER_START(total) \
|
||||
TIMER_START(timer) \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
insertbody; \
|
||||
} \
|
||||
\
|
||||
TIMER_STOP(timer) \
|
||||
\
|
||||
TIMER_CALC(timer) \
|
||||
\
|
||||
size_t s1 = PFX##_count(coll); \
|
||||
\
|
||||
#define CMC_ARGS_FALLTHROUGH
|
||||
#define V int
|
||||
#define K int
|
||||
#define CMC_EXT_ITER
|
||||
|
||||
#define SNAME bitset
|
||||
#define PFX bs
|
||||
#include "cmc/bitset.h"
|
||||
#define SNAME deque
|
||||
#define PFX d
|
||||
#include "cmc/deque.h"
|
||||
#define SNAME hashbidimap
|
||||
#define PFX hbm
|
||||
#include "cmc/hashbidimap.h"
|
||||
#define SNAME hashmap
|
||||
#define PFX hm
|
||||
#include "cmc/hashmap.h"
|
||||
#define SNAME hashmultimap
|
||||
#define PFX hmm
|
||||
#include "cmc/hashmultimap.h"
|
||||
#define SNAME hashmultiset
|
||||
#define PFX hms
|
||||
#include "cmc/hashmultiset.h"
|
||||
#define SNAME hashset
|
||||
#define PFX hs
|
||||
#include "cmc/hashset.h"
|
||||
#define SNAME heap
|
||||
#define PFX h
|
||||
#include "cmc/heap.h"
|
||||
#define SNAME intervalheap
|
||||
#define PFX ih
|
||||
#include "cmc/intervalheap.h"
|
||||
#define SNAME linkedlist
|
||||
#define PFX ll
|
||||
#include "cmc/linkedlist.h"
|
||||
#define SNAME list
|
||||
#define PFX l
|
||||
#include "cmc/list.h"
|
||||
#define SNAME queue
|
||||
#define PFX q
|
||||
#include "cmc/queue.h"
|
||||
#define SNAME sortedlist
|
||||
#define PFX sl
|
||||
#include "cmc/sortedlist.h"
|
||||
#define SNAME stack
|
||||
#define PFX s
|
||||
#include "cmc/stack.h"
|
||||
#define SNAME treemap
|
||||
#define PFX tm
|
||||
#include "cmc/treemap.h"
|
||||
#define SNAME treeset
|
||||
#define PFX ts
|
||||
#include "cmc/treeset.h"
|
||||
|
||||
#undef CMC_ARGS_FALLTHROUGH
|
||||
#include "cmc/cor/undef.h"
|
||||
|
||||
#define BENCHMARK(NAME, PFX, SNAME, initfunc, insertbody, removebody, searchbody) \
|
||||
void NAME##_io_benchmark(int *array, int *sarray, size_t s) \
|
||||
{ \
|
||||
printf("+------------------------------------------------------------ %10s\n", #NAME); \
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
struct cmc_timer timer, total; \
|
||||
CMC_UNUSED int r; \
|
||||
\
|
||||
struct SNAME *coll = initfunc; \
|
||||
\
|
||||
cmc_timer_start(total); \
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
insertbody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
size_t s1 = PFX##_count(coll); \
|
||||
\
|
||||
printf(" INPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double input_time = timer.result; \
|
||||
\
|
||||
TIMER_START(timer) \
|
||||
\
|
||||
for (size_t i = 0; i < s; i++) \
|
||||
{ \
|
||||
searchbody; \
|
||||
} \
|
||||
\
|
||||
TIMER_STOP(timer) \
|
||||
\
|
||||
TIMER_CALC(timer) \
|
||||
\
|
||||
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
|
||||
\
|
||||
double search_time = timer.result; \
|
||||
\
|
||||
sname##_iter iter; \
|
||||
\
|
||||
TIMER_START(timer) \
|
||||
\
|
||||
for (PFX##_iter_init(&iter, coll); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
TIMER_STOP(timer) \
|
||||
\
|
||||
TIMER_CALC(timer) \
|
||||
\
|
||||
\
|
||||
double input_time = timer.result; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < s; i++) \
|
||||
{ \
|
||||
searchbody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
|
||||
\
|
||||
double search_time = timer.result; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
CMC_FOREACH (PFX, SNAME, iter, coll) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
printf("ITERATION %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double iter_time = timer.result; \
|
||||
\
|
||||
TIMER_START(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
removebody; \
|
||||
} \
|
||||
\
|
||||
TIMER_STOP(timer) \
|
||||
\
|
||||
TIMER_CALC(timer) \
|
||||
\
|
||||
size_t s2 = PFX##_count(coll); \
|
||||
\
|
||||
\
|
||||
double iter_time = timer.result; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
removebody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
size_t s2 = PFX##_count(coll); \
|
||||
\
|
||||
printf(" OUTPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double output_time = timer.result; \
|
||||
\
|
||||
TIMER_STOP(total) \
|
||||
TIMER_CALC(total) \
|
||||
\
|
||||
PFX##_free(coll); \
|
||||
\
|
||||
double adj_search_time = (total.result - search_time) + (search_time * (double)NTOTAL) / (double)s; \
|
||||
double no_search = input_time + iter_time + output_time; \
|
||||
\
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
printf("TOTAL TIME : %.0lf milliseconds\n", total.result); \
|
||||
printf("ADJUSTED TIME : %.0lf milliseconds\n", adj_search_time); \
|
||||
\
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
printf(" INPUT : %5.2lf%% (%5.2f%%)\n", PC(input_time / total.result), PC(input_time / no_search)); \
|
||||
printf(" SEARCH : %5.2lf%%\n", PC(search_time / total.result)); \
|
||||
printf("ITERATION : %5.2lf%% (%5.2f%%)\n", PC(iter_time / total.result), PC(iter_time / no_search)); \
|
||||
\
|
||||
double output_time = timer.result; \
|
||||
\
|
||||
cmc_timer_stop(total); \
|
||||
\
|
||||
PFX##_free(coll); \
|
||||
\
|
||||
double adj_search_time = (total.result - search_time) + (search_time * (double)NTOTAL) / (double)s; \
|
||||
double no_search = input_time + iter_time + output_time; \
|
||||
\
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
printf("TOTAL TIME : %.0lf milliseconds\n", total.result); \
|
||||
printf("ADJUSTED TIME : %.0lf milliseconds\n", adj_search_time); \
|
||||
\
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
printf(" INPUT : %5.2lf%% (%5.2f%%)\n", PC(input_time / total.result), PC(input_time / no_search)); \
|
||||
printf(" SEARCH : %5.2lf%%\n", PC(search_time / total.result)); \
|
||||
printf("ITERATION : %5.2lf%% (%5.2f%%)\n", PC(iter_time / total.result), PC(iter_time / no_search)); \
|
||||
printf(" OUTPUT : %5.2lf%% (%5.2f%%)\n", PC(output_time / total.result), PC(output_time / no_search)); \
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
\
|
||||
assert(s1 == NTOTAL && s2 == 0); \
|
||||
\
|
||||
printf("+------------------------------------------------------------ %10s\n\n", #NAME); \
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
\
|
||||
assert(s1 == NTOTAL && s2 == 0); \
|
||||
\
|
||||
printf("+------------------------------------------------------------ %10s\n\n", #NAME); \
|
||||
}
|
||||
|
||||
BENCHMARK(DEQUE, d, deque, d_new(NTOTAL), d_push_back(coll, array[i]), d_pop_back(coll), d_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(HASHMAP, hm, hmap, hm_new(NTOTAL, 0.8, intcmp, inthash), hm_insert(coll, array[i], array[i]), hm_remove(coll, array[i], &r), hm_contains(coll, sarray[i]))
|
||||
BENCHMARK(HASHSET, hs, hset, hs_new(NTOTAL, 0.8, intcmp, inthash), hs_insert(coll, array[i]), hs_remove(coll, array[i]), hs_contains(coll, sarray[i]))
|
||||
BENCHMARK(HEAP, h, heap, h_new(NTOTAL, MinHeap, intcmp), h_insert(coll, array[i]), h_remove(coll, &r), h_contains(coll, sarray[i]))
|
||||
BENCHMARK(LINKEDLIST, ll, linked, ll_new(), ll_push_back(coll, array[i]), ll_pop_back(coll), ll_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(LIST, l, list, l_new(NTOTAL), l_push_back(coll, array[i]), l_pop_back(coll), l_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(QUEUE, q, queue, q_new(NTOTAL), q_enqueue(coll, array[i]), q_dequeue(coll), q_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(STACK, s, stack, s_new(NTOTAL), s_push(coll, array[i]), s_pop(coll), s_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(TREEMAP, tm, tmap, tm_new(intcmp), tm_insert(coll, array[i], array[i]), tm_remove(coll, array[i], &r), tm_contains(coll, sarray[i]))
|
||||
BENCHMARK(TREESET, ts, tset, ts_new(intcmp), ts_insert(coll, array[i]), ts_remove(coll, array[i]), ts_contains(coll, sarray[i]))
|
||||
BENCHMARK(DEQUE, d, deque, d_new(NTOTAL, (struct deque_fval *)&int_ftab), d_push_back(coll, array[i]), d_pop_back(coll),
|
||||
d_contains(coll, sarray[i]))
|
||||
BENCHMARK(HASHMAP, hm, hashmap, hm_new(NTOTAL, 0.6, (struct hashmap_fkey *)&int_ftab, (struct hashmap_fval *)&int_ftab),
|
||||
hm_insert(coll, array[i], array[i]), hm_remove(coll, array[i], &r), hm_contains(coll, sarray[i]))
|
||||
BENCHMARK(HASHSET, hs, hashset, hs_new(NTOTAL, 0.6, (struct hashset_fval *)&int_ftab), hs_insert(coll, array[i]),
|
||||
hs_remove(coll, array[i]), hs_contains(coll, sarray[i]))
|
||||
BENCHMARK(HEAP, h, heap, h_new(NTOTAL, CMC_MIN_HEAP, (struct heap_fval *)&int_ftab), h_insert(coll, array[i]),
|
||||
h_remove(coll), h_contains(coll, sarray[i]))
|
||||
BENCHMARK(LINKEDLIST, ll, linkedlist, ll_new((struct linkedlist_fval *)&int_ftab), ll_push_back(coll, array[i]),
|
||||
ll_pop_back(coll), ll_contains(coll, sarray[i]))
|
||||
BENCHMARK(LIST, l, list, l_new(NTOTAL, (struct list_fval *)&int_ftab), l_push_back(coll, array[i]), l_pop_back(coll),
|
||||
l_contains(coll, sarray[i]))
|
||||
BENCHMARK(QUEUE, q, queue, q_new(NTOTAL, (struct queue_fval *)&int_ftab), q_enqueue(coll, array[i]), q_dequeue(coll),
|
||||
q_contains(coll, sarray[i]))
|
||||
BENCHMARK(STACK, s, stack, s_new(NTOTAL, (struct stack_fval *)&int_ftab), s_push(coll, array[i]), s_pop(coll),
|
||||
s_contains(coll, sarray[i]))
|
||||
BENCHMARK(TREEMAP, tm, treemap, tm_new((struct treemap_fkey *)&int_ftab, (struct treemap_fval *)&int_ftab),
|
||||
tm_insert(coll, array[i], array[i]), tm_remove(coll, array[i], &r), tm_contains(coll, sarray[i]))
|
||||
BENCHMARK(TREESET, ts, treeset, ts_new((struct treeset_fval *)&int_ftab), ts_insert(coll, array[i]),
|
||||
ts_remove(coll, array[i]), ts_contains(coll, sarray[i]))
|
||||
|
||||
BENCHMARK(INTERVALHEAP, ih, intervalheap, ih_new(NTOTAL, (struct intervalheap_fval *)&int_ftab),
|
||||
ih_insert(coll, array[i]), ih_remove_max(coll), ih_contains(coll, sarray[i]))
|
||||
BENCHMARK(MULTIMAP, hmm, hashmultimap,
|
||||
hmm_new(NTOTAL, 0.8, (struct hashmultimap_fkey *)&int_ftab, (struct hashmultimap_fval *)&int_ftab),
|
||||
hmm_insert(coll, array[i], array[i]), hmm_remove(coll, array[i], &r), hmm_contains(coll, sarray[i]))
|
||||
BENCHMARK(MULTISET, hms, hashmultiset, hms_new(NTOTAL, 0.6, (struct hashmultiset_fval *)&int_ftab),
|
||||
hms_insert(coll, array[i]), hms_remove(coll, array[i]), hms_contains(coll, sarray[i]))
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@@ -210,10 +260,14 @@ int main(void)
|
||||
|
||||
shuffle(sarray, &st);
|
||||
|
||||
printf("\nNote: Adjusted Time refers to if the container had done a search over all %" PRIuMAX " elements.\n\n", NTOTAL);
|
||||
printf("\nNote: Adjusted Time refers to if the container had done a search over all %" PRIuMAX " elements.\n\n",
|
||||
NTOTAL);
|
||||
|
||||
// Linear containers have to search for NMIN elements and non-linear (hash
|
||||
// and tree) have to search for all elements.
|
||||
struct cmc_timer timer;
|
||||
cmc_timer_start(timer);
|
||||
|
||||
DEQUE_io_benchmark(array, sarray, NMIN);
|
||||
HASHMAP_io_benchmark(array, sarray, NTOTAL);
|
||||
HASHSET_io_benchmark(array, sarray, NTOTAL);
|
||||
@@ -225,6 +279,16 @@ int main(void)
|
||||
TREEMAP_io_benchmark(array, sarray, NTOTAL);
|
||||
TREESET_io_benchmark(array, sarray, NTOTAL);
|
||||
|
||||
// INTERVALHEAP_io_benchmark(array, array, NMIN);
|
||||
// MULTIMAP_io_benchmark(array, array, NTOTAL);
|
||||
// MULTISET_io_benchmark(array, array, NTOTAL);
|
||||
|
||||
cmc_timer_stop(timer);
|
||||
|
||||
printf("+-----------------------------------------------------------+ \n");
|
||||
printf("| Total Benchmark Running Time : %12.0lf seconds | \n", timer.result / 1000);
|
||||
printf("+-----------------------------------------------------------+ \n");
|
||||
|
||||
free(array);
|
||||
free(sarray);
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
INCLUDE=-I ../../..
|
||||
CFLAGS=-O3 -Wall -Wextra -Werror -DCOUNT=20000000 -DCMC_NO_CALLBACKS
|
||||
|
||||
# Install hyperfine
|
||||
# https://github.com/sharkdp/hyperfine
|
||||
|
||||
run: build
|
||||
hyperfine --warmup 2 --runs 5 './hashmap.exe'
|
||||
hyperfine --warmup 2 --runs 5 './hashmultimap.exe'
|
||||
hyperfine --warmup 2 --runs 5 './unorderedmap.exe'
|
||||
|
||||
build:
|
||||
gcc hashmap.c -o hashmap.exe $(INCLUDE) $(CFLAGS)
|
||||
gcc hashmultimap.c -o hashmultimap.exe $(INCLUDE) $(CFLAGS)
|
||||
g++ unorderedmap.cpp $(INCLUDE) -o unorderedmap.exe $(CFLAGS)
|
||||
|
||||
clean:
|
||||
rm *.exe -f
|
||||
rm *.txt -f
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef COUNT
|
||||
#error "Please define COUNT"
|
||||
#endif
|
||||
|
||||
#include "murmurhash.h"
|
||||
|
||||
#include "../../util/twister.c"
|
||||
|
||||
#define K uint64_t
|
||||
#define V uint64_t
|
||||
#define PFX hm
|
||||
#define SNAME hashmap
|
||||
#include "cmc/hashmap.h"
|
||||
|
||||
int cmp(uint64_t a, uint64_t b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
// size_t hash(uint64_t a)
|
||||
// {
|
||||
// size_t x = (size_t)a;
|
||||
// x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
// x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
// x = (x >> 16) ^ x;
|
||||
// return x;
|
||||
// }
|
||||
|
||||
size_t hash(uint64_t k)
|
||||
{
|
||||
static size_t seed = 211106232532969;
|
||||
return MurMurHash(&k, sizeof(k), seed);
|
||||
}
|
||||
|
||||
struct hashmap_fkey *fkey = &(struct hashmap_fkey){ .cmp = cmp, .hash = hash, NULL };
|
||||
|
||||
struct hashmap_fval *fval = &(struct hashmap_fval){ .cmp = cmp, .hash = hash, NULL };
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mt_state tw;
|
||||
twist_init(&tw, 50331653);
|
||||
|
||||
struct hashmap *map = hm_new(COUNT, 0.6, fkey, fval);
|
||||
|
||||
for (uint64_t i = 0; i < COUNT; i++)
|
||||
{
|
||||
uint64_t v = twist_uint64(&tw);
|
||||
hm_insert(map, v, v);
|
||||
}
|
||||
|
||||
hm_free(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef COUNT
|
||||
#error "Please define COUNT"
|
||||
#endif
|
||||
|
||||
#include "murmurhash.h"
|
||||
|
||||
#include "../../util/twister.c"
|
||||
|
||||
#define K uint64_t
|
||||
#define V uint64_t
|
||||
#define PFX hmm
|
||||
#define SNAME hashmultimap
|
||||
#include "cmc/hashmultimap.h"
|
||||
|
||||
int cmp(uint64_t a, uint64_t b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
// size_t hash(uint64_t a)
|
||||
// {
|
||||
// size_t x = (size_t)a;
|
||||
// x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
// x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
// x = (x >> 16) ^ x;
|
||||
// return x;
|
||||
// }
|
||||
|
||||
size_t hash(uint64_t k)
|
||||
{
|
||||
static size_t seed = 211106232532969;
|
||||
return MurMurHash(&k, sizeof(k), seed);
|
||||
}
|
||||
|
||||
struct hashmultimap_fkey *fkey = &(struct hashmultimap_fkey){ .cmp = cmp, .hash = hash, NULL };
|
||||
|
||||
struct hashmultimap_fval *fval = &(struct hashmultimap_fval){ .cmp = cmp, .hash = hash, NULL };
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mt_state tw;
|
||||
twist_init(&tw, 50331653);
|
||||
|
||||
struct hashmultimap *map = hmm_new(COUNT, 0.6, fkey, fval);
|
||||
|
||||
for (uint64_t i = 0; i < COUNT; i++)
|
||||
{
|
||||
uint64_t v = twist_uint64(&tw);
|
||||
hmm_insert(map, v, v);
|
||||
}
|
||||
|
||||
hmm_free(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/hash_bytes.cc
|
||||
|
||||
#ifndef MURMURHASH
|
||||
#define MURMURHASH
|
||||
|
||||
#include <string.h>
|
||||
|
||||
inline size_t unaligned_load(const char *p)
|
||||
{
|
||||
size_t result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline size_t load_bytes(const char *p, int n)
|
||||
{
|
||||
size_t result = 0;
|
||||
--n;
|
||||
do
|
||||
{
|
||||
result = (result << 8) + (unsigned char)(p[n]);
|
||||
} while (--n >= 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline size_t shift_mix(size_t v)
|
||||
{
|
||||
return v ^ (v >> 47);
|
||||
}
|
||||
|
||||
size_t MurMurHash(const void *ptr, size_t len, size_t seed)
|
||||
{
|
||||
static const size_t mul = (((size_t)0xc6a4a793UL) << 32UL) + (size_t)0x5bd1e995UL;
|
||||
const char *const buf = (const char *)(ptr);
|
||||
|
||||
// Remove the bytes not divisible by the sizeof(size_t). This
|
||||
// allows the main loop to process the data as 64-bit integers.
|
||||
const size_t len_aligned = len & ~(size_t)0x7;
|
||||
const char *const end = buf + len_aligned;
|
||||
size_t hash = seed ^ (len * mul);
|
||||
for (const char *p = buf; p != end; p += 8)
|
||||
{
|
||||
const size_t data = shift_mix(unaligned_load(p) * mul) * mul;
|
||||
hash ^= data;
|
||||
hash *= mul;
|
||||
}
|
||||
if ((len & 0x7) != 0)
|
||||
{
|
||||
const size_t data = load_bytes(end, len & 0x7);
|
||||
hash ^= data;
|
||||
hash *= mul;
|
||||
}
|
||||
hash = shift_mix(hash) * mul;
|
||||
hash = shift_mix(hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
#endif /* MURMURHASH */
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef COUNT
|
||||
#error "Please define COUNT"
|
||||
#endif
|
||||
|
||||
#include "murmurhash.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../../util/twister.c"
|
||||
|
||||
struct IntHasher
|
||||
{
|
||||
std::size_t operator()(const uint64_t &k) const
|
||||
{
|
||||
static size_t seed = 211106232532969;
|
||||
return MurMurHash(&k, sizeof(k), seed);
|
||||
}
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mt_state tw;
|
||||
twist_init(&tw, 50331653);
|
||||
|
||||
std::unordered_map<uint64_t, uint64_t, IntHasher> map(COUNT);
|
||||
|
||||
for (uint64_t i = 0; i < COUNT; i++)
|
||||
{
|
||||
uint64_t v = twist_uint64(&tw);
|
||||
map.insert({ v, v });
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* timer.h
|
||||
*
|
||||
* Creation Date: 12/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Simple timer macros.
|
||||
*/
|
||||
#include <time.h>
|
||||
|
||||
typedef struct timer_s
|
||||
{
|
||||
clock_t start;
|
||||
clock_t stop;
|
||||
double result;
|
||||
} timer_t;
|
||||
|
||||
#define TIMER_START(timer) \
|
||||
timer.start = clock();
|
||||
|
||||
#define TIMER_STOP(timer) \
|
||||
timer.stop = clock();
|
||||
|
||||
#define TIMER_CALC(timer) \
|
||||
timer.result = (double)(((timer.stop - timer.start) * 1000.0) / CLOCKS_PER_SEC);
|
||||
@@ -7,7 +7,7 @@
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Mersenne Twister PRNG utility
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
[book]
|
||||
authors = ["Leonardo Vencovsky"]
|
||||
language = "en"
|
||||
multilingual = false
|
||||
src = "documentation/"
|
||||
title = "C Macro Collections"
|
||||
|
||||
[build]
|
||||
build-dir = "docs/"
|
||||
|
||||
[preprocessor.index]
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* bitset.h
|
||||
*
|
||||
* Creation Date: 30/04/2020
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* BitSet
|
||||
*
|
||||
* A Bit Set is an array where each bit can be individually modified and queried
|
||||
* by using bitwise operators such as |, &, ^, ~, >> and << (or, and, xor, not,
|
||||
* right shift, left shift respectively).
|
||||
*
|
||||
* Implementation
|
||||
*
|
||||
* This BitSet implementation uses an array of type cmc_bitset_word which can be
|
||||
* typedefed to any unsigned type such as uint8_t, uint16_t, uint32_t, uint64_t,
|
||||
* size_t, etc. The BitSet does not make use of K or V. Because of that, it also
|
||||
* doesn't have Functions Tables.
|
||||
*
|
||||
* The BitSet is initialized with a custom capacity but, if a bit index accessed
|
||||
* is greater than the total capacity, the BitSet will resize. This means that
|
||||
* the BitSet will try to guarantee that every bit index is accessible, as long
|
||||
* as there is enough memory.
|
||||
*/
|
||||
|
||||
#include "cor/bitset.h"
|
||||
#include "cor/core.h"
|
||||
|
||||
#ifdef CMC_DEV
|
||||
#include "utl/log.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
|
||||
/* Structs definition */
|
||||
#include "cmc/bitset/struct.h"
|
||||
|
||||
/* Function declaration */
|
||||
#include "cmc/bitset/header.h"
|
||||
|
||||
/* Function implementation */
|
||||
#include "cmc/bitset/code.h"
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* INIT - Initializes the struct on the stack
|
||||
* ITER - bitset iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_BITSET_PARTS INIT, ITER, STR
|
||||
/**/
|
||||
#include "cmc/bitset/ext/struct.h"
|
||||
/**/
|
||||
#include "cmc/bitset/ext/header.h"
|
||||
/**/
|
||||
#include "cmc/bitset/ext/code.h"
|
||||
|
||||
#include "cor/undef.h"
|
||||
@@ -0,0 +1,512 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
bool CMC_(PFX, _impl_resize)(struct SNAME *_bitset_, size_t n_bits, bool do_resize);
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t n_bits)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _new_custom)(n_bits, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t n_bits, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (n_bits < 1)
|
||||
return NULL;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
size_t capacity = cmc_bidx_to_widx(n_bits - 1) + 1;
|
||||
|
||||
struct SNAME *_bitset_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_bitset_)
|
||||
return NULL;
|
||||
|
||||
_bitset_->buffer = alloc->calloc(capacity, sizeof(cmc_bitset_word));
|
||||
|
||||
if (!_bitset_->buffer)
|
||||
{
|
||||
alloc->free(_bitset_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_bitset_->capacity = capacity;
|
||||
_bitset_->flag = CMC_FLAG_OK;
|
||||
_bitset_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_bitset_, callbacks);
|
||||
|
||||
return _bitset_;
|
||||
}
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t n_bits)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _init_custom)(n_bits, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t n_bits, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
struct SNAME _bitset_ = { 0 };
|
||||
|
||||
if (n_bits < 1)
|
||||
return _bitset_;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
size_t capacity = cmc_bidx_to_widx(n_bits - 1) + 1;
|
||||
|
||||
_bitset_.buffer = alloc->calloc(capacity, sizeof(cmc_bitset_word));
|
||||
|
||||
if (!_bitset_.buffer)
|
||||
return _bitset_;
|
||||
|
||||
_bitset_.capacity = capacity;
|
||||
_bitset_.flag = CMC_FLAG_OK;
|
||||
_bitset_.alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(&_bitset_, callbacks);
|
||||
|
||||
return _bitset_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_bitset_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
free(_bitset_->buffer);
|
||||
free(_bitset_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _release)(struct SNAME _bitset_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
free(_bitset_.buffer);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_bitset_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_bitset_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_bitset_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_bitset_, callbacks);
|
||||
|
||||
_bitset_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _set)(struct SNAME *_bitset_, size_t bit_index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _impl_resize)(_bitset_, bit_index + 1, false))
|
||||
return false;
|
||||
|
||||
/* How many bits in a word */
|
||||
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
|
||||
|
||||
size_t i = cmc_bidx_to_widx(bit_index);
|
||||
|
||||
_bitset_->buffer[i] |= ((cmc_bitset_word)1) << (bit_index % bits);
|
||||
|
||||
_bitset_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_bitset_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _set_range)(struct SNAME *_bitset_, size_t from, size_t to)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (to < from)
|
||||
{
|
||||
_bitset_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CMC_(PFX, _impl_resize)(_bitset_, to + 1, false))
|
||||
return false;
|
||||
|
||||
size_t start_index = cmc_bidx_to_widx(from);
|
||||
size_t end_index = cmc_bidx_to_widx(to);
|
||||
|
||||
/* How many bits in a word */
|
||||
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
|
||||
|
||||
/* 1111 ... 1111 */
|
||||
const cmc_bitset_word ones = ~((cmc_bitset_word)0);
|
||||
|
||||
cmc_bitset_word shift_start = from % bits;
|
||||
cmc_bitset_word shift_end = (cmc_bitset_word)(-(to + 1)) % bits;
|
||||
|
||||
cmc_bitset_word start_mask = ones << shift_start;
|
||||
cmc_bitset_word end_mask = ones >> shift_end;
|
||||
|
||||
if (start_index == end_index)
|
||||
{
|
||||
_bitset_->buffer[end_index] |= (start_mask & end_mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
_bitset_->buffer[start_index] |= start_mask;
|
||||
|
||||
for (size_t i = start_index + 1; i < end_index; i++)
|
||||
_bitset_->buffer[i] |= ~((cmc_bitset_word)0);
|
||||
|
||||
_bitset_->buffer[end_index] |= end_mask;
|
||||
}
|
||||
|
||||
_bitset_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_bitset_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _clear)(struct SNAME *_bitset_, size_t bit_index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _impl_resize)(_bitset_, bit_index + 1, false))
|
||||
return false;
|
||||
|
||||
/* How many bits in a word */
|
||||
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
|
||||
|
||||
size_t i = cmc_bidx_to_widx(bit_index);
|
||||
|
||||
_bitset_->buffer[i] &= ~(((cmc_bitset_word)1) << (bit_index % bits));
|
||||
|
||||
_bitset_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_bitset_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _clear_range)(struct SNAME *_bitset_, size_t from, size_t to)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (to < from)
|
||||
{
|
||||
_bitset_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CMC_(PFX, _impl_resize)(_bitset_, to + 1, false))
|
||||
return false;
|
||||
|
||||
size_t start_index = cmc_bidx_to_widx(from);
|
||||
size_t end_index = cmc_bidx_to_widx(to);
|
||||
|
||||
/* How many bits in a word */
|
||||
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
|
||||
|
||||
/* 1111 ... 1111 */
|
||||
const cmc_bitset_word ones = ~((cmc_bitset_word)0);
|
||||
|
||||
cmc_bitset_word shift_start = from % bits;
|
||||
cmc_bitset_word shift_end = (cmc_bitset_word)(-(to + 1)) % bits;
|
||||
|
||||
cmc_bitset_word start_mask = ones << shift_start;
|
||||
cmc_bitset_word end_mask = ones >> shift_end;
|
||||
|
||||
if (start_index == end_index)
|
||||
{
|
||||
_bitset_->buffer[end_index] &= ~(start_mask & end_mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
_bitset_->buffer[start_index] &= ~start_mask;
|
||||
|
||||
for (size_t i = start_index + 1; i < end_index; i++)
|
||||
_bitset_->buffer[i] = 0;
|
||||
|
||||
_bitset_->buffer[end_index] &= ~end_mask;
|
||||
}
|
||||
|
||||
_bitset_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_bitset_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _flip)(struct SNAME *_bitset_, size_t bit_index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _impl_resize)(_bitset_, bit_index + 1, false))
|
||||
return false;
|
||||
|
||||
/* How many bits in a word */
|
||||
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
|
||||
|
||||
size_t i = cmc_bidx_to_widx(bit_index);
|
||||
|
||||
_bitset_->buffer[i] ^= ((cmc_bitset_word)1) << (bit_index % bits);
|
||||
|
||||
_bitset_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_bitset_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _flip_range)(struct SNAME *_bitset_, size_t from, size_t to)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (to < from)
|
||||
{
|
||||
_bitset_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CMC_(PFX, _impl_resize)(_bitset_, to + 1, false))
|
||||
return false;
|
||||
|
||||
size_t start_index = cmc_bidx_to_widx(from);
|
||||
size_t end_index = cmc_bidx_to_widx(to);
|
||||
|
||||
/* How many bits in a word */
|
||||
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
|
||||
|
||||
/* 1111 ... 1111 */
|
||||
const cmc_bitset_word ones = ~((cmc_bitset_word)0);
|
||||
|
||||
cmc_bitset_word shift_start = from % bits;
|
||||
cmc_bitset_word shift_end = (cmc_bitset_word)(-(to + 1)) % bits;
|
||||
|
||||
cmc_bitset_word start_mask = ones << shift_start;
|
||||
cmc_bitset_word end_mask = ones >> shift_end;
|
||||
|
||||
if (start_index == end_index)
|
||||
{
|
||||
_bitset_->buffer[end_index] ^= (start_mask & end_mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
_bitset_->buffer[start_index] ^= start_mask;
|
||||
|
||||
for (size_t i = start_index + 1; i < end_index; i++)
|
||||
_bitset_->buffer[i] ^= ones;
|
||||
|
||||
_bitset_->buffer[end_index] ^= end_mask;
|
||||
}
|
||||
|
||||
_bitset_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_bitset_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _put)(struct SNAME *_bitset_, size_t bit_index, bool state)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (state)
|
||||
return CMC_(PFX, _set)(_bitset_, bit_index);
|
||||
else
|
||||
return CMC_(PFX, _clear)(_bitset_, bit_index);
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _put_range)(struct SNAME *_bitset_, size_t from, size_t to, bool state)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (state)
|
||||
return CMC_(PFX, _set_range)(_bitset_, from, to);
|
||||
else
|
||||
return CMC_(PFX, _clear_range)(_bitset_, from, to);
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _set_all)(struct SNAME *_bitset_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < _bitset_->capacity; i++)
|
||||
_bitset_->buffer[i] = ~((cmc_bitset_word)0);
|
||||
|
||||
_bitset_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_bitset_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _clear_all)(struct SNAME *_bitset_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < _bitset_->capacity; i++)
|
||||
_bitset_->buffer[i] = 0;
|
||||
|
||||
_bitset_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_bitset_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _flip_all)(struct SNAME *_bitset_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < _bitset_->capacity; i++)
|
||||
_bitset_->buffer[i] ^= ~((cmc_bitset_word)0);
|
||||
|
||||
_bitset_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_bitset_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _get)(struct SNAME *_bitset_, size_t bit_index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* How many bits in a word */
|
||||
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
|
||||
|
||||
cmc_bitset_word w = _bitset_->buffer[cmc_bidx_to_widx(bit_index)];
|
||||
|
||||
return w & ((cmc_bitset_word)1 << (bit_index % bits));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_bitset_, size_t n_bits)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _impl_resize)(_bitset_, n_bits, true);
|
||||
}
|
||||
|
||||
/* When do_resize is false, then we just want to assure that the bitset */
|
||||
/* can accommodate n_bits */
|
||||
bool CMC_(PFX, _impl_resize)(struct SNAME *_bitset_, size_t n_bits, bool do_resize)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (n_bits == 0)
|
||||
{
|
||||
_bitset_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -1 because n_bits is 1-based and we need to pass a 0-based index */
|
||||
/* +1 to have a 1-based result */
|
||||
size_t words = cmc_bidx_to_widx(n_bits - 1) + 1;
|
||||
|
||||
/* Be sure we are not always shrinking when we just want to make */
|
||||
/* sure that we have enough size for n_bits */
|
||||
if (!do_resize && words <= _bitset_->capacity)
|
||||
return true;
|
||||
|
||||
cmc_bitset_word *new_buffer = realloc(_bitset_->buffer, words * sizeof(cmc_bitset_word));
|
||||
|
||||
if (!new_buffer)
|
||||
{
|
||||
_bitset_->flag = CMC_FLAG_ALLOC;
|
||||
return false;
|
||||
}
|
||||
|
||||
_bitset_->buffer = new_buffer;
|
||||
|
||||
/* Make new bits be all zeroes */
|
||||
if (_bitset_->capacity < words)
|
||||
memset(_bitset_->buffer + _bitset_->capacity, 0, (words - _bitset_->capacity) * sizeof(cmc_bitset_word));
|
||||
|
||||
_bitset_->capacity = words;
|
||||
|
||||
CMC_CALLBACKS_CALL(_bitset_);
|
||||
|
||||
_bitset_->flag = CMC_FLAG_OK;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Bitset bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* Iterator Functions */
|
||||
/* Iterator Initialization */
|
||||
/* Iterator State */
|
||||
/* Iterator Movement */
|
||||
/* Iterator Access */
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Bitset bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* Iterator Functions */
|
||||
/* Iterator Initialization */
|
||||
/* Iterator State */
|
||||
/* Iterator Movement */
|
||||
/* Iterator Access */
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Bitset bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* BitSet Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target bitset */
|
||||
struct SNAME *target;
|
||||
/* Cursor's position (index) */
|
||||
size_t cursor;
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t n_bits);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t n_bits, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
|
||||
struct SNAME CMC_(PFX, _init)(size_t n_bits);
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t n_bits, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
|
||||
void CMC_(PFX, _free)(struct SNAME *_bitset_);
|
||||
void CMC_(PFX, _release)(struct SNAME _bitset_);
|
||||
void CMC_(PFX, _customize)(struct SNAME *_bitset_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _set)(struct SNAME *_bitset_, size_t bit_index);
|
||||
bool CMC_(PFX, _set_range)(struct SNAME *_bitset_, size_t from, size_t to);
|
||||
bool CMC_(PFX, _clear)(struct SNAME *_bitset_, size_t bit_index);
|
||||
bool CMC_(PFX, _clear_range)(struct SNAME *_bitset_, size_t from, size_t to);
|
||||
bool CMC_(PFX, _flip)(struct SNAME *_bitset_, size_t bit_index);
|
||||
bool CMC_(PFX, _flip_range)(struct SNAME *_bitset_, size_t from, size_t to);
|
||||
bool CMC_(PFX, _put)(struct SNAME *_bitset_, size_t bit_index, bool state);
|
||||
bool CMC_(PFX, _put_range)(struct SNAME *_bitset_, size_t from, size_t to, bool state);
|
||||
bool CMC_(PFX, _set_all)(struct SNAME *_bitset_);
|
||||
bool CMC_(PFX, _clear_all)(struct SNAME *_bitset_);
|
||||
bool CMC_(PFX, _flip_all)(struct SNAME *_bitset_);
|
||||
/* Element Access */
|
||||
bool CMC_(PFX, _get)(struct SNAME *_bitset_, size_t bit_index);
|
||||
/* Collection State */
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_bitset_, size_t n_bits);
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* BitSet Structure */
|
||||
struct SNAME
|
||||
{
|
||||
/* Dynamic Array of Bits */
|
||||
cmc_bitset_word *buffer;
|
||||
/* Current array capacity */
|
||||
size_t capacity;
|
||||
/* Currently used bits */
|
||||
/* This should always be true: */
|
||||
/* capacity - count < sizeof(cmc_bitset_word) * CHAR_BIT */
|
||||
size_t count;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Custom allocation functions */
|
||||
CMC_ALLOC_TYPE alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* alloc.h
|
||||
*
|
||||
* Creation Date: 24/05/2020
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CMC_COR_ALLOC_H
|
||||
#define CMC_COR_ALLOC_H
|
||||
|
||||
#ifndef CMC_NO_ALLOC
|
||||
|
||||
#ifdef CMC_CAMEL_CASE
|
||||
#define CMC_ALLOC_NODE_NAME CMCAllocNode
|
||||
#else
|
||||
#define CMC_ALLOC_NODE_NAME cmc_alloc_node
|
||||
#endif
|
||||
|
||||
#include "core.h"
|
||||
/**
|
||||
* struct cmc_alloc_node
|
||||
*
|
||||
* Custom allocation node. Allows collections to use custom allocation
|
||||
* functions. The cmc_alloc_node_default is the default heap allocator provided
|
||||
* by the standard library.
|
||||
*/
|
||||
|
||||
#define CMC_ALLOC_TYPE struct CMC_ALLOC_NODE_NAME *
|
||||
|
||||
static struct CMC_ALLOC_NODE_NAME
|
||||
{
|
||||
void *(*malloc)(size_t);
|
||||
void *(*calloc)(size_t, size_t);
|
||||
void *(*realloc)(void *, size_t);
|
||||
void (*free)(void *);
|
||||
} CMC_UNUSED cmc_alloc_node_default = { malloc, calloc, realloc, free };
|
||||
|
||||
#endif /* CMC_NO_ALLOC */
|
||||
|
||||
#endif /* CMC_COR_ALLOC_H */
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* bitset.h
|
||||
*
|
||||
* Creation Date: 20/05/2020
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Things commonly used by bitset collections.
|
||||
*/
|
||||
|
||||
#ifndef CMC_COR_BITSET_H
|
||||
#define CMC_COR_BITSET_H
|
||||
|
||||
#include "core.h"
|
||||
|
||||
/* Defines the underlaying data type for the bitset array */
|
||||
/* Possible values: uint64_t, uint32_t, uint16_t, uint8_t, size_t */
|
||||
#ifndef CMC_BITSET_WORD_TYPE
|
||||
#define CMC_BITSET_WORD_TYPE uint32_t
|
||||
#endif /* CMC_BITSET_WORD_TYPE */
|
||||
|
||||
typedef CMC_BITSET_WORD_TYPE cmc_bitset_word;
|
||||
|
||||
/**
|
||||
* cmc_bidx_to_widx
|
||||
*
|
||||
* Translates a bit index to a word index
|
||||
*/
|
||||
static inline size_t cmc_bidx_to_widx(size_t idx)
|
||||
{
|
||||
/* Calculate how many shifts based on the size of cmc_bitset_word */
|
||||
static const size_t shift = ((sizeof(cmc_bitset_word) * 8) >> 6) > 0 ? 6
|
||||
: ((sizeof(cmc_bitset_word) * 8) >> 5) > 0 ? 5
|
||||
: ((sizeof(cmc_bitset_word) * 8) >> 4) > 0 ? 4
|
||||
: 3;
|
||||
|
||||
return idx >> shift;
|
||||
}
|
||||
|
||||
#endif /* CMC_COR_BITSET_H */
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* callbacks.h
|
||||
*
|
||||
* Creation Date: 24/05/2020
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CMC_COR_CALLBACKS_H
|
||||
#define CMC_COR_CALLBACKS_H
|
||||
|
||||
typedef void (*cmc_callback)(const char func_name[], void *self);
|
||||
#define CMC_CALLBACK_TYPE cmc_callback
|
||||
|
||||
#ifdef CMC_CALLBACKS
|
||||
|
||||
#define CMC_CALLBACKS_DECL cmc_callback callbacks
|
||||
#define CMC_CALLBACKS_MAYBE_UNUSED(param)
|
||||
#define CMC_CALLBACKS_GET(ds) (ds)->callbacks
|
||||
#define CMC_CALLBACKS_ASSIGN(ds, cb) CMC_CALLBACKS_GET(ds) = cb
|
||||
#define CMC_CALLBACKS_CALL(ds) \
|
||||
if (CMC_CALLBACKS_GET(ds)) \
|
||||
CMC_CALLBACKS_GET(ds)(__func__, (void *)ds);
|
||||
|
||||
#else
|
||||
|
||||
#define CMC_CALLBACKS_DECL
|
||||
#define CMC_CALLBACKS_MAYBE_UNUSED(param) CMC_UNUSED_PARAM(param) /* Prevent -Wunused-parameter */
|
||||
#define CMC_CALLBACKS_GET(ds) NULL /* Helps with compatibility */
|
||||
#define CMC_CALLBACKS_ASSIGN(ds, cb)
|
||||
#define CMC_CALLBACKS_CALL(ds)
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* CMC_COR_CALLBACKS_H */
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* core.h
|
||||
*
|
||||
* Creation Date: 17/03/2020
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Core includes and macros for the entire library.
|
||||
*
|
||||
* Here you will find:
|
||||
* - CMC_
|
||||
* - CMC_TO_STRING
|
||||
* - CMC_INTERNAL_PREFIX_[ITER|NODE|ENTRY|FKEY|FVAL]
|
||||
* - CMC_DEF_[ITER|NODE|ENTRY|FKEY|FVAL]
|
||||
*/
|
||||
|
||||
#ifndef CMC_COR_CORE_H
|
||||
#define CMC_COR_CORE_H
|
||||
|
||||
#ifndef CMC_NO_IMPORTS
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#endif /* CMC_NO_IMPORTS */
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define CMC_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define CMC_UNUSED
|
||||
#endif
|
||||
|
||||
#define CMC_UNUSED_PARAM(param) ((void)param)
|
||||
|
||||
#define CMC__(A, B) A##B
|
||||
#define CMC_(A, B) CMC__(A, B)
|
||||
|
||||
#define CMC_TO_STRING_(X) #X
|
||||
#define CMC_TO_STRING(X) CMC_TO_STRING_(X)
|
||||
|
||||
#include "alloc.h"
|
||||
#include "callbacks.h"
|
||||
#include "dev.h"
|
||||
#include "flags.h"
|
||||
#include "ftable.h"
|
||||
|
||||
#if defined(CMC_CAMEL_CASE)
|
||||
#define CMC_INTERNAL_PREFIX_ITER Iter
|
||||
#define CMC_INTERNAL_PREFIX_NODE Node
|
||||
#define CMC_INTERNAL_PREFIX_ENTRY Entry
|
||||
#define CMC_INTERNAL_PREFIX_FVAL FVal
|
||||
#define CMC_INTERNAL_PREFIX_FKEY FKey
|
||||
#else
|
||||
#define CMC_INTERNAL_PREFIX_ITER _iter
|
||||
#define CMC_INTERNAL_PREFIX_NODE _node
|
||||
#define CMC_INTERNAL_PREFIX_ENTRY _entry
|
||||
#define CMC_INTERNAL_PREFIX_FVAL _fval
|
||||
#define CMC_INTERNAL_PREFIX_FKEY _fkey
|
||||
#endif
|
||||
|
||||
#define CMC_DEF_ITER(SNAME) CMC_(SNAME, CMC_INTERNAL_PREFIX_ITER)
|
||||
#define CMC_DEF_NODE(SNAME) CMC_(SNAME, CMC_INTERNAL_PREFIX_NODE)
|
||||
#define CMC_DEF_ENTRY(SNAME) CMC_(SNAME, CMC_INTERNAL_PREFIX_ENTRY)
|
||||
#define CMC_DEF_FVAL(SNAME) CMC_(SNAME, CMC_INTERNAL_PREFIX_FVAL)
|
||||
#define CMC_DEF_FKEY(SNAME) CMC_(SNAME, CMC_INTERNAL_PREFIX_FKEY)
|
||||
|
||||
#endif /* CMC_COR_CORE_H */
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* dev.h
|
||||
*
|
||||
* Creation Date: 01/02/2023
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CMC_COR_DEV_H
|
||||
#define CMC_COR_DEV_H
|
||||
|
||||
/**
|
||||
* Macros for tracing and debugging data structures when CMC_DEV is enabled
|
||||
*/
|
||||
|
||||
#ifndef CMC_DEV_FCALL
|
||||
#define CMC_DEV_FCALL cmc_log_trace("fcall")
|
||||
#endif
|
||||
|
||||
#endif /* CMC_COR_DEV_H */
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* flags.h
|
||||
*
|
||||
* Creation Date: 14/05/2020
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CMC_COR_FLAGS_H
|
||||
#define CMC_COR_FLAGS_H
|
||||
|
||||
#include "core.h"
|
||||
|
||||
/**
|
||||
* enum cmc_flags
|
||||
*
|
||||
* Defines common error codes used by the entire library.
|
||||
*/
|
||||
// clang-format off
|
||||
enum cmc_flags
|
||||
{
|
||||
CMC_FLAG_OK = 0, // No errors
|
||||
CMC_FLAG_ALLOC = 1, // Allocation failed
|
||||
CMC_FLAG_EMPTY = 2, // The collection is empty when it should not
|
||||
CMC_FLAG_NOT_FOUND = 3, // Key or value not found
|
||||
CMC_FLAG_INVALID = 4, // Invalid argument or operation
|
||||
CMC_FLAG_RANGE = 5, // Index out of range
|
||||
CMC_FLAG_DUPLICATE = 6, // Duplicate key or value
|
||||
CMC_FLAG_ERROR = 7, // Generic error, usually caused by algorithm error
|
||||
CMC_FLAG_THREAD = 8, // Generic error regarding threads
|
||||
CMC_FLAG_MUTEX = 9, // Generic error regarding mutexes
|
||||
CMC_FLAG_FULL = 10, // When a collection that doesn't resize is full
|
||||
CMC_FLAG_FTABLE = 11, // When a required ftable function is missing
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
/**
|
||||
* cmc_flags_to_str
|
||||
*
|
||||
* Maps the error codes to their character representation.
|
||||
*/
|
||||
CMC_UNUSED static const char *cmc_flags_to_str[12] = {
|
||||
"OK", "ALLOC", "EMPTY", "NOT_FOUND", "INVALID", "RANGE", "DUPLICATE", "ERROR", "THREAD", "MUTEX", "FULL", "FTABLE"
|
||||
};
|
||||
|
||||
#endif /* CMC_COR_FLAGS_H */
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ftable.h
|
||||
*
|
||||
* Creation Date: 27/05/2020
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Type definitions for Functions Tables.
|
||||
*/
|
||||
|
||||
#ifndef CMC_COR_FTABLE_H
|
||||
#define CMC_COR_FTABLE_H
|
||||
|
||||
/**
|
||||
* Where T can either be K or V
|
||||
*/
|
||||
#define CMC_DEF_FTAB_CMP(T) int (*cmp)(T, T)
|
||||
#define CMC_DEF_FTAB_CPY(T) T (*cpy)(T)
|
||||
#define CMC_DEF_FTAB_STR(T) bool (*str)(FILE *, T)
|
||||
#define CMC_DEF_FTAB_FREE(T) void (*free)(T)
|
||||
#define CMC_DEF_FTAB_HASH(T) size_t (*hash)(T)
|
||||
#define CMC_DEF_FTAB_PRI(T) int (*pri)(T, T)
|
||||
|
||||
#endif /* CMC_COR_FTABLE_H */
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* hashtable.h
|
||||
*
|
||||
* Creation Date: 17/03/2020
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Things commonly used by hashtable-based collections.
|
||||
*/
|
||||
|
||||
#ifndef CMC_COR_HASHTABLE_H
|
||||
#define CMC_COR_HASHTABLE_H
|
||||
|
||||
#include "core.h"
|
||||
|
||||
/**
|
||||
* CMC_ENTRY_DELETED
|
||||
*
|
||||
* Defines a pointer to an entry that has been deleted
|
||||
*/
|
||||
#define CMC_ENTRY_DELETED ((void *)1)
|
||||
|
||||
/**
|
||||
* enum cmc_entry_state
|
||||
*
|
||||
* Defines the three possible states for a node on a flat hashtable.
|
||||
*/
|
||||
enum cmc_entry_state
|
||||
{
|
||||
CMC_ES_DELETED = -1,
|
||||
CMC_ES_EMPTY = 0,
|
||||
CMC_ES_FILLED = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* static const size_t cmc_hashtable_primes[59]
|
||||
*
|
||||
* Prime numbers used to define a capacity for the hashtables for better
|
||||
* hashing.
|
||||
*/
|
||||
// clang-format off
|
||||
static const size_t cmc_hashtable_primes[] = {
|
||||
/* < 1e3 */
|
||||
53, 97, 191, 383, 769,
|
||||
/* < 1e4 */
|
||||
1531, 3067, 6143,
|
||||
/* < 1e5 */
|
||||
12289, 24571, 49157, 98299,
|
||||
/* < 1e6 */
|
||||
196613, 393209, 786431,
|
||||
/* < 1e7 */
|
||||
1572869, 3145721, 6291449,
|
||||
/* < 1e8 */
|
||||
12582917, 25165813, 50331653,
|
||||
/* < 1e9 */
|
||||
100663291, 201326611, 402653189, 805306357,
|
||||
/* < 1e10 */
|
||||
1610612741, 3221225473, 6442450939,
|
||||
/* < 1e11 */
|
||||
12884901893, 25769803799, 51539607551,
|
||||
/* < 1e12 */
|
||||
103079215111, 206158430209, 412316860441, 824633720831,
|
||||
/* < 1e13 */
|
||||
1649267441651, 3298534883309, 6597069766657,
|
||||
/* < 1e14 */
|
||||
13194139533299, 26388279066623, 52776558133303,
|
||||
/* < 1e15 */
|
||||
105553116266489, 211106232532969, 422212465066001, 844424930131963,
|
||||
/* < 1e16 */
|
||||
1688849860263953, 3377699720527861, 6755399441055731,
|
||||
/* < 1e17 */
|
||||
13510798882111483, 27021597764222939, 54043195528445957,
|
||||
/* < 1e18 */
|
||||
108086391056891903, 216172782113783773, 432345564227567621, 864691128455135207,
|
||||
/* < 1e19 */
|
||||
1729382256910270481, 3458764513820540933, 6917529027641081903,
|
||||
/* < 1e20 */
|
||||
13835058055282163729llu,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
#endif /* CMC_COR_HASHTABLE_H */
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* heap.h
|
||||
*
|
||||
* Creation Date: 01/06/2020
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Things commonly used by heap collections.
|
||||
*/
|
||||
|
||||
#ifndef CMC_COR_HEAP_H
|
||||
#define CMC_COR_HEAP_H
|
||||
|
||||
/**
|
||||
* enum cmc_heap_order
|
||||
*
|
||||
* Defines the two possible heaps:
|
||||
* - Max Heap has the greatest element at the top
|
||||
* - Min Heap has the smallest element at the top
|
||||
*/
|
||||
enum cmc_heap_order
|
||||
{
|
||||
CMC_MAX_HEAP = 1,
|
||||
CMC_MIN_HEAP = -1
|
||||
};
|
||||
|
||||
#endif /* CMC_COR_HEAP_H */
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* undef.h
|
||||
*
|
||||
* Creation Date: 12/01/2023
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Common undefs
|
||||
*/
|
||||
|
||||
/* You never want these to fallthrough since they should be unique for each collection */
|
||||
#undef PFX
|
||||
#undef SNAME
|
||||
|
||||
#ifndef CMC_ARGS_FALLTHROUGH
|
||||
|
||||
#undef CMC_DEV
|
||||
#undef CMC_SAC
|
||||
|
||||
#ifndef CMC_ARGS_KEY_FALLTHROUGH
|
||||
#undef K
|
||||
#endif
|
||||
|
||||
#ifndef CMC_ARGS_VAL_FALLTHROUGH
|
||||
#undef V
|
||||
#endif
|
||||
|
||||
#undef SIZE
|
||||
|
||||
#ifndef CMC_EXT_FALLTHROUGH
|
||||
#undef CMC_EXT_INIT
|
||||
#undef CMC_EXT_ITER
|
||||
#undef CMC_EXT_NODE
|
||||
#undef CMC_EXT_SEQ
|
||||
#undef CMC_EXT_SETF
|
||||
#undef CMC_EXT_STR
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* deque.h
|
||||
*
|
||||
* Creation Date: 20/03/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Deque
|
||||
*
|
||||
* A Deque (double-ended queue) is a linear data structure that is able to add
|
||||
* or remove elements from both ends. It can also be thought of a double-ended
|
||||
* stack since you can push and pop elements from two ends. The Deque can also
|
||||
* be used as a Queue.
|
||||
*
|
||||
* There is no random access for a Deque. The only elements accessible are the
|
||||
* front element and the back.
|
||||
*
|
||||
* Implementation
|
||||
*
|
||||
* This implementation uses a circular buffer (ring buffer or cyclic buffer) in
|
||||
* order to operate on O(1) for push and pop on either ends (only case where it
|
||||
* takes longer than O(1) is when the buffer is reallocated). If it was
|
||||
* implemented as a regular array, adding or removing elements from the front
|
||||
* would take O(N) due to the need to shift all elements in the deque.
|
||||
*/
|
||||
|
||||
#include "cor/core.h"
|
||||
|
||||
#ifdef CMC_DEV
|
||||
#include "utl/log.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* V - deque data type
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
|
||||
/* Structs definition */
|
||||
#include "cmc/deque/struct.h"
|
||||
|
||||
/* Function declaration */
|
||||
#include "cmc/deque/header.h"
|
||||
|
||||
/* Function implementation */
|
||||
#include "cmc/deque/code.h"
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* INIT - Initializes the struct on the stack
|
||||
* ITER - Deque iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_DEQUE_PARTS INIT, ITER, STR
|
||||
/**/
|
||||
#include "cmc/deque/ext/struct.h"
|
||||
/**/
|
||||
#include "cmc/deque/ext/header.h"
|
||||
/**/
|
||||
#include "cmc/deque/ext/code.h"
|
||||
|
||||
#include "cor/undef.h"
|
||||
@@ -0,0 +1,461 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
/* None */
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _new_custom)(capacity, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (capacity < 1)
|
||||
return NULL;
|
||||
|
||||
if (!f_val)
|
||||
return NULL;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
struct SNAME *_deque_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_deque_)
|
||||
return NULL;
|
||||
|
||||
_deque_->buffer = alloc->calloc(capacity, sizeof(V));
|
||||
|
||||
if (!_deque_->buffer)
|
||||
{
|
||||
alloc->free(_deque_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_deque_->capacity = capacity;
|
||||
_deque_->count = 0;
|
||||
_deque_->front = 0;
|
||||
_deque_->back = 0;
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
_deque_->f_val = f_val;
|
||||
_deque_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_deque_, callbacks);
|
||||
|
||||
return _deque_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_deque_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_deque_->f_val->free)
|
||||
{
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
|
||||
{
|
||||
_deque_->f_val->free(_deque_->buffer[i]);
|
||||
|
||||
i = (i + 1) % _deque_->capacity;
|
||||
}
|
||||
}
|
||||
|
||||
memset(_deque_->buffer, 0, sizeof(V) * _deque_->capacity);
|
||||
|
||||
_deque_->count = 0;
|
||||
_deque_->front = 0;
|
||||
_deque_->back = 0;
|
||||
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_deque_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_deque_->f_val->free)
|
||||
{
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
|
||||
{
|
||||
_deque_->f_val->free(_deque_->buffer[i]);
|
||||
|
||||
i = (i + 1) % _deque_->capacity;
|
||||
}
|
||||
}
|
||||
|
||||
_deque_->alloc->free(_deque_->buffer);
|
||||
_deque_->alloc->free(_deque_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_deque_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_deque_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_deque_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_deque_, callbacks);
|
||||
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _push_front)(struct SNAME *_deque_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _full)(_deque_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_deque_, _deque_->capacity * 2))
|
||||
return false;
|
||||
}
|
||||
|
||||
_deque_->front = (_deque_->front == 0) ? _deque_->capacity - 1 : _deque_->front - 1;
|
||||
|
||||
_deque_->buffer[_deque_->front] = value;
|
||||
|
||||
_deque_->count++;
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _push_back)(struct SNAME *_deque_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _full)(_deque_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_deque_, _deque_->capacity * 2))
|
||||
return false;
|
||||
}
|
||||
|
||||
_deque_->buffer[_deque_->back] = value;
|
||||
|
||||
_deque_->back = (_deque_->back == _deque_->capacity - 1) ? 0 : _deque_->back + 1;
|
||||
|
||||
_deque_->count++;
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _pop_front)(struct SNAME *_deque_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_deque_))
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
_deque_->buffer[_deque_->front] = (V){ 0 };
|
||||
|
||||
_deque_->front = (_deque_->front == _deque_->capacity - 1) ? 0 : _deque_->front + 1;
|
||||
|
||||
_deque_->count--;
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _pop_back)(struct SNAME *_deque_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_deque_))
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
_deque_->back = (_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1;
|
||||
|
||||
_deque_->buffer[_deque_->back] = (V){ 0 };
|
||||
|
||||
_deque_->count--;
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _front)(struct SNAME *_deque_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_deque_))
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_);
|
||||
|
||||
return _deque_->buffer[_deque_->front];
|
||||
}
|
||||
|
||||
V CMC_(PFX, _back)(struct SNAME *_deque_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_deque_))
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_);
|
||||
|
||||
return _deque_->buffer[(_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1];
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_deque_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = false;
|
||||
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
|
||||
{
|
||||
if (_deque_->f_val->cmp(_deque_->buffer[i], value) == 0)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
i = (i + 1) % _deque_->capacity;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_deque_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _deque_->count == 0;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _full)(struct SNAME *_deque_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _deque_->count >= _deque_->capacity;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_deque_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _deque_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_deque_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _deque_->capacity;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_deque_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _deque_->flag;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_deque_, size_t capacity)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_deque_->capacity == capacity)
|
||||
goto success;
|
||||
|
||||
if (capacity < _deque_->count)
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
V *new_buffer = _deque_->alloc->malloc(sizeof(V) * capacity);
|
||||
|
||||
if (!new_buffer)
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_ALLOC;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
|
||||
{
|
||||
new_buffer[j] = _deque_->buffer[i];
|
||||
|
||||
i = (i + 1) % _deque_->capacity;
|
||||
}
|
||||
|
||||
_deque_->alloc->free(_deque_->buffer);
|
||||
|
||||
_deque_->buffer = new_buffer;
|
||||
_deque_->capacity = capacity;
|
||||
_deque_->front = 0;
|
||||
_deque_->back = _deque_->count;
|
||||
|
||||
success:
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_deque_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *result = CMC_(PFX, _new_custom)(_deque_->capacity, _deque_->f_val, _deque_->alloc, NULL);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(result, _deque_->callbacks);
|
||||
|
||||
if (_deque_->f_val->cpy)
|
||||
{
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
|
||||
{
|
||||
result->buffer[j] = _deque_->f_val->cpy(_deque_->buffer[i]);
|
||||
|
||||
i = (i + 1) % _deque_->capacity;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
|
||||
{
|
||||
result->buffer[j] = _deque_->buffer[i];
|
||||
|
||||
i = (i + 1) % _deque_->capacity;
|
||||
}
|
||||
}
|
||||
|
||||
result->count = _deque_->count;
|
||||
result->front = 0;
|
||||
result->back = _deque_->count;
|
||||
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_deque1_, struct SNAME *_deque2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_deque1_->flag = CMC_FLAG_OK;
|
||||
_deque2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_deque1_->count != _deque2_->count)
|
||||
return false;
|
||||
|
||||
size_t i, j, k;
|
||||
for (i = _deque1_->front, j = _deque2_->front, k = 0; k < _deque1_->count; k++)
|
||||
{
|
||||
if (_deque1_->f_val->cmp(_deque1_->buffer[i], _deque2_->buffer[j]) != 0)
|
||||
return false;
|
||||
|
||||
i = (i + 1) % _deque1_->capacity;
|
||||
j = (j + 1) % _deque2_->capacity;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,430 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _init_custom)(capacity, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
struct SNAME _deque_ = { 0 };
|
||||
|
||||
if (capacity < 1)
|
||||
return _deque_;
|
||||
|
||||
if (!f_val)
|
||||
return _deque_;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
_deque_.buffer = alloc->calloc(capacity, sizeof(V));
|
||||
|
||||
if (!_deque_.buffer)
|
||||
return _deque_;
|
||||
|
||||
_deque_.capacity = capacity;
|
||||
_deque_.count = 0;
|
||||
_deque_.front = 0;
|
||||
_deque_.back = 0;
|
||||
_deque_.flag = CMC_FLAG_OK;
|
||||
_deque_.f_val = f_val;
|
||||
_deque_.alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(&_deque_, callbacks);
|
||||
|
||||
return _deque_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _release)(struct SNAME _deque_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_deque_.f_val->free)
|
||||
{
|
||||
for (size_t i = _deque_.front, j = 0; j < _deque_.count; j++)
|
||||
{
|
||||
_deque_.f_val->free(_deque_.buffer[i]);
|
||||
|
||||
i = (i + 1) % _deque_.capacity;
|
||||
}
|
||||
}
|
||||
|
||||
_deque_.alloc->free(_deque_.buffer);
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Deque bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = target->front;
|
||||
iter.index = 0;
|
||||
iter.start = true;
|
||||
iter.end = CMC_(PFX, _empty)(target);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
if (iter.target->back == 0)
|
||||
iter.cursor = iter.target->capacity - 1;
|
||||
else
|
||||
iter.cursor = iter.target->back - 1;
|
||||
|
||||
iter.index = iter.target->count - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
}
|
||||
|
||||
iter.start = CMC_(PFX, _empty)(target);
|
||||
iter.end = true;
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->target->front;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
if (iter->target->back == 0)
|
||||
iter->cursor = iter->target->capacity - 1;
|
||||
else
|
||||
iter->cursor = iter->target->back - 1;
|
||||
|
||||
iter->index = iter->target->count - 1;
|
||||
|
||||
iter->start = false;
|
||||
iter->end = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor = (iter->cursor + 1) % (iter->target->capacity);
|
||||
iter->index++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1;
|
||||
iter->index--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->index += steps;
|
||||
iter->cursor = (iter->cursor + steps) % iter->target->capacity;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index < steps)
|
||||
return false;
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->index -= steps;
|
||||
|
||||
/* Prevent underflow */
|
||||
if (iter->cursor < steps)
|
||||
iter->cursor += iter->target->capacity;
|
||||
|
||||
iter->cursor -= steps;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at the */
|
||||
/* given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->index > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
|
||||
else if (iter->index < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (V){ 0 };
|
||||
|
||||
return iter->target->buffer[iter->cursor];
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return NULL;
|
||||
|
||||
return &(iter->target->buffer[iter->cursor]);
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return iter->index;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_deque_, FILE *fptr)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *d_ = _deque_;
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"front:%" PRIuMAX ", "
|
||||
"back:%" PRIuMAX ", "
|
||||
"flag:%d, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), d_, d_->buffer, d_->capacity, d_->count, d_->front,
|
||||
d_->back, d_->flag, d_->f_val, d_->alloc, CMC_CALLBACKS_GET(d_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_deque_, FILE *fptr, const char *start, const char *separator, const char *end)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
|
||||
{
|
||||
if (!_deque_->f_val->str(fptr, _deque_->buffer[i]))
|
||||
return false;
|
||||
|
||||
i = (i + 1) % _deque_->capacity;
|
||||
|
||||
if (j + 1 < _deque_->count)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks);
|
||||
void CMC_(PFX, _release)(struct SNAME _deque_);
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Deque bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* Iterator Initialization */
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
/* Debug prints the struct to fptr */
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_deque_, FILE *fptr);
|
||||
/* Prints each item in the deque as an array */
|
||||
bool CMC_(PFX, _print)(struct SNAME *_deque_, FILE *fptr, const char *start, const char *separator, const char *end);
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Deque bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* Deque Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target deque */
|
||||
struct SNAME *target;
|
||||
/* Cursor's position (index) */
|
||||
size_t cursor;
|
||||
/* Keeps track of relative index to the iteration of elements */
|
||||
size_t index;
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks);
|
||||
void CMC_(PFX, _clear)(struct SNAME *_deque_);
|
||||
void CMC_(PFX, _free)(struct SNAME *_deque_);
|
||||
/* Customization of Allocation and Callbacks */
|
||||
void CMC_(PFX, _customize)(struct SNAME *_deque_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _push_front)(struct SNAME *_deque_, V value);
|
||||
bool CMC_(PFX, _push_back)(struct SNAME *_deque_, V value);
|
||||
bool CMC_(PFX, _pop_front)(struct SNAME *_deque_);
|
||||
bool CMC_(PFX, _pop_back)(struct SNAME *_deque_);
|
||||
/* Element Access */
|
||||
V CMC_(PFX, _front)(struct SNAME *_deque_);
|
||||
V CMC_(PFX, _back)(struct SNAME *_deque_);
|
||||
/* Collection State */
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_deque_, V value);
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_deque_);
|
||||
bool CMC_(PFX, _full)(struct SNAME *_deque_);
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_deque_);
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_deque_);
|
||||
int CMC_(PFX, _flag)(struct SNAME *_deque_);
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_deque_, size_t capacity);
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_deque_);
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_deque1_, struct SNAME *_deque2_);
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
struct SNAME
|
||||
{
|
||||
/* Dynamic circular array of elements */
|
||||
V *buffer;
|
||||
/* Current circular array capacity */
|
||||
size_t capacity;
|
||||
/* Current amount of elements */
|
||||
size_t count;
|
||||
/* Index representing the front of the deque */
|
||||
size_t front;
|
||||
/* Index representing the back of the deque */
|
||||
size_t back;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Functions Table */
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val;
|
||||
/* Custom allocation functions */
|
||||
CMC_ALLOC_TYPE alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* hashbidimap.h
|
||||
*
|
||||
* Creation Date: 26/09/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* HashBidiMap
|
||||
*
|
||||
* A bidirectional map is a map that allows you to create a bijection in both
|
||||
* directions between two sets of elements (K <-> V). It is possible to retrieve
|
||||
* the value using a key or retrieve a key using a value. The naming (key and
|
||||
* value) is simply used to differentiate between one set of elements and the
|
||||
* other set of elements.
|
||||
*
|
||||
* Implementation
|
||||
*
|
||||
* This implementation uses two arrays of pointers to an entry containing both
|
||||
* the key and the value.
|
||||
*/
|
||||
|
||||
#include "cor/core.h"
|
||||
#include "cor/hashtable.h"
|
||||
|
||||
#ifdef CMC_DEV
|
||||
#include "utl/log.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* K - hashbidimap key data type
|
||||
* V - hashbidimap value data type
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
|
||||
/* Structs definition */
|
||||
#include "cmc/hashbidimap/struct.h"
|
||||
|
||||
/* Function declaration */
|
||||
#include "cmc/hashbidimap/header.h"
|
||||
|
||||
/* Function implementation */
|
||||
#include "cmc/hashbidimap/code.h"
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* INIT - Initializes the struct on the stack
|
||||
* ITER - Hashbidimap iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_HASHBIDIMAP_PARTS INIT, ITER, STR
|
||||
/**/
|
||||
#include "cmc/hashbidimap/ext/struct.h"
|
||||
/**/
|
||||
#include "cmc/hashbidimap/ext/header.h"
|
||||
/**/
|
||||
#include "cmc/hashbidimap/ext/code.h"
|
||||
|
||||
#include "cor/undef.h"
|
||||
@@ -0,0 +1,961 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value);
|
||||
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_key)(struct SNAME *_map_, K key);
|
||||
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_val)(struct SNAME *_map_, V val);
|
||||
static struct CMC_DEF_ENTRY(SNAME) *
|
||||
*CMC_(PFX, _impl_add_entry_to_key)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry);
|
||||
static struct CMC_DEF_ENTRY(SNAME) *
|
||||
*CMC_(PFX, _impl_add_entry_to_val)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry);
|
||||
static size_t CMC_(PFX, _impl_calculate_size)(size_t required);
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _new_custom)(capacity, load, f_key, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (capacity == 0 || load <= 0 || load >= 1)
|
||||
return NULL;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= (double)UINTMAX_MAX * load)
|
||||
return NULL;
|
||||
|
||||
if (!f_key || !f_val)
|
||||
return NULL;
|
||||
|
||||
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_map_)
|
||||
return NULL;
|
||||
|
||||
_map_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]));
|
||||
|
||||
if (!_map_->buffer)
|
||||
{
|
||||
alloc->free(_map_->buffer);
|
||||
alloc->free(_map_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_map_->count = 0;
|
||||
_map_->capacity = real_capacity;
|
||||
_map_->load = load;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
_map_->f_key = f_key;
|
||||
_map_->f_val = f_val;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
_map_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
|
||||
|
||||
return _map_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i][0];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
if (_map_->f_key->free)
|
||||
_map_->f_key->free(entry->key);
|
||||
if (_map_->f_val->free)
|
||||
_map_->f_val->free(entry->value);
|
||||
|
||||
_map_->alloc->free(entry);
|
||||
}
|
||||
|
||||
_map_->buffer[i][0] = NULL;
|
||||
_map_->buffer[i][1] = NULL;
|
||||
}
|
||||
|
||||
_map_->count = 0;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_(PFX, _clear)(_map_);
|
||||
|
||||
_map_->alloc->free(_map_->buffer);
|
||||
_map_->alloc->free(_map_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_map_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_map_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _full)(_map_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_map_, _map_->capacity + 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry_by_key)(_map_, key) != NULL ||
|
||||
CMC_(PFX, _impl_get_entry_by_val)(_map_, value) != NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_DUPLICATE;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_new_entry)(_map_, key, value);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) **key_entry = CMC_(PFX, _impl_add_entry_to_key)(_map_, entry);
|
||||
struct CMC_DEF_ENTRY(SNAME) **val_entry = CMC_(PFX, _impl_add_entry_to_val)(_map_, entry);
|
||||
|
||||
if (!key_entry || !val_entry)
|
||||
{
|
||||
if (key_entry)
|
||||
*key_entry = CMC_ENTRY_DELETED;
|
||||
if (val_entry)
|
||||
*val_entry = CMC_ENTRY_DELETED;
|
||||
|
||||
_map_->alloc->free(entry);
|
||||
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_map_->count++;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _update_key)(struct SNAME *_map_, V val, K new_key)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
|
||||
|
||||
val_entry = CMC_(PFX, _impl_get_entry_by_val)(_map_, val);
|
||||
|
||||
if (!val_entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The mapping val -> new_key is already true */
|
||||
if (_map_->f_key->cmp(new_key, (*val_entry)->key) == 0)
|
||||
goto success;
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry_by_key)(_map_, new_key) != NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_DUPLICATE;
|
||||
return false;
|
||||
}
|
||||
|
||||
key_entry = (*val_entry)->ref[0];
|
||||
|
||||
if (!key_entry || *key_entry != *val_entry)
|
||||
{
|
||||
/* Should never happen */
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Remove entry from key buffer and add it again with new key */
|
||||
struct CMC_DEF_ENTRY(SNAME) *to_add = *key_entry;
|
||||
K tmp_key = to_add->key;
|
||||
to_add->key = new_key;
|
||||
|
||||
*key_entry = CMC_ENTRY_DELETED;
|
||||
|
||||
if (!CMC_(PFX, _impl_add_entry_to_key)(_map_, to_add))
|
||||
{
|
||||
/* Revert changes */
|
||||
to_add->key = tmp_key;
|
||||
*key_entry = to_add;
|
||||
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
success:
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _update_val)(struct SNAME *_map_, K key, V new_val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
|
||||
|
||||
key_entry = CMC_(PFX, _impl_get_entry_by_key)(_map_, key);
|
||||
|
||||
if (!key_entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The mapping key -> new_val is already true */
|
||||
if (_map_->f_val->cmp(new_val, (*key_entry)->value) == 0)
|
||||
goto success;
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry_by_val)(_map_, new_val) != NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_DUPLICATE;
|
||||
return false;
|
||||
}
|
||||
|
||||
val_entry = (*key_entry)->ref[1];
|
||||
|
||||
if (!val_entry || *val_entry != *key_entry)
|
||||
{
|
||||
/* Should never happen */
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Remove entry from value buffer and add it again with new value */
|
||||
struct CMC_DEF_ENTRY(SNAME) *to_add = *val_entry;
|
||||
V tmp_val = to_add->value;
|
||||
to_add->value = new_val;
|
||||
|
||||
*val_entry = CMC_ENTRY_DELETED;
|
||||
|
||||
if (!CMC_(PFX, _impl_add_entry_to_val)(_map_, to_add))
|
||||
{
|
||||
/* Revert changes */
|
||||
to_add->value = tmp_val;
|
||||
*val_entry = to_add;
|
||||
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
success:
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _remove_by_key)(struct SNAME *_map_, K key, K *out_key, V *out_val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
|
||||
|
||||
key_entry = CMC_(PFX, _impl_get_entry_by_key)(_map_, key);
|
||||
|
||||
if (!key_entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
val_entry = (*key_entry)->ref[1];
|
||||
|
||||
if (!val_entry || *val_entry != *key_entry)
|
||||
{
|
||||
/* Should never happen */
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out_key)
|
||||
*out_key = (*key_entry)->key;
|
||||
if (out_val)
|
||||
*out_val = (*key_entry)->value;
|
||||
|
||||
_map_->alloc->free(*key_entry);
|
||||
|
||||
*key_entry = CMC_ENTRY_DELETED;
|
||||
*val_entry = CMC_ENTRY_DELETED;
|
||||
|
||||
_map_->count--;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _remove_by_val)(struct SNAME *_map_, V val, K *out_key, V *out_val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
|
||||
|
||||
val_entry = CMC_(PFX, _impl_get_entry_by_val)(_map_, val);
|
||||
|
||||
if (!val_entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
key_entry = (*val_entry)->ref[0];
|
||||
|
||||
if (!key_entry || *key_entry != *val_entry)
|
||||
{
|
||||
/* Should never happen */
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out_key)
|
||||
*out_key = (*val_entry)->key;
|
||||
if (out_val)
|
||||
*out_val = (*val_entry)->value;
|
||||
|
||||
_map_->alloc->free(*val_entry);
|
||||
|
||||
*key_entry = CMC_ENTRY_DELETED;
|
||||
*val_entry = CMC_ENTRY_DELETED;
|
||||
|
||||
_map_->count--;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
K CMC_(PFX, _get_key)(struct SNAME *_map_, V val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) **entry = CMC_(PFX, _impl_get_entry_by_val)(_map_, val);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return (K){ 0 };
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return (*entry)->key;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _get_val)(struct SNAME *_map_, K key)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) **entry = CMC_(PFX, _impl_get_entry_by_key)(_map_, key);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return (*entry)->value;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains_key)(struct SNAME *_map_, K key)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = CMC_(PFX, _impl_get_entry_by_key)(_map_, key) != NULL;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains_val)(struct SNAME *_map_, V val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = CMC_(PFX, _impl_get_entry_by_val)(_map_, val) != NULL;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->count == 0;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _full)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return (double)_map_->capacity * _map_->load <= (double)_map_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->capacity;
|
||||
}
|
||||
|
||||
double CMC_(PFX, _load)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->load;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->flag;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_map_->capacity == capacity)
|
||||
goto success;
|
||||
|
||||
if (_map_->capacity > capacity / _map_->load)
|
||||
goto success;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= (double)UINTMAX_MAX * _map_->load)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Calculate required capacity based on the prime numbers */
|
||||
size_t new_cap = CMC_(PFX, _impl_calculate_size)(capacity);
|
||||
|
||||
/* Not possible to shrink with current available prime numbers */
|
||||
if (new_cap < _map_->count / _map_->load)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* No callbacks since _new_map_ is just a temporary hashtable */
|
||||
struct SNAME *_new_map_ =
|
||||
CMC_(PFX, _new_custom)(capacity, _map_->load, _map_->f_key, _map_->f_val, _map_->alloc, NULL);
|
||||
|
||||
if (!_new_map_)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ALLOC;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
if (scan && scan != CMC_ENTRY_DELETED)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) **e1 = CMC_(PFX, _impl_add_entry_to_key)(_new_map_, scan);
|
||||
struct CMC_DEF_ENTRY(SNAME) **e2 = CMC_(PFX, _impl_add_entry_to_val)(_new_map_, scan);
|
||||
|
||||
if (!e1 || !e2)
|
||||
{
|
||||
/* Prevent the map from freeing the data */
|
||||
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ 0 };
|
||||
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
|
||||
|
||||
_map_->alloc->free(_new_map_->buffer);
|
||||
_map_->alloc->free(_new_map_);
|
||||
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_new_map_->count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (_map_->count != _new_map_->count)
|
||||
{
|
||||
/* Prevent the map from freeing the data */
|
||||
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ 0 };
|
||||
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
|
||||
|
||||
_map_->alloc->free(_new_map_->buffer);
|
||||
_map_->alloc->free(_new_map_);
|
||||
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * (*tmp_buff)[2] = _map_->buffer;
|
||||
|
||||
_map_->buffer = _new_map_->buffer;
|
||||
_map_->capacity = _new_map_->capacity;
|
||||
|
||||
_map_->alloc->free(tmp_buff);
|
||||
_map_->alloc->free(_new_map_);
|
||||
|
||||
success:
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* TODO this function can be optimized */
|
||||
struct SNAME *result = CMC_(PFX, _new_custom)(_map_->capacity * _map_->load, _map_->load, _map_->f_key,
|
||||
_map_->f_val, _map_->alloc, NULL);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(result, _map_->callbacks);
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
if (scan && scan != CMC_ENTRY_DELETED)
|
||||
{
|
||||
K tmp_key;
|
||||
V tmp_val;
|
||||
|
||||
if (_map_->f_key->cpy)
|
||||
tmp_key = _map_->f_key->cpy(scan->key);
|
||||
else
|
||||
tmp_key = scan->key;
|
||||
|
||||
if (_map_->f_val->cpy)
|
||||
tmp_val = _map_->f_val->cpy(scan->value);
|
||||
else
|
||||
tmp_val = scan->value;
|
||||
|
||||
/* TODO treat the possible errors */
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_new_entry)(result, tmp_key, tmp_val);
|
||||
|
||||
CMC_(PFX, _impl_add_entry_to_key)(result, entry);
|
||||
CMC_(PFX, _impl_add_entry_to_val)(result, entry);
|
||||
|
||||
result->count++;
|
||||
}
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_map1_->flag = CMC_FLAG_OK;
|
||||
_map2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_map1_->count != _map2_->count)
|
||||
return false;
|
||||
|
||||
struct SNAME *_mapA_;
|
||||
struct SNAME *_mapB_;
|
||||
|
||||
if (_map1_->capacity < _map2_->capacity)
|
||||
{
|
||||
_mapA_ = _map1_;
|
||||
_mapB_ = _map2_;
|
||||
}
|
||||
else
|
||||
{
|
||||
_mapA_ = _map2_;
|
||||
_mapB_ = _map1_;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _mapA_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _mapA_->buffer[i][0];
|
||||
|
||||
if (scan && scan != CMC_ENTRY_DELETED)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) **entry_B = CMC_(PFX, _impl_get_entry_by_key)(_mapB_, scan->key);
|
||||
|
||||
if (!entry_B)
|
||||
return false;
|
||||
|
||||
if (_mapA_->f_val->cmp((*entry_B)->value, scan->value) != 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->alloc->malloc(sizeof(struct CMC_DEF_ENTRY(SNAME)));
|
||||
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
entry->key = key;
|
||||
entry->value = value;
|
||||
entry->dist[0] = 0;
|
||||
entry->dist[1] = 0;
|
||||
entry->ref[0] = NULL;
|
||||
entry->ref[1] = NULL;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_key)(struct SNAME *_map_, K key)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
size_t pos = hash % _map_->capacity;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = _map_->buffer[pos][0];
|
||||
|
||||
while (target != NULL)
|
||||
{
|
||||
if (target != CMC_ENTRY_DELETED && _map_->f_key->cmp(target->key, key) == 0)
|
||||
return &(_map_->buffer[pos % _map_->capacity][0]);
|
||||
|
||||
pos++;
|
||||
target = _map_->buffer[pos % _map_->capacity][0];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_val)(struct SNAME *_map_, V val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
size_t hash = _map_->f_val->hash(val);
|
||||
size_t pos = hash % _map_->capacity;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = _map_->buffer[pos][1];
|
||||
|
||||
while (target != NULL)
|
||||
{
|
||||
if (target != CMC_ENTRY_DELETED && _map_->f_val->cmp(target->value, val) == 0)
|
||||
return &(_map_->buffer[pos % _map_->capacity][1]);
|
||||
|
||||
pos++;
|
||||
target = _map_->buffer[pos % _map_->capacity][1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) *
|
||||
*CMC_(PFX, _impl_add_entry_to_key)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) **to_return = NULL;
|
||||
|
||||
size_t hash = _map_->f_key->hash(entry->key);
|
||||
size_t original_pos = hash % _map_->capacity;
|
||||
size_t pos = original_pos;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) **scan = &(_map_->buffer[hash % _map_->capacity][0]);
|
||||
|
||||
if (*scan == NULL)
|
||||
{
|
||||
*scan = entry;
|
||||
|
||||
entry->ref[0] = scan;
|
||||
|
||||
return scan;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
pos++;
|
||||
scan = &(_map_->buffer[pos % _map_->capacity][0]);
|
||||
|
||||
if (*scan == NULL || *scan == CMC_ENTRY_DELETED)
|
||||
{
|
||||
if (!to_return)
|
||||
to_return = scan;
|
||||
|
||||
*scan = entry;
|
||||
entry->ref[0] = scan;
|
||||
entry->dist[0] = pos - original_pos;
|
||||
|
||||
return to_return;
|
||||
}
|
||||
else if ((*scan)->dist[0] < pos - original_pos)
|
||||
{
|
||||
if (!to_return)
|
||||
to_return = scan;
|
||||
|
||||
size_t tmp_dist = (*scan)->dist[0];
|
||||
entry->dist[0] = pos - original_pos;
|
||||
original_pos = pos - tmp_dist;
|
||||
|
||||
entry->ref[0] = scan;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *_tmp_ = *scan;
|
||||
*scan = entry;
|
||||
entry = _tmp_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) *
|
||||
*CMC_(PFX, _impl_add_entry_to_val)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) **to_return = NULL;
|
||||
|
||||
size_t hash = _map_->f_val->hash(entry->value);
|
||||
size_t original_pos = hash % _map_->capacity;
|
||||
size_t pos = original_pos;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) **scan = &(_map_->buffer[hash % _map_->capacity][1]);
|
||||
|
||||
if (*scan == NULL)
|
||||
{
|
||||
*scan = entry;
|
||||
|
||||
entry->ref[1] = scan;
|
||||
|
||||
return scan;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
pos++;
|
||||
scan = &(_map_->buffer[pos % _map_->capacity][1]);
|
||||
|
||||
if (*scan == NULL || *scan == CMC_ENTRY_DELETED)
|
||||
{
|
||||
if (!to_return)
|
||||
to_return = scan;
|
||||
|
||||
*scan = entry;
|
||||
entry->ref[1] = scan;
|
||||
entry->dist[1] = pos - original_pos;
|
||||
|
||||
return to_return;
|
||||
}
|
||||
else if ((*scan)->dist[1] < pos - original_pos)
|
||||
{
|
||||
if (!to_return)
|
||||
to_return = scan;
|
||||
|
||||
size_t tmp_dist = (*scan)->dist[1];
|
||||
entry->dist[1] = pos - original_pos;
|
||||
original_pos = pos - tmp_dist;
|
||||
|
||||
entry->ref[1] = scan;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *_tmp_ = *scan;
|
||||
*scan = entry;
|
||||
entry = _tmp_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t CMC_(PFX, _impl_calculate_size)(size_t required)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
|
||||
|
||||
if (cmc_hashtable_primes[count - 1] < required)
|
||||
return required;
|
||||
|
||||
size_t i = 0;
|
||||
while (cmc_hashtable_primes[i] < required)
|
||||
i++;
|
||||
|
||||
return cmc_hashtable_primes[i];
|
||||
}
|
||||
@@ -0,0 +1,473 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _init_custom)(capacity, load, f_key, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
struct SNAME _map_ = { 0 };
|
||||
|
||||
if (capacity == 0 || load <= 0 || load >= 1)
|
||||
return _map_;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= (double)UINTMAX_MAX * load)
|
||||
return _map_;
|
||||
|
||||
if (!f_key || !f_val)
|
||||
return _map_;
|
||||
|
||||
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
_map_.buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]));
|
||||
|
||||
if (!_map_.buffer)
|
||||
return _map_;
|
||||
|
||||
_map_.count = 0;
|
||||
_map_.capacity = real_capacity;
|
||||
_map_.load = load;
|
||||
_map_.flag = CMC_FLAG_OK;
|
||||
_map_.f_key = f_key;
|
||||
_map_.f_val = f_val;
|
||||
_map_.flag = CMC_FLAG_OK;
|
||||
_map_.alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(&_map_, callbacks);
|
||||
|
||||
return _map_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _release)(struct SNAME _map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_(PFX, _clear)(&_map_);
|
||||
|
||||
_map_.alloc->free(_map_.buffer);
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashbidimap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) * CMC_(PFX, _iter_new)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) *iter = target->alloc->malloc(sizeof(struct CMC_DEF_ITER(SNAME)));
|
||||
|
||||
if (!iter)
|
||||
return NULL;
|
||||
|
||||
CMC_(PFX, _iter_init)(iter, target);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _iter_free)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
iter->target->alloc->free(iter);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _iter_init)(struct CMC_DEF_ITER(SNAME) * iter, struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
memset(iter, 0, sizeof(struct CMC_DEF_ITER(SNAME)));
|
||||
|
||||
iter->target = target;
|
||||
iter->start = true;
|
||||
iter->end = CMC_(PFX, _empty)(target);
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i][0];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
iter->first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter->cursor = iter->first;
|
||||
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i - 1][0];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
iter->last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->first;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->last;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = false;
|
||||
iter->end = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = iter->target->buffer[iter->cursor][0];
|
||||
|
||||
iter->index++;
|
||||
|
||||
while (1)
|
||||
{
|
||||
iter->cursor++;
|
||||
scan = iter->target->buffer[iter->cursor][0];
|
||||
|
||||
if (scan != NULL && scan != CMC_ENTRY_DELETED)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = iter->target->buffer[iter->cursor][0];
|
||||
|
||||
iter->index--;
|
||||
|
||||
while (1)
|
||||
{
|
||||
iter->cursor--;
|
||||
scan = iter->target->buffer[iter->cursor][0];
|
||||
|
||||
if (scan != NULL && scan != CMC_ENTRY_DELETED)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_next)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index < steps)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_prev)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at */
|
||||
/* the given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->index > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
|
||||
else if (iter->index < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->target->flag = CMC_FLAG_EMPTY;
|
||||
return (K){ 0 };
|
||||
}
|
||||
|
||||
return iter->target->buffer[iter->cursor][0]->key;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->target->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
return iter->target->buffer[iter->cursor][0]->value;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return iter->index;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *m_ = _map_;
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s, %s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"load:%lf, "
|
||||
"flag:%d, "
|
||||
"f_key:%p, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(K), CMC_TO_STRING(V), m_, m_->buffer, m_->capacity,
|
||||
m_->count, m_->load, m_->flag, m_->f_key, m_->f_val, m_->alloc, CMC_CALLBACKS_GET(m_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
|
||||
const char *key_val_sep)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
size_t last = 0;
|
||||
for (size_t i = _map_->capacity; i > 0; i--)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i - 1][0];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i][0];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
if (!_map_->f_key->str(fptr, entry->key))
|
||||
return false;
|
||||
|
||||
fprintf(fptr, "%s", key_val_sep);
|
||||
|
||||
if (!_map_->f_val->str(fptr, entry->value))
|
||||
return false;
|
||||
|
||||
if (i + 1 < last)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks);
|
||||
void CMC_(PFX, _release)(struct SNAME _map_);
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashbidimap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* Iterator Functions */
|
||||
/* Iterator Allocation and Deallocation */
|
||||
struct CMC_DEF_ITER(SNAME) * CMC_(PFX, _iter_new)(struct SNAME *target);
|
||||
void CMC_(PFX, _iter_free)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Initialization */
|
||||
void CMC_(PFX, _iter_init)(struct CMC_DEF_ITER(SNAME) * iter, struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
void CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
void CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
/* Debug prints the struct to fptr */
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr);
|
||||
/* Prints each item in the hashbidimap as an array */
|
||||
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
|
||||
const char *key_val_sep);
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashbidimap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* HashBidiMap Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target hashbidimap */
|
||||
struct SNAME *target;
|
||||
/* Cursor's position (index) */
|
||||
size_t cursor;
|
||||
/* Keeps track of relative index to the iteration of elements */
|
||||
size_t index;
|
||||
/* The index of the first element */
|
||||
size_t first;
|
||||
/* The index of the last element */
|
||||
size_t last;
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Key struct function table */
|
||||
struct CMC_DEF_FKEY(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(K);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(K);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(K);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(K);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(K);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(K);
|
||||
};
|
||||
|
||||
/* Value struct function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks);
|
||||
void CMC_(PFX, _clear)(struct SNAME *_map_);
|
||||
void CMC_(PFX, _free)(struct SNAME *_map_);
|
||||
/* Customization of Allocation and Callbacks */
|
||||
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value);
|
||||
bool CMC_(PFX, _update_key)(struct SNAME *_map_, V val, K new_key);
|
||||
bool CMC_(PFX, _update_val)(struct SNAME *_map_, K key, V new_val);
|
||||
bool CMC_(PFX, _remove_by_key)(struct SNAME *_map_, K key, K *out_key, V *out_val);
|
||||
bool CMC_(PFX, _remove_by_val)(struct SNAME *_map_, V val, K *out_key, V *out_val);
|
||||
/* Element Access */
|
||||
K CMC_(PFX, _get_key)(struct SNAME *_map_, V val);
|
||||
V CMC_(PFX, _get_val)(struct SNAME *_map_, K key);
|
||||
/* Collection State */
|
||||
bool CMC_(PFX, _contains_key)(struct SNAME *_map_, K key);
|
||||
bool CMC_(PFX, _contains_val)(struct SNAME *_map_, V val);
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_map_);
|
||||
bool CMC_(PFX, _full)(struct SNAME *_map_);
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_map_);
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_map_);
|
||||
double CMC_(PFX, _load)(struct SNAME *_map_);
|
||||
int CMC_(PFX, _flag)(struct SNAME *_map_);
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity);
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_);
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_);
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
struct SNAME
|
||||
{
|
||||
/* Array 0 is K -> V and array 1 is V -> K */
|
||||
struct CMC_DEF_ENTRY(SNAME) * (*buffer)[2];
|
||||
/* Current arrays capacity */
|
||||
size_t capacity;
|
||||
/* Current amount of keys */
|
||||
size_t count;
|
||||
/* Load factor in range (0.0, 1.0) */
|
||||
double load;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Key function table */
|
||||
struct CMC_DEF_FKEY(SNAME) * f_key;
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val;
|
||||
/* Custom allocation functions */
|
||||
CMC_ALLOC_TYPE alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
/* Methods */
|
||||
/* Returns an iterator to the start of the hashbidimap */
|
||||
struct CMC_DEF_ITER(SNAME) (*it_start)(struct SNAME *);
|
||||
/* Returns an iterator to the end of the hashbidimap */
|
||||
struct CMC_DEF_ITER(SNAME) (*it_end)(struct SNAME *);
|
||||
};
|
||||
|
||||
/* HashBidiMap Entry */
|
||||
struct CMC_DEF_ENTRY(SNAME)
|
||||
{
|
||||
/* Entry Key */
|
||||
K key;
|
||||
/* Entry Value */
|
||||
V value;
|
||||
/* The distance of this node to its original position */
|
||||
/* dist[0] is relative to K -> V */
|
||||
/* dist[1] is relative to V -> K */
|
||||
size_t dist[2];
|
||||
/* References to this node in the hashbidimap buffer. Used to */
|
||||
/* prevent searching for this node twice for update() and */
|
||||
/* remove(). Increases memory overhead but reduces execution time */
|
||||
/* ref[0] is relative to K -> V */
|
||||
/* ref[1] is relative to V -> K */
|
||||
struct CMC_DEF_ENTRY(SNAME) * *ref[2];
|
||||
};
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* hashmap.h
|
||||
*
|
||||
* Creation Date: 03/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* HashMap
|
||||
*
|
||||
* A HashMap is an implementation of a Map with unique keys, where every key is
|
||||
* mapped to a value. The keys are not sorted. It is implemented as a flat
|
||||
* hashtable with linear probing and robin hood hashing.
|
||||
*/
|
||||
|
||||
#include "cor/core.h"
|
||||
#include "cor/hashtable.h"
|
||||
|
||||
#ifdef CMC_DEV
|
||||
#include "utl/log.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* K - hashmap key data type
|
||||
* V - hashmap value data type
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
|
||||
/* Structs definition */
|
||||
#include "cmc/hashmap/struct.h"
|
||||
|
||||
/* Function declaration */
|
||||
#include "cmc/hashmap/header.h"
|
||||
|
||||
/* Function implementation */
|
||||
#include "cmc/hashmap/code.h"
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* INIT - Initializes the struct on the stack
|
||||
* ITER - hashmap iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_HASHMAP_PARTS INIT, ITER, STR
|
||||
/**/
|
||||
#include "cmc/hashmap/ext/struct.h"
|
||||
/**/
|
||||
#include "cmc/hashmap/ext/header.h"
|
||||
/**/
|
||||
#include "cmc/hashmap/ext/code.h"
|
||||
|
||||
#include "cor/undef.h"
|
||||
@@ -0,0 +1,728 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key);
|
||||
static size_t CMC_(PFX, _impl_calculate_size)(size_t required);
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
return CMC_(PFX, _new_custom)(capacity, load, f_key, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (capacity == 0 || load <= 0 || load >= 1)
|
||||
return NULL;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= (double)UINTMAX_MAX * load)
|
||||
return NULL;
|
||||
|
||||
if (!f_key || !f_val)
|
||||
return NULL;
|
||||
|
||||
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_map_)
|
||||
return NULL;
|
||||
|
||||
_map_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME)));
|
||||
|
||||
if (!_map_->buffer)
|
||||
{
|
||||
alloc->free(_map_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_map_->count = 0;
|
||||
_map_->capacity = real_capacity;
|
||||
_map_->load = load;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
_map_->f_key = f_key;
|
||||
_map_->f_val = f_val;
|
||||
_map_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
|
||||
|
||||
return _map_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_map_->f_key->free || _map_->f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_->buffer[i]);
|
||||
|
||||
if (entry->state == CMC_ES_FILLED)
|
||||
{
|
||||
if (_map_->f_key->free)
|
||||
_map_->f_key->free(entry->key);
|
||||
if (_map_->f_val->free)
|
||||
_map_->f_val->free(entry->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(_map_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _map_->capacity);
|
||||
|
||||
_map_->count = 0;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_map_->f_key->free || _map_->f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_->buffer[i]);
|
||||
|
||||
if (entry->state == CMC_ES_FILLED)
|
||||
{
|
||||
if (_map_->f_key->free)
|
||||
_map_->f_key->free(entry->key);
|
||||
if (_map_->f_val->free)
|
||||
_map_->f_val->free(entry->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_map_->alloc->free(_map_->buffer);
|
||||
_map_->alloc->free(_map_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_map_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_map_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _full)(_map_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_map_, _map_->capacity + 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry)(_map_, key) != NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_DUPLICATE;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
size_t original_pos = hash % _map_->capacity;
|
||||
size_t pos = original_pos;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = &(_map_->buffer[pos]);
|
||||
|
||||
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
target->key = key;
|
||||
target->value = value;
|
||||
target->dist = 0;
|
||||
target->state = CMC_ES_FILLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
pos++;
|
||||
target = &(_map_->buffer[pos % _map_->capacity]);
|
||||
|
||||
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
target->key = key;
|
||||
target->value = value;
|
||||
target->dist = pos - original_pos;
|
||||
target->state = CMC_ES_FILLED;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (target->dist < pos - original_pos)
|
||||
{
|
||||
K tmp_k = target->key;
|
||||
V tmp_v = target->value;
|
||||
size_t tmp_dist = target->dist;
|
||||
|
||||
target->key = key;
|
||||
target->value = value;
|
||||
target->dist = pos - original_pos;
|
||||
|
||||
key = tmp_k;
|
||||
value = tmp_v;
|
||||
original_pos = pos - tmp_dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_map_->count++;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (old_value)
|
||||
*old_value = entry->value;
|
||||
|
||||
entry->value = new_value;
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_map_, key);
|
||||
|
||||
if (result == NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out_value)
|
||||
*out_value = result->value;
|
||||
|
||||
result->key = (K){ 0 };
|
||||
result->value = (V){ 0 };
|
||||
result->dist = 0;
|
||||
result->state = CMC_ES_DELETED;
|
||||
|
||||
_map_->count--;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
K max_key = (K){ 0 };
|
||||
V max_val = (V){ 0 };
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
if (_map_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
max_key = _map_->buffer[i].key;
|
||||
max_val = _map_->buffer[i].value;
|
||||
first = false;
|
||||
}
|
||||
else if (_map_->f_key->cmp(_map_->buffer[i].key, max_key) > 0)
|
||||
{
|
||||
max_key = _map_->buffer[i].key;
|
||||
max_val = _map_->buffer[i].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (key)
|
||||
*key = max_key;
|
||||
if (value)
|
||||
*value = max_val;
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
K min_key = (K){ 0 };
|
||||
V min_val = (V){ 0 };
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
if (_map_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
min_key = _map_->buffer[i].key;
|
||||
min_val = _map_->buffer[i].value;
|
||||
first = false;
|
||||
}
|
||||
else if (_map_->f_key->cmp(_map_->buffer[i].key, min_key) < 0)
|
||||
{
|
||||
min_key = _map_->buffer[i].key;
|
||||
min_val = _map_->buffer[i].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (key)
|
||||
*key = min_key;
|
||||
if (value)
|
||||
*value = min_val;
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _get)(struct SNAME *_map_, K key)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return entry->value;
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return &(entry->value);
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = CMC_(PFX, _impl_get_entry)(_map_, key) != NULL;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->count == 0;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _full)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return (double)_map_->capacity * _map_->load <= (double)_map_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->capacity;
|
||||
}
|
||||
|
||||
double CMC_(PFX, _load)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->load;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->flag;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_map_->capacity == capacity)
|
||||
goto success;
|
||||
|
||||
if (_map_->capacity > capacity / _map_->load)
|
||||
goto success;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= (double)UINTMAX_MAX * _map_->load)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Calculate required capacity based on the prime numbers */
|
||||
size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity);
|
||||
|
||||
/* Not possible to shrink with current available prime numbers */
|
||||
if (theoretical_size < _map_->count / _map_->load)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* No callbacks since _new_map_ is just a temporary hashtable */
|
||||
struct SNAME *_new_map_ =
|
||||
CMC_(PFX, _new_custom)(capacity, _map_->load, _map_->f_key, _map_->f_val, _map_->alloc, NULL);
|
||||
|
||||
if (!_new_map_)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ALLOC;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
if (_map_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
K key = _map_->buffer[i].key;
|
||||
V value = _map_->buffer[i].value;
|
||||
|
||||
/* TODO check this for possible errors */
|
||||
CMC_(PFX, _insert)(_new_map_, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Unlikely */
|
||||
if (_map_->count != _new_map_->count)
|
||||
{
|
||||
CMC_(PFX, _free)(_new_map_);
|
||||
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *tmp_b = _map_->buffer;
|
||||
_map_->buffer = _new_map_->buffer;
|
||||
_new_map_->buffer = tmp_b;
|
||||
|
||||
size_t tmp_c = _map_->capacity;
|
||||
_map_->capacity = _new_map_->capacity;
|
||||
_new_map_->capacity = tmp_c;
|
||||
|
||||
/* Prevent the map from freeing the data */
|
||||
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ 0 };
|
||||
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
|
||||
|
||||
CMC_(PFX, _free)(_new_map_);
|
||||
|
||||
success:
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *result = CMC_(PFX, _new_custom)(_map_->capacity * _map_->load, _map_->load, _map_->f_key,
|
||||
_map_->f_val, _map_->alloc, NULL);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(result, _map_->callbacks);
|
||||
|
||||
if (_map_->f_key->cpy || _map_->f_val->cpy)
|
||||
{
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = &(_map_->buffer[i]);
|
||||
|
||||
if (scan->state != CMC_ES_EMPTY)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = &(result->buffer[i]);
|
||||
|
||||
if (scan->state == CMC_ES_DELETED)
|
||||
target->state = CMC_ES_DELETED;
|
||||
else
|
||||
{
|
||||
target->state = scan->state;
|
||||
target->dist = scan->dist;
|
||||
|
||||
if (_map_->f_key->cpy)
|
||||
target->key = _map_->f_key->cpy(scan->key);
|
||||
else
|
||||
target->key = scan->key;
|
||||
|
||||
if (_map_->f_val->cpy)
|
||||
target->value = _map_->f_val->cpy(scan->value);
|
||||
else
|
||||
target->value = scan->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
memcpy(result->buffer, _map_->buffer, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _map_->capacity);
|
||||
|
||||
result->count = _map_->count;
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_map1_->flag = CMC_FLAG_OK;
|
||||
_map2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_map1_->count != _map2_->count)
|
||||
return false;
|
||||
|
||||
/* Optimize loop using the smallest hashtable */
|
||||
struct SNAME *_map_a_;
|
||||
struct SNAME *_map_b_;
|
||||
|
||||
_map_a_ = _map1_->capacity < _map2_->capacity ? _map1_ : _map2_;
|
||||
_map_b_ = _map_a_ == _map1_ ? _map2_ : _map1_;
|
||||
|
||||
for (size_t i = 0; i < _map_a_->capacity; i++)
|
||||
{
|
||||
if (_map_a_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry_a = &(_map_a_->buffer[i]);
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry_b = CMC_(PFX, _impl_get_entry)(_map_b_, entry_a->key);
|
||||
|
||||
if (!entry_b)
|
||||
return false;
|
||||
|
||||
if (_map_a_->f_val->cmp(entry_a->value, entry_b->value) != 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
size_t pos = hash % _map_->capacity;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = &(_map_->buffer[pos]);
|
||||
|
||||
while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
if (target->state != CMC_ES_DELETED && _map_->f_key->cmp(target->key, key) == 0)
|
||||
return target;
|
||||
|
||||
pos++;
|
||||
target = &(_map_->buffer[pos % _map_->capacity]);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t CMC_(PFX, _impl_calculate_size)(size_t required)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
|
||||
|
||||
if (cmc_hashtable_primes[count - 1] < required)
|
||||
return required;
|
||||
|
||||
size_t i = 0;
|
||||
while (cmc_hashtable_primes[i] < required)
|
||||
i++;
|
||||
|
||||
return cmc_hashtable_primes[i];
|
||||
}
|
||||
@@ -0,0 +1,514 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _init_custom)(capacity, load, f_key, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
struct SNAME _map_ = { 0 };
|
||||
|
||||
if (capacity == 0 || load <= 0 || load >= 1)
|
||||
return _map_;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= (double)UINTMAX_MAX * load)
|
||||
return _map_;
|
||||
|
||||
if (!f_key || !f_val)
|
||||
return _map_;
|
||||
|
||||
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
_map_.buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME)));
|
||||
|
||||
if (!_map_.buffer)
|
||||
return _map_;
|
||||
|
||||
_map_.count = 0;
|
||||
_map_.capacity = real_capacity;
|
||||
_map_.load = load;
|
||||
_map_.flag = CMC_FLAG_OK;
|
||||
_map_.f_key = f_key;
|
||||
_map_.f_val = f_val;
|
||||
_map_.alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(&_map_, callbacks);
|
||||
|
||||
return _map_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _release)(struct SNAME _map_)
|
||||
{
|
||||
if (_map_.f_key->free || _map_.f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _map_.capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_.buffer[i]);
|
||||
|
||||
if (entry->state == CMC_ES_FILLED)
|
||||
{
|
||||
if (_map_.f_key->free)
|
||||
_map_.f_key->free(entry->key);
|
||||
if (_map_.f_val->free)
|
||||
_map_.f_val->free(entry->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_map_.alloc->free(_map_.buffer);
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashmap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
iter.first = 0;
|
||||
iter.last = 0;
|
||||
iter.start = true;
|
||||
iter.end = CMC_(PFX, _empty)(target);
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
if (target->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter.cursor = iter.first;
|
||||
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
if (target->buffer[i - 1].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
iter.first = 0;
|
||||
iter.last = 0;
|
||||
iter.start = CMC_(PFX, _empty)(target);
|
||||
iter.end = true;
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
if (target->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
if (target->buffer[i - 1].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter.cursor = iter.last;
|
||||
iter.index = target->count - 1;
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->first;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->last;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
iter->end = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
iter->index++;
|
||||
|
||||
while (1)
|
||||
{
|
||||
iter->cursor++;
|
||||
scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
if (scan->state == CMC_ES_FILLED)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
iter->index--;
|
||||
|
||||
while (1)
|
||||
{
|
||||
iter->cursor--;
|
||||
scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
if (scan->state == CMC_ES_FILLED)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_next)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index < steps)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_prev)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at the */
|
||||
/* given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->index > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
|
||||
else if (iter->index < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (K){ 0 };
|
||||
|
||||
return iter->target->buffer[iter->cursor].key;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (V){ 0 };
|
||||
|
||||
return iter->target->buffer[iter->cursor].value;
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return NULL;
|
||||
|
||||
return &(iter->target->buffer[iter->cursor].value);
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return iter->index;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *m_ = _map_;
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s, %s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"load:%lf, "
|
||||
"flag:%d, "
|
||||
"f_key:%p, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(K), CMC_TO_STRING(V), m_, m_->buffer, m_->capacity,
|
||||
m_->count, m_->load, m_->flag, m_->f_key, m_->f_val, m_->alloc, CMC_CALLBACKS_GET(m_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
|
||||
const char *key_val_sep)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
size_t last = 0;
|
||||
for (size_t i = _map_->capacity; i > 0; i--)
|
||||
{
|
||||
if ((_map_->buffer[i - 1]).state == CMC_ES_FILLED)
|
||||
{
|
||||
last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_->buffer[i]);
|
||||
|
||||
if (entry->state == CMC_ES_FILLED)
|
||||
{
|
||||
if (!_map_->f_key->str(fptr, entry->key))
|
||||
return false;
|
||||
|
||||
fprintf(fptr, "%s", key_val_sep);
|
||||
|
||||
if (!_map_->f_val->str(fptr, entry->value))
|
||||
return false;
|
||||
|
||||
if (i + 1 < last)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks);
|
||||
void CMC_(PFX, _release)(struct SNAME _map_);
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashmap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* Iterator Initialization */
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr);
|
||||
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
|
||||
const char *key_val_sep);
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashmap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* HashMap Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target hashmap */
|
||||
struct SNAME *target;
|
||||
/* Cursor's position (index) */
|
||||
size_t cursor;
|
||||
/* Keeps track of relative index to the iteration of elements */
|
||||
size_t index;
|
||||
/* The index of the first element */
|
||||
size_t first;
|
||||
/* The index of the last element */
|
||||
size_t last;
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Key struct function table */
|
||||
struct CMC_DEF_FKEY(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(K);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(K);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(K);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(K);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(K);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(K);
|
||||
};
|
||||
|
||||
/* Value struct function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks);
|
||||
void CMC_(PFX, _clear)(struct SNAME *_map_);
|
||||
void CMC_(PFX, _free)(struct SNAME *_map_);
|
||||
/* Customization of Allocation and Callbacks */
|
||||
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value);
|
||||
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value);
|
||||
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value);
|
||||
/* Element Access */
|
||||
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value);
|
||||
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value);
|
||||
V CMC_(PFX, _get)(struct SNAME *_map_, K key);
|
||||
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key);
|
||||
/* Collection State */
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key);
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_map_);
|
||||
bool CMC_(PFX, _full)(struct SNAME *_map_);
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_map_);
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_map_);
|
||||
double CMC_(PFX, _load)(struct SNAME *_map_);
|
||||
int CMC_(PFX, _flag)(struct SNAME *_map_);
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity);
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_);
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_);
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* HashMap Structure */
|
||||
struct SNAME
|
||||
{
|
||||
/* Array of Entries */
|
||||
struct CMC_DEF_ENTRY(SNAME) * buffer;
|
||||
/* Current array capacity */
|
||||
size_t capacity;
|
||||
/* Current amount of keys */
|
||||
size_t count;
|
||||
/* Load factor in range (0.0, 1.0) */
|
||||
double load;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Key function table */
|
||||
struct CMC_DEF_FKEY(SNAME) * f_key;
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val;
|
||||
/* Custom allocation functions */
|
||||
CMC_ALLOC_TYPE alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
|
||||
/* HashMap Entry */
|
||||
struct CMC_DEF_ENTRY(SNAME)
|
||||
{
|
||||
/* Entry Key */
|
||||
K key;
|
||||
/* Entry Value */
|
||||
V value;
|
||||
/* The distance of this node to its original position, used by */
|
||||
/* robin-hood hashing */
|
||||
size_t dist;
|
||||
/* The sate of this node (DELETED, EMPTY, FILLED) */
|
||||
enum cmc_entry_state state;
|
||||
};
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* hashmultimap.h
|
||||
*
|
||||
* Creation Date: 26/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* HashMultiMap
|
||||
*
|
||||
* The HashMultiMap is a Map that allows for multiple keys. This is a data
|
||||
* structure that has a very narrow usage. A Map (either TreeMap or HashMap) can
|
||||
* also work like a HashMultiMap if a certain key is mapped to another
|
||||
* collection.
|
||||
*
|
||||
* Map<K = int, V = List<int>> maps an integer to a list of integer.
|
||||
* HashMultiMap<K = int, V = int> maps many integer keys to integer values.
|
||||
*
|
||||
* The difference is that in a HashMultiMap you can store keys that are the same
|
||||
* but might be different instances of the same value. This is also relevant if
|
||||
* your data type is more complex like a struct where its ID is the same but
|
||||
* some other members of this data type are different.
|
||||
*
|
||||
* Implementation
|
||||
*
|
||||
* The map uses separate chaining and robin hood hashing. Its internal buffer
|
||||
* is made of a pair of pointers to entries that represent a linked list. So
|
||||
* accessing map->buffer[0] would give the first pair of pointers. Each entry
|
||||
* has both a pointer to a previous entry and a next entry. This design choice
|
||||
* was made so that every collection in this library has a two-way iterator
|
||||
* with a very few exceptions.
|
||||
*
|
||||
* Each entry is composed of a Key and a Value. Entries with the same key should
|
||||
* always hash to the same linked list. Also, keys that hash to the same bucket
|
||||
* will also be in the same linked list.
|
||||
*
|
||||
* The order of inserting and removing the same keys will behave like a FIFO. So
|
||||
* the first key added will be the first to be removed.
|
||||
*/
|
||||
|
||||
#include "cor/core.h"
|
||||
#include "cor/hashtable.h"
|
||||
|
||||
#ifdef CMC_DEV
|
||||
#include "utl/log.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* K - hashmultimap key data type
|
||||
* V - hashmultimap value data type
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
|
||||
/* Structs definition */
|
||||
#include "cmc/hashmultimap/struct.h"
|
||||
|
||||
/* Function declaration */
|
||||
#include "cmc/hashmultimap/header.h"
|
||||
|
||||
/* Function implementation */
|
||||
#include "cmc/hashmultimap/code.h"
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* INIT - Initializes the struct on the stack
|
||||
* ITER - hashmultimap iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_HASHMULTIMAP_PARTS INIT, ITER, STR
|
||||
/**/
|
||||
#include "cmc/hashmultimap/ext/struct.h"
|
||||
/**/
|
||||
#include "cmc/hashmultimap/ext/header.h"
|
||||
/**/
|
||||
#include "cmc/hashmultimap/ext/code.h"
|
||||
|
||||
#include "cor/undef.h"
|
||||
@@ -0,0 +1,986 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value);
|
||||
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key);
|
||||
size_t CMC_(PFX, _impl_key_count)(struct SNAME *_map_, K key);
|
||||
size_t CMC_(PFX, _impl_calculate_size)(size_t required);
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _new_custom)(capacity, load, f_key, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (capacity == 0 || load <= 0)
|
||||
return NULL;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= (double)UINTMAX_MAX * load)
|
||||
return NULL;
|
||||
|
||||
if (!f_key || !f_val)
|
||||
return NULL;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
|
||||
|
||||
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_map_)
|
||||
return NULL;
|
||||
|
||||
_map_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]));
|
||||
|
||||
if (!_map_->buffer)
|
||||
{
|
||||
alloc->free(_map_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_map_->count = 0;
|
||||
_map_->capacity = real_capacity;
|
||||
_map_->load = load;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
_map_->f_key = f_key;
|
||||
_map_->f_val = f_val;
|
||||
_map_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
|
||||
|
||||
return _map_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
while (scan)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *next = scan->next;
|
||||
|
||||
if (_map_->f_key->free)
|
||||
_map_->f_key->free(scan->key);
|
||||
if (_map_->f_val->free)
|
||||
_map_->f_val->free(scan->value);
|
||||
|
||||
_map_->alloc->free(scan);
|
||||
|
||||
scan = next;
|
||||
}
|
||||
}
|
||||
|
||||
memset(_map_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]) * _map_->capacity);
|
||||
|
||||
_map_->count = 0;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
while (index < _map_->capacity)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[index][0];
|
||||
|
||||
if (scan)
|
||||
{
|
||||
if (scan->next == NULL && scan->prev == NULL)
|
||||
{
|
||||
if (_map_->f_key->free)
|
||||
_map_->f_key->free(scan->key);
|
||||
if (_map_->f_val->free)
|
||||
_map_->f_val->free(scan->value);
|
||||
|
||||
_map_->alloc->free(scan);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (scan)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *tmp = scan;
|
||||
|
||||
scan = scan->next;
|
||||
|
||||
if (_map_->f_key->free)
|
||||
_map_->f_key->free(tmp->key);
|
||||
if (_map_->f_val->free)
|
||||
_map_->f_val->free(tmp->value);
|
||||
|
||||
_map_->alloc->free(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
_map_->alloc->free(_map_->buffer);
|
||||
_map_->alloc->free(_map_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_map_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_map_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _full)(_map_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_map_, _map_->capacity + 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
size_t pos = hash % _map_->capacity;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_new_entry)(_map_, key, value);
|
||||
|
||||
if (_map_->buffer[pos][0] == NULL)
|
||||
{
|
||||
_map_->buffer[pos][0] = entry;
|
||||
_map_->buffer[pos][1] = entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->prev = _map_->buffer[pos][1];
|
||||
|
||||
_map_->buffer[pos][1]->next = entry;
|
||||
_map_->buffer[pos][1] = entry;
|
||||
}
|
||||
|
||||
_map_->count++;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (old_value)
|
||||
*old_value = entry->value;
|
||||
|
||||
entry->value = new_value;
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _update_all)(struct SNAME *_map_, K key, V new_value, V **old_values)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[hash % _map_->capacity][0];
|
||||
|
||||
if (entry == NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (old_values)
|
||||
{
|
||||
size_t total = CMC_(PFX, _impl_key_count)(_map_, key);
|
||||
|
||||
if (total == 0)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*old_values = _map_->alloc->malloc(sizeof(V) * total);
|
||||
|
||||
if (!(*old_values))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ALLOC;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
if (_map_->f_key->cmp(entry->key, key) == 0)
|
||||
{
|
||||
if (old_values)
|
||||
(*old_values)[index] = entry->value;
|
||||
|
||||
index++;
|
||||
entry->value = new_value;
|
||||
}
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) **head = &(_map_->buffer[hash % _map_->capacity][0]);
|
||||
struct CMC_DEF_ENTRY(SNAME) **tail = &(_map_->buffer[hash % _map_->capacity][1]);
|
||||
|
||||
if (*head == NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = *head;
|
||||
|
||||
if (entry->next == NULL && entry->prev == NULL)
|
||||
{
|
||||
if (_map_->f_key->cmp(entry->key, key) == 0)
|
||||
{
|
||||
*head = NULL;
|
||||
*tail = NULL;
|
||||
|
||||
if (out_value)
|
||||
*out_value = entry->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
if (_map_->f_key->cmp(entry->key, key) == 0)
|
||||
{
|
||||
if (*head == entry)
|
||||
*head = entry->next;
|
||||
if (*tail == entry)
|
||||
*tail = entry->prev;
|
||||
|
||||
if (entry->prev)
|
||||
entry->prev->next = entry->next;
|
||||
if (entry->next)
|
||||
entry->next->prev = entry->prev;
|
||||
|
||||
if (out_value)
|
||||
*out_value = entry->value;
|
||||
|
||||
found = true;
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_map_->alloc->free(entry);
|
||||
|
||||
_map_->count--;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _remove_all)(struct SNAME *_map_, K key, V **out_values)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) **head = &(_map_->buffer[hash % _map_->capacity][0]);
|
||||
struct CMC_DEF_ENTRY(SNAME) **tail = &(_map_->buffer[hash % _map_->capacity][1]);
|
||||
|
||||
if (*head == NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (out_values)
|
||||
{
|
||||
size_t total = CMC_(PFX, _impl_key_count)(_map_, key);
|
||||
|
||||
if (total == 0)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out_values = _map_->alloc->malloc(sizeof(V) * total);
|
||||
|
||||
if (!(*out_values))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ALLOC;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = *head;
|
||||
|
||||
if (entry->next == NULL)
|
||||
{
|
||||
*head = NULL;
|
||||
*tail = NULL;
|
||||
|
||||
if (out_values)
|
||||
(*out_values)[index] = entry->value;
|
||||
|
||||
index++;
|
||||
_map_->alloc->free(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (entry)
|
||||
{
|
||||
if (_map_->f_key->cmp(entry->key, key) == 0)
|
||||
{
|
||||
if (*head == entry)
|
||||
*head = entry->next;
|
||||
if (*tail == entry)
|
||||
*tail = entry->prev;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *next = entry->next;
|
||||
|
||||
if (entry->prev)
|
||||
entry->prev->next = entry->next;
|
||||
if (entry->next)
|
||||
entry->next->prev = entry->prev;
|
||||
|
||||
if (out_values)
|
||||
(*out_values)[index] = entry->value;
|
||||
|
||||
index++;
|
||||
_map_->alloc->free(entry);
|
||||
|
||||
entry = next;
|
||||
}
|
||||
else
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
_map_->count -= index;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
K max_key = (K){ 0 };
|
||||
V max_val = (V){ 0 };
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
while (scan)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
max_key = scan->key;
|
||||
max_val = scan->value;
|
||||
|
||||
first = false;
|
||||
}
|
||||
else if (_map_->f_key->cmp(scan->key, max_key) > 0)
|
||||
{
|
||||
max_key = scan->key;
|
||||
max_val = scan->value;
|
||||
}
|
||||
|
||||
scan = scan->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (key)
|
||||
*key = max_key;
|
||||
if (value)
|
||||
*value = max_val;
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
K min_key = (K){ 0 };
|
||||
V min_val = (V){ 0 };
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
while (scan)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
min_key = scan->key;
|
||||
min_val = scan->value;
|
||||
|
||||
first = false;
|
||||
}
|
||||
else if (_map_->f_key->cmp(scan->key, min_key) < 0)
|
||||
{
|
||||
min_key = scan->key;
|
||||
min_val = scan->value;
|
||||
}
|
||||
|
||||
scan = scan->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (key)
|
||||
*key = min_key;
|
||||
if (value)
|
||||
*value = min_val;
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _get)(struct SNAME *_map_, K key)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return entry->value;
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return &(entry->value);
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = CMC_(PFX, _impl_get_entry)(_map_, key) != NULL;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->count == 0;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _full)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return (double)_map_->capacity * _map_->load <= (double)_map_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _key_count)(struct SNAME *_map_, K key)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _impl_key_count)(_map_, key);
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->capacity;
|
||||
}
|
||||
|
||||
double CMC_(PFX, _load)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->load;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _map_->flag;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_map_->capacity == capacity)
|
||||
goto success;
|
||||
|
||||
if (_map_->capacity > capacity / _map_->load)
|
||||
goto success;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= (double)UINTMAX_MAX * _map_->load)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Calculate required capacity based on the prime numbers */
|
||||
size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity);
|
||||
|
||||
/* Not possible to shrink with current available prime numbers */
|
||||
if (theoretical_size < _map_->count / _map_->load)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* No callbacks since _new_map_ is just a temporary hashtable */
|
||||
struct SNAME *_new_map_ =
|
||||
CMC_(PFX, _new_custom)(capacity, _map_->load, _map_->f_key, _map_->f_val, _map_->alloc, NULL);
|
||||
|
||||
if (!_new_map_)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ALLOC;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
while (scan)
|
||||
{
|
||||
/* TODO check for errors */
|
||||
CMC_(PFX, _insert)(_new_map_, scan->key, scan->value);
|
||||
|
||||
scan = scan->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (_map_->count != _new_map_->count)
|
||||
{
|
||||
CMC_(PFX, _free)(_new_map_);
|
||||
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * (*tmp_b)[2] = _map_->buffer;
|
||||
_map_->buffer = _new_map_->buffer;
|
||||
_new_map_->buffer = tmp_b;
|
||||
|
||||
size_t tmp_c = _map_->capacity;
|
||||
_map_->capacity = _new_map_->capacity;
|
||||
_new_map_->capacity = tmp_c;
|
||||
|
||||
/* Prevent the map from freeing the data */
|
||||
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ 0 };
|
||||
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
|
||||
|
||||
CMC_(PFX, _free)(_new_map_);
|
||||
|
||||
success:
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* Callback will be added later */
|
||||
struct SNAME *result = CMC_(PFX, _new_custom)(_map_->capacity * _map_->load, _map_->load, _map_->f_key,
|
||||
_map_->f_val, _map_->alloc, NULL);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
while (scan)
|
||||
{
|
||||
K key;
|
||||
V value;
|
||||
|
||||
if (_map_->f_key->cpy)
|
||||
key = _map_->f_key->cpy(scan->key);
|
||||
else
|
||||
key = scan->key;
|
||||
if (_map_->f_val->cpy)
|
||||
value = _map_->f_val->cpy(scan->value);
|
||||
else
|
||||
value = scan->value;
|
||||
|
||||
/* TODO check for errors */
|
||||
CMC_(PFX, _insert)(result, key, value);
|
||||
|
||||
scan = scan->next;
|
||||
}
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(result, _map_->callbacks);
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_map1_->flag = CMC_FLAG_OK;
|
||||
_map2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_map1_->count != _map2_->count)
|
||||
return false;
|
||||
|
||||
/* Optimize loop using the smallest hashtable */
|
||||
struct SNAME *_map_a_;
|
||||
struct SNAME *_map_b_;
|
||||
|
||||
_map_a_ = _map1_->capacity < _map2_->capacity ? _map1_ : _map2_;
|
||||
_map_b_ = _map_a_ == _map1_ ? _map2_ : _map1_;
|
||||
|
||||
for (size_t i = 0; i < _map_a_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_a_->buffer[i][0];
|
||||
|
||||
while (scan)
|
||||
{
|
||||
/* OPTIMIZE - This is calling key_count for repeating keys */
|
||||
if (CMC_(PFX, _impl_key_count)(_map_a_, scan->key) != CMC_(PFX, _impl_key_count)(_map_b_, scan->key))
|
||||
return false;
|
||||
|
||||
scan = scan->next;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->alloc->malloc(sizeof(struct CMC_DEF_ENTRY(SNAME)));
|
||||
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
entry->key = key;
|
||||
entry->value = value;
|
||||
entry->next = NULL;
|
||||
entry->prev = NULL;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[hash % _map_->capacity][0];
|
||||
|
||||
while (entry)
|
||||
{
|
||||
if (_map_->f_key->cmp(entry->key, key) == 0)
|
||||
return entry;
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _impl_key_count)(struct SNAME *_map_, K key)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[hash % _map_->capacity][0];
|
||||
|
||||
size_t total_count = 0;
|
||||
|
||||
if (!entry)
|
||||
return total_count;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
if (_map_->f_key->cmp(entry->key, key) == 0)
|
||||
total_count++;
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
return total_count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _impl_calculate_size)(size_t required)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
|
||||
|
||||
if (cmc_hashtable_primes[count - 1] < required)
|
||||
return required;
|
||||
|
||||
size_t i = 0;
|
||||
while (cmc_hashtable_primes[i] < required)
|
||||
i++;
|
||||
|
||||
return cmc_hashtable_primes[i];
|
||||
}
|
||||
@@ -0,0 +1,465 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* List bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.curr_entry = NULL;
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
iter.first = 0;
|
||||
iter.last = 0;
|
||||
iter.start = true;
|
||||
iter.end = CMC_(PFX, _empty)(target);
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i][0];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
iter.curr_entry = target->buffer[i][0];
|
||||
iter.first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter.cursor = iter.first;
|
||||
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i - 1][1];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
iter.last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.curr_entry = NULL;
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
iter.first = 0;
|
||||
iter.last = 0;
|
||||
iter.start = CMC_(PFX, _empty)(target);
|
||||
iter.end = true;
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i][0];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
iter.first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i - 1][1];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
iter.curr_entry = target->buffer[i - 1][1];
|
||||
iter.last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter.cursor = iter.last;
|
||||
iter.index = target->count - 1;
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->first;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
iter->curr_entry = iter->target->buffer[iter->first][0];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->last;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
iter->end = true;
|
||||
iter->curr_entry = iter->target->buffer[iter->last][1];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->curr_entry->next != NULL)
|
||||
{
|
||||
iter->curr_entry = iter->curr_entry->next;
|
||||
iter->index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iter->cursor == iter->last)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->cursor++;
|
||||
|
||||
while (iter->target->buffer[iter->cursor][0] == NULL)
|
||||
iter->cursor++;
|
||||
|
||||
iter->curr_entry = iter->target->buffer[iter->cursor][0];
|
||||
|
||||
iter->index++;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->curr_entry->prev != NULL)
|
||||
{
|
||||
iter->curr_entry = iter->curr_entry->prev;
|
||||
iter->index--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iter->cursor == iter->first)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->cursor--;
|
||||
|
||||
while (iter->target->buffer[iter->cursor][1] == NULL)
|
||||
iter->cursor--;
|
||||
|
||||
iter->curr_entry = iter->target->buffer[iter->cursor][1];
|
||||
|
||||
iter->index--;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_next)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index < steps)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_prev)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at the */
|
||||
/* given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->index > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
|
||||
else if (iter->index < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (K){ 0 };
|
||||
|
||||
return iter->curr_entry->key;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (V){ 0 };
|
||||
|
||||
return iter->curr_entry->value;
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return NULL;
|
||||
|
||||
return &(iter->curr_entry->value);
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return iter->index;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *m_ = _map_;
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s, %s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"load:%lf, "
|
||||
"flag:%d, "
|
||||
"f_key:%p, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(K), CMC_TO_STRING(V), m_, m_->buffer, m_->capacity,
|
||||
m_->count, m_->load, m_->flag, m_->f_key, m_->f_val, m_->alloc, CMC_CALLBACKS_GET(m_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
|
||||
const char *key_val_sep)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
size_t last = 0;
|
||||
for (size_t i = _map_->capacity; i > 0; i--)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i - 1][1];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
while (scan != NULL)
|
||||
{
|
||||
if (!_map_->f_key->str(fptr, scan->key))
|
||||
return false;
|
||||
|
||||
fprintf(fptr, "%s", key_val_sep);
|
||||
|
||||
if (!_map_->f_val->str(fptr, scan->value))
|
||||
return false;
|
||||
|
||||
scan = scan->next;
|
||||
|
||||
if (i + 1 < last)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashmultimap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* Iterator Initialization */
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr);
|
||||
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
|
||||
const char *key_val_sep);
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashmultimap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* HashMultiMap Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target hashmultimap */
|
||||
struct SNAME *target;
|
||||
/* Current entry */
|
||||
struct CMC_DEF_ENTRY(SNAME) * curr_entry;
|
||||
/* Cursor`s position (index) */
|
||||
size_t cursor;
|
||||
/* Keeps track of relative index to the iteration of elements */
|
||||
size_t index;
|
||||
/* The index of the first element */
|
||||
size_t first;
|
||||
/* The index of the last element */
|
||||
size_t last;
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Key struct function table */
|
||||
struct CMC_DEF_FKEY(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(K);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(K);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(K);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(K);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(K);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(K);
|
||||
};
|
||||
|
||||
/* Value struct function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks);
|
||||
void CMC_(PFX, _clear)(struct SNAME *_map_);
|
||||
void CMC_(PFX, _free)(struct SNAME *_map_);
|
||||
/* Customization of Allocation and Callbacks */
|
||||
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value);
|
||||
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value);
|
||||
size_t CMC_(PFX, _update_all)(struct SNAME *_map_, K key, V new_value, V **old_values);
|
||||
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value);
|
||||
size_t CMC_(PFX, _remove_all)(struct SNAME *_map_, K key, V **out_values);
|
||||
/* Element Access */
|
||||
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value);
|
||||
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value);
|
||||
V CMC_(PFX, _get)(struct SNAME *_map_, K key);
|
||||
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key);
|
||||
/* Collection State */
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key);
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_map_);
|
||||
bool CMC_(PFX, _full)(struct SNAME *_map_);
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_map_);
|
||||
size_t CMC_(PFX, _key_count)(struct SNAME *_map_, K key);
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_map_);
|
||||
double CMC_(PFX, _load)(struct SNAME *_map_);
|
||||
int CMC_(PFX, _flag)(struct SNAME *_map_);
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity);
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_);
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_);
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* HashMultimap Structure */
|
||||
struct SNAME
|
||||
{
|
||||
/* Array of linked list to entries */
|
||||
struct CMC_DEF_ENTRY(SNAME) * (*buffer)[2];
|
||||
/* Current array capacity */
|
||||
size_t capacity;
|
||||
/* Current amount of keys */
|
||||
size_t count;
|
||||
/* Load factor in range (0.0, infinity) */
|
||||
double load;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Key function table */
|
||||
struct CMC_DEF_FKEY(SNAME) * f_key;
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val;
|
||||
/* Custom allocation functions */
|
||||
CMC_ALLOC_TYPE alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
|
||||
/* HashMultimap Entry */
|
||||
struct CMC_DEF_ENTRY(SNAME)
|
||||
{
|
||||
/* Entry Key */
|
||||
K key;
|
||||
/* Entry Value */
|
||||
V value;
|
||||
/* Next entry on the linked list */
|
||||
struct CMC_DEF_ENTRY(SNAME) * next;
|
||||
/* Previous entry on the linked list */
|
||||
struct CMC_DEF_ENTRY(SNAME) * prev;
|
||||
};
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* hashmultiset.h
|
||||
*
|
||||
* Creation Date: 10/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* HashMultiSet
|
||||
*
|
||||
* In mathematics, a multiset is a modification of the concept of a set that,
|
||||
* unlike a set, allows for multiple instances for each of its elements. The
|
||||
* positive integer number of instances, given for each element is called the
|
||||
* multiplicity of this element in the multiset. A multiSet also has a
|
||||
* cardinality which equals the sum of the multiplicities of its elements.
|
||||
*
|
||||
* Implementation
|
||||
*
|
||||
* In this implementation, the values are stored in a flat hashtable and are
|
||||
* mapped to their multiplicity.
|
||||
*/
|
||||
|
||||
#include "cor/core.h"
|
||||
#include "cor/hashtable.h"
|
||||
|
||||
#ifdef CMC_DEV
|
||||
#include "utl/log.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* V - hashmultiset value data type
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
|
||||
/* Structs definition */
|
||||
#include "cmc/hashmultiset/struct.h"
|
||||
|
||||
/* Function declaration */
|
||||
#include "cmc/hashmultiset/header.h"
|
||||
|
||||
/* Function implementation */
|
||||
#include "cmc/hashmultiset/code.h"
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* INIT - Initializes the struct on the stack
|
||||
* ITER - hashmultiset iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_HASHMULTISET_PARTS INIT, ITER, SETF, STR
|
||||
/**/
|
||||
#include "cmc/hashmultiset/ext/struct.h"
|
||||
/**/
|
||||
#include "cmc/hashmultiset/ext/header.h"
|
||||
/**/
|
||||
#include "cmc/hashmultiset/ext/code.h"
|
||||
|
||||
#include "cor/undef.h"
|
||||
@@ -0,0 +1,825 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_insert_and_return)(struct SNAME *_set_, V value, bool *new_node);
|
||||
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value);
|
||||
static size_t CMC_(PFX, _impl_calculate_size)(size_t required);
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _new_custom)(capacity, load, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (capacity == 0 || load <= 0 || load >= 1)
|
||||
return NULL;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= (double)UINTMAX_MAX * load)
|
||||
return NULL;
|
||||
|
||||
if (!f_val)
|
||||
return NULL;
|
||||
|
||||
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_set_)
|
||||
return NULL;
|
||||
|
||||
_set_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME)));
|
||||
|
||||
if (!_set_->buffer)
|
||||
{
|
||||
alloc->free(_set_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_set_->count = 0;
|
||||
_set_->cardinality = 0;
|
||||
_set_->capacity = real_capacity;
|
||||
_set_->load = load;
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
_set_->f_val = f_val;
|
||||
_set_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_set_, callbacks);
|
||||
|
||||
return _set_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_set_->f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _set_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
|
||||
|
||||
if (entry->state == CMC_ES_FILLED)
|
||||
{
|
||||
_set_->f_val->free(entry->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(_set_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity);
|
||||
|
||||
_set_->count = 0;
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_set_->f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _set_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
|
||||
|
||||
if (entry->state == CMC_ES_FILLED)
|
||||
{
|
||||
_set_->f_val->free(entry->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_set_->alloc->free(_set_->buffer);
|
||||
_set_->alloc->free(_set_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_set_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_set_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_set_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_set_, callbacks);
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_set_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
bool new_node;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_set_, value, &new_node);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_set_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!new_node)
|
||||
entry->multiplicity++;
|
||||
|
||||
_set_->cardinality++;
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _insert_many)(struct SNAME *_set_, V value, size_t count)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (count == 0)
|
||||
goto success;
|
||||
|
||||
bool new_node;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_set_, value, &new_node);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_set_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (new_node)
|
||||
entry->multiplicity = count;
|
||||
else
|
||||
entry->multiplicity += count;
|
||||
|
||||
_set_->cardinality += count;
|
||||
|
||||
success:
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _update)(struct SNAME *_set_, V value, size_t multiplicity)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (multiplicity == 0)
|
||||
{
|
||||
/* Effectively delete the entry */
|
||||
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value);
|
||||
|
||||
if (!result)
|
||||
/* If no entry was found then its multiplicity is already 0 */
|
||||
goto success;
|
||||
|
||||
_set_->count--;
|
||||
_set_->cardinality -= result->multiplicity;
|
||||
|
||||
result->value = (V){ 0 };
|
||||
result->multiplicity = 0;
|
||||
result->dist = 0;
|
||||
result->state = CMC_ES_DELETED;
|
||||
|
||||
goto success;
|
||||
}
|
||||
|
||||
bool new_node;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_set_, value, &new_node);
|
||||
|
||||
if (!entry)
|
||||
return false;
|
||||
|
||||
if (new_node)
|
||||
_set_->cardinality++;
|
||||
|
||||
_set_->cardinality = (_set_->cardinality - entry->multiplicity) + multiplicity;
|
||||
|
||||
entry->multiplicity = multiplicity;
|
||||
|
||||
success:
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _remove)(struct SNAME *_set_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_set_))
|
||||
{
|
||||
_set_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_set_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result->multiplicity > 1)
|
||||
result->multiplicity--;
|
||||
else
|
||||
{
|
||||
result->value = (V){ 0 };
|
||||
result->multiplicity = 0;
|
||||
result->dist = 0;
|
||||
result->state = CMC_ES_DELETED;
|
||||
|
||||
_set_->count--;
|
||||
}
|
||||
|
||||
_set_->cardinality--;
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _remove_all)(struct SNAME *_set_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_set_))
|
||||
{
|
||||
_set_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_set_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t removed = result->multiplicity;
|
||||
|
||||
result->value = (V){ 0 };
|
||||
result->multiplicity = 0;
|
||||
result->dist = 0;
|
||||
result->state = CMC_ES_DELETED;
|
||||
|
||||
_set_->count--;
|
||||
_set_->cardinality -= removed;
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _max)(struct SNAME *_set_, V *value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_set_))
|
||||
{
|
||||
_set_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
V max_val = (V){ 0 };
|
||||
|
||||
for (size_t i = 0; i < _set_->capacity; i++)
|
||||
{
|
||||
if (_set_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
max_val = _set_->buffer[i].value;
|
||||
first = false;
|
||||
}
|
||||
else if (_set_->f_val->cmp(_set_->buffer[i].value, max_val) > 0)
|
||||
{
|
||||
max_val = _set_->buffer[i].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value)
|
||||
*value = max_val;
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _min)(struct SNAME *_set_, V *value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_set_))
|
||||
{
|
||||
_set_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
V min_val = (V){ 0 };
|
||||
|
||||
for (size_t i = 0; i < _set_->capacity; i++)
|
||||
{
|
||||
if (_set_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
min_val = _set_->buffer[i].value;
|
||||
first = false;
|
||||
}
|
||||
else if (_set_->f_val->cmp(_set_->buffer[i].value, min_val) < 0)
|
||||
{
|
||||
min_val = _set_->buffer[i].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value)
|
||||
*value = min_val;
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _multiplicity_of)(struct SNAME *_set_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_set_, value);
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
if (!entry)
|
||||
return 0;
|
||||
|
||||
return entry->multiplicity;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_set_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = CMC_(PFX, _impl_get_entry)(_set_, value) != NULL;
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _set_->count == 0;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _full)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return (double)_set_->capacity * _set_->load <= (double)_set_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _set_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _cardinality)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _set_->cardinality;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _set_->capacity;
|
||||
}
|
||||
|
||||
double CMC_(PFX, _load)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _set_->load;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _set_->flag;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_set_->capacity == capacity)
|
||||
goto success;
|
||||
|
||||
if (_set_->capacity > capacity / _set_->load)
|
||||
goto success;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= (double)UINTMAX_MAX * _set_->load)
|
||||
{
|
||||
_set_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Calculate required capacity based on the prime numbers */
|
||||
size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity);
|
||||
|
||||
/* Not possible to shrink with current available prime numbers */
|
||||
if (theoretical_size < _set_->count / _set_->load)
|
||||
{
|
||||
_set_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* No callbacks since _new_set_ is just a temporary hashtable */
|
||||
struct SNAME *_new_set_ = CMC_(PFX, _new_custom)(capacity, _set_->load, _set_->f_val, _set_->alloc, NULL);
|
||||
|
||||
if (!_new_set_)
|
||||
{
|
||||
_set_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _set_->capacity; i++)
|
||||
{
|
||||
if (_set_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
V value = _set_->buffer[i].value;
|
||||
size_t multiplicity = _set_->buffer[i].multiplicity;
|
||||
|
||||
/* TODO check this for possible errors where entry == NULL */
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_new_set_, value, NULL);
|
||||
|
||||
entry->multiplicity = multiplicity;
|
||||
/* Setting cardinality not required, _new_set_ is temporary */
|
||||
}
|
||||
}
|
||||
|
||||
if (_set_->count != _new_set_->count)
|
||||
{
|
||||
CMC_(PFX, _free)(_new_set_);
|
||||
|
||||
_set_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *tmp_b = _set_->buffer;
|
||||
_set_->buffer = _new_set_->buffer;
|
||||
_new_set_->buffer = tmp_b;
|
||||
|
||||
size_t tmp_c = _set_->capacity;
|
||||
_set_->capacity = _new_set_->capacity;
|
||||
_new_set_->capacity = tmp_c;
|
||||
|
||||
/* Prevent the set from freeing the data */
|
||||
_new_set_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
|
||||
|
||||
CMC_(PFX, _free)(_new_set_);
|
||||
|
||||
success:
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *result =
|
||||
CMC_(PFX, _new_custom)(_set_->capacity * _set_->load, _set_->load, _set_->f_val, _set_->alloc, NULL);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_set_->flag = CMC_FLAG_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(result, _set_->callbacks);
|
||||
|
||||
if (_set_->f_val->cpy)
|
||||
{
|
||||
for (size_t i = 0; i < _set_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = &(_set_->buffer[i]);
|
||||
|
||||
if (scan->state != CMC_ES_EMPTY)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = &(result->buffer[i]);
|
||||
|
||||
if (scan->state == CMC_ES_DELETED)
|
||||
target->state = CMC_ES_DELETED;
|
||||
else
|
||||
{
|
||||
target->state = scan->state;
|
||||
target->dist = scan->dist;
|
||||
target->multiplicity = scan->multiplicity;
|
||||
|
||||
target->value = _set_->f_val->cpy(scan->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
memcpy(result->buffer, _set_->buffer, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity);
|
||||
|
||||
result->count = _set_->count;
|
||||
result->cardinality = _set_->cardinality;
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_set1_->flag = CMC_FLAG_OK;
|
||||
_set2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_set1_->count != _set2_->count)
|
||||
return false;
|
||||
|
||||
if (_set1_->cardinality != _set2_->cardinality)
|
||||
return false;
|
||||
|
||||
if (_set1_->count == 0)
|
||||
return true;
|
||||
|
||||
/* Optimize loop using the smallest hashtable */
|
||||
struct SNAME *_set_a_;
|
||||
struct SNAME *_set_b_;
|
||||
|
||||
_set_a_ = _set1_->capacity < _set2_->capacity ? _set1_ : _set2_;
|
||||
_set_b_ = _set_a_ == _set1_ ? _set2_ : _set1_;
|
||||
|
||||
for (size_t i = 0; i < _set_a_->capacity; i++)
|
||||
{
|
||||
if (_set_a_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry_a = &(_set_a_->buffer[i]);
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry_b = CMC_(PFX, _impl_get_entry)(_set_b_, entry_a->value);
|
||||
|
||||
if (!entry_b)
|
||||
return false;
|
||||
|
||||
if (entry_a->multiplicity != entry_b->multiplicity)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_insert_and_return)(struct SNAME *_set_, V value, bool *new_node)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* If the entry already exists simply return it as we might do */
|
||||
/* something with it. This function only guarantees that there is */
|
||||
/* a valid entry for a given value */
|
||||
|
||||
if (new_node)
|
||||
*new_node = false;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_set_, value);
|
||||
|
||||
if (entry != NULL)
|
||||
return entry;
|
||||
|
||||
if (new_node)
|
||||
*new_node = true;
|
||||
|
||||
if (CMC_(PFX, _full)(_set_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_set_, _set_->capacity + 1))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t hash = _set_->f_val->hash(value);
|
||||
size_t original_pos = hash % _set_->capacity;
|
||||
size_t pos = original_pos;
|
||||
/* Current multiplicity. Might change due to robin hood hashing */
|
||||
size_t curr_mul = 1;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]);
|
||||
struct CMC_DEF_ENTRY(SNAME) *to_return = NULL;
|
||||
|
||||
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
target->value = value;
|
||||
target->multiplicity = curr_mul;
|
||||
target->dist = pos - original_pos;
|
||||
target->state = CMC_ES_FILLED;
|
||||
|
||||
to_return = target;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
pos++;
|
||||
target = &(_set_->buffer[pos % _set_->capacity]);
|
||||
|
||||
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
target->value = value;
|
||||
target->multiplicity = curr_mul;
|
||||
target->dist = pos - original_pos;
|
||||
target->state = CMC_ES_FILLED;
|
||||
|
||||
if (!to_return)
|
||||
to_return = target;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (target->dist < pos - original_pos)
|
||||
{
|
||||
/* Swap everything */
|
||||
V tmp = target->value;
|
||||
size_t tmp_dist = target->dist;
|
||||
size_t tmp_mul = target->multiplicity;
|
||||
|
||||
target->value = value;
|
||||
target->dist = pos - original_pos;
|
||||
target->multiplicity = curr_mul;
|
||||
|
||||
value = tmp;
|
||||
original_pos = pos - tmp_dist;
|
||||
curr_mul = tmp_mul;
|
||||
|
||||
if (!to_return)
|
||||
to_return = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_set_->count++;
|
||||
|
||||
return to_return;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
size_t hash = _set_->f_val->hash(value);
|
||||
size_t pos = hash % _set_->capacity;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]);
|
||||
|
||||
while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
if (target->state != CMC_ES_DELETED && _set_->f_val->cmp(target->value, value) == 0)
|
||||
return target;
|
||||
|
||||
pos++;
|
||||
target = &(_set_->buffer[pos % _set_->capacity]);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t CMC_(PFX, _impl_calculate_size)(size_t required)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
|
||||
|
||||
if (cmc_hashtable_primes[count - 1] < required)
|
||||
return required;
|
||||
|
||||
size_t i = 0;
|
||||
while (cmc_hashtable_primes[i] < required)
|
||||
i++;
|
||||
|
||||
return cmc_hashtable_primes[i];
|
||||
}
|
||||
@@ -0,0 +1,742 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* List bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
iter.first = 0;
|
||||
iter.last = 0;
|
||||
iter.start = true;
|
||||
iter.end = CMC_(PFX, _empty)(target);
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
if (target->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter.cursor = iter.first;
|
||||
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
if (target->buffer[i - 1].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
iter.first = 0;
|
||||
iter.last = 0;
|
||||
iter.start = CMC_(PFX, _empty)(target);
|
||||
iter.end = true;
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
if (target->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
if (target->buffer[i - 1].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter.cursor = iter.last;
|
||||
iter.index = target->count - 1;
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->first;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->last;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
iter->end = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
iter->index++;
|
||||
|
||||
while (1)
|
||||
{
|
||||
iter->cursor++;
|
||||
scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
if (scan->state == CMC_ES_FILLED)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
iter->index--;
|
||||
|
||||
while (1)
|
||||
{
|
||||
iter->cursor--;
|
||||
scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
if (scan->state == CMC_ES_FILLED)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_next)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index < steps)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_prev)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at the */
|
||||
/* given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->index > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
|
||||
else if (iter->index < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (V){ 0 };
|
||||
|
||||
return iter->target->buffer[iter->cursor].value;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_multiplicity)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return 0;
|
||||
|
||||
return iter->target->buffer[iter->cursor].multiplicity;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return iter->index;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* SETF
|
||||
*
|
||||
* Set functions
|
||||
*/
|
||||
#ifdef CMC_EXT_SETF
|
||||
|
||||
/* Implementation detail function */
|
||||
static size_t CMC_(PFX, _impl_multiplicity_of)(struct SNAME *_set_, V value);
|
||||
|
||||
struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* Callbacks are added later */
|
||||
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
|
||||
|
||||
if (!_set_r_)
|
||||
return NULL;
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
|
||||
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter1);
|
||||
|
||||
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter1);
|
||||
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
|
||||
size_t max_ = m1 > m2 ? m1 : m2;
|
||||
|
||||
CMC_(PFX, _update)(_set_r_, value, max_);
|
||||
}
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter2);
|
||||
|
||||
size_t m1 = CMC_(PFX, _impl_multiplicity_of)(_set1_, value);
|
||||
size_t m2 = CMC_(PFX, _iter_multiplicity)(&iter2);
|
||||
size_t max_ = m1 > m2 ? m1 : m2;
|
||||
|
||||
CMC_(PFX, _update)(_set_r_, value, max_);
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
|
||||
|
||||
return _set_r_;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* Callbacks are added later */
|
||||
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
|
||||
|
||||
if (!_set_r_)
|
||||
return NULL;
|
||||
|
||||
struct SNAME *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_;
|
||||
struct SNAME *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_;
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set_A_);
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter);
|
||||
|
||||
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter);
|
||||
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set_B_, value);
|
||||
size_t max_ = m1 < m2 ? m1 : m2;
|
||||
|
||||
CMC_(PFX, _update)(_set_r_, value, max_);
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
|
||||
|
||||
return _set_r_;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* Callbacks are added later */
|
||||
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
|
||||
|
||||
if (!_set_r_)
|
||||
return NULL;
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter);
|
||||
|
||||
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter);
|
||||
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
|
||||
|
||||
if (m1 > m2)
|
||||
CMC_(PFX, _update)(_set_r_, value, m1 - m2);
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
|
||||
|
||||
return _set_r_;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _summation)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* Callbacks are added later */
|
||||
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
|
||||
|
||||
if (!_set_r_)
|
||||
return NULL;
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
|
||||
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
|
||||
{
|
||||
CMC_(PFX, _insert_many)
|
||||
(_set_r_, CMC_(PFX, _iter_value)(&iter1), CMC_(PFX, _iter_multiplicity)(&iter1));
|
||||
}
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
|
||||
{
|
||||
CMC_(PFX, _insert_many)
|
||||
(_set_r_, CMC_(PFX, _iter_value)(&iter2), CMC_(PFX, _iter_multiplicity)(&iter2));
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
|
||||
|
||||
return _set_r_;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* Callbacks are added later */
|
||||
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
|
||||
|
||||
if (!_set_r_)
|
||||
return NULL;
|
||||
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
|
||||
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter1);
|
||||
|
||||
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter1);
|
||||
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
|
||||
|
||||
if (m1 != m2)
|
||||
{
|
||||
if (m1 > m2)
|
||||
CMC_(PFX, _update)(_set_r_, value, m1 - m2);
|
||||
else
|
||||
CMC_(PFX, _update)(_set_r_, value, m2 - m1);
|
||||
}
|
||||
}
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter2);
|
||||
|
||||
size_t m1 = CMC_(PFX, _impl_multiplicity_of)(_set1_, value);
|
||||
size_t m2 = CMC_(PFX, _iter_multiplicity)(&iter2);
|
||||
|
||||
if (m1 != m2)
|
||||
{
|
||||
if (m1 > m2)
|
||||
CMC_(PFX, _update)(_set_r_, value, m1 - m2);
|
||||
else
|
||||
CMC_(PFX, _update)(_set_r_, value, m2 - m1);
|
||||
}
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
|
||||
|
||||
return _set_r_;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_set1_->count > _set2_->count)
|
||||
return false;
|
||||
|
||||
if (CMC_(PFX, _empty)(_set1_))
|
||||
return true;
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter);
|
||||
|
||||
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter);
|
||||
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
|
||||
|
||||
if (m1 > m2)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _is_subset)(_set2_, _set1_);
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_set1_->count >= _set2_->count)
|
||||
return false;
|
||||
|
||||
if (CMC_(PFX, _empty)(_set1_))
|
||||
{
|
||||
if (!CMC_(PFX, _empty)(_set2_))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter);
|
||||
|
||||
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter);
|
||||
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
|
||||
|
||||
if (m1 >= m2)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _is_proper_subset)(_set2_, _set1_);
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_set1_))
|
||||
return true;
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter);
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry)(_set2_, value) != NULL)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t CMC_(PFX, _impl_multiplicity_of)(struct SNAME *_set_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_set_, value);
|
||||
|
||||
if (!entry)
|
||||
return 0;
|
||||
|
||||
return entry->multiplicity;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_SETF */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *s_ = _set_;
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"cardinality:%" PRIuMAX ", "
|
||||
"load:%lf, "
|
||||
"flag:%d, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), s_, s_->buffer, s_->capacity, s_->count,
|
||||
s_->cardinality, s_->load, s_->flag, s_->f_val, s_->alloc, CMC_CALLBACKS_GET(s_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end,
|
||||
const char *val_mul_sep)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
size_t last = 0;
|
||||
for (size_t i = _set_->capacity; i > 0; i--)
|
||||
{
|
||||
if ((_set_->buffer[i - 1]).state == CMC_ES_FILLED)
|
||||
{
|
||||
last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _set_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
|
||||
|
||||
if (entry->state == CMC_ES_FILLED)
|
||||
{
|
||||
if (!_set_->f_val->str(fptr, entry->value))
|
||||
return false;
|
||||
|
||||
fprintf(fptr, "%s", val_mul_sep);
|
||||
|
||||
if (fprintf(fptr, "%" PRIuMAX "", entry->multiplicity) < 0)
|
||||
return false;
|
||||
|
||||
if (i + 1 < last)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* List bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* Iterator Initialization */
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_multiplicity)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* SETF
|
||||
*
|
||||
* Set functions
|
||||
*/
|
||||
#ifdef CMC_EXT_SETF
|
||||
|
||||
/* Set Operations */
|
||||
struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
struct SNAME *CMC_(PFX, _summation)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
|
||||
#endif /* CMC_EXT_SETF */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr);
|
||||
bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end,
|
||||
const char *key_val_sep);
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashmultiset bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* HashMultiSet Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target HashMultiset */
|
||||
struct SNAME *target;
|
||||
|
||||
/* Cursor's position (index) */
|
||||
size_t cursor;
|
||||
|
||||
/* Keeps track of relative index to the iteration of elements */
|
||||
size_t index;
|
||||
|
||||
/* The index of the first element */
|
||||
size_t first;
|
||||
|
||||
/* The index of the last element */
|
||||
size_t last;
|
||||
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Value struct function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
|
||||
void CMC_(PFX, _clear)(struct SNAME *_set_);
|
||||
void CMC_(PFX, _free)(struct SNAME *_set_);
|
||||
/* Customization of Allocation and Callbacks */
|
||||
void CMC_(PFX, _customize)(struct SNAME *_set_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_set_, V value);
|
||||
bool CMC_(PFX, _insert_many)(struct SNAME *_set_, V value, size_t count);
|
||||
bool CMC_(PFX, _update)(struct SNAME *_set_, V value, size_t multiplicity);
|
||||
bool CMC_(PFX, _remove)(struct SNAME *_set_, V value);
|
||||
size_t CMC_(PFX, _remove_all)(struct SNAME *_set_, V value);
|
||||
/* Element Access */
|
||||
bool CMC_(PFX, _max)(struct SNAME *_set_, V *value);
|
||||
bool CMC_(PFX, _min)(struct SNAME *_set_, V *value);
|
||||
size_t CMC_(PFX, _multiplicity_of)(struct SNAME *_set_, V value);
|
||||
/* Collection State */
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_set_, V value);
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_set_);
|
||||
bool CMC_(PFX, _full)(struct SNAME *_set_);
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_set_);
|
||||
size_t CMC_(PFX, _cardinality)(struct SNAME *_set_);
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_set_);
|
||||
double CMC_(PFX, _load)(struct SNAME *_set_);
|
||||
int CMC_(PFX, _flag)(struct SNAME *_set_);
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity);
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_);
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
struct SNAME
|
||||
{
|
||||
/* Array of Entries */
|
||||
struct CMC_DEF_ENTRY(SNAME) * buffer;
|
||||
/* Current Array Capcity */
|
||||
size_t capacity;
|
||||
/* Current amount of unique elements */
|
||||
size_t count;
|
||||
/* Total amount of elements taking into account their multiplicity */
|
||||
size_t cardinality;
|
||||
/* Load factor in range (0.0, 1.0) */
|
||||
double load;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Key function table */
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val;
|
||||
/* Custom allocation functions */
|
||||
CMC_ALLOC_TYPE alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME)
|
||||
{
|
||||
/* Entry element */
|
||||
V value;
|
||||
/* The element's multiplicity */
|
||||
size_t multiplicity;
|
||||
/* The distance of this node to its original position, used by */
|
||||
/* robin-hood hashing */
|
||||
size_t dist;
|
||||
/* The sate of this node (DELETED, EMPTY, FILLED) */
|
||||
enum cmc_entry_state state;
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* hashset.h
|
||||
*
|
||||
* Creation Date: 01/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* HashSet
|
||||
*
|
||||
* A HashSet is an implementation of a Set with unique keys. The keys are not
|
||||
* sorted. It is implemented as a flat hashtable with linear probing and robin
|
||||
* hood hashing.
|
||||
*/
|
||||
|
||||
#include "cor/core.h"
|
||||
#include "cor/hashtable.h"
|
||||
|
||||
#ifdef CMC_DEV
|
||||
#include "utl/log.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* V - hashset value data type
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
|
||||
/* Structs definition */
|
||||
#include "cmc/hashset/struct.h"
|
||||
|
||||
/* Function declaration */
|
||||
#include "cmc/hashset/header.h"
|
||||
|
||||
/* Function implementation */
|
||||
#include "cmc/hashset/code.h"
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* INIT - Initializes the struct on the stack
|
||||
* ITER - hashset iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_HASHSET_PARTS ITER, SETF, STR
|
||||
/**/
|
||||
#include "cmc/hashset/ext/struct.h"
|
||||
/**/
|
||||
#include "cmc/hashset/ext/header.h"
|
||||
/**/
|
||||
#include "cmc/hashset/ext/code.h"
|
||||
|
||||
#include "cor/undef.h"
|
||||
@@ -0,0 +1,602 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value);
|
||||
static size_t CMC_(PFX, _impl_calculate_size)(size_t required);
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _new_custom)(capacity, load, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (capacity == 0 || load <= 0 || load >= 1)
|
||||
return NULL;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= (double)UINTMAX_MAX * load)
|
||||
return NULL;
|
||||
|
||||
if (!f_val)
|
||||
return NULL;
|
||||
|
||||
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_set_)
|
||||
return NULL;
|
||||
|
||||
_set_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME)));
|
||||
|
||||
if (!_set_->buffer)
|
||||
{
|
||||
alloc->free(_set_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_set_->count = 0;
|
||||
_set_->capacity = real_capacity;
|
||||
_set_->load = load;
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
_set_->f_val = f_val;
|
||||
_set_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_set_, callbacks);
|
||||
|
||||
return _set_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_set_->f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _set_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
|
||||
|
||||
if (entry->state == CMC_ES_FILLED)
|
||||
{
|
||||
_set_->f_val->free(entry->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(_set_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity);
|
||||
|
||||
_set_->count = 0;
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_set_->f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _set_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
|
||||
|
||||
if (entry->state == CMC_ES_FILLED)
|
||||
{
|
||||
_set_->f_val->free(entry->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_set_->alloc->free(_set_->buffer);
|
||||
_set_->alloc->free(_set_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_set_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_set_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_set_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_set_, callbacks);
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_set_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _full)(_set_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_set_, _set_->capacity + 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry)(_set_, value) != NULL)
|
||||
{
|
||||
_set_->flag = CMC_FLAG_DUPLICATE;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t hash = _set_->f_val->hash(value);
|
||||
size_t original_pos = hash % _set_->capacity;
|
||||
size_t pos = original_pos;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]);
|
||||
|
||||
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
target->value = value;
|
||||
target->dist = 0;
|
||||
target->state = CMC_ES_FILLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
pos++;
|
||||
target = &(_set_->buffer[pos % _set_->capacity]);
|
||||
|
||||
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
target->value = value;
|
||||
target->dist = pos - original_pos;
|
||||
target->state = CMC_ES_FILLED;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (target->dist < pos - original_pos)
|
||||
{
|
||||
V tmp = target->value;
|
||||
size_t tmp_dist = target->dist;
|
||||
|
||||
target->value = value;
|
||||
target->dist = pos - original_pos;
|
||||
|
||||
value = tmp;
|
||||
original_pos = pos - tmp_dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_set_->count++;
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _remove)(struct SNAME *_set_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_set_))
|
||||
{
|
||||
_set_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value);
|
||||
|
||||
if (result == NULL)
|
||||
{
|
||||
_set_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
result->value = (V){ 0 };
|
||||
result->dist = 0;
|
||||
result->state = CMC_ES_DELETED;
|
||||
|
||||
_set_->count--;
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _max)(struct SNAME *_set_, V *value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_set_))
|
||||
{
|
||||
_set_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
V max_val = (V){ 0 };
|
||||
|
||||
for (size_t i = 0; i < _set_->capacity; i++)
|
||||
{
|
||||
if (_set_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
max_val = _set_->buffer[i].value;
|
||||
first = false;
|
||||
}
|
||||
else if (_set_->f_val->cmp(_set_->buffer[i].value, max_val) > 0)
|
||||
{
|
||||
max_val = _set_->buffer[i].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value)
|
||||
*value = max_val;
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _min)(struct SNAME *_set_, V *value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_set_))
|
||||
{
|
||||
_set_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
V min_val = (V){ 0 };
|
||||
|
||||
for (size_t i = 0; i < _set_->capacity; i++)
|
||||
{
|
||||
if (_set_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
min_val = _set_->buffer[i].value;
|
||||
first = false;
|
||||
}
|
||||
else if (_set_->f_val->cmp(_set_->buffer[i].value, min_val) < 0)
|
||||
{
|
||||
min_val = _set_->buffer[i].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value)
|
||||
*value = min_val;
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_set_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = CMC_(PFX, _impl_get_entry)(_set_, value) != NULL;
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _set_->count == 0;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _full)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return (double)_set_->capacity * _set_->load <= (double)_set_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _set_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _set_->capacity;
|
||||
}
|
||||
|
||||
double CMC_(PFX, _load)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _set_->load;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _set_->flag;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_set_->capacity == capacity)
|
||||
goto success;
|
||||
|
||||
if (_set_->capacity > capacity / _set_->load)
|
||||
goto success;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= (double)UINTMAX_MAX * _set_->load)
|
||||
{
|
||||
_set_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Calculate required capacity based on the prime numbers */
|
||||
size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity);
|
||||
|
||||
/* Not possible to shrink with current available prime numbers */
|
||||
if (theoretical_size < _set_->count / _set_->load)
|
||||
{
|
||||
_set_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* No callbacks since _new_set_ is just a temporary hashtable */
|
||||
struct SNAME *_new_set_ = CMC_(PFX, _new_custom)(capacity, _set_->load, _set_->f_val, _set_->alloc, NULL);
|
||||
|
||||
if (!_new_set_)
|
||||
{
|
||||
_set_->flag = CMC_FLAG_ALLOC;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _set_->capacity; i++)
|
||||
{
|
||||
if (_set_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
V value = _set_->buffer[i].value;
|
||||
|
||||
/* TODO check this for possible errors */
|
||||
CMC_(PFX, _insert)(_new_set_, value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Unlikely */
|
||||
if (_set_->count != _new_set_->count)
|
||||
{
|
||||
CMC_(PFX, _free)(_new_set_);
|
||||
|
||||
_set_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *tmp_b = _set_->buffer;
|
||||
_set_->buffer = _new_set_->buffer;
|
||||
_new_set_->buffer = tmp_b;
|
||||
|
||||
size_t tmp_c = _set_->capacity;
|
||||
_set_->capacity = _new_set_->capacity;
|
||||
_new_set_->capacity = tmp_c;
|
||||
|
||||
/* Prevent the set from freeing the data */
|
||||
_new_set_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
|
||||
|
||||
CMC_(PFX, _free)(_new_set_);
|
||||
|
||||
success:
|
||||
|
||||
CMC_CALLBACKS_CALL(_set_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *result =
|
||||
CMC_(PFX, _new_custom)(_set_->capacity * _set_->load, _set_->load, _set_->f_val, _set_->alloc, NULL);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_set_->flag = CMC_FLAG_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(result, _set_->callbacks);
|
||||
|
||||
if (_set_->f_val->cpy)
|
||||
{
|
||||
for (size_t i = 0; i < _set_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = &(_set_->buffer[i]);
|
||||
|
||||
if (scan->state != CMC_ES_EMPTY)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = &(result->buffer[i]);
|
||||
|
||||
if (scan->state == CMC_ES_DELETED)
|
||||
target->state = CMC_ES_DELETED;
|
||||
else
|
||||
{
|
||||
target->state = scan->state;
|
||||
target->dist = scan->dist;
|
||||
|
||||
target->value = _set_->f_val->cpy(scan->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
memcpy(result->buffer, _set_->buffer, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity);
|
||||
|
||||
result->count = _set_->count;
|
||||
|
||||
_set_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_set1_->flag = CMC_FLAG_OK;
|
||||
_set2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_set1_->count != _set2_->count)
|
||||
return false;
|
||||
|
||||
/* Optimize loop using the smallest hashtable */
|
||||
struct SNAME *_set_a_;
|
||||
struct SNAME *_set_b_;
|
||||
|
||||
_set_a_ = _set1_->capacity < _set2_->capacity ? _set1_ : _set2_;
|
||||
_set_b_ = _set_a_ == _set1_ ? _set2_ : _set1_;
|
||||
|
||||
for (size_t i = 0; i < _set_a_->capacity; i++)
|
||||
{
|
||||
if (_set_a_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
|
||||
if (!CMC_(PFX, _impl_get_entry)(_set_b_, _set_a_->buffer[i].value))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
size_t hash = _set_->f_val->hash(value);
|
||||
size_t pos = hash % _set_->capacity;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]);
|
||||
|
||||
while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
if (target->state != CMC_ES_DELETED && _set_->f_val->cmp(target->value, value) == 0)
|
||||
return target;
|
||||
|
||||
pos++;
|
||||
target = &(_set_->buffer[pos % _set_->capacity]);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t CMC_(PFX, _impl_calculate_size)(size_t required)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
|
||||
|
||||
if (cmc_hashtable_primes[count - 1] < required)
|
||||
return required;
|
||||
|
||||
size_t i = 0;
|
||||
while (cmc_hashtable_primes[i] < required)
|
||||
i++;
|
||||
|
||||
return cmc_hashtable_primes[i];
|
||||
}
|
||||
@@ -0,0 +1,687 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashset bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
iter.first = 0;
|
||||
iter.last = 0;
|
||||
iter.start = true;
|
||||
iter.end = CMC_(PFX, _empty)(target);
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
if (target->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter.cursor = iter.first;
|
||||
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
if (target->buffer[i - 1].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
iter.first = 0;
|
||||
iter.last = 0;
|
||||
iter.start = CMC_(PFX, _empty)(target);
|
||||
iter.end = true;
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
if (target->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
if (target->buffer[i - 1].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter.cursor = iter.last;
|
||||
iter.index = target->count - 1;
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->first;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->last;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
iter->end = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
iter->index++;
|
||||
|
||||
while (1)
|
||||
{
|
||||
iter->cursor++;
|
||||
scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
if (scan->state == CMC_ES_FILLED)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
iter->index--;
|
||||
|
||||
while (1)
|
||||
{
|
||||
iter->cursor--;
|
||||
scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
if (scan->state == CMC_ES_FILLED)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_next)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index < steps)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_prev)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at the */
|
||||
/* given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->index > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
|
||||
else if (iter->index < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (V){ 0 };
|
||||
|
||||
return iter->target->buffer[iter->cursor].value;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return iter->index;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* SETF
|
||||
*
|
||||
* Set functions
|
||||
*/
|
||||
#ifdef CMC_EXT_SETF
|
||||
|
||||
struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* Callbacks are added later */
|
||||
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
|
||||
|
||||
if (!_set_r_)
|
||||
{
|
||||
_set1_->flag = CMC_FLAG_ALLOC;
|
||||
_set2_->flag = CMC_FLAG_ALLOC;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
|
||||
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
|
||||
|
||||
/* TODO turn this into a normal loop and check for errors */
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
|
||||
{
|
||||
CMC_(PFX, _insert)(_set_r_, CMC_(PFX, _iter_value)(&iter1));
|
||||
}
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
|
||||
{
|
||||
CMC_(PFX, _insert)(_set_r_, CMC_(PFX, _iter_value)(&iter2));
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
|
||||
|
||||
return _set_r_;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* Callbacks are added later */
|
||||
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
|
||||
|
||||
if (!_set_r_)
|
||||
{
|
||||
_set1_->flag = CMC_FLAG_ALLOC;
|
||||
_set2_->flag = CMC_FLAG_ALLOC;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct SNAME *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_;
|
||||
struct SNAME *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_;
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set_A_);
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter);
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry)(_set_B_, value) != NULL)
|
||||
CMC_(PFX, _insert)(_set_r_, value);
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
|
||||
|
||||
return _set_r_;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* Callbacks are added later */
|
||||
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
|
||||
|
||||
if (!_set_r_)
|
||||
{
|
||||
_set1_->flag = CMC_FLAG_ALLOC;
|
||||
_set2_->flag = CMC_FLAG_ALLOC;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter);
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL)
|
||||
CMC_(PFX, _insert)(_set_r_, value);
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
|
||||
|
||||
return _set_r_;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* Callbacks are added later */
|
||||
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
|
||||
|
||||
if (!_set_r_)
|
||||
{
|
||||
_set1_->flag = CMC_FLAG_ALLOC;
|
||||
_set2_->flag = CMC_FLAG_ALLOC;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
|
||||
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter1);
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL)
|
||||
CMC_(PFX, _insert)(_set_r_, value);
|
||||
}
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter2);
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry)(_set1_, value) == NULL)
|
||||
CMC_(PFX, _insert)(_set_r_, value);
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
|
||||
|
||||
return _set_r_;
|
||||
}
|
||||
|
||||
/* Is _set1_ a subset of _set2_ ? */
|
||||
/* A set X is a subset of a set Y when: X <= Y */
|
||||
/* If X is a subset of Y, then Y is a superset of X */
|
||||
bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_set1_->flag = CMC_FLAG_OK;
|
||||
_set2_->flag = CMC_FLAG_OK;
|
||||
|
||||
/* If the cardinality of _set1_ is greater than that of _set2_, */
|
||||
/* then it is safe to say that _set1_ can't be a subset of _set2_ */
|
||||
if (_set1_->count > _set2_->count)
|
||||
return false;
|
||||
|
||||
/* The empty set is a subset of all sets */
|
||||
if (CMC_(PFX, _empty)(_set1_))
|
||||
return true;
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter);
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Is _set1_ a superset of _set2_ ? */
|
||||
/* A set X is a superset of a set Y when: X >= Y */
|
||||
/* If X is a superset of Y, then Y is a subset of X */
|
||||
bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _is_subset)(_set2_, _set1_);
|
||||
}
|
||||
|
||||
/* Is _set1_ a proper subset of _set2_ ? */
|
||||
/* A set X is a proper subset of a set Y when: X < Y */
|
||||
/* If X is a proper subset of Y, then Y is a proper superset of X */
|
||||
bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_set1_->flag = CMC_FLAG_OK;
|
||||
_set2_->flag = CMC_FLAG_OK;
|
||||
|
||||
/* If the cardinality of _set1_ is greater than or equal to that of */
|
||||
/* _set2_, then it is safe to say that _set1_ can't be a proper */
|
||||
/* subset of _set2_ */
|
||||
if (_set1_->count >= _set2_->count)
|
||||
return false;
|
||||
|
||||
if (CMC_(PFX, _empty)(_set1_))
|
||||
{
|
||||
/* The empty set is a proper subset of all non-empty sets */
|
||||
if (!CMC_(PFX, _empty)(_set2_))
|
||||
return true;
|
||||
/* The empty set is not a proper subset of itself (this is true */
|
||||
/* for any set) */
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter);
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Is _set1_ a proper superset of _set2_ ? */
|
||||
/* A set X is a proper superset of a set Y when: X > Y */
|
||||
/* If X is a proper superset of Y, then Y is a proper subset of X */
|
||||
bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _is_proper_subset)(_set2_, _set1_);
|
||||
}
|
||||
|
||||
/* Is _set1_ a disjointset of _set2_ ? */
|
||||
/* A set X is a disjointset of a set Y if their intersection is empty, */
|
||||
/* that is, if there are no elements in common between the two */
|
||||
bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_set1_->flag = CMC_FLAG_OK;
|
||||
_set2_->flag = CMC_FLAG_OK;
|
||||
|
||||
/* The intersection of an empty set with any other set will result */
|
||||
/* in an empty set */
|
||||
if (CMC_(PFX, _empty)(_set1_))
|
||||
return true;
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
|
||||
|
||||
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
|
||||
{
|
||||
V value = CMC_(PFX, _iter_value)(&iter);
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry)(_set2_, value) != NULL)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_SETF */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *s_ = _set_;
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"load:%lf, "
|
||||
"flag:%d, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks: %p }",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), s_, s_->buffer, s_->capacity, s_->count, s_->load,
|
||||
s_->flag, s_->f_val, s_->alloc, CMC_CALLBACKS_GET(s_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
size_t last = 0;
|
||||
for (size_t i = _set_->capacity; i > 0; i--)
|
||||
{
|
||||
if ((_set_->buffer[i - 1]).state == CMC_ES_FILLED)
|
||||
{
|
||||
last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _set_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
|
||||
|
||||
if (entry->state == CMC_ES_FILLED)
|
||||
{
|
||||
if (!_set_->f_val->str(fptr, entry->value))
|
||||
return false;
|
||||
|
||||
if (i + 1 < last)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* List bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* Iterator Initialization */
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* SETF
|
||||
*
|
||||
* Set functions
|
||||
*/
|
||||
#ifdef CMC_EXT_SETF
|
||||
|
||||
/* Set Operations */
|
||||
struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
|
||||
#endif /* CMC_EXT_SETF */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr);
|
||||
bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end);
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashset bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* HashSet Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target HashSet */
|
||||
struct SNAME *target;
|
||||
/* Cursor's position (index) */
|
||||
size_t cursor;
|
||||
/* Keeps track of relative index to the iteration of elements */
|
||||
size_t index;
|
||||
/* The index of the first element */
|
||||
size_t first;
|
||||
/* The index of the last element */
|
||||
size_t last;
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Value struct function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
|
||||
void CMC_(PFX, _clear)(struct SNAME *_set_);
|
||||
void CMC_(PFX, _free)(struct SNAME *_set_);
|
||||
/* Customization of Allocation and Callbacks */
|
||||
void CMC_(PFX, _customize)(struct SNAME *_set_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_set_, V value);
|
||||
bool CMC_(PFX, _remove)(struct SNAME *_set_, V value);
|
||||
/* Element Access */
|
||||
bool CMC_(PFX, _max)(struct SNAME *_set_, V *value);
|
||||
bool CMC_(PFX, _min)(struct SNAME *_set_, V *value);
|
||||
/* Collection State */
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_set_, V value);
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_set_);
|
||||
bool CMC_(PFX, _full)(struct SNAME *_set_);
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_set_);
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_set_);
|
||||
double CMC_(PFX, _load)(struct SNAME *_set_);
|
||||
int CMC_(PFX, _flag)(struct SNAME *_set_);
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity);
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_);
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_);
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Hashset Structure */
|
||||
struct SNAME
|
||||
{
|
||||
/* Array of Entries */
|
||||
struct CMC_DEF_ENTRY(SNAME) * buffer;
|
||||
/* Current Array Capcity */
|
||||
size_t capacity;
|
||||
/* Current amount of elements */
|
||||
size_t count;
|
||||
/* Load factor in range (0.0, 1.0) */
|
||||
double load;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val;
|
||||
/* Custom allocation functions */
|
||||
CMC_ALLOC_TYPE alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME)
|
||||
{
|
||||
/* Entry value */
|
||||
V value;
|
||||
/* The distance of this node to its original position, used by */
|
||||
/* robin-hood hashing */
|
||||
size_t dist;
|
||||
/* The sate of this node (DELETED, EMPTY, FILLED) */
|
||||
enum cmc_entry_state state;
|
||||
};
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* heap.h
|
||||
*
|
||||
* Creation Date: 25/03/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Heap
|
||||
*
|
||||
* The Heap is a specialized tree-based data structure which is essentially a
|
||||
* complete tree that satisfies the heap property:
|
||||
* - MaxHeap:
|
||||
* - The root node is the greatest element of the unique set of keys.
|
||||
* - A node key is always greater than or equal to its children keys.
|
||||
* - Minheap:
|
||||
* - The root node is the smallest element of the unique set of keys.
|
||||
* - A node Key is always greater than or equal to its children keys.
|
||||
*
|
||||
* The heap is mostly used to implement priority queues. Sometimes it can also
|
||||
* be used to sort elements. There are three main functions:
|
||||
* - insert : Adds an element to the heap
|
||||
* - remove_(min/max): Removes the min/max element from the heap
|
||||
* - min/max : Accesses the min/max element from the heap
|
||||
*/
|
||||
|
||||
#include "cor/core.h"
|
||||
#include "cor/heap.h"
|
||||
|
||||
#ifdef CMC_DEV
|
||||
#include "utl/log.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* V - heap value data type
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
|
||||
/* Structs definition */
|
||||
#include "cmc/heap/struct.h"
|
||||
|
||||
/* Function declaration */
|
||||
#include "cmc/heap/header.h"
|
||||
|
||||
/* Function implementation */
|
||||
#include "cmc/heap/code.h"
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* INIT - Initializes the struct on the stack
|
||||
* ITER - heap iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_HEAP_PARTS ITER, SETF, STR
|
||||
/**/
|
||||
#include "cmc/heap/ext/struct.h"
|
||||
/**/
|
||||
#include "cmc/heap/ext/header.h"
|
||||
/**/
|
||||
#include "cmc/heap/ext/code.h"
|
||||
|
||||
#include "cor/undef.h"
|
||||
+437
@@ -0,0 +1,437 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
static void CMC_(PFX, _impl_float_up)(struct SNAME *_heap_, size_t index);
|
||||
static void CMC_(PFX, _impl_float_down)(struct SNAME *_heap_, size_t index);
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _new_custom)(capacity, HO, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (capacity < 1)
|
||||
return NULL;
|
||||
|
||||
if (HO != CMC_MIN_HEAP && HO != CMC_MAX_HEAP)
|
||||
return NULL;
|
||||
|
||||
if (!f_val)
|
||||
return NULL;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
struct SNAME *_heap_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_heap_)
|
||||
return NULL;
|
||||
|
||||
_heap_->buffer = alloc->calloc(capacity, sizeof(V));
|
||||
|
||||
if (!_heap_->buffer)
|
||||
{
|
||||
alloc->free(_heap_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_heap_->capacity = capacity;
|
||||
_heap_->count = 0;
|
||||
_heap_->HO = HO;
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
_heap_->f_val = f_val;
|
||||
_heap_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_heap_, callbacks);
|
||||
|
||||
return _heap_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_heap_->f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _heap_->count; i++)
|
||||
{
|
||||
_heap_->f_val->free(_heap_->buffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
memset(_heap_->buffer, 0, sizeof(V) * _heap_->capacity);
|
||||
|
||||
_heap_->count = 0;
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_heap_->f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _heap_->count; i++)
|
||||
{
|
||||
_heap_->f_val->free(_heap_->buffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
_heap_->alloc->free(_heap_->buffer);
|
||||
_heap_->alloc->free(_heap_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_heap_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_heap_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_heap_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_heap_, callbacks);
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _full)(_heap_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_heap_, _heap_->count * 2))
|
||||
return false;
|
||||
}
|
||||
|
||||
_heap_->buffer[_heap_->count++] = value;
|
||||
|
||||
if (_heap_->count > 1)
|
||||
{
|
||||
CMC_(PFX, _impl_float_up)(_heap_, _heap_->count - 1);
|
||||
}
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_heap_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _remove)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_heap_))
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
_heap_->buffer[0] = _heap_->buffer[_heap_->count - 1];
|
||||
_heap_->buffer[_heap_->count - 1] = (V){ 0 };
|
||||
|
||||
_heap_->count--;
|
||||
|
||||
CMC_(PFX, _impl_float_down)(_heap_, 0);
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_heap_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _peek)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_heap_))
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_heap_);
|
||||
|
||||
return _heap_->buffer[0];
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = false;
|
||||
|
||||
for (size_t i = 0; i < _heap_->count; i++)
|
||||
{
|
||||
if (_heap_->f_val->cmp(_heap_->buffer[i], value) == 0)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_CALL(_heap_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _heap_->count == 0;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _full)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _heap_->count >= _heap_->capacity;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _heap_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _heap_->capacity;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _heap_->flag;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_heap_->capacity == capacity)
|
||||
goto success;
|
||||
|
||||
if (capacity < _heap_->count)
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
V *new_buffer = _heap_->alloc->realloc(_heap_->buffer, sizeof(V) * capacity);
|
||||
|
||||
if (!new_buffer)
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_ALLOC;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO zero out new slots */
|
||||
|
||||
_heap_->buffer = new_buffer;
|
||||
_heap_->capacity = capacity;
|
||||
|
||||
success:
|
||||
|
||||
CMC_CALLBACKS_CALL(_heap_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *result = CMC_(PFX, _new_custom)(_heap_->capacity, _heap_->HO, _heap_->f_val, _heap_->alloc, NULL);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(result, _heap_->callbacks);
|
||||
|
||||
if (_heap_->f_val->cpy)
|
||||
{
|
||||
for (size_t i = 0; i < _heap_->count; i++)
|
||||
result->buffer[i] = _heap_->f_val->cpy(_heap_->buffer[i]);
|
||||
}
|
||||
else
|
||||
memcpy(result->buffer, _heap_->buffer, sizeof(V) * _heap_->count);
|
||||
|
||||
result->count = _heap_->count;
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_heap1_->flag = CMC_FLAG_OK;
|
||||
_heap2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_heap1_->count != _heap2_->count)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < _heap1_->count; i++)
|
||||
{
|
||||
if (_heap1_->f_val->cmp(_heap1_->buffer[i], _heap2_->buffer[i]) != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void CMC_(PFX, _impl_float_up)(struct SNAME *_heap_, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* Current index */
|
||||
size_t C = index;
|
||||
V child = _heap_->buffer[C];
|
||||
V parent = _heap_->buffer[(index - 1) / 2];
|
||||
|
||||
int mod = _heap_->HO;
|
||||
|
||||
while (C > 0 && _heap_->f_val->cmp(child, parent) * mod > 0)
|
||||
{
|
||||
/* Swap between C (current element) and its parent */
|
||||
V tmp = _heap_->buffer[C];
|
||||
_heap_->buffer[C] = _heap_->buffer[(C - 1) / 2];
|
||||
_heap_->buffer[(C - 1) / 2] = tmp;
|
||||
|
||||
/* Go to parent */
|
||||
C = (C - 1) / 2;
|
||||
|
||||
/* Prevent the two lines below from accessing a negative index */
|
||||
if (C == 0)
|
||||
break;
|
||||
|
||||
child = _heap_->buffer[C];
|
||||
parent = _heap_->buffer[(C - 1) / 2];
|
||||
}
|
||||
}
|
||||
|
||||
static void CMC_(PFX, _impl_float_down)(struct SNAME *_heap_, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
int mod = _heap_->HO;
|
||||
|
||||
while (index < _heap_->count)
|
||||
{
|
||||
size_t L = 2 * index + 1;
|
||||
size_t R = 2 * index + 2;
|
||||
size_t C = index;
|
||||
|
||||
/* Determine if we swap with the left or right element */
|
||||
if (L < _heap_->count && _heap_->f_val->cmp(_heap_->buffer[L], _heap_->buffer[C]) * mod > 0)
|
||||
{
|
||||
C = L;
|
||||
}
|
||||
|
||||
if (R < _heap_->count && _heap_->f_val->cmp(_heap_->buffer[R], _heap_->buffer[C]) * mod > 0)
|
||||
{
|
||||
C = R;
|
||||
}
|
||||
|
||||
/* Swap only if either left or right was picked, otherwise done */
|
||||
if (C != index)
|
||||
{
|
||||
V tmp = _heap_->buffer[index];
|
||||
_heap_->buffer[index] = _heap_->buffer[C];
|
||||
_heap_->buffer[C] = tmp;
|
||||
|
||||
index = C;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Heap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = 0;
|
||||
iter.start = true;
|
||||
iter.end = CMC_(PFX, _empty)(target);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = 0;
|
||||
iter.start = CMC_(PFX, _empty)(target);
|
||||
iter.end = true;
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
iter.cursor = target->count - 1;
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = 0;
|
||||
iter->start = true;
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->target->count - 1;
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
iter->end = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->cursor + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->cursor == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->cursor + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->cursor + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor += steps;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->cursor == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->cursor < steps)
|
||||
return false;
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor -= steps;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at the */
|
||||
/* given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->cursor > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->cursor - index);
|
||||
else if (iter->cursor < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->cursor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (V){ 0 };
|
||||
|
||||
return iter->target->buffer[iter->cursor];
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return iter->cursor;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *h_ = _heap_;
|
||||
const char *t = h_->HO == 1 ? "MaxHeap" : "MinHeap";
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"type:%s, "
|
||||
"flag:%d, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks: %p}",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), h_, h_->buffer, h_->capacity, h_->count, t, h_->flag,
|
||||
h_->f_val, h_->alloc, CMC_CALLBACKS_GET(h_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
for (size_t i = 0; i < _heap_->count; i++)
|
||||
{
|
||||
if (!_heap_->f_val->str(fptr, _heap_->buffer[i]))
|
||||
return false;
|
||||
|
||||
if (i + 1 < _heap_->count)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Heap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* Iterator Initialization */
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr);
|
||||
bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end);
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Heap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* Heap Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target heap */
|
||||
struct SNAME *target;
|
||||
/* Cursor's position (index) */
|
||||
size_t cursor;
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Value struct function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
|
||||
void CMC_(PFX, _clear)(struct SNAME *_heap_);
|
||||
void CMC_(PFX, _free)(struct SNAME *_heap_);
|
||||
/* Customization of Allocation and Callbacks */
|
||||
void CMC_(PFX, _customize)(struct SNAME *_heap_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value);
|
||||
bool CMC_(PFX, _remove)(struct SNAME *_heap_);
|
||||
/* Element Access */
|
||||
V CMC_(PFX, _peek)(struct SNAME *_heap_);
|
||||
/* Collection State */
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value);
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_heap_);
|
||||
bool CMC_(PFX, _full)(struct SNAME *_heap_);
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_heap_);
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_heap_);
|
||||
int CMC_(PFX, _flag)(struct SNAME *_heap_);
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity);
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_);
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_);
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
struct SNAME
|
||||
{
|
||||
/* Dynamic array of elements */
|
||||
V *buffer;
|
||||
/* Current array capacity */
|
||||
size_t capacity;
|
||||
/* Current amount of elements in the heap */
|
||||
size_t count;
|
||||
/* Heap order (MaxHeap or MinHeap) */
|
||||
enum cmc_heap_order HO;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val;
|
||||
/* Custom allocation functions */
|
||||
CMC_ALLOC_TYPE alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* intervalheap.h
|
||||
*
|
||||
* Creation Date: 06/07/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interval Heap
|
||||
*
|
||||
* An interval heap is a specialized heap with:
|
||||
*
|
||||
* - O(1) - Find Min
|
||||
* - O(1) - Find Max
|
||||
* - O(log n) - Insert
|
||||
* - O(log n) - Remove Min
|
||||
* - O(log n) - Remove Max
|
||||
*/
|
||||
|
||||
#include "cor/core.h"
|
||||
|
||||
#ifdef CMC_DEV
|
||||
#include "utl/log.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* V - intervalheap value data type
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
|
||||
/* Structs definition */
|
||||
#include "cmc/intervalheap/struct.h"
|
||||
|
||||
/* Function declaration */
|
||||
#include "cmc/intervalheap/header.h"
|
||||
|
||||
/* Function implementation */
|
||||
#include "cmc/intervalheap/code.h"
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* INIT - Initializes the struct on the stack
|
||||
* ITER - intervalheap iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_HEAP_PARTS ITER, SETF, STR
|
||||
/**/
|
||||
#include "cmc/intervalheap/ext/struct.h"
|
||||
/**/
|
||||
#include "cmc/intervalheap/ext/header.h"
|
||||
/**/
|
||||
#include "cmc/intervalheap/ext/code.h"
|
||||
|
||||
#include "cor/undef.h"
|
||||
@@ -0,0 +1,860 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
static void CMC_(PFX, _impl_float_up_max)(struct SNAME *_heap_);
|
||||
static void CMC_(PFX, _impl_float_up_min)(struct SNAME *_heap_);
|
||||
static void CMC_(PFX, _impl_float_down_max)(struct SNAME *_heap_);
|
||||
static void CMC_(PFX, _impl_float_down_min)(struct SNAME *_heap_);
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _new_custom)(capacity, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (capacity == 0 || capacity == UINTMAX_MAX)
|
||||
return NULL;
|
||||
|
||||
if (!f_val)
|
||||
return NULL;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
struct SNAME *_heap_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_heap_)
|
||||
return NULL;
|
||||
|
||||
capacity = (capacity + capacity % 2) / 2;
|
||||
|
||||
_heap_->buffer = alloc->calloc(capacity, sizeof(V[2]));
|
||||
|
||||
if (!_heap_->buffer)
|
||||
{
|
||||
alloc->free(_heap_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_heap_->capacity = capacity;
|
||||
_heap_->size = 0;
|
||||
_heap_->count = 0;
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
_heap_->f_val = f_val;
|
||||
_heap_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_heap_, callbacks);
|
||||
|
||||
return _heap_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_heap_->f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _heap_->count; i++)
|
||||
{
|
||||
_heap_->f_val->free(_heap_->buffer[i / 2][i % 2]);
|
||||
}
|
||||
}
|
||||
|
||||
memset(_heap_->buffer, 0, sizeof(V[2]) * _heap_->capacity);
|
||||
|
||||
_heap_->size = 0;
|
||||
_heap_->count = 0;
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_heap_->f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _heap_->count; i++)
|
||||
{
|
||||
_heap_->f_val->free(_heap_->buffer[i / 2][i % 2]);
|
||||
}
|
||||
}
|
||||
|
||||
_heap_->alloc->free(_heap_->buffer);
|
||||
|
||||
_heap_->alloc->free(_heap_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_heap_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_heap_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_heap_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_heap_, callbacks);
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _full)(_heap_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_heap_, _heap_->capacity * 4))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_heap_->count % 2 == 0)
|
||||
{
|
||||
/* Occupying a new node */
|
||||
_heap_->buffer[_heap_->size][0] = value;
|
||||
_heap_->buffer[_heap_->size][1] = (V){ 0 };
|
||||
|
||||
_heap_->size++;
|
||||
}
|
||||
else
|
||||
{
|
||||
V(*node)[2] = &(_heap_->buffer[_heap_->size - 1]);
|
||||
|
||||
/* Decide if the new element goes into the MinHeap or MaxHeap */
|
||||
if (_heap_->f_val->cmp((*node)[0], value) > 0)
|
||||
{
|
||||
/* Swap current value and add new element to the MinHeap */
|
||||
(*node)[1] = (*node)[0];
|
||||
(*node)[0] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No need to swap and add the new element to the MaxHeap */
|
||||
(*node)[1] = value;
|
||||
}
|
||||
}
|
||||
|
||||
_heap_->count++;
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_heap_->count > 2)
|
||||
{
|
||||
/* Determine wheather to do a MaxHeap insert or a MinHeap */
|
||||
/* insert. For any integer this index calculation results in */
|
||||
/* an even number representing the parent of the last value */
|
||||
V(*parent)[2] = &(_heap_->buffer[(_heap_->size - 2) / 2]);
|
||||
|
||||
if (_heap_->f_val->cmp((*parent)[0], value) > 0)
|
||||
CMC_(PFX, _impl_float_up_min)(_heap_);
|
||||
else if (_heap_->f_val->cmp((*parent)[1], value) < 0)
|
||||
CMC_(PFX, _impl_float_up_max)(_heap_);
|
||||
/* else no float up required */
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_CALL(_heap_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _remove_max)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_heap_))
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_heap_->count == 1)
|
||||
{
|
||||
_heap_->buffer[0][0] = (V){ 0 };
|
||||
|
||||
_heap_->count--;
|
||||
_heap_->size--;
|
||||
|
||||
goto success;
|
||||
}
|
||||
|
||||
/* Swap the result with the last element in the MaxHeap and float */
|
||||
/* it down */
|
||||
V(*last_node)[2] = &(_heap_->buffer[_heap_->size - 1]);
|
||||
|
||||
if (_heap_->count % 2 == 1)
|
||||
{
|
||||
/* Grab from MinHeap and discard last node */
|
||||
_heap_->buffer[0][1] = (*last_node)[0];
|
||||
|
||||
(*last_node)[0] = (V){ 0 };
|
||||
|
||||
_heap_->size--;
|
||||
}
|
||||
else
|
||||
{
|
||||
_heap_->buffer[0][1] = (*last_node)[1];
|
||||
|
||||
(*last_node)[1] = (V){ 0 };
|
||||
}
|
||||
|
||||
_heap_->count--;
|
||||
|
||||
/* FLoat Down on the MaxHeap */
|
||||
CMC_(PFX, _impl_float_down_max)(_heap_);
|
||||
|
||||
success:
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_heap_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _remove_min)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_heap_))
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_heap_->count == 1)
|
||||
{
|
||||
_heap_->buffer[0][0] = (V){ 0 };
|
||||
|
||||
_heap_->count--;
|
||||
_heap_->size--;
|
||||
|
||||
goto success;
|
||||
}
|
||||
|
||||
/* Swap the result with the last element in the MinHeap and float */
|
||||
/* it down */
|
||||
V(*last_node)[2] = &(_heap_->buffer[_heap_->size - 1]);
|
||||
|
||||
_heap_->buffer[0][0] = (*last_node)[0];
|
||||
|
||||
if (_heap_->count % 2 == 1)
|
||||
{
|
||||
/* Discard last node */
|
||||
(*last_node)[0] = (V){ 0 };
|
||||
|
||||
_heap_->size--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Place the MaxHeap value in the MinHeap value spot */
|
||||
(*last_node)[0] = (*last_node)[1];
|
||||
(*last_node)[1] = (V){ 0 };
|
||||
}
|
||||
|
||||
_heap_->count--;
|
||||
|
||||
/* FLoat Down on the MinHeap */
|
||||
CMC_(PFX, _impl_float_down_min)(_heap_);
|
||||
|
||||
success:
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_heap_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _update_max)(struct SNAME *_heap_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_heap_))
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_heap_->count == 1)
|
||||
{
|
||||
_heap_->buffer[0][0] = value;
|
||||
}
|
||||
else if (_heap_->f_val->cmp(value, _heap_->buffer[0][0]) < 0)
|
||||
{
|
||||
/* Corner case: we are updating the Max value but it is less */
|
||||
/* than the Min value */
|
||||
_heap_->buffer[0][1] = _heap_->buffer[0][0];
|
||||
_heap_->buffer[0][0] = value;
|
||||
|
||||
CMC_(PFX, _impl_float_down_max)(_heap_);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Update Max element and float it down */
|
||||
_heap_->buffer[0][1] = value;
|
||||
|
||||
CMC_(PFX, _impl_float_down_max)(_heap_);
|
||||
}
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_heap_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _update_min)(struct SNAME *_heap_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_heap_))
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_heap_->count == 1)
|
||||
{
|
||||
_heap_->buffer[0][0] = value;
|
||||
}
|
||||
else if (_heap_->f_val->cmp(value, _heap_->buffer[0][1]) > 0)
|
||||
{
|
||||
/* Corner case: we are updating the Min value but it is greater */
|
||||
/* than the Max value. */
|
||||
_heap_->buffer[0][0] = _heap_->buffer[0][1];
|
||||
_heap_->buffer[0][1] = value;
|
||||
|
||||
CMC_(PFX, _impl_float_down_min)(_heap_);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Update Min element and float it down */
|
||||
_heap_->buffer[0][0] = value;
|
||||
|
||||
CMC_(PFX, _impl_float_down_min)(_heap_);
|
||||
}
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_heap_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _max)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_heap_))
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_heap_);
|
||||
|
||||
/* If there is only one element, then the maximum element is the */
|
||||
/* same as the one in the MinHeap */
|
||||
if (_heap_->count == 1)
|
||||
return _heap_->buffer[0][0];
|
||||
|
||||
return _heap_->buffer[0][1];
|
||||
}
|
||||
|
||||
V CMC_(PFX, _min)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_heap_))
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_heap_);
|
||||
|
||||
return _heap_->buffer[0][0];
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = false;
|
||||
|
||||
for (size_t i = 0; i < _heap_->count; i++)
|
||||
{
|
||||
if (_heap_->f_val->cmp(_heap_->buffer[i / 2][i % 2], value) == 0)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_CALL(_heap_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _heap_->count == 0;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _full)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* The heap is full if all nodes are completely filled */
|
||||
return _heap_->size >= _heap_->capacity && _heap_->count % 2 == 0;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _heap_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _heap_->capacity;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _heap_->flag;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_heap_->capacity == capacity)
|
||||
goto success;
|
||||
|
||||
if (capacity < _heap_->count)
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Prevent overflow */
|
||||
if (capacity == UINTMAX_MAX)
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
capacity += capacity % 2;
|
||||
|
||||
V(*new_buffer)[2] = _heap_->alloc->realloc(_heap_->buffer, sizeof(V[2]) * capacity);
|
||||
|
||||
if (!new_buffer)
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_ALLOC;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (capacity > _heap_->capacity)
|
||||
{
|
||||
memset(new_buffer + _heap_->capacity, 0, sizeof(V[2]) * (capacity - _heap_->capacity));
|
||||
}
|
||||
|
||||
_heap_->buffer = new_buffer;
|
||||
_heap_->capacity = capacity;
|
||||
|
||||
success:
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_heap_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *result = _heap_->alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_heap_->flag = CMC_FLAG_ALLOC;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(result, _heap_, sizeof(struct SNAME));
|
||||
|
||||
result->buffer = _heap_->alloc->malloc(sizeof(V[2]) * _heap_->capacity);
|
||||
|
||||
if (!result->buffer)
|
||||
{
|
||||
_heap_->alloc->free(result);
|
||||
_heap_->flag = CMC_FLAG_ALLOC;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_heap_->f_val->cpy)
|
||||
{
|
||||
for (size_t i = 0; i < _heap_->count; i++)
|
||||
result->buffer[i / 2][i % 2] = _heap_->f_val->cpy(_heap_->buffer[i / 2][i % 2]);
|
||||
}
|
||||
else
|
||||
memcpy(result->buffer, _heap_->buffer, sizeof(V[2]) * _heap_->capacity);
|
||||
|
||||
result->capacity = _heap_->capacity;
|
||||
result->size = _heap_->size;
|
||||
result->count = _heap_->count;
|
||||
result->flag = CMC_FLAG_OK;
|
||||
result->f_val = _heap_->f_val;
|
||||
result->alloc = _heap_->alloc;
|
||||
CMC_CALLBACKS_ASSIGN(result, _heap_->callbacks);
|
||||
|
||||
_heap_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_heap1_->flag = CMC_FLAG_OK;
|
||||
_heap2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_heap1_->count != _heap2_->count)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < _heap1_->count; i++)
|
||||
{
|
||||
V value1 = _heap1_->buffer[i / 2][i % 2];
|
||||
V value2 = _heap2_->buffer[i / 2][i % 2];
|
||||
|
||||
if (_heap1_->f_val->cmp(value1, value2) != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void CMC_(PFX, _impl_float_up_max)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
size_t index = _heap_->size - 1;
|
||||
|
||||
V(*curr_node)[2] = &(_heap_->buffer[index]);
|
||||
|
||||
/* FLoat Up on the MaxHeap */
|
||||
while (index > 0)
|
||||
{
|
||||
/* Parent index */
|
||||
size_t P_index = (index - 1) / 2;
|
||||
|
||||
V(*parent)[2] = &(_heap_->buffer[P_index]);
|
||||
|
||||
if (index == _heap_->size - 1 && _heap_->count % 2 != 0)
|
||||
{
|
||||
/* In this case, the current node has no MaxHeap value so */
|
||||
/* we instead compare with the MinHeap value */
|
||||
if (_heap_->f_val->cmp((*curr_node)[0], (*parent)[1]) < 0)
|
||||
break;
|
||||
|
||||
/* Since the comparison above passed now we need to swap */
|
||||
/* the current node with the parent but it will have to be */
|
||||
/* done with the node's MinHeap value since the MaxHeap */
|
||||
/* value doesn't exist */
|
||||
V tmp = (*curr_node)[0];
|
||||
(*curr_node)[0] = (*parent)[1];
|
||||
(*parent)[1] = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Usual case, just compare both MaxHeap values */
|
||||
if (_heap_->f_val->cmp((*curr_node)[1], (*parent)[1]) < 0)
|
||||
break;
|
||||
|
||||
/* Swap with parent and repeat */
|
||||
V tmp = (*curr_node)[1];
|
||||
(*curr_node)[1] = (*parent)[1];
|
||||
(*parent)[1] = tmp;
|
||||
}
|
||||
|
||||
/* Update indexe and node */
|
||||
index = P_index;
|
||||
curr_node = parent;
|
||||
}
|
||||
}
|
||||
|
||||
static void CMC_(PFX, _impl_float_up_min)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
size_t index = _heap_->size - 1;
|
||||
|
||||
V(*curr_node)[2] = &(_heap_->buffer[index]);
|
||||
|
||||
/* FLoat Up on the MinHeap */
|
||||
while (index > 0)
|
||||
{
|
||||
/* Parent index */
|
||||
size_t P_index = (index - 1) / 2;
|
||||
|
||||
V(*parent)[2] = &(_heap_->buffer[P_index]);
|
||||
|
||||
if (_heap_->f_val->cmp((*curr_node)[0], (*parent)[0]) >= 0)
|
||||
break;
|
||||
|
||||
/* Swap with parent and repeat */
|
||||
V tmp = (*curr_node)[0];
|
||||
(*curr_node)[0] = (*parent)[0];
|
||||
(*parent)[0] = tmp;
|
||||
|
||||
/* Update indexe and node */
|
||||
index = P_index;
|
||||
curr_node = parent;
|
||||
}
|
||||
}
|
||||
|
||||
static void CMC_(PFX, _impl_float_down_max)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* Floats Down from the MaxHeap */
|
||||
size_t index = 0;
|
||||
|
||||
V(*curr_node)[2] = &(_heap_->buffer[index]);
|
||||
|
||||
while (true)
|
||||
{
|
||||
/* If there are no children it is done */
|
||||
if (2 * index + 1 >= _heap_->size)
|
||||
break;
|
||||
|
||||
/* Child index to be compared with current value */
|
||||
size_t child;
|
||||
size_t L_index = index * 2 + 1;
|
||||
size_t R_index = index * 2 + 2;
|
||||
|
||||
/* If there are two children, pick the smallest one */
|
||||
if (R_index < _heap_->size)
|
||||
{
|
||||
V(*L)[2] = &(_heap_->buffer[L_index]);
|
||||
V(*R)[2] = &(_heap_->buffer[R_index]);
|
||||
|
||||
/* If the right child is the last node and there is no */
|
||||
/* MaxHeap value */
|
||||
/* then do the comparison with the MinHeap value */
|
||||
if (R_index == _heap_->size - 1 && _heap_->count % 2 != 0)
|
||||
child = _heap_->f_val->cmp((*L)[1], (*R)[0]) > 0 ? L_index : R_index;
|
||||
else
|
||||
child = _heap_->f_val->cmp((*L)[1], (*R)[1]) > 0 ? L_index : R_index;
|
||||
}
|
||||
/* Pick the only one available */
|
||||
else
|
||||
child = L_index;
|
||||
|
||||
V(*child_node)[2] = &(_heap_->buffer[child]);
|
||||
|
||||
/* Again, check if the child node is the last one and has no */
|
||||
/* MaxHeap value */
|
||||
if (child == _heap_->size - 1 && _heap_->count % 2 != 0)
|
||||
{
|
||||
/* Odd case, compare with MinHeap value */
|
||||
/* If current value is not less than the child node's */
|
||||
/* value it is done */
|
||||
if (_heap_->f_val->cmp((*curr_node)[1], (*child_node)[0]) >= 0)
|
||||
break;
|
||||
|
||||
/* Otherwise swap and continue */
|
||||
V tmp = (*child_node)[0];
|
||||
(*child_node)[0] = (*curr_node)[1];
|
||||
(*curr_node)[1] = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If current value is not less than the child node's */
|
||||
/* value it is done */
|
||||
if (_heap_->f_val->cmp((*curr_node)[1], (*child_node)[1]) >= 0)
|
||||
break;
|
||||
|
||||
/* Otherwise swap and continue */
|
||||
V tmp = (*child_node)[1];
|
||||
(*child_node)[1] = (*curr_node)[1];
|
||||
(*curr_node)[1] = tmp;
|
||||
|
||||
/* Check if the MinHeap and MaxHeap values need to be */
|
||||
/* swapped */
|
||||
if (_heap_->f_val->cmp((*child_node)[0], (*child_node)[1]) > 0)
|
||||
{
|
||||
/* Swap because the MinHeap value is greater than the */
|
||||
/* MaxHeap value */
|
||||
tmp = (*child_node)[0];
|
||||
(*child_node)[0] = (*child_node)[1];
|
||||
(*child_node)[1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update index and node */
|
||||
index = child;
|
||||
curr_node = child_node;
|
||||
}
|
||||
}
|
||||
|
||||
static void CMC_(PFX, _impl_float_down_min)(struct SNAME *_heap_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
/* Floats Down from the MinHeap */
|
||||
size_t index = 0;
|
||||
|
||||
V(*curr_node)[2] = &(_heap_->buffer[index]);
|
||||
|
||||
while (true)
|
||||
{
|
||||
/* If there are no children it is done */
|
||||
if (2 * index + 1 >= _heap_->size)
|
||||
break;
|
||||
|
||||
/* Child index to be compared with current value */
|
||||
size_t child;
|
||||
size_t L_index = index * 2 + 1;
|
||||
size_t R_index = index * 2 + 2;
|
||||
|
||||
/* If there are two children, pick the smallest one */
|
||||
if (R_index < _heap_->size)
|
||||
{
|
||||
V(*L)[2] = &(_heap_->buffer[L_index]);
|
||||
V(*R)[2] = &(_heap_->buffer[R_index]);
|
||||
|
||||
child = _heap_->f_val->cmp((*L)[0], (*R)[0]) < 0 ? L_index : R_index;
|
||||
}
|
||||
/* Pick the only one available */
|
||||
else
|
||||
child = L_index;
|
||||
|
||||
V(*child_node)[2] = &(_heap_->buffer[child]);
|
||||
|
||||
/* If current value is smaller than the child node's value, it */
|
||||
/* is done */
|
||||
if (_heap_->f_val->cmp((*curr_node)[0], (*child_node)[0]) < 0)
|
||||
break;
|
||||
|
||||
/* Otherwise swap and continue */
|
||||
V tmp = (*child_node)[0];
|
||||
(*child_node)[0] = (*curr_node)[0];
|
||||
(*curr_node)[0] = tmp;
|
||||
|
||||
/* If the child node is the last node check if the MinHeap and */
|
||||
/* MaxHeap values need to be swapped */
|
||||
if (child != _heap_->size - 1 || _heap_->count % 2 == 0)
|
||||
{
|
||||
if (_heap_->f_val->cmp((*child_node)[0], (*child_node)[1]) > 0)
|
||||
{
|
||||
/* Swap because the MinHeap value is greater than the */
|
||||
/* MaxHeap value */
|
||||
tmp = (*child_node)[0];
|
||||
(*child_node)[0] = (*child_node)[1];
|
||||
(*child_node)[1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update index and node */
|
||||
index = child;
|
||||
curr_node = child_node;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Intervalheap bi-directional iterator.
|
||||
*
|
||||
* TODO allow creation of iterators exclusively for min or max heap
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = 0;
|
||||
iter.start = true;
|
||||
iter.end = CMC_(PFX, _empty)(target);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = 0;
|
||||
iter.start = CMC_(PFX, _empty)(target);
|
||||
iter.end = true;
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
iter.cursor = target->count - 1;
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = 0;
|
||||
iter->start = true;
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->target->count - 1;
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
iter->end = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->cursor + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->cursor == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->cursor + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->cursor + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor += steps;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->cursor == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->cursor < steps)
|
||||
return false;
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor -= steps;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at the */
|
||||
/* given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->cursor > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->cursor - index);
|
||||
else if (iter->cursor < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->cursor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (V){ 0 };
|
||||
|
||||
return iter->target->buffer[iter->cursor / 2][iter->cursor % 2];
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return iter->cursor;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *h_ = _heap_;
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"size:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"flag:%d, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), h_, h_->buffer, h_->capacity, h_->size, h_->count,
|
||||
h_->flag, h_->f_val, h_->alloc, CMC_CALLBACKS_GET(h_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
for (size_t i = 0; i < _heap_->count; i++)
|
||||
{
|
||||
if (!_heap_->f_val->str(fptr, _heap_->buffer[i / 2][i % 2]))
|
||||
return false;
|
||||
|
||||
if (i + 1 < _heap_->count)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* List bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* IntervalHeap Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target IntervalHeap */
|
||||
struct SNAME *target;
|
||||
|
||||
/* Cursor's position (index) */
|
||||
size_t cursor;
|
||||
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
/* Iterator Initialization */
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr);
|
||||
bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end);
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Value struct function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Functions */
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks);
|
||||
void CMC_(PFX, _clear)(struct SNAME *_heap_);
|
||||
void CMC_(PFX, _free)(struct SNAME *_heap_);
|
||||
/* Customization of Allocation and Callbacks */
|
||||
void CMC_(PFX, _customize)(struct SNAME *_heap_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value);
|
||||
bool CMC_(PFX, _remove_max)(struct SNAME *_heap_);
|
||||
bool CMC_(PFX, _remove_min)(struct SNAME *_heap_);
|
||||
/* Collection Update */
|
||||
bool CMC_(PFX, _update_max)(struct SNAME *_heap_, V value);
|
||||
bool CMC_(PFX, _update_min)(struct SNAME *_heap_, V value);
|
||||
/* Element Access */
|
||||
V CMC_(PFX, _max)(struct SNAME *_heap_);
|
||||
V CMC_(PFX, _min)(struct SNAME *_heap_);
|
||||
/* Collection State */
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value);
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_heap_);
|
||||
bool CMC_(PFX, _full)(struct SNAME *_heap_);
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_heap_);
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_heap_);
|
||||
int CMC_(PFX, _flag)(struct SNAME *_heap_);
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity);
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_);
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_);
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
struct SNAME
|
||||
{
|
||||
/* Dynamic array of elements */
|
||||
/* buffer[n][0] is MinHeap and buffer[n][1] is MaxHeap */
|
||||
V (*buffer)[2];
|
||||
/* Current array capacity */
|
||||
size_t capacity;
|
||||
/* Current amount of pairs of values in the array */
|
||||
size_t size;
|
||||
/* Current amount of elements in the heap */
|
||||
size_t count;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val;
|
||||
/* Custom allocation functions */
|
||||
CMC_ALLOC_TYPE alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* linkedlist.h
|
||||
*
|
||||
* Creation Date: 22/03/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* LinkedList
|
||||
*
|
||||
* A LinkedList is a linear collection of elements, whose order is not given by
|
||||
* their physical placement in memory. Instead, each element points to the next
|
||||
* (singly-linked list) and to a previous one (doubly-linked list). It consists
|
||||
* of nodes connected by these next or previous pointers. Unlike an array, the
|
||||
* LinkedList can indefinitely grow.
|
||||
*
|
||||
* Implementation
|
||||
*
|
||||
* The LinkedList is implemented as a doubly-linked list and allows insertions
|
||||
* and removals at both ends in O(1) and in a given index in O(N). The list has
|
||||
* a head and tail pointer. The head points to the first element in the sequence
|
||||
* and tail points to the last.
|
||||
*/
|
||||
|
||||
#include "cor/core.h"
|
||||
|
||||
#ifdef CMC_DEV
|
||||
#include "utl/log.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* V - linkedlist data type
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
|
||||
/* Structs definition */
|
||||
#include "cmc/linkedlist/struct.h"
|
||||
|
||||
/* Function declaration */
|
||||
#include "cmc/linkedlist/header.h"
|
||||
|
||||
/* Function implementation */
|
||||
#include "cmc/linkedlist/code.h"
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* INIT - Initializes the struct on the stack
|
||||
* ITER - List iterator
|
||||
* NODE - Operations relative to a linkedlist node
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_LINKEDLIST_PARTS INIT, ITER, NODE, STR
|
||||
/**/
|
||||
#include "cmc/linkedlist/ext/struct.h"
|
||||
/**/
|
||||
#include "cmc/linkedlist/ext/header.h"
|
||||
/**/
|
||||
#include "cmc/linkedlist/ext/code.h"
|
||||
|
||||
#include "cor/undef.h"
|
||||
@@ -0,0 +1,619 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _impl_get_node)(struct SNAME *_list_, size_t index);
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _impl_new_node)(struct SNAME *_list_, V value);
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _new_custom)(f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
|
||||
CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!f_val)
|
||||
return NULL;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_list_)
|
||||
return NULL;
|
||||
|
||||
_list_->count = 0;
|
||||
_list_->head = NULL;
|
||||
_list_->tail = NULL;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
_list_->f_val = f_val;
|
||||
_list_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_list_, callbacks);
|
||||
|
||||
return _list_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_list_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *scan = _list_->head;
|
||||
|
||||
while (_list_->head != NULL)
|
||||
{
|
||||
_list_->head = _list_->head->next;
|
||||
|
||||
if (_list_->f_val->free)
|
||||
{
|
||||
_list_->f_val->free(scan->value);
|
||||
}
|
||||
|
||||
_list_->alloc->free(scan);
|
||||
|
||||
scan = _list_->head;
|
||||
}
|
||||
|
||||
_list_->count = 0;
|
||||
_list_->head = NULL;
|
||||
_list_->tail = NULL;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_list_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_(PFX, _clear)(_list_);
|
||||
|
||||
_list_->alloc->free(_list_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_list_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_list_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_list_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_list_, callbacks);
|
||||
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _push_front)(struct SNAME *_list_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *_node_ = CMC_(PFX, _impl_new_node)(_list_, value);
|
||||
|
||||
if (!_node_)
|
||||
return false;
|
||||
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->head = _node_;
|
||||
_list_->tail = _node_;
|
||||
}
|
||||
else
|
||||
{
|
||||
_node_->next = _list_->head;
|
||||
_list_->head->prev = _node_;
|
||||
_list_->head = _node_;
|
||||
}
|
||||
|
||||
_list_->count++;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _push_at)(struct SNAME *_list_, V value, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (index > _list_->count)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_RANGE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
return CMC_(PFX, _push_front)(_list_, value);
|
||||
}
|
||||
else if (index == _list_->count)
|
||||
{
|
||||
return CMC_(PFX, _push_back)(_list_, value);
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *_node_ = CMC_(PFX, _impl_new_node)(_list_, value);
|
||||
|
||||
if (!_node_)
|
||||
return false;
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *scan = CMC_(PFX, _impl_get_node)(_list_, index - 1);
|
||||
|
||||
_node_->next = scan->next;
|
||||
_node_->prev = scan;
|
||||
_node_->next->prev = _node_;
|
||||
_node_->prev->next = _node_;
|
||||
|
||||
_list_->count++;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _push_back)(struct SNAME *_list_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *_node_ = CMC_(PFX, _impl_new_node)(_list_, value);
|
||||
|
||||
if (!_node_)
|
||||
return false;
|
||||
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->head = _node_;
|
||||
_list_->tail = _node_;
|
||||
}
|
||||
else
|
||||
{
|
||||
_node_->prev = _list_->tail;
|
||||
_list_->tail->next = _node_;
|
||||
_list_->tail = _node_;
|
||||
}
|
||||
|
||||
_list_->count++;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _pop_front)(struct SNAME *_list_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *_node_ = _list_->head;
|
||||
_list_->head = _list_->head->next;
|
||||
|
||||
_list_->alloc->free(_node_);
|
||||
|
||||
if (_list_->head == NULL)
|
||||
_list_->tail = NULL;
|
||||
else
|
||||
_list_->head->prev = NULL;
|
||||
|
||||
_list_->count--;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _pop_at)(struct SNAME *_list_, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index >= _list_->count)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_RANGE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
return CMC_(PFX, _pop_front)(_list_);
|
||||
}
|
||||
else if (index == _list_->count - 1)
|
||||
{
|
||||
return CMC_(PFX, _pop_back)(_list_);
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *_node_ = CMC_(PFX, _impl_get_node)(_list_, index);
|
||||
|
||||
if (!_node_)
|
||||
return false;
|
||||
|
||||
_node_->next->prev = _node_->prev;
|
||||
_node_->prev->next = _node_->next;
|
||||
|
||||
_list_->alloc->free(_node_);
|
||||
|
||||
_list_->count--;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _pop_back)(struct SNAME *_list_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *_node_ = _list_->tail;
|
||||
_list_->tail = _list_->tail->prev;
|
||||
|
||||
_list_->alloc->free(_node_);
|
||||
|
||||
if (_list_->tail == NULL)
|
||||
_list_->head = NULL;
|
||||
else
|
||||
_list_->tail->next = NULL;
|
||||
|
||||
_list_->count--;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _front)(struct SNAME *_list_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_);
|
||||
|
||||
return _list_->head->value;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _get)(struct SNAME *_list_, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
if (index >= _list_->count)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_RANGE;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *scan = CMC_(PFX, _impl_get_node)(_list_, index);
|
||||
|
||||
if (scan == NULL)
|
||||
return (V){ 0 };
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_);
|
||||
|
||||
return scan->value;
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _get_ref)(struct SNAME *_list_, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (index >= _list_->count)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_RANGE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *scan = CMC_(PFX, _impl_get_node)(_list_, index);
|
||||
|
||||
if (scan == NULL)
|
||||
return NULL;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_);
|
||||
|
||||
return &(scan->value);
|
||||
}
|
||||
|
||||
V CMC_(PFX, _back)(struct SNAME *_list_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_);
|
||||
|
||||
return _list_->tail->value;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_list_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = false;
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *scan = _list_->head;
|
||||
|
||||
while (scan != NULL)
|
||||
{
|
||||
if (_list_->f_val->cmp(scan->value, value) == 0)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
scan = scan->next;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_list_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _list_->count == 0;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_list_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _list_->count;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_list_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _list_->flag;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_list_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *result = CMC_(PFX, _new_custom)(_list_->f_val, _list_->alloc, NULL);
|
||||
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(result, _list_->callbacks);
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *scan = _list_->head;
|
||||
|
||||
while (scan != NULL)
|
||||
{
|
||||
/* This allocation should never fail since it might not be */
|
||||
/* possible to recover from it. That is why it isn't checked */
|
||||
struct CMC_DEF_NODE(SNAME) * new_node;
|
||||
|
||||
if (_list_->f_val->cpy)
|
||||
new_node = CMC_(PFX, _impl_new_node)(_list_, _list_->f_val->cpy(scan->value));
|
||||
else
|
||||
new_node = CMC_(PFX, _impl_new_node)(_list_, scan->value);
|
||||
|
||||
if (!result->head)
|
||||
{
|
||||
result->head = new_node;
|
||||
result->tail = new_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_node->prev = result->tail;
|
||||
result->tail->next = new_node;
|
||||
result->tail = new_node;
|
||||
}
|
||||
|
||||
scan = scan->next;
|
||||
}
|
||||
|
||||
result->count = _list_->count;
|
||||
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_list1_, struct SNAME *_list2_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_list1_->flag = CMC_FLAG_OK;
|
||||
_list2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_list1_->count != _list2_->count)
|
||||
return false;
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *scan1 = _list1_->head;
|
||||
struct CMC_DEF_NODE(SNAME) *scan2 = _list2_->head;
|
||||
|
||||
while (scan1 != NULL && scan2 != NULL)
|
||||
{
|
||||
if (_list1_->f_val->cmp(scan1->value, scan2->value) != 0)
|
||||
return false;
|
||||
|
||||
scan1 = scan1->next;
|
||||
scan2 = scan2->next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _impl_new_node)(struct SNAME *_list_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *_node_ = _list_->alloc->malloc(sizeof(struct CMC_DEF_NODE(SNAME)));
|
||||
|
||||
if (!_node_)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_ALLOC;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_node_->value = value;
|
||||
_node_->next = NULL;
|
||||
_node_->prev = NULL;
|
||||
|
||||
return _node_;
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _impl_get_node)(struct SNAME *_list_, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (index >= _list_->count)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_RANGE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *_node_ = NULL;
|
||||
|
||||
if (index <= _list_->count / 2)
|
||||
{
|
||||
_node_ = _list_->head;
|
||||
for (size_t i = 0; i < index; i++)
|
||||
{
|
||||
_node_ = _node_->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_node_ = _list_->tail;
|
||||
for (size_t i = _list_->count - 1; i > index; i--)
|
||||
{
|
||||
_node_ = _node_->prev;
|
||||
}
|
||||
}
|
||||
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
return _node_;
|
||||
}
|
||||
@@ -0,0 +1,610 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* List bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = target->head;
|
||||
iter.index = 0;
|
||||
iter.start = true;
|
||||
iter.end = CMC_(PFX, _empty)(target);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = target->tail;
|
||||
iter.index = 0;
|
||||
iter.start = CMC_(PFX, _empty)(target);
|
||||
iter.end = true;
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
iter.index = target->count - 1;
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->target->head;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->target->tail;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
iter->end = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->cursor->next == NULL)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor = iter->cursor->next;
|
||||
iter->index++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->cursor->prev == NULL)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor = iter->cursor->prev;
|
||||
iter->index--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->cursor->next == NULL)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->index += steps;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
iter->cursor = iter->cursor->next;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->cursor->prev == NULL)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index < steps)
|
||||
return false;
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->index -= steps;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
iter->cursor = iter->cursor->prev;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at the */
|
||||
/* given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->index > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
|
||||
else if (iter->index < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (V){ 0 };
|
||||
|
||||
return iter->cursor->value;
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return NULL;
|
||||
|
||||
return &(iter->cursor->value);
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return iter->index;
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _iter_node)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return iter->cursor;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* NODE
|
||||
*
|
||||
* Operations relative to a linkedlist node
|
||||
*/
|
||||
#ifdef CMC_EXT_NODE
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _new_node)(struct SNAME *_list_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *_node_ = _list_->alloc->malloc(sizeof(struct CMC_DEF_NODE(SNAME)));
|
||||
|
||||
if (!_node_)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_ALLOC;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_node_->value = value;
|
||||
_node_->next = NULL;
|
||||
_node_->prev = NULL;
|
||||
|
||||
return _node_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free_node)(struct SNAME *_list_, struct CMC_DEF_NODE(SNAME) * _node_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
_list_->alloc->free(_node_);
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _head)(struct SNAME *_list_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _list_->head;
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _get_node)(struct SNAME *_list_, size_t index)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (index >= _list_->count)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_RANGE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *_node_ = NULL;
|
||||
|
||||
if (index <= _list_->count / 2)
|
||||
{
|
||||
_node_ = _list_->head;
|
||||
for (size_t i = 0; i < index; i++)
|
||||
{
|
||||
_node_ = _node_->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_node_ = _list_->tail;
|
||||
for (size_t i = _list_->count - 1; i > index; i--)
|
||||
{
|
||||
_node_ = _node_->prev;
|
||||
}
|
||||
}
|
||||
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
return _node_;
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _tail)(struct SNAME *_list_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _list_->tail;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _add_next)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *new_node = CMC_(PFX, _new_node)(_owner_, value);
|
||||
|
||||
if (!new_node)
|
||||
return false;
|
||||
|
||||
new_node->next = _node_->next;
|
||||
|
||||
if (_node_->next != NULL)
|
||||
_node_->next->prev = new_node;
|
||||
else
|
||||
_owner_->tail = new_node;
|
||||
|
||||
new_node->prev = _node_;
|
||||
_node_->next = new_node;
|
||||
|
||||
_owner_->count++;
|
||||
_owner_->flag = CMC_FLAG_OK;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _add_prev)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_, V value)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *new_node = CMC_(PFX, _new_node)(_owner_, value);
|
||||
|
||||
if (!new_node)
|
||||
return false;
|
||||
|
||||
new_node->prev = _node_->prev;
|
||||
|
||||
if (_node_->prev != NULL)
|
||||
_node_->prev->next = new_node;
|
||||
else
|
||||
_owner_->head = new_node;
|
||||
|
||||
new_node->next = _node_;
|
||||
_node_->prev = new_node;
|
||||
|
||||
_owner_->count++;
|
||||
_owner_->flag = CMC_FLAG_OK;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _del_next)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_node_->next == NULL)
|
||||
{
|
||||
_owner_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *tmp = _node_->next;
|
||||
|
||||
_node_->next = _node_->next->next;
|
||||
|
||||
if (tmp->next != NULL)
|
||||
tmp->next->prev = _node_;
|
||||
else
|
||||
_owner_->tail = _node_;
|
||||
|
||||
_owner_->alloc->free(tmp);
|
||||
|
||||
_owner_->count--;
|
||||
_owner_->flag = CMC_FLAG_OK;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _del_curr)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_node_->prev != NULL)
|
||||
_node_->prev->next = _node_->next;
|
||||
else
|
||||
_owner_->head = _node_->next;
|
||||
|
||||
if (_node_->next != NULL)
|
||||
_node_->next->prev = _node_->prev;
|
||||
else
|
||||
_owner_->tail = _node_->prev;
|
||||
|
||||
_owner_->alloc->free(_node_);
|
||||
|
||||
_owner_->count--;
|
||||
_owner_->flag = CMC_FLAG_OK;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _del_prev)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
if (_node_->prev == NULL)
|
||||
{
|
||||
_owner_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *tmp = _node_->prev;
|
||||
|
||||
_node_->prev = _node_->prev->prev;
|
||||
|
||||
if (tmp->prev != NULL)
|
||||
tmp->prev->next = _node_;
|
||||
else
|
||||
_owner_->head = _node_;
|
||||
|
||||
_owner_->alloc->free(tmp);
|
||||
|
||||
_owner_->count--;
|
||||
_owner_->flag = CMC_FLAG_OK;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _next_node)(struct CMC_DEF_NODE(SNAME) * _node_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _node_->next;
|
||||
}
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _prev_node)(struct CMC_DEF_NODE(SNAME) * _node_)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
return _node_->prev;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_NODE */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_list_, FILE *fptr)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
struct SNAME *l_ = _list_;
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s> "
|
||||
"at %p { "
|
||||
"count:%" PRIuMAX ", "
|
||||
"head:%p, "
|
||||
"tail:%p, "
|
||||
"flag:%d, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), l_, l_->count, l_->head, l_->tail, l_->flag, l_->f_val,
|
||||
l_->alloc, CMC_CALLBACKS_GET(l_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_list_, FILE *fptr, const char *start, const char *separator, const char *end)
|
||||
{
|
||||
#ifdef CMC_DEV
|
||||
CMC_DEV_FCALL;
|
||||
#endif
|
||||
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
struct CMC_DEF_NODE(SNAME) *scan = _list_->head;
|
||||
|
||||
while (scan != NULL)
|
||||
{
|
||||
if (!_list_->f_val->str(fptr, scan->value))
|
||||
return false;
|
||||
|
||||
scan = scan->next;
|
||||
|
||||
if (scan)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_INIT
|
||||
|
||||
#endif /* CMC_EXT_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* List bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
/* LinkedList Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target Linked List */
|
||||
struct SNAME *target;
|
||||
/* Cursor's current node */
|
||||
struct CMC_DEF_NODE(SNAME) * cursor;
|
||||
/* Keeps track of relative index to the iteration of elements */
|
||||
size_t index;
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
/* Iterator Initialization */
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _iter_node)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
|
||||
/**
|
||||
* NODE
|
||||
*
|
||||
* Operations relative to a linkedlist node
|
||||
*/
|
||||
#ifdef CMC_EXT_NODE
|
||||
|
||||
/* Node Allocation and Deallocation */
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _new_node)(struct SNAME *_list_, V value);
|
||||
void CMC_(PFX, _free_node)(struct SNAME *_list_, struct CMC_DEF_NODE(SNAME) * _node_);
|
||||
/* Node Access Relative to a Linked List */
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _head)(struct SNAME *_list_);
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _get_node)(struct SNAME *_list_, size_t index);
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _tail)(struct SNAME *_list_);
|
||||
/* Input and Output Relative to a Node */
|
||||
bool CMC_(PFX, _add_next)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_, V value);
|
||||
bool CMC_(PFX, _add_prev)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_, V value);
|
||||
bool CMC_(PFX, _del_next)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_);
|
||||
bool CMC_(PFX, _del_curr)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_);
|
||||
bool CMC_(PFX, _del_prev)(struct SNAME *_owner_, struct CMC_DEF_NODE(SNAME) * _node_);
|
||||
/* Node Access Relative to a Linked List Node */
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _next_node)(struct CMC_DEF_NODE(SNAME) * _node_);
|
||||
struct CMC_DEF_NODE(SNAME) * CMC_(PFX, _prev_node)(struct CMC_DEF_NODE(SNAME) * _node_);
|
||||
|
||||
#endif /* CMC_EXT_NODE */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_list_, FILE *fptr);
|
||||
bool CMC_(PFX, _print)(struct SNAME *_list_, FILE *fptr, const char *start, const char *separator, const char *end);
|
||||
|
||||
#endif /* CMC_EXT_STR */
|
||||
Loaded 100 of 394 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user