Compare commits
189
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 |
No files matched your search
+2
-2
@@ -1,13 +1,13 @@
|
||||
# clang-format 9.0.0
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
AlignEscapedNewlines: Left
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
BreakBeforeBraces: Allman
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 80
|
||||
ColumnLimit: 120
|
||||
Cpp11BracedListStyle: false
|
||||
ForEachMacros: ["CMC_FOREACH", "CMC_FOREACH_REV"]
|
||||
IndentCaseLabels: true
|
||||
|
||||
@@ -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
|
||||
@@ -56,3 +56,9 @@ dkms.conf
|
||||
|
||||
# Experimental folder
|
||||
experimental/
|
||||
|
||||
# Test / Code Coverage build folder
|
||||
build
|
||||
|
||||
tests/coverage
|
||||
tests/out
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
dist: trusty
|
||||
os: linux
|
||||
language: c
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-7
|
||||
- cmake
|
||||
script:
|
||||
- sudo ln -s /usr/bin/gcc-6 /usr/local/bin/gcc
|
||||
- export CC=gcc-7
|
||||
# - make -C ./tests/
|
||||
- make -C ./tests/main/
|
||||
- make -C ./tests/codecov/
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
@@ -1,6 +1,54 @@
|
||||
# RELEASE.MAJOR.MINOR
|
||||
|
||||
1.8.0
|
||||
0.26.0
|
||||
Complete refactor of the library, using a different approach to code generation
|
||||
|
||||
0.25.0
|
||||
New Project Architecture - Files are no longer separated in folders, but rather prefixed by their sub-library
|
||||
Added sac_list.h
|
||||
|
||||
0.24.0
|
||||
A lot of breaking changes, with the library more modular now
|
||||
Comeback of PUBLIC and PRIVATE for the CMC sub-library
|
||||
Callbacks are now optional and can be turned off by defining CMC_NO_CALLBACKS
|
||||
Added EXT library
|
||||
New macro CMC_CAMEL_CASE can change the library's style where the default is snake case
|
||||
Added:
|
||||
./cor/alloc.h
|
||||
./cor/callbacks.h
|
||||
./cor/heap.h
|
||||
Complete rework of tests and code coverage using autogen.py
|
||||
Removed cmc_flags, where now every flag is an enum (CMC_FLAGS_OK, CMC_FLAGS_ERROR, etc)
|
||||
Different include guards
|
||||
New way to generate code using PARAM
|
||||
Code now completely changed by using the CMC_ macro to concatenate tokens
|
||||
Token concatenation with SNAME now uses special macros that allow customization of the suffixes
|
||||
|
||||
0.23.1
|
||||
Added ./cor/bitset.h
|
||||
Added foreach tests
|
||||
Updating foreach macros with the new iterators API
|
||||
Bug fixes for ./cmc/hashmultiset.h
|
||||
|
||||
0.23.0
|
||||
Added ./cmc/bitset.h
|
||||
Added ./cor/flags.h
|
||||
Added ./utl/futils.h
|
||||
Added ./utl/mutex.h
|
||||
Added ./utl/thread.h
|
||||
Added cmc_flags_to_str
|
||||
Added autogen.py for automated code generation for code coverage
|
||||
Changed the iterator API
|
||||
Merged ./tests/codecov and ./tests/main
|
||||
Renamed ftab_key to fkey and ftab_val to fval
|
||||
Renamed collections
|
||||
- bidimap -> hashbidimap
|
||||
- multimap -> hashmultimap
|
||||
- multiset -> hashmultiset
|
||||
|
||||
-- Versioning restarted for compatibility with SemVer (https://semver.org/)
|
||||
|
||||
1.8.0 (0.22.0)
|
||||
Added Function Tables
|
||||
Added Error Codes
|
||||
Added Callback Functions
|
||||
@@ -14,13 +62,13 @@
|
||||
Removed ./utl/cmc_string.h
|
||||
Replaced CMC_FOR_EACH and CMC_FOR_EACH_REV by CMC_FOREACH and CMC_FOREACH_REV
|
||||
|
||||
1.7.3
|
||||
1.7.3 (0.21.0)
|
||||
Breaking changes:
|
||||
- ext collections merged to cmc
|
||||
- No more typedefs in code generated
|
||||
Fast forwarded codecov
|
||||
|
||||
1.7.2
|
||||
1.7.2 (0.20.0)
|
||||
Added resize function to array based collections
|
||||
Added the following functions to hashtable based collections:
|
||||
- load
|
||||
@@ -31,18 +79,18 @@
|
||||
Removed unnecessary conditional input and output functions
|
||||
Minor fixes throughout the library
|
||||
|
||||
1.7.1
|
||||
1.7.1 (0.19.0)
|
||||
Added new assert macro cmc_assert_sorted
|
||||
Fixed some include guards for hashtables
|
||||
Moved the cmc string format to each file
|
||||
Renamed some list functions (sequence input/output)
|
||||
Renamed list and linkedlist functions push and pop to push_at and pop_at
|
||||
|
||||
1.7.0
|
||||
1.7.0 (0.18.0)
|
||||
Removed FMOD (function modifier)
|
||||
Added CMC prefix to all macros defined within the library
|
||||
|
||||
1.6.3
|
||||
1.6.3 (0.17.0)
|
||||
Added iterator functions to all collections:
|
||||
- iter_advance
|
||||
- iter_rewind
|
||||
@@ -50,7 +98,7 @@
|
||||
Added cmc prefix to the logging utility
|
||||
Integrated the assert utility with the test utility. Now any assertion that fails inside the unit test will trigger failure and is no longer needed to manually pass or fail tests.
|
||||
|
||||
1.6.2
|
||||
1.6.2 (0.16.0)
|
||||
Added new functions to all collections:
|
||||
- copy_of
|
||||
- equals
|
||||
@@ -58,11 +106,11 @@
|
||||
Fixed some collections and some improvements to the hashtables
|
||||
Unified the functions set and update from the map implementations
|
||||
|
||||
1.6.1
|
||||
1.6.1 (0.15.0)
|
||||
Removed ./ext/linkedqueue.h
|
||||
Added a deallocator parameter to all _free and _clear functions
|
||||
|
||||
1.6.0
|
||||
1.6.0 (0.14.0)
|
||||
Added ./ext/intervalheap.h
|
||||
Added ./ext/multimap.h
|
||||
Added ./ext/multiset.h
|
||||
@@ -72,12 +120,12 @@
|
||||
Fixed hashtables integer overflow when the capacity is divided by the load factor
|
||||
Changed timer.h struct name from timer_t to cmc_timer to prevent name collisions on linux
|
||||
|
||||
1.5.3
|
||||
1.5.3 (0.13.0)
|
||||
Tests completely reorganized and now with full code coverage
|
||||
Some fixes where there was a missing return statement
|
||||
Expanded ./utl/assert.h
|
||||
|
||||
1.5.2
|
||||
1.5.2 (0.12.0)
|
||||
Added ./utl/test.h
|
||||
Added ./utl/assert.h
|
||||
Added ./tests/list.c - UnitTest for LIST
|
||||
@@ -85,13 +133,13 @@
|
||||
Removed ./utl/log.h functions that were unnecessary
|
||||
Added the CMC namespace to CONCATC and CONCATH at macro_collections.h
|
||||
|
||||
1.5.1
|
||||
1.5.1 (0.11.0)
|
||||
New queue benchmark
|
||||
Added ./sac/queue.h
|
||||
Added ./utl/timer.h
|
||||
Fixing descriptions and other minor fixes
|
||||
|
||||
1.5.0
|
||||
1.5.0 (0.10.0)
|
||||
Changed tests compilation and execution to a single Makefile
|
||||
Changed project structure
|
||||
./src/
|
||||
@@ -105,7 +153,7 @@
|
||||
Added ./ext/linkedqueue.h - A singly-linked list based queue
|
||||
Added ./sac/stack.h - A Stack purely allocated on the stack
|
||||
|
||||
1.4.3
|
||||
1.4.3 (0.9.0)
|
||||
Fixed some functions names
|
||||
Added set functions for both Tree and Hash Set
|
||||
- is_subset
|
||||
@@ -114,7 +162,7 @@
|
||||
- is_proper_subset
|
||||
- is_disjointset
|
||||
|
||||
1.4.2
|
||||
1.4.2 (0.8.0)
|
||||
Adapted code so that plain struct type is accepted
|
||||
Changed TreeSet max and min to be compatible with the TreeMap and the hash collections
|
||||
Changed function modifier of all implementation detail to static
|
||||
@@ -122,12 +170,12 @@
|
||||
Added types.c to test if it is possible to compile all the collections' generated code accepting all C data types
|
||||
Removed pointertype.c (replaced by types.c)
|
||||
|
||||
1.4.1
|
||||
1.4.1 (0.7.0)
|
||||
Removed PUBLIC and PRIVATE from the main macro
|
||||
Corrected examples and benchmark
|
||||
Added new test consisting of compiling the header and source separately
|
||||
|
||||
1.4.0
|
||||
1.4.0 (0.6.0)
|
||||
New way on how iterators work to all collections
|
||||
Added iter_init to work with stack allocated iterators
|
||||
Added iter_new and iter_free to work with heap allocated iterators
|
||||
@@ -139,48 +187,48 @@
|
||||
Changed pointertype test to be a pointer to struct instead of pointer to char
|
||||
Added CHANGELOG and TODO
|
||||
|
||||
1.3.0
|
||||
1.3.0 (0.5.0)
|
||||
Changed how the linkedlist functions relative to nodes work
|
||||
Removed reference to owner list on each node
|
||||
Renamed some functions for consistency
|
||||
|
||||
1.2.4
|
||||
1.2.4 (0.4.1)
|
||||
Fixing some declarations in hashset and hashmap where a pointer type would cause problems
|
||||
Added a test to make sure all collections support pointer type
|
||||
Tests:
|
||||
- pointertype
|
||||
|
||||
1.2.3
|
||||
1.2.3 (0.4.0)
|
||||
Added get_ref functions to all collections that support it (only included in hashmap, linkedlist, list and treemap)
|
||||
|
||||
1.2.2
|
||||
1.2.2 (0.3.2)
|
||||
Removed unnecessary modulo operation in hashtable functions
|
||||
|
||||
1.2.1
|
||||
1.2.1 (0.3.1)
|
||||
Optimized list - now using 'string.h' functions to shift elements around instead of for-loops:
|
||||
- memset
|
||||
- memcpy
|
||||
- memmove
|
||||
|
||||
1.2.0
|
||||
1.2.0 (0.3.0)
|
||||
'contains' functions added to all collections
|
||||
'contains' tests and benchmark
|
||||
Unified Benchmark
|
||||
Updated examples
|
||||
|
||||
1.1.3
|
||||
1.1.3 (0.2.3)
|
||||
Renamed deque's 'rear' struct member to 'back' to be more consistent with other collections
|
||||
Better benchmark and foreach tests are alphabetically ordered
|
||||
|
||||
1.1.2
|
||||
1.1.2 (0.2.2)
|
||||
Fixing iterators for when they are initialized with an empty target
|
||||
Better iterator tests
|
||||
More examples
|
||||
|
||||
1.1.1
|
||||
1.1.1 (0.2.1)
|
||||
Reordering functions (implementation details are now at the end of each file)
|
||||
|
||||
1.1.0
|
||||
1.1.0 (0.2.0)
|
||||
Added new list functions:
|
||||
- new_from
|
||||
- prepend
|
||||
@@ -189,10 +237,10 @@
|
||||
- remove
|
||||
- fits
|
||||
|
||||
1.0.1
|
||||
1.0.1 (0.1.1)
|
||||
Fixed hashset logic in robin-hood hashing
|
||||
|
||||
1.0.0
|
||||
1.0.0 (0.1.0)
|
||||
First stable version
|
||||
Includes the following collections:
|
||||
- deque
|
||||
|
||||
@@ -1,22 +1,35 @@
|
||||
# This file is useful to format all the source files and header in this library using clang-format
|
||||
|
||||
.PHONY: all cmc dev sac utl tests FORCE
|
||||
help:
|
||||
@echo Welcome to the C Macro Collections Library. Targets:
|
||||
@echo
|
||||
@echo - tests: run tests
|
||||
@echo - tests_dev: run tests for dev
|
||||
@echo - format: formats the entire project
|
||||
@echo - bench: runs benchmarks
|
||||
@echo - docbuild: builds documentation to ./docs
|
||||
@echo - docserve: serves mdbook docs
|
||||
@echo - install_dev_deps: install dev dependencies
|
||||
|
||||
all: cmc dev sac utl tests
|
||||
tests:
|
||||
make -C ./tests
|
||||
|
||||
cmc: FORCE
|
||||
clang-format --style=file -i ./src/cmc/*.h
|
||||
tests_dev:
|
||||
make -C ./tests dev
|
||||
|
||||
dev: FORCE
|
||||
clang-format --style=file -i ./src/dev/*.h
|
||||
format:
|
||||
- find ./ -name *.h -type f | xargs clang-format --style=file --verbose -i
|
||||
|
||||
sac: FORCE
|
||||
clang-format --style=file -i ./src/sac/*.h
|
||||
bench:
|
||||
make -C ./benchmarks benchmark
|
||||
|
||||
utl: FORCE
|
||||
clang-format --style=file -i ./src/utl/*.h
|
||||
docbuild:
|
||||
mdbook build -d ../docs documentation
|
||||
|
||||
tests: FORCE
|
||||
clang-format --style=file -i ./tests/main/unt/*.c ./tests/*.c
|
||||
docserve:
|
||||
mdbook serve documentation
|
||||
|
||||
FORCE:
|
||||
install_dev_deps:
|
||||
sudo apt install gcc make valgrind lcov clang-format hyperfine
|
||||
cargo install mdbook
|
||||
|
||||
.PHONY: tests tests_dev format bench docbuild docserve install_dev_deps
|
||||
@@ -1,94 +1,194 @@
|
||||
# C Macro Collections
|
||||
|
||||
<p align="center">
|
||||
<img src="https://leoven.github.io/C-Macro-Collections/images/logo.png" alt="C Macro Collections Logo" width="300"/>
|
||||
<img src="https://leoven.github.io/C-Macro-Collections/img/logo.png" alt="C Macro Collections Logo" width="300"/>
|
||||
</p>
|
||||
|
||||
<p align="center">Header only, macro generated, generic and type-safe Collections in C.</p>
|
||||
<p align="center">Easy to use, modular, header only, macro based, generic and type-safe Data Structures in C</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/LeoVen/C-Macro-Collections"><img src="https://img.shields.io/badge/GitHub-C%20Macro%20Collections-lightgrey.svg?logo=github" alt="LinkToRepo"/></a>
|
||||
<a href="https://leoven.github.io/C-Macro-Collections/"><img style="color: #ffffff;" src="https://img.shields.io/badge/Read%20the%20Docs-5A5A5A.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHN0eWxlPSIiPjxyZWN0IGlkPSJiYWNrZ3JvdW5kcmVjdCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgeD0iMCIgeT0iMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJub25lIi8%2BPHRpdGxlPmljbi9kb2MtdGV4dDwvdGl0bGU%2BPGcgY2xhc3M9ImN1cnJlbnRMYXllciIgc3R5bGU9IiI%2BPHRpdGxlPkxheWVyIDE8L3RpdGxlPjxwYXRoIGQ9Ik01IDFoNC4yNDRhMiAyIDAgMCAxIDEuNDM0LjYwNmwyLjc1NiAyLjgzNEEyIDIgMCAwIDEgMTQgNS44MzVWMTJhMyAzIDAgMCAxLTMgM0g1YTMgMyAwIDAgMS0zLTNWNGEzIDMgMCAwIDEgMy0zem0wIDJhMSAxIDAgMCAwLTEgMXY4YTEgMSAwIDAgMCAxIDFoNmExIDEgMCAwIDAgMS0xVjUuODM1TDkuMjQ0IDNINXptMS41IDdoM2EuNS41IDAgMSAxIDAgMWgtM2EuNS41IDAgMSAxIDAtMXptMC0yaDJhLjUuNSAwIDAgMSAwIDFoLTJhLjUuNSAwIDAgMSAwLTF6TTggMmwzIDEuOTk1TDEzIDdIOWExIDEgMCAwIDEtMS0xVjJ6IiBpZD0iYSIgY2xhc3M9IiIgZmlsbD0iI2ZmZmZmZiIgZmlsbC1vcGFjaXR5PSIxIi8%2BPC9nPjwvc3ZnPg%3D%3D" alt="LinkToDocs"/></a>
|
||||
<a href="https://github.com/LeoVen/C-Macro-Collections"><img src="https://img.shields.io/badge/GitHub-C%20Macro%20Collections-2195F3.svg?logo=github" alt="LinkToRepo"/></a>
|
||||
<a href="https://leoven.github.io/C-Macro-Collections/"><img style="color: #ffffff;" src="https://img.shields.io/badge/Read%20the%20Docs-D13636.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHN0eWxlPSIiPjxyZWN0IGlkPSJiYWNrZ3JvdW5kcmVjdCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgeD0iMCIgeT0iMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJub25lIi8%2BPHRpdGxlPmljbi9kb2MtdGV4dDwvdGl0bGU%2BPGcgY2xhc3M9ImN1cnJlbnRMYXllciIgc3R5bGU9IiI%2BPHRpdGxlPkxheWVyIDE8L3RpdGxlPjxwYXRoIGQ9Ik01IDFoNC4yNDRhMiAyIDAgMCAxIDEuNDM0LjYwNmwyLjc1NiAyLjgzNEEyIDIgMCAwIDEgMTQgNS44MzVWMTJhMyAzIDAgMCAxLTMgM0g1YTMgMyAwIDAgMS0zLTNWNGEzIDMgMCAwIDEgMy0zem0wIDJhMSAxIDAgMCAwLTEgMXY4YTEgMSAwIDAgMCAxIDFoNmExIDEgMCAwIDAgMS0xVjUuODM1TDkuMjQ0IDNINXptMS41IDdoM2EuNS41IDAgMSAxIDAgMWgtM2EuNS41IDAgMSAxIDAtMXptMC0yaDJhLjUuNSAwIDAgMSAwIDFoLTJhLjUuNSAwIDAgMSAwLTF6TTggMmwzIDEuOTk1TDEzIDdIOWExIDEgMCAwIDEtMS0xVjJ6IiBpZD0iYSIgY2xhc3M9IiIgZmlsbD0iI2ZmZmZmZiIgZmlsbC1vcGFjaXR5PSIxIi8%2BPC9nPjwvc3ZnPg%3D%3D" alt="LinkToDocs"/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/LeoVen/C-Macro-Collections/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License"/></a>
|
||||
<a href="#"><img src="https://img.shields.io/badge/Version-v1.8.0-orange.svg" alt="Version"/></a>
|
||||
<a href="https://github.com/LeoVen/C-Macro-Collections/releases"><img src="https://img.shields.io/badge/Version-v0.26.0-orange.svg" alt="Version"/></a>
|
||||
<a href="https://travis-ci.org/LeoVen/C-Macro-Collections"><img src="https://travis-ci.org/LeoVen/C-Macro-Collections.svg?branch=master" alt="travis-ci"/></a>
|
||||
<a href="https://codecov.io/gh/LeoVen/C-Macro-Collections"><img src="https://codecov.io/gh/LeoVen/C-Macro-Collections/branch/master/graph/badge.svg" alt="codecov"/></a>
|
||||
<a href="https://github.com/LeoVen/C-Macro-Collections/actions"><img src="https://github.com/LeoVen/C-Macro-Collections/workflows/Test%20Suit/badge.svg?branch=master" alt="test_suit"/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/LeoVen/C-Macro-Collections/stargazers"><img src="https://img.shields.io/github/stars/LeoVen/C-Macro-Collections?style=flat&color=ffa000" alt="Stars"/></a>
|
||||
<a href="https://github.com/XAMPPRocky/tokei"><img src="https://img.shields.io/badge/Lines%20of%20Code-28513-007596.svg" alt="loc"/></a>
|
||||
<a href="https://github.com/XAMPPRocky/tokei"><img src="https://img.shields.io/badge/Files-130-961c00.svg" alt="loc"/></a>
|
||||
</p>
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* Project Structure
|
||||
* Available Collections
|
||||
* Features
|
||||
* Overall To-Do
|
||||
* Design Decisions
|
||||
* What to use
|
||||
* How to use
|
||||
* [Installation](#installation)
|
||||
* [Contributing](#contributing)
|
||||
* [Usage](#usage)
|
||||
* [Features](#features)
|
||||
* [Project Structure](#project-structure)
|
||||
* [Available Collections](#available-collections)
|
||||
* [Other Features](#other-features)
|
||||
* [Design Decisions](#design-decisions)
|
||||
|
||||
## Installation
|
||||
|
||||
No installation is required. The entire library is made of header files and can be directly included into your project.
|
||||
|
||||
## Contributing
|
||||
|
||||
There is a lot to be done. You can check the `TODO` file in the root of the repository or the issues in the github page. Also, tests and documentation are in constant development.
|
||||
|
||||
## Usage
|
||||
|
||||
Below is a minimal example that makes use of some core functionalities. And a lot of explanation too!
|
||||
|
||||
```c
|
||||
// The C Macro Collections takes advantage of headers that can be included
|
||||
// multiple times. You can check the contents of src/cmc/list.h and there are no
|
||||
// include guards, meaning they can be included multiple times and this is what
|
||||
// generates the code.
|
||||
// Before including it though we need to define a few basic macros. You can
|
||||
// check the documentation to see which ones are required.
|
||||
#define V int // list value data type
|
||||
#define PFX intl // list function's prefix
|
||||
#define SNAME int_list // list struct name (struct int_list)
|
||||
#define CMC_EXT_STR // Enables an extra functionality (STR) of the list
|
||||
#include "cmc/list.h"
|
||||
|
||||
// This header file includes a lot of functions that can be used as methods to
|
||||
// basic data types. In this case, cmc_i32_str is used
|
||||
#include "cmc/utl/futils.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Our list type is defined by SNAME and all functions are prefixed by PFX
|
||||
// (PFX can also be thought as the function's namespace). Also, nodes,
|
||||
// entries, iterators and other structures are prefixed by SNAME. So PFX is
|
||||
// for functions and SNAME is for structs, where the main one is simply
|
||||
// 'struct SNAME'.
|
||||
// To initialize a list we need to pass in an initial capacity and something
|
||||
// that is called a function table for the V type.
|
||||
// This function table is a struct with methods that will extract some
|
||||
// (sometimes) necessary behaviour from your custom data type. Things like
|
||||
// hash, comparison and printing. A list doesn't require any of these
|
||||
// functions. That is, the CORE module doesn't use any of them.
|
||||
// But since we are using the STR module, we will need to define the 'str'
|
||||
// function. Luckily, for the 'int' type, the library already provides such
|
||||
// function (cmc_i32_str), provided by the cmc/utl/futils.h header file.
|
||||
struct int_list *list = intl_new(32, &(struct int_list_fval){ .str = cmc_i32_str, NULL });
|
||||
|
||||
// Check if the list was successfully initialized. It could fail if the
|
||||
// initial capacity is too big or if 'struct int_list_fval *' is NULL,
|
||||
// because every data structure must have a valid function table.
|
||||
if (!list)
|
||||
return 1;
|
||||
|
||||
// Add some items to the list. The CMC data structures are all dynamically
|
||||
// sized. So there can be as many items as you want as long as you have
|
||||
// enough memory.
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// Try to add an element to the list. If it fails you can check what
|
||||
// caused it by getting its flag.
|
||||
if (!intl_push_back(list, i))
|
||||
{
|
||||
enum cmc_flags flag = intl_flag(list);
|
||||
// Use cmc_flags_to_str (global variable) to map the enum error to a
|
||||
// string.
|
||||
fprintf(stderr, "%s : push_back failed\n", cmc_flags_to_str[flag]);
|
||||
}
|
||||
}
|
||||
|
||||
// Now we will use the STR module, the _print() function. This is where the
|
||||
// '.str' from the function table comes into play. If we haven't defined it,
|
||||
// the program would've crashed. We also need to define to which file we
|
||||
// will be printing the list's content. In this case, the terminal. Also,
|
||||
// some strings need to be defined. They will be printed: before all
|
||||
// elements, between each one, and after all elements. This is very useful
|
||||
// for debugging.
|
||||
intl_print(list, stdout, "[ ", ", ", " ]\n");
|
||||
|
||||
// Free all of its resources
|
||||
intl_free(list);
|
||||
}
|
||||
```
|
||||
|
||||
Now all you have to do is to compile the source code with `-I /path/to/library/src`. There is no required installation or pre-compilation.
|
||||
|
||||
## Features
|
||||
|
||||
The C Macro Collections library is organized into many other sub-libraries. The following table is a quick overview.
|
||||
|
||||
| Library | Name | Description |
|
||||
| :-----: | -------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| CMC | Macro Collections | The main library with dynamically-sized collections |
|
||||
| COR | Core | Core functionalities used by more than one collection, usually from different sub-libraries |
|
||||
| EXT | Extensions | Extension to collections |
|
||||
| SAC | Statically Allocated Collections | Collections with a fixed sized array that don't use any heap allocation |
|
||||
| TSC | Thread-Safe Collections | Collections that allow multiple operations from multiple threads |
|
||||
| UTL | Utilities | General utilities |
|
||||
|
||||
## Project Structure
|
||||
|
||||
* __benchmarks__ - Where all benchmarks are hosted
|
||||
* __docs__ - A folder hosting the generated documentation by [Slate](https://github.com/slatedocs/slate)
|
||||
* __documentation__ - Backup folder of the markdowns and custom styles used in [Slate](https://github.com/slatedocs/slate)
|
||||
* __docs__ - A folder hosting the generated documentation by [mdBook](https://github.com/rust-lang/mdBook)
|
||||
* __documentation__ - The markdowns used by [mdBook](https://github.com/rust-lang/mdBook) to generate the website
|
||||
* __examples__ - Examples using the C Macro Collections Library
|
||||
* __src__ - All headers part of the C Macro Collections Library
|
||||
* __cmc__ - The main C Macro Collections Library
|
||||
* __cor__ - Core includes in the C Macro Collections Library
|
||||
* __dev__ - The main C Macro Collections Library for development (containing logging)
|
||||
* __sac__ - Statically Allocated Collections
|
||||
* __utl__ - Utility like ForEach macros, logging, etc
|
||||
* __macro\_collections.h__ - Master header containing all collections and utilities
|
||||
* __tests__ - Where all tests are hosted
|
||||
|
||||
## Available Collections
|
||||
|
||||
* Linear Collections
|
||||
* List, LinkedList, Deque, Stack, Queue, SortedList
|
||||
* Sets
|
||||
* HashSet, TreeSet, MultiSet
|
||||
* Maps
|
||||
* BidiMap, HashMap, TreeMap, MultiMap
|
||||
* Heaps
|
||||
* Heap, IntervalHeap
|
||||
__The following table is an overview of all the currently available or upcoming data structures__:
|
||||
|
||||
| Collection <img width=250/> | Abstract Data Type <img width=250/> | Data Structure <img width=250/> | Details |
|
||||
| :--------------------------------: | :---------------------------------: | :-----------------------------: | :-----------------------------------: |
|
||||
| BidiMap <br> _bidimap.h_ | Bidirectional Map | Two Hashtables | A bijection between two sets of unique keys and unique values `K <-> V` using two hashtables |
|
||||
| Deque <br> _deque.h_ | Double-Ended Queue | Dynamic Circular Array | A circular array that allows `push` and `pop` on both ends (only) at constant time |
|
||||
| HashMap <br> _hashmap.h_ | Map | Hashtable | A unique set of keys associated with a value `K -> V` with constant time look up using a hashtable with open addressing and robin hood hashing |
|
||||
| HashSet <br> _hashset.h_ | Set | Hashtable | A unique set of values with constant time look up using a hashtable with open addressing and robin hood hashing |
|
||||
| Heap <br> _heap.h_ | Priority Queue | Dynamic Array | A binary heap as a dynamic array as an implicit data structure |
|
||||
| IntervalHeap <br> _intervalheap.h_ | Double-Ended Priority Queue | Custom Dynamic Array | A dynamic array of nodes, each hosting one value from the MinHeap and one from the MaxHeap |
|
||||
| LinkedList <br> _linkedlist.h_ | List | Doubly-Linked List | A default doubly-linked list |
|
||||
| List <br> _list.h_ | List | Dynamic Array | A dynamic array with `push` and `pop` anywhere on the array |
|
||||
| MultiMap <br> _multimap.h_ | Multimap | Custom Hashtable | A mapping of multiple keys with one node per key using a hashtable with separate chaining |
|
||||
| Multiset <br> _multiset.h_ | Multiset | Hashtable | A mapping of a value and its multiplicity using a hashtable with open addressing and robin hood hashing |
|
||||
| Queue <br> _queue.h_ | FIFO | Dynamic Circular Array | A queue using a circular array with `enqueue` at the `back` index and `dequeue` at the `front` index |
|
||||
| SortedList <br> _sortedlist.h_ | Sorted List | Sorted Dynamic Array | A lazily sorted dynamic array that is sorted only when necessary |
|
||||
| Stack <br> _stack.h_ | FILO | Dynamic Array | A stack with push and pop at the end of a dynamic array |
|
||||
| TreeMap <br> _treemap.h_ | Sorted Map | AVL Tree | A unique set of keys associated with a value `K -> V` using an AVL tree with `log(n)` look up and sorted iteration |
|
||||
| TreeSet <br> _treeset.h_ | Sorted Set | AVL Tree | A unique set of keys using an AVL tree with `log(n)` look up and sorted iteration |
|
||||
| Collection <img width=250/> | Abstract Data Type <img width=250/> | Data Structure <img width=250/> | Details |
|
||||
| :--------------------------------: | :---------------------------------: | :-----------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------: |
|
||||
| BitSet <br> _bitset.h_ | Set | Dynamic Array | A set of bits that can be individually modified and queried, each identified by a bit index |
|
||||
| Deque <br> _deque.h_ | Double-Ended Queue | Dynamic Circular Array | A circular array that allows `push` and `pop` on both ends (only) at constant time |
|
||||
| HashBidiMap <br> _hashbidimap.h_ | Bidirectional Map | Two Hashtables | A bijection between two sets of unique keys and unique values `K <-> V` using two hashtables |
|
||||
| HashMap <br> _hashmap.h_ | Map | Flat Hashtable | A unique set of keys associated with a value `K -> V` with constant time look up using a hashtable with open addressing and robin hood hashing |
|
||||
| HashMultiMap <br> _hashmultimap.h_ | Multimap | Hashtable | A mapping of multiple keys with one node per key using a hashtable with separate chaining |
|
||||
| HashMultiSet <br> _hashmultiset.h_ | Multiset | Flat Hashtable | A mapping of a value and its multiplicity using a hashtable with open addressing and robin hood hashing |
|
||||
| HashSet <br> _hashset.h_ | Set | Flat Hashtable | A unique set of values with constant time look up using a hashtable with open addressing and robin hood hashing |
|
||||
| Heap <br> _heap.h_ | Priority Queue | Dynamic Array | A binary heap as a dynamic array as an implicit data structure |
|
||||
| IntervalHeap <br> _intervalheap.h_ | Double-Ended Priority Queue | Custom Dynamic Array | A dynamic array of nodes, each hosting one value from the MinHeap and one from the MaxHeap |
|
||||
| LinkedList <br> _linkedlist.h_ | List | Doubly-Linked List | A default doubly-linked list |
|
||||
| List <br> _list.h_ | List | Dynamic Array | A dynamic array with `push` and `pop` anywhere on the array |
|
||||
| Queue <br> _queue.h_ | FIFO | Dynamic Circular Array | A queue using a circular array with `enqueue` at the `back` index and `dequeue` at the `front` index |
|
||||
| SkipList <br> _WIP_ | Sorted List | Skip List | A sorted Linked List with average O(log n) search, insertion and deletion complexity |
|
||||
| SortedList <br> _sortedlist.h_ | Sorted List | Sorted Dynamic Array | A lazily sorted dynamic array that is sorted only when necessary |
|
||||
| Stack <br> _stack.h_ | FILO | Dynamic Array | A stack with push and pop at the end of a dynamic array |
|
||||
| TreeBidiMap <br> _WIP_ | Sorted Bidirectional Map | Two AVL Trees | A sorted bijection between two sets of unique keys and unique values `K <-> V` using two AVL trees |
|
||||
| TreeMap <br> _treemap.h_ | Sorted Map | AVL Tree | A unique set of keys associated with a value `K -> V` using an AVL tree with `log(n)` look up and sorted iteration |
|
||||
| TreeMultiMap <br> _WIP_ | Sorted Multimap | AVL Tree | A sorted mapping of multiple keys with one node per key using an AVL Tree of linked-lists |
|
||||
| TreeMultiSet <br> _WIP_ | Sorted Multiset | AVL Tree | A sorted mapping of a value and its multiplicity using an AVL tree |
|
||||
| TreeSet <br> _treeset.h_ | Sorted Set | AVL Tree | A unique set of keys using an AVL tree with `log(n)` look up and sorted iteration |
|
||||
|
||||
## Features
|
||||
## Other Features
|
||||
|
||||
### Two-way iterators
|
||||
These are some features within the library that are implemented by all collections.
|
||||
|
||||
## Two-way iterators
|
||||
|
||||
All collections come with a two-way iterator. You can go back and forwards in constant time and access elements in constant time.
|
||||
|
||||
### Custom Allocation
|
||||
## Custom Allocation
|
||||
|
||||
All collections have a `cmc_alloc_node` which provides pointers to the four dynamic memory allocation functions in C: `malloc`, `calloc`, `realloc` and `free`. These pointers can be customized for each individual collection created or a default can be used, as specified in `cmc_alloc_node_default`.
|
||||
|
||||
### Callbacks
|
||||
## Callbacks
|
||||
|
||||
Every function that operates on a collection can be separated in 5 different types. Create, Read, Update, Delete and (an extra one besides CRUD) Resize. You can define one callback function for each operation. Check out the documentation to see when each callback function is called.
|
||||
|
||||
### Functions Table
|
||||
## Functions Table
|
||||
|
||||
Functions table is a `struct` of function pointers containing 'methods' for a custom data type. Some methods are optional and others are needed in order to a collection to operate. They are:
|
||||
Functions table is a `struct` of function pointers containing 'methods' for a custom data type. Some methods are optional and others are needed in order for a collection to operate. They are:
|
||||
|
||||
#### CMP
|
||||
|
||||
@@ -124,41 +224,32 @@ A priority function works much like the comparator function except that it compa
|
||||
|
||||
The following table shows which functions are required, optional or never used for each Collection:
|
||||
|
||||
| Collection | CMP | CPY | STR | FREE | HASH | PRI |
|
||||
| ---------- | :-: | :-: | :-: | :--: | :--: | :-: |
|
||||
| BidiMap |  |  |  |  |  |  |
|
||||
| Deque |  |  |  |  |  |  |
|
||||
| HashMap |  |  |  |  |  |  |
|
||||
| HashSet |  |  |  |  |  |  |
|
||||
| Heap |  |  |  |  |  |  |
|
||||
| IntervalHeap |  |  |  |  |  |  |
|
||||
| List |  |  |  |  |  |  |
|
||||
| LinkedList |  |  |  |  |  |  |
|
||||
| MultiMap |  |  |  |  |  |  |
|
||||
| MultiSet |  |  |  |  |  |  |
|
||||
| Queue |  |  |  |  |  |  |
|
||||
| SortedList |  |  |  |  |  |  |
|
||||
| Stack |  |  |  |  |  |  |
|
||||
| TreeMap |  |  |  |  |  |  |
|
||||
| TreeSet |  |  |  |  |  |  |
|
||||
| Collection | CMP | CPY | STR | FREE | HASH | PRI |
|
||||
| ------------ | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: |
|
||||
| BitSet |  |  |  |  |  |  |
|
||||
| Deque |  |  |  |  |  |  |
|
||||
| HashMap |  |  |  |  |  |  |
|
||||
| HashBidiMap |  |  |  |  |  |  |
|
||||
| HashMultiMap |  |  |  |  |  |  |
|
||||
| HashMultiSet |  |  |  |  |  |  |
|
||||
| HashSet |  |  |  |  |  |  |
|
||||
| Heap |  |  |  |  |  |  |
|
||||
| IntervalHeap |  |  |  |  |  |  |
|
||||
| List |  |  |  |  |  |  |
|
||||
| LinkedList |  |  |  |  |  |  |
|
||||
| Queue |  |  |  |  |  |  |
|
||||
| SortedList |  |  |  |  |  |  |
|
||||
| Stack |  |  |  |  |  |  |
|
||||
| TreeMap |  |  |  |  |  |  |
|
||||
| TreeSet |  |  |  |  |  |  |
|
||||
|
||||
| Color | Label |
|
||||
| :---: | ----- |
|
||||
|  | Required for basic functionality. |
|
||||
|  | Required for specific functions. |
|
||||
|  | Required for non-core specific functions. |
|
||||
|  | Optional. |
|
||||
|  | Not Used. |
|
||||
|
||||
## Overall To-Do
|
||||
|
||||
In the long term, these are the steps left for the completion of this library:
|
||||
|
||||
* Complete the implementation of all the functions in the scope of the TODO file for the main collections;
|
||||
* Reorganize and complete all tests for the `cmc` collections;
|
||||
* Make an exact copy of all collections to `dev` with many logging utility, for them to be used under development;
|
||||
* Port all of these collections to be statically allocated and be part of the `sac` library;
|
||||
* Complete all tests for `sac`.
|
||||
| Color | Label |
|
||||
| :-------------------------------------------------------------: | ----------------------------------------- |
|
||||
|  | Required for basic functionality. |
|
||||
|  | Required for specific functions. |
|
||||
|  | Required for non-core specific functions. |
|
||||
|  | Optional. |
|
||||
|  | Not Used. |
|
||||
|
||||
## Design Decisions
|
||||
|
||||
@@ -184,76 +275,7 @@ You can use them as Stacks, Queues and Deques, but with modern memory hierarchy
|
||||
|
||||
Modifying a collection will possibly invalidate all iterators currently initialized by it. Currently, the only collection that allows this is the LinkedList (using the node-based functions, not the iterator).
|
||||
|
||||
## What to use
|
||||
## Special Macros
|
||||
|
||||
The following table shows how each collection is implemented and how well they do when using as common [abstract data types](https://en.wikipedia.org/wiki/Abstract_data_type).
|
||||
|
||||
* **Ideal** - The collection implements correctly the abstract data type;
|
||||
* **Not Ideal** - The implementation is fulfilled but some functionalities are either not part of the ADT or not present;
|
||||
* **Bad** - It can be done, but its a bad idea.
|
||||
|
||||

|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## How to use
|
||||
|
||||
To generate the collection, all you need to do is to include the necessary header files. You can include the containers you want to use individually or you can include the master header, `macro_collections.h`, that comes with the entire C-Macro-Collections library.
|
||||
|
||||
### Macros
|
||||
|
||||
> Note here that `SNAME` represents the uppercase name of the collection.
|
||||
|
||||
Every collection is separated by two parts:
|
||||
|
||||
* `HEADER` - Contains all struct definitions and function definitions.
|
||||
* `SOURCE` - Contains all function implementations.
|
||||
|
||||
All collections have three main macros:
|
||||
|
||||
* `CMC_GENERATE_SNAME` - Generates `CMC_GENERATE_SNAME_HEADER` and `CMC_GENERATE_SNAME_SOURCE`.
|
||||
|
||||
Or you can generate each part individually:
|
||||
|
||||
* `CMC_GENERATE_SNAME_HEADER` - Generates all struct definitions and function definitions.
|
||||
* `CMC_GENERATE_SNAME_SOURCE` - Generates all function implementations.
|
||||
|
||||
### Parameters
|
||||
|
||||
When including `macro_collections.h` in your source code you gain access to a macro called `CMC_COLLECTION_GENERATE` with the following parameters:
|
||||
|
||||
* __C__ - Container name in uppercase (*BIDIMAP*, *DEQUE*, *HASHMAP*, *HASHSET*, *HEAP*, *INTERVALHEAP*, *LINKEDLIST*, *LIST*, *MULTIMAP*, *MULTISET*, *QUEUE*, *SORTEDLIST*, *STACK*, *TREEMAP*, *TREESET*).
|
||||
* __PFX__ - Functions prefix or namespace.
|
||||
* __SNAME__ - Structure name (`struct SNAME`).
|
||||
* __K__ - Key type. Only used in *HASHMAP*, *TREEMAP*, *MULTIMAP* and *BIDIMAP*; ignored by others.
|
||||
* __V__ - Value type. Primary type for most collections, or value to be mapped by *HASHMAP*, *TREEMAP*, *MULTIMAP* and *BIDIMAP*.
|
||||
|
||||
**In fact, all macros follow this pattern.** So whenever you see a macro with a bunch of parameters and you don't know what they are, you can check out the above list.
|
||||
|
||||
### For Each
|
||||
|
||||
There are 2 for-each macros:
|
||||
|
||||
* `CMC_FOREACH` - Starts at the start of the collection towards the end.
|
||||
* `CMC_FOREACH_REV` - Starts at the end of the collection towards the start.
|
||||
|
||||
* __PFX__ - Functions prefix or namespace.
|
||||
* __SNAME__ - Structure name.
|
||||
* __TARGET__ - The variable name of the collection you wish to iterate over.
|
||||
* __ITERNAME__ - Iterator variable name.
|
||||
|
||||
For `CMC_FOREACH` and `CMC_FOREACH_REV` you will be able to name the iterator variable through the __ITERNAME__ parameter.
|
||||
|
||||
<hr>
|
||||
|
||||
Check out some code reviews that covers some parts the project:
|
||||
|
||||
| About | Link |
|
||||
|-------|--------|
|
||||
| Unit Test *./utl/test.h* | [](http://codereview.stackexchange.com/q/222954/178948) |
|
||||
| Interval Heap *./cmc/intervalheap.h* | [](http://codereview.stackexchange.com/q/223595/178948) |
|
||||
| Hash Set *./cmc/hashset.h* | [](http://codereview.stackexchange.com/q/217333/178948) |
|
||||
| Linked List *./cmc/linkedlist.h* | [](http://codereview.stackexchange.com/q/216737/178948) |
|
||||
| Others | [](http://codereview.stackexchange.com/q/213553/178948) |
|
||||
* `CMC_NO_ALLOC` - disables `"cor/alloc.h"`, useful for statically allocated collections (SAC)
|
||||
* `CMC_NO_IMPORTS` - disables all imports from the standard library at `"cor/core.h"`
|
||||
@@ -1,19 +1,53 @@
|
||||
TODO
|
||||
|
||||
Patch - Changes that can be released by a patch version
|
||||
Minor - Changes that require a bit more time than a simple patch
|
||||
Major - 1.0.0 version or breaking changes
|
||||
|
||||
The library follows https://semver.org/
|
||||
Check out CHANGELOG
|
||||
|
||||
[/] - In Progress
|
||||
[X] - Finished
|
||||
|
||||
#!! High Priority ----------------------------------------------------------------------------------
|
||||
|
||||
[/] Tests
|
||||
[/] Documentation
|
||||
#!! Next Patch -----------------------------------------------------------------
|
||||
|
||||
#!! Medium Priority --------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#!! Major ----------------------------------------------------------------------
|
||||
|
||||
[ ] Stabilize the library
|
||||
[ ] Add SAC library
|
||||
[ ] Add TSC library
|
||||
[ ] Separate inner Data Structure implementation from the Collection's one
|
||||
[ ] CMC_NAMES - Full customization of function names (see CMC_CAMEL_CASE)
|
||||
[\] Tests
|
||||
[\] Documentation
|
||||
|
||||
|
||||
#!! Minor ----------------------------------------------------------------------
|
||||
|
||||
[ ] Fix BitSet, using capacity vs. counter
|
||||
[ ] #13 - Properly implement HashBidiMap iterator
|
||||
[ ] More SortedList functions
|
||||
[ ] BidiMap's _is_mapping() to check if a mapping K <=> V exists
|
||||
[ ] New asserts - _array_int(), _array_not_in() and str
|
||||
[ ] Add Stack's _peek() and _top() (get by value, get by pointer)
|
||||
[ ] CMC_TIMED for timed blocks
|
||||
[ ] _iter_at() iterator
|
||||
|
||||
|
||||
#!! Patch ----------------------------------------------------------------------
|
||||
|
||||
[ ] MultiSets replace existing value with the new added one
|
||||
|
||||
|
||||
#!! Considerations -------------------------------------------------------------
|
||||
|
||||
[ ] rand.h utility
|
||||
[ ] Redo `while (true)` in hashtables' _insert()
|
||||
[ ] Add to_array and from_array functions
|
||||
|
||||
#!! Being Considered -------------------------------------------------------------------------------
|
||||
|
||||
[ ] Serialization
|
||||
[ ] save {all}
|
||||
[ ] load {all}
|
||||
@@ -22,13 +56,14 @@ TODO
|
||||
[ ] Zip Iterators
|
||||
[ ] Consumer Iterators
|
||||
|
||||
#!! Optimizations ----------------------------------------------------------------------------------
|
||||
|
||||
[ ] Use binary search to find optimum hashtable prime size inside impl_calculate_size
|
||||
[ ] Optimize certain loops that use iterators that can simply use a normal loop
|
||||
[ ] Replace IntervalHeap node by a simple buffer of two pointers (V (*buffer)[2])
|
||||
#!! Optimizations --------------------------------------------------------------
|
||||
|
||||
#!! Done -------------------------------------------------------------------------------------------
|
||||
[ ] Use binary search to find optimum hashtable prime size inside
|
||||
impl_calculate_size
|
||||
|
||||
|
||||
#!! Done -----------------------------------------------------------------------
|
||||
|
||||
[X] Remove PUBLIC and PRIVATE
|
||||
[X] Utility
|
||||
@@ -62,3 +97,8 @@ TODO
|
||||
[X] Merge bidirectional map key_buffer and val_buffer to a single buffer and make key_dist and val_dist into dist[2]
|
||||
[X] Callback utility
|
||||
on_create, on_read, on_update, on_delete, on_resize
|
||||
[X] Replace IntervalHeap node by a simple buffer of two pointers (V (*buffer)[2])
|
||||
[X] PUBLIC and PRIVATE is back (opaque data structures)
|
||||
[X] Add EXT library
|
||||
[X] #12 - Fix the collections that depend on ITER
|
||||
[X] #10 - Fix Benchmarks and Examples
|
||||
@@ -0,0 +1,11 @@
|
||||
CC=gcc
|
||||
INCLUDE=-I ..
|
||||
CFLAGS=-Wall -Wextra -Werror
|
||||
|
||||
benchmark: benchmark.c
|
||||
$(CC) $(CFLAGS) $(INCLUDE) $< -o ./$@.exe -lm
|
||||
./$@.exe
|
||||
|
||||
clean:
|
||||
rm *.exe -f
|
||||
rm *.txt -f
|
||||
+191
-148
@@ -12,13 +12,19 @@
|
||||
* - Iteration
|
||||
* - Output
|
||||
*/
|
||||
#include "macro_collections.h"
|
||||
#include "util/twister.c"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "util/twister.c"
|
||||
|
||||
#include "cmc/cor/hashtable.h"
|
||||
#include "cmc/cor/heap.h"
|
||||
#include "cmc/utl/foreach.h"
|
||||
#include "cmc/utl/futils.h"
|
||||
#include "cmc/utl/timer.h"
|
||||
|
||||
#define NTOTAL UINT64_C(10000000)
|
||||
#define NMIN UINT64_C(100)
|
||||
@@ -26,23 +32,6 @@
|
||||
// Percentage % macro
|
||||
#define PC(x) x * 100.0
|
||||
|
||||
static int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
size_t randsize(size_t min, size_t max, mt_state_ptr st)
|
||||
{
|
||||
return (size_t)floor(twist_real(st) * ((double)max - (double)min + 1.0) + (double)min);
|
||||
@@ -59,136 +48,190 @@ void shuffle(int *array, mt_state_ptr st)
|
||||
}
|
||||
}
|
||||
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d, deque, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm, hmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs, hset, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h, heap, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll, linked, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(LIST, l, list, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q, queue, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(STACK, s, stack, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm, tmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts, tset, /* K */, int)
|
||||
struct
|
||||
{
|
||||
CMC_DEF_FTAB_CMP(size_t);
|
||||
CMC_DEF_FTAB_CPY(size_t);
|
||||
CMC_DEF_FTAB_STR(size_t);
|
||||
CMC_DEF_FTAB_FREE(size_t);
|
||||
CMC_DEF_FTAB_HASH(size_t);
|
||||
CMC_DEF_FTAB_PRI(size_t);
|
||||
} int_ftab = { cmc_size_cmp, NULL, cmc_size_str, NULL, cmc_size_hash, cmc_size_cmp };
|
||||
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih, iheap, /* k */, int)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm, mmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms, mset, /* K */, int)
|
||||
#define CMC_ARGS_FALLTHROUGH
|
||||
#define V int
|
||||
#define K int
|
||||
#define CMC_EXT_ITER
|
||||
|
||||
#define BENCHMARK(NAME, PFX, sname, initfunc, insertbody, removebody, searchbody) \
|
||||
void NAME##_io_benchmark(int *array, int *sarray, size_t s) \
|
||||
{ \
|
||||
printf("+------------------------------------------------------------ %10s\n", #NAME); \
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
struct cmc_timer timer, total; \
|
||||
int r, k, v; \
|
||||
size_t j; \
|
||||
\
|
||||
struct sname *coll = initfunc; \
|
||||
\
|
||||
cmc_timer_start(total); \
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
insertbody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
cmc_timer_calc(timer); \
|
||||
\
|
||||
size_t s1 = PFX##_count(coll); \
|
||||
\
|
||||
#define SNAME bitset
|
||||
#define PFX bs
|
||||
#include "cmc/bitset.h"
|
||||
#define SNAME deque
|
||||
#define PFX d
|
||||
#include "cmc/deque.h"
|
||||
#define SNAME hashbidimap
|
||||
#define PFX hbm
|
||||
#include "cmc/hashbidimap.h"
|
||||
#define SNAME hashmap
|
||||
#define PFX hm
|
||||
#include "cmc/hashmap.h"
|
||||
#define SNAME hashmultimap
|
||||
#define PFX hmm
|
||||
#include "cmc/hashmultimap.h"
|
||||
#define SNAME hashmultiset
|
||||
#define PFX hms
|
||||
#include "cmc/hashmultiset.h"
|
||||
#define SNAME hashset
|
||||
#define PFX hs
|
||||
#include "cmc/hashset.h"
|
||||
#define SNAME heap
|
||||
#define PFX h
|
||||
#include "cmc/heap.h"
|
||||
#define SNAME intervalheap
|
||||
#define PFX ih
|
||||
#include "cmc/intervalheap.h"
|
||||
#define SNAME linkedlist
|
||||
#define PFX ll
|
||||
#include "cmc/linkedlist.h"
|
||||
#define SNAME list
|
||||
#define PFX l
|
||||
#include "cmc/list.h"
|
||||
#define SNAME queue
|
||||
#define PFX q
|
||||
#include "cmc/queue.h"
|
||||
#define SNAME sortedlist
|
||||
#define PFX sl
|
||||
#include "cmc/sortedlist.h"
|
||||
#define SNAME stack
|
||||
#define PFX s
|
||||
#include "cmc/stack.h"
|
||||
#define SNAME treemap
|
||||
#define PFX tm
|
||||
#include "cmc/treemap.h"
|
||||
#define SNAME treeset
|
||||
#define PFX ts
|
||||
#include "cmc/treeset.h"
|
||||
|
||||
#undef CMC_ARGS_FALLTHROUGH
|
||||
#include "cmc/cor/undef.h"
|
||||
|
||||
#define BENCHMARK(NAME, PFX, SNAME, initfunc, insertbody, removebody, searchbody) \
|
||||
void NAME##_io_benchmark(int *array, int *sarray, size_t s) \
|
||||
{ \
|
||||
printf("+------------------------------------------------------------ %10s\n", #NAME); \
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
struct cmc_timer timer, total; \
|
||||
CMC_UNUSED int r; \
|
||||
\
|
||||
struct SNAME *coll = initfunc; \
|
||||
\
|
||||
cmc_timer_start(total); \
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
insertbody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
size_t s1 = PFX##_count(coll); \
|
||||
\
|
||||
printf(" INPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double input_time = timer.result; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < s; i++) \
|
||||
{ \
|
||||
searchbody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
cmc_timer_calc(timer); \
|
||||
\
|
||||
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
|
||||
\
|
||||
double search_time = timer.result; \
|
||||
\
|
||||
struct sname##_iter iter; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (PFX##_iter_init(&iter, coll); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
cmc_timer_calc(timer); \
|
||||
\
|
||||
\
|
||||
double input_time = timer.result; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < s; i++) \
|
||||
{ \
|
||||
searchbody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
|
||||
\
|
||||
double search_time = timer.result; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
CMC_FOREACH (PFX, SNAME, iter, coll) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
printf("ITERATION %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double iter_time = timer.result; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
removebody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
cmc_timer_calc(timer); \
|
||||
\
|
||||
size_t s2 = PFX##_count(coll); \
|
||||
\
|
||||
\
|
||||
double iter_time = timer.result; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
removebody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
size_t s2 = PFX##_count(coll); \
|
||||
\
|
||||
printf(" OUTPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double output_time = timer.result; \
|
||||
\
|
||||
cmc_timer_stop(total); \
|
||||
cmc_timer_calc(total); \
|
||||
\
|
||||
PFX##_free(coll, NULL); \
|
||||
\
|
||||
double adj_search_time = (total.result - search_time) + (search_time * (double)NTOTAL) / (double)s; \
|
||||
double no_search = input_time + iter_time + output_time; \
|
||||
\
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
printf("TOTAL TIME : %.0lf milliseconds\n", total.result); \
|
||||
printf("ADJUSTED TIME : %.0lf milliseconds\n", adj_search_time); \
|
||||
\
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
printf(" INPUT : %5.2lf%% (%5.2f%%)\n", PC(input_time / total.result), PC(input_time / no_search)); \
|
||||
printf(" SEARCH : %5.2lf%%\n", PC(search_time / total.result)); \
|
||||
printf("ITERATION : %5.2lf%% (%5.2f%%)\n", PC(iter_time / total.result), PC(iter_time / no_search)); \
|
||||
\
|
||||
double output_time = timer.result; \
|
||||
\
|
||||
cmc_timer_stop(total); \
|
||||
\
|
||||
PFX##_free(coll); \
|
||||
\
|
||||
double adj_search_time = (total.result - search_time) + (search_time * (double)NTOTAL) / (double)s; \
|
||||
double no_search = input_time + iter_time + output_time; \
|
||||
\
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
printf("TOTAL TIME : %.0lf milliseconds\n", total.result); \
|
||||
printf("ADJUSTED TIME : %.0lf milliseconds\n", adj_search_time); \
|
||||
\
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
printf(" INPUT : %5.2lf%% (%5.2f%%)\n", PC(input_time / total.result), PC(input_time / no_search)); \
|
||||
printf(" SEARCH : %5.2lf%%\n", PC(search_time / total.result)); \
|
||||
printf("ITERATION : %5.2lf%% (%5.2f%%)\n", PC(iter_time / total.result), PC(iter_time / no_search)); \
|
||||
printf(" OUTPUT : %5.2lf%% (%5.2f%%)\n", PC(output_time / total.result), PC(output_time / no_search)); \
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
\
|
||||
assert(s1 == NTOTAL && s2 == 0); \
|
||||
\
|
||||
printf("+------------------------------------------------------------ %10s\n\n", #NAME); \
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
\
|
||||
assert(s1 == NTOTAL && s2 == 0); \
|
||||
\
|
||||
printf("+------------------------------------------------------------ %10s\n\n", #NAME); \
|
||||
}
|
||||
|
||||
BENCHMARK(DEQUE, d, deque, d_new(NTOTAL), d_push_back(coll, array[i]), d_pop_back(coll), d_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(HASHMAP, hm, hmap, hm_new(NTOTAL, 0.6, intcmp, inthash), hm_insert(coll, array[i], array[i]), hm_remove(coll, array[i], &r), hm_contains(coll, sarray[i]))
|
||||
BENCHMARK(HASHSET, hs, hset, hs_new(NTOTAL, 0.6, intcmp, inthash), hs_insert(coll, array[i]), hs_remove(coll, array[i]), hs_contains(coll, sarray[i]))
|
||||
BENCHMARK(HEAP, h, heap, h_new(NTOTAL, cmc_min_heap, intcmp), h_insert(coll, array[i]), h_remove(coll, &r), h_contains(coll, sarray[i]))
|
||||
BENCHMARK(LINKEDLIST, ll, linked, ll_new(), ll_push_back(coll, array[i]), ll_pop_back(coll), ll_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(LIST, l, list, l_new(NTOTAL), l_push_back(coll, array[i]), l_pop_back(coll), l_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(QUEUE, q, queue, q_new(NTOTAL), q_enqueue(coll, array[i]), q_dequeue(coll), q_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(STACK, s, stack, s_new(NTOTAL), s_push(coll, array[i]), s_pop(coll), s_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(TREEMAP, tm, tmap, tm_new(intcmp), tm_insert(coll, array[i], array[i]), tm_remove(coll, array[i], &r), tm_contains(coll, sarray[i]))
|
||||
BENCHMARK(TREESET, ts, tset, ts_new(intcmp), ts_insert(coll, array[i]), ts_remove(coll, array[i]), ts_contains(coll, sarray[i]))
|
||||
BENCHMARK(DEQUE, d, deque, d_new(NTOTAL, (struct deque_fval *)&int_ftab), d_push_back(coll, array[i]), d_pop_back(coll),
|
||||
d_contains(coll, sarray[i]))
|
||||
BENCHMARK(HASHMAP, hm, hashmap, hm_new(NTOTAL, 0.6, (struct hashmap_fkey *)&int_ftab, (struct hashmap_fval *)&int_ftab),
|
||||
hm_insert(coll, array[i], array[i]), hm_remove(coll, array[i], &r), hm_contains(coll, sarray[i]))
|
||||
BENCHMARK(HASHSET, hs, hashset, hs_new(NTOTAL, 0.6, (struct hashset_fval *)&int_ftab), hs_insert(coll, array[i]),
|
||||
hs_remove(coll, array[i]), hs_contains(coll, sarray[i]))
|
||||
BENCHMARK(HEAP, h, heap, h_new(NTOTAL, CMC_MIN_HEAP, (struct heap_fval *)&int_ftab), h_insert(coll, array[i]),
|
||||
h_remove(coll), h_contains(coll, sarray[i]))
|
||||
BENCHMARK(LINKEDLIST, ll, linkedlist, ll_new((struct linkedlist_fval *)&int_ftab), ll_push_back(coll, array[i]),
|
||||
ll_pop_back(coll), ll_contains(coll, sarray[i]))
|
||||
BENCHMARK(LIST, l, list, l_new(NTOTAL, (struct list_fval *)&int_ftab), l_push_back(coll, array[i]), l_pop_back(coll),
|
||||
l_contains(coll, sarray[i]))
|
||||
BENCHMARK(QUEUE, q, queue, q_new(NTOTAL, (struct queue_fval *)&int_ftab), q_enqueue(coll, array[i]), q_dequeue(coll),
|
||||
q_contains(coll, sarray[i]))
|
||||
BENCHMARK(STACK, s, stack, s_new(NTOTAL, (struct stack_fval *)&int_ftab), s_push(coll, array[i]), s_pop(coll),
|
||||
s_contains(coll, sarray[i]))
|
||||
BENCHMARK(TREEMAP, tm, treemap, tm_new((struct treemap_fkey *)&int_ftab, (struct treemap_fval *)&int_ftab),
|
||||
tm_insert(coll, array[i], array[i]), tm_remove(coll, array[i], &r), tm_contains(coll, sarray[i]))
|
||||
BENCHMARK(TREESET, ts, treeset, ts_new((struct treeset_fval *)&int_ftab), ts_insert(coll, array[i]),
|
||||
ts_remove(coll, array[i]), ts_contains(coll, sarray[i]))
|
||||
|
||||
BENCHMARK(INTERVALHEAP, ih, iheap, ih_new(NTOTAL, intcmp), ih_insert(coll, array[i]), ih_remove_max(coll, &r), ih_contains(coll, sarray[i]))
|
||||
BENCHMARK(MULTIMAP, mm, mmap, mm_new(NTOTAL, 0.8, intcmp, inthash), mm_insert(coll, array[i], array[i]), mm_remove(coll, array[i], &r), mm_contains(coll, sarray[i]))
|
||||
BENCHMARK(MULTISET, ms, mset, ms_new(NTOTAL, 0.6, intcmp, inthash), ms_insert(coll, array[i]), ms_remove(coll, array[i]), ms_contains(coll, sarray[i]))
|
||||
BENCHMARK(INTERVALHEAP, ih, intervalheap, ih_new(NTOTAL, (struct intervalheap_fval *)&int_ftab),
|
||||
ih_insert(coll, array[i]), ih_remove_max(coll), ih_contains(coll, sarray[i]))
|
||||
BENCHMARK(MULTIMAP, hmm, hashmultimap,
|
||||
hmm_new(NTOTAL, 0.8, (struct hashmultimap_fkey *)&int_ftab, (struct hashmultimap_fval *)&int_ftab),
|
||||
hmm_insert(coll, array[i], array[i]), hmm_remove(coll, array[i], &r), hmm_contains(coll, sarray[i]))
|
||||
BENCHMARK(MULTISET, hms, hashmultiset, hms_new(NTOTAL, 0.6, (struct hashmultiset_fval *)&int_ftab),
|
||||
hms_insert(coll, array[i]), hms_remove(coll, array[i]), hms_contains(coll, sarray[i]))
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@@ -217,7 +260,8 @@ int main(void)
|
||||
|
||||
shuffle(sarray, &st);
|
||||
|
||||
printf("\nNote: Adjusted Time refers to if the container had done a search over all %" PRIuMAX " elements.\n\n", NTOTAL);
|
||||
printf("\nNote: Adjusted Time refers to if the container had done a search over all %" PRIuMAX " elements.\n\n",
|
||||
NTOTAL);
|
||||
|
||||
// Linear containers have to search for NMIN elements and non-linear (hash
|
||||
// and tree) have to search for all elements.
|
||||
@@ -235,12 +279,11 @@ int main(void)
|
||||
TREEMAP_io_benchmark(array, sarray, NTOTAL);
|
||||
TREESET_io_benchmark(array, sarray, NTOTAL);
|
||||
|
||||
INTERVALHEAP_io_benchmark(array, array, NMIN);
|
||||
MULTIMAP_io_benchmark(array, array, NTOTAL);
|
||||
MULTISET_io_benchmark(array, array, NTOTAL);
|
||||
// INTERVALHEAP_io_benchmark(array, array, NMIN);
|
||||
// MULTIMAP_io_benchmark(array, array, NTOTAL);
|
||||
// MULTISET_io_benchmark(array, array, NTOTAL);
|
||||
|
||||
cmc_timer_stop(timer);
|
||||
cmc_timer_calc(timer);
|
||||
|
||||
printf("+-----------------------------------------------------------+ \n");
|
||||
printf("| Total Benchmark Running Time : %12.0lf seconds | \n", timer.result / 1000);
|
||||
|
||||
@@ -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,2 +0,0 @@
|
||||
main:
|
||||
gcc compile_time.c -c -O3 -ftime-report -I ../../src
|
||||
@@ -1,178 +0,0 @@
|
||||
/* Compilation time for over 90 collections */
|
||||
#include <macro_collections.h>
|
||||
|
||||
struct imaginary
|
||||
{
|
||||
double real;
|
||||
double imag;
|
||||
};
|
||||
|
||||
enum app_state
|
||||
{
|
||||
TRACE = 1,
|
||||
DEBUG = 2,
|
||||
INFO = 3,
|
||||
WARN = 4,
|
||||
ERROR = 5,
|
||||
FATAL = 6
|
||||
};
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd0, bidimap0, struct imaginary, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d0, deque0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm0, hmap0, struct imaginary, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs0, hset0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h0, heap0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih0, iheap0, struct imaginary, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll0, linked0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(LIST, l0, list0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm0, mmap0, struct imaginary, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms0, mset0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(STACK, s0, stack0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl0, sotredlist0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q0, queue0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts0, tset0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm0, tmap0, struct imaginary, struct imaginary)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd1, bidimap1, int, int)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d1, deque1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm1, hmap1, int, int)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs1, hset1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h1, heap1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih1, iheap1, int, int)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll1, linked1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(LIST, l1, list1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm1, mmap1, int, int)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms1, mset1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(STACK, s1, stack1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl1, sotredlist1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q1, queue1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts1, tset1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm1, tmap1, int, int)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd2, bidimap2, double, double)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d2, deque2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm2, hmap2, double, double)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs2, hset2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h2, heap2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih2, iheap2, double, double)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll2, linked2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(LIST, l2, list2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm2, mmap2, double, double)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms2, mset2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(STACK, s2, stack2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl2, sotredlist2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q2, queue2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts2, tset2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm2, tmap2, double, double)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd3, bidimap3, size_t, size_t)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d3, deque3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm3, hmap3, size_t, size_t)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs3, hset3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h3, heap3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih3, iheap3, size_t, size_t)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll3, linked3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(LIST, l3, list3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm3, mmap3, size_t, size_t)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms3, mset3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(STACK, s3, stack3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl3, sotredlist3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q3, queue3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts3, tset3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm3, tmap3, size_t, size_t)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd4, bidimap4, enum app_state, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d4, deque4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm4, hmap4, enum app_state, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs4, hset4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h4, heap4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih4, iheap4, enum app_state, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll4, linked4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(LIST, l4, list4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm4, mmap4, enum app_state, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms4, mset4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(STACK, s4, stack4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl4, sotredlist4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q4, queue4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts4, tset4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm4, tmap4, enum app_state, enum app_state)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd5, bidimap5, void *, void *)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d5, deque5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm5, hmap5, void *, void *)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs5, hset5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h5, heap5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih5, iheap5, void *, void *)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll5, linked5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(LIST, l5, list5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm5, mmap5, void *, void *)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms5, mset5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(STACK, s5, stack5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl5, sotredlist5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q5, queue5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts5, tset5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm5, tmap5, void *, void *)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd6, bidimap6, int *, int *)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d6, deque6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm6, hmap6, int *, int *)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs6, hset6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h6, heap6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih6, iheap6, int *, int *)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll6, linked6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(LIST, l6, list6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm6, mmap6, int *, int *)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms6, mset6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(STACK, s6, stack6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl6, sotredlist6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q6, queue6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts6, tset6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm6, tmap6, int *, int *)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd7, bidimap7, struct imaginary *, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d7, deque7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm7, hmap7, struct imaginary *, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs7, hset7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h7, heap7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih7, iheap7, struct imaginary *, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll7, linked7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(LIST, l7, list7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm7, mmap7, struct imaginary *, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms7, mset7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(STACK, s7, stack7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl7, sotredlist7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q7, queue7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts7, tset7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm7, tmap7, struct imaginary *, struct imaginary *)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd8, bidimap8, double *, double *)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d8, deque8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm8, hmap8, double *, double *)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs8, hset8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h8, heap8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih8, iheap8, double *, double *)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll8, linked8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(LIST, l8, list8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm8, mmap8, double *, double *)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms8, mset8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(STACK, s8, stack8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl8, sotredlist8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q8, queue8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts8, tset8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm8, tmap8, double *, double *)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd9, bidimap9, enum app_state *, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d9, deque9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm9, hmap9, enum app_state *, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs9, hset9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h9, heap9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih9, iheap9, enum app_state *, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll9, linked9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(LIST, l9, list9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm9, mmap9, enum app_state *, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms9, mset9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(STACK, s9, stack9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl9, sotredlist9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q9, queue9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts9, tset9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm9, tmap9, enum app_state *, enum app_state *)
|
||||
@@ -1,433 +0,0 @@
|
||||
#include <macro_collections.h>
|
||||
|
||||
/**
|
||||
* HashMap, MultiMap and BidiMap use hashtables with different strategies. This
|
||||
* benchmark is aimed to explore the pros and cons of each implementation.
|
||||
*
|
||||
* HashMap - A plain hashtable with no indirection using linear probing and
|
||||
* robin hood hashing.
|
||||
* Expectations:
|
||||
* - Constant memory usage which leads to high memory usage per element
|
||||
* ratio when the hashtable has few elements but the ratio is
|
||||
* somewhat good as it starts to fill up;
|
||||
* - Faster lookup due to no indirection and good caching;
|
||||
* - Faster insertion and removal due to no calls to free or malloc.
|
||||
*
|
||||
* MultiMap - A hashtable using separate chaining where each bucket is a doubly
|
||||
* linked list.
|
||||
* Expectations:
|
||||
* - High memory usage per element ratio due to the double linked
|
||||
* lists;
|
||||
* - Pointer indirection might lead to slower lookup and poor caching
|
||||
* due to using nodes to store the key and the value;
|
||||
* - A bit slower insertion and removal as calls to free and malloc are
|
||||
* needed.
|
||||
*
|
||||
* BidiMap - Two arrays, one representing the key set and one the value set.
|
||||
* Each array is made of pointers to an entry. This way one entry can
|
||||
* be referenced by both the key set and the value set using only one
|
||||
* node. Uses robin hood hashing to adjust the pointers.
|
||||
* Expectations:
|
||||
* - Overrall low memory usage compared to other implementations;
|
||||
* - Pointer indirection might lead to slower lookupand poor caching
|
||||
* due to using nodes to store the key and the value;
|
||||
* - Very slow insertion and removal as a node needs to be added or
|
||||
* removed on both arrays.
|
||||
*/
|
||||
|
||||
/* Generate Code */
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hmap, hmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mmap, mmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bmap, bmap, int, int)
|
||||
|
||||
/* Forward declaration of benchmarks */
|
||||
void benchmark_bidimap(const char *collection, int total_elements,
|
||||
double load_factor);
|
||||
void benchmark_hashmap(const char *collection, int total_elements,
|
||||
double load_factor);
|
||||
void benchmark_multimap(const char *collection, int total_elements,
|
||||
double load_factor);
|
||||
|
||||
/* Comparator and Hash function */
|
||||
int cmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
size_t hash(int a)
|
||||
{
|
||||
size_t x = (size_t)a;
|
||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
x = (x >> 16) ^ x;
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Custom allocators to count memory usage */
|
||||
size_t total_memory = 0;
|
||||
|
||||
/* Report Functions */
|
||||
void print_overview(const char *collection, int total_elements,
|
||||
double load_factor)
|
||||
{
|
||||
printf("Overview\n"
|
||||
" Collection : %s\n"
|
||||
" Total Elements : %d\n"
|
||||
" Load Factor : %.4lf\n\n",
|
||||
collection, total_elements, load_factor);
|
||||
}
|
||||
|
||||
void print_time(const char *collection, double C, double R, double U, double D)
|
||||
{
|
||||
/* C - Create, R - Read, U - Update, D - Delete */
|
||||
printf("Time [%s]: \n"
|
||||
" Total : %8.0lf milliseconds \n"
|
||||
" Create : %8.0lf milliseconds\n"
|
||||
" Read : %8.0lf milliseconds\n"
|
||||
" Update : %8.0lf milliseconds\n"
|
||||
" Delete : %8.0lf milliseconds\n\n",
|
||||
collection, C + R + U + D, C, R, U, D);
|
||||
}
|
||||
|
||||
void print_memory(const char *s, size_t memory[11], int partition_size)
|
||||
{
|
||||
printf("Each Partition : %d elements\n\n", partition_size);
|
||||
|
||||
for (size_t i = 0; i < 11; i++)
|
||||
{
|
||||
printf(" %3" PRIuMAX "%% : %12" PRIuMAX " B | %10" PRIuMAX " kB | %8" PRIuMAX " MB (+ %2.0lf%%)\n",
|
||||
i * 10, memory[i], memory[i] / 1000, memory[i] / 1000000, (1 - ((double)memory[0] / (double)memory[i])) * 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom allocation functions */
|
||||
void *my_malloc(size_t size)
|
||||
{
|
||||
void *result = malloc(size);
|
||||
|
||||
if (result)
|
||||
total_memory += size;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void *my_calloc(size_t count, size_t size)
|
||||
{
|
||||
void *result = calloc(count, size);
|
||||
|
||||
if (result)
|
||||
total_memory += count * size;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void *my_realloc(void *buffer, size_t size)
|
||||
{
|
||||
/* This assumes that this benchmark never uses realloc */
|
||||
return realloc(buffer, size);
|
||||
}
|
||||
|
||||
void my_free(void *block)
|
||||
{
|
||||
free(block);
|
||||
}
|
||||
|
||||
/* Default custom allocation node */
|
||||
struct cmc_alloc_node alloc_default = { .malloc = my_malloc,
|
||||
.calloc = my_calloc,
|
||||
.realloc = my_realloc,
|
||||
.free = my_free };
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
if (argc != 4)
|
||||
{
|
||||
fprintf(
|
||||
stderr,
|
||||
"Usage:\n"
|
||||
" %s collection_name total_elements load_factor\n"
|
||||
"\nOPTIONS\n"
|
||||
" - collection_name : (BIDIMAP|HASHMAP|MULTIMAP|ALL)\n"
|
||||
" - total_elements : Total elements to be added to the hashtable (int > 0)\n"
|
||||
" - load_factor : The hashtable's load factor (0 < l < 1.0)\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int total_elements = atoi(argv[2]);
|
||||
double load_factor = atof(argv[3]);
|
||||
|
||||
bool error = false;
|
||||
|
||||
if (total_elements < 1)
|
||||
{
|
||||
error = true;
|
||||
fprintf(stderr, "Invalid value for total_elements: %s\n", argv[2]);
|
||||
}
|
||||
|
||||
if (load_factor <= 0.0 || load_factor >= 1.0)
|
||||
{
|
||||
error = true;
|
||||
fprintf(stderr, "Invalid value for load_factor: %s\n", argv[3]);
|
||||
}
|
||||
|
||||
if (error)
|
||||
return 1;
|
||||
|
||||
const char *collection = argv[1];
|
||||
|
||||
if (strcmp(collection, "BIDIMAP") == 0)
|
||||
{
|
||||
benchmark_bidimap(collection, total_elements, load_factor);
|
||||
}
|
||||
else if (strcmp(collection, "HASHMAP") == 0)
|
||||
{
|
||||
benchmark_hashmap(collection, total_elements, load_factor);
|
||||
}
|
||||
else if (strcmp(collection, "MULTIMAP") == 0)
|
||||
{
|
||||
benchmark_multimap(collection, total_elements, load_factor);
|
||||
}
|
||||
else if (strcmp(collection, "ALL") == 0)
|
||||
{
|
||||
benchmark_bidimap("BIDIMAP", total_elements, load_factor);
|
||||
benchmark_hashmap("HASHMAP", total_elements, load_factor);
|
||||
benchmark_multimap("MULTIMAP", total_elements, load_factor);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Unknown parameter collection_name = %s\n", collection);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void benchmark_bidimap(const char *collection, int total_elements,
|
||||
double load_factor)
|
||||
{
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
|
||||
total_memory = 0;
|
||||
|
||||
/* Normalize total_elements to be a multiple of 10 and calculate partition size */
|
||||
total_elements = total_elements % 10 == 0 ? total_elements : total_elements + (10 - total_elements % 10);
|
||||
int partition = total_elements / 10;
|
||||
|
||||
print_overview(collection, total_elements, load_factor);
|
||||
|
||||
struct bmap *map = bmap_new_custom(total_elements, load_factor, cmp, hash,
|
||||
cmp, hash, &alloc_default, NULL);
|
||||
|
||||
/* Create, Read, Update, Delete */
|
||||
struct cmc_timer timers[4] = { 0 };
|
||||
|
||||
/* Memory Usage 0%, 10%, 20%, ... 100% */
|
||||
size_t memory[11] = {0};
|
||||
|
||||
memory[0] = total_memory;
|
||||
|
||||
/* Create */
|
||||
cmc_timer_start(timers[0]);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
for (int j = partition * i; j < partition * (i + 1); j++)
|
||||
{
|
||||
bmap_insert(map, j, j);
|
||||
}
|
||||
|
||||
memory[i + 1] = total_memory;
|
||||
}
|
||||
|
||||
cmc_timer_stop(timers[0]);
|
||||
cmc_timer_calc(timers[0]);
|
||||
/* Create End */
|
||||
|
||||
/* Read */
|
||||
cmc_timer_start(timers[1]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
bmap_contains_key(map, i);
|
||||
|
||||
cmc_timer_stop(timers[1]);
|
||||
cmc_timer_calc(timers[1]);
|
||||
/* Read End */
|
||||
|
||||
/* Update */
|
||||
cmc_timer_start(timers[2]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
bmap_update_val_by_key(map, i, total_elements - i - 1);
|
||||
|
||||
cmc_timer_stop(timers[2]);
|
||||
cmc_timer_calc(timers[2]);
|
||||
/* Update End */
|
||||
|
||||
/* Delete */
|
||||
cmc_timer_start(timers[3]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
bmap_remove_by_key(map, i, NULL, NULL);
|
||||
|
||||
cmc_timer_stop(timers[3]);
|
||||
cmc_timer_calc(timers[3]);
|
||||
/* Delete End */
|
||||
|
||||
print_time(collection, timers[0].result, timers[1].result, timers[2].result,
|
||||
timers[3].result);
|
||||
|
||||
print_memory(collection, memory, partition);
|
||||
|
||||
bmap_free(map, NULL);
|
||||
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
}
|
||||
|
||||
void benchmark_hashmap(const char *collection, int total_elements,
|
||||
double load_factor)
|
||||
{
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
|
||||
total_memory = 0;
|
||||
|
||||
/* Normalize total_elements to be a multiple of 10 and calculate partition size */
|
||||
total_elements = total_elements % 10 == 0 ? total_elements : total_elements + (10 - total_elements % 10);
|
||||
int partition = total_elements / 10;
|
||||
|
||||
print_overview(collection, total_elements, load_factor);
|
||||
|
||||
struct hmap *map = hmap_new_custom(total_elements, load_factor, cmp, hash, &alloc_default, NULL);
|
||||
|
||||
/* Create, Read, Update, Delete */
|
||||
struct cmc_timer timers[4] = { 0 };
|
||||
|
||||
/* Memory Usage 0%, 10%, 20%, ... 100% */
|
||||
size_t memory[11] = {0};
|
||||
|
||||
memory[0] = total_memory;
|
||||
|
||||
/* Create */
|
||||
cmc_timer_start(timers[0]);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
for (int j = partition * i; j < partition * (i + 1); j++)
|
||||
{
|
||||
hmap_insert(map, j, j);
|
||||
}
|
||||
|
||||
memory[i + 1] = total_memory;
|
||||
}
|
||||
|
||||
cmc_timer_stop(timers[0]);
|
||||
cmc_timer_calc(timers[0]);
|
||||
/* Create End */
|
||||
|
||||
/* Read */
|
||||
cmc_timer_start(timers[1]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
hmap_contains(map, i);
|
||||
|
||||
cmc_timer_stop(timers[1]);
|
||||
cmc_timer_calc(timers[1]);
|
||||
/* Read End */
|
||||
|
||||
/* Update */
|
||||
cmc_timer_start(timers[2]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
hmap_update(map, i, total_elements - i - 1, NULL);
|
||||
|
||||
cmc_timer_stop(timers[2]);
|
||||
cmc_timer_calc(timers[2]);
|
||||
/* Update End */
|
||||
|
||||
/* Delete */
|
||||
cmc_timer_start(timers[3]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
hmap_remove(map, i, NULL);
|
||||
|
||||
cmc_timer_stop(timers[3]);
|
||||
cmc_timer_calc(timers[3]);
|
||||
/* Delete End */
|
||||
|
||||
print_time(collection, timers[0].result, timers[1].result, timers[2].result,
|
||||
timers[3].result);
|
||||
|
||||
print_memory(collection, memory, partition);
|
||||
|
||||
hmap_free(map, NULL);
|
||||
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
}
|
||||
|
||||
void benchmark_multimap(const char *collection, int total_elements,
|
||||
double load_factor)
|
||||
{
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
|
||||
total_memory = 0;
|
||||
|
||||
/* Normalize total_elements to be a multiple of 10 and calculate partition size */
|
||||
total_elements = total_elements % 10 == 0 ? total_elements : total_elements + (10 - total_elements % 10);
|
||||
int partition = total_elements / 10;
|
||||
|
||||
print_overview(collection, total_elements, load_factor);
|
||||
|
||||
struct mmap *map = mmap_new_custom(total_elements, load_factor, cmp, hash, &alloc_default, NULL);
|
||||
|
||||
/* Create, Read, Update, Delete */
|
||||
struct cmc_timer timers[4] = { 0 };
|
||||
|
||||
/* Memory Usage 0%, 10%, 20%, ... 100% */
|
||||
size_t memory[11] = {0};
|
||||
|
||||
memory[0] = total_memory;
|
||||
|
||||
/* Create */
|
||||
cmc_timer_start(timers[0]);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
for (int j = partition * i; j < partition * (i + 1); j++)
|
||||
{
|
||||
mmap_insert(map, j, j);
|
||||
}
|
||||
|
||||
memory[i + 1] = total_memory;
|
||||
}
|
||||
|
||||
cmc_timer_stop(timers[0]);
|
||||
cmc_timer_calc(timers[0]);
|
||||
/* Create End */
|
||||
|
||||
/* Read */
|
||||
cmc_timer_start(timers[1]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
mmap_contains(map, i);
|
||||
|
||||
cmc_timer_stop(timers[1]);
|
||||
cmc_timer_calc(timers[1]);
|
||||
/* Read End */
|
||||
|
||||
/* Update */
|
||||
cmc_timer_start(timers[2]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
mmap_update(map, i, total_elements - i - 1, NULL);
|
||||
|
||||
cmc_timer_stop(timers[2]);
|
||||
cmc_timer_calc(timers[2]);
|
||||
/* Update End */
|
||||
|
||||
/* Delete */
|
||||
cmc_timer_start(timers[3]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
mmap_remove(map, i, NULL);
|
||||
|
||||
cmc_timer_stop(timers[3]);
|
||||
cmc_timer_calc(timers[3]);
|
||||
/* Delete End */
|
||||
|
||||
print_time(collection, timers[0].result, timers[1].result, timers[2].result,
|
||||
timers[3].result);
|
||||
|
||||
print_memory(collection, memory, partition);
|
||||
|
||||
mmap_free(map, NULL);
|
||||
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
CFLAGS = -Wall -Wextra
|
||||
INCLUDE = ../../src
|
||||
|
||||
main:
|
||||
gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DCMC_QUEUE
|
||||
a.exe
|
||||
gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DSAC_QUEUE
|
||||
a.exe
|
||||
@@ -1,76 +0,0 @@
|
||||
/**
|
||||
* queue.c
|
||||
*
|
||||
* Creation Date: 24/06/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/* Showing off how different queue implementations affect runtime cost */
|
||||
|
||||
#include "utl/timer.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define MAX 200000
|
||||
|
||||
#if defined(CMC_QUEUE)
|
||||
#include "cmc/queue.h"
|
||||
CMC_GENERATE_QUEUE(q, queue, int)
|
||||
#define TARGET "QUEUE"
|
||||
#elif defined(SAC_QUEUE)
|
||||
#include "sac/queue.h"
|
||||
SAC_QUEUE_GENERATE(q, queue, , int, MAX)
|
||||
#define TARGET "SAC QUEUE"
|
||||
#else
|
||||
#error Please define either CMC_QUEUE, SAC_QUEUE or EXT_QUEUE
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
#if defined(CMC_QUEUE)
|
||||
struct queue *q = q_new(MAX);
|
||||
#elif defined(SAC_QUEUE)
|
||||
queue _q = q_new();
|
||||
queue_ptr q = &_q;
|
||||
#endif
|
||||
|
||||
size_t sum = 0;
|
||||
int i = 0;
|
||||
|
||||
struct cmc_timer timer;
|
||||
cmc_timer_start(timer);
|
||||
|
||||
while (q_count(q) != MAX)
|
||||
{
|
||||
q_enqueue(q, i++);
|
||||
|
||||
if (i % 10 == 0)
|
||||
{
|
||||
for (size_t i = 0; i < 9; i++)
|
||||
{
|
||||
sum += q_peek(q);
|
||||
q_dequeue(q);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cmc_timer_stop(timer);
|
||||
cmc_timer_calc(timer);
|
||||
|
||||
printf("----------------------------------------\n");
|
||||
printf("%s\n", TARGET);
|
||||
printf("Execution time: %.0lf milliseconds\n", timer.result);
|
||||
printf("SUM: %" PRIuMAX "\n", sum);
|
||||
printf("----------------------------------------\n");
|
||||
|
||||
#if defined(CMC_QUEUE)
|
||||
q_free(q, NULL);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -1,3 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Library.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* hashtable.h
|
||||
*
|
||||
@@ -12,8 +36,8 @@
|
||||
* Things commonly used by hashtable-based collections.
|
||||
*/
|
||||
|
||||
#ifndef CMC_IMPL_HASHTABLE_H
|
||||
#define CMC_IMPL_HASHTABLE_H
|
||||
#ifndef CMC_COR_HASHTABLE_H
|
||||
#define CMC_COR_HASHTABLE_H
|
||||
|
||||
#include "core.h"
|
||||
|
||||
@@ -39,7 +63,8 @@ enum cmc_entry_state
|
||||
/**
|
||||
* static const size_t cmc_hashtable_primes[59]
|
||||
*
|
||||
* Prime numbers used to define a capacity for the hashtables for better hashing.
|
||||
* Prime numbers used to define a capacity for the hashtables for better
|
||||
* hashing.
|
||||
*/
|
||||
// clang-format off
|
||||
static const size_t cmc_hashtable_primes[] = {
|
||||
@@ -82,4 +107,4 @@ static const size_t cmc_hashtable_primes[] = {
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
#endif /* CMC_IMPL_HASHTABLE_H */
|
||||
#endif /* CMC_COR_HASHTABLE_H */
|
||||
@@ -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 */
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* List bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_ITER
|
||||
|
||||
#endif /* CMC_EXT_ITER */
|
||||
Loaded 100 of 492 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user